?
/**
@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_PROCESS_TREE_MAX_SIZE 32
#define FILE_CONTEXT_PROCESS_TREE_LRU_CLEAN_SIZE 10
#define FILE_CONTEXT_BIG_TABLE_SIZE_BITS 15 // 32768
#define FILE_CONTEXT_BIG_TABLE_SIZE (1 << (FILE_CONTEXT_BIG_TABLE_SIZE_BITS - 1)) // 16384
#define FILE_CONTEXT_BIG_TABLE_LRU_CLEAN_SIZE (100)
#define FILE_CONTEXT_BIG_TABLE_EXPIRE_TIME_MS (24 * 60 * 60 * 1000)
#define FILE_CONTEXT_RW_TABLE_EXPIRE_TIME_MS (180 * 1000)
#define FILE_CONTEXT_TREE_EXPIRE_TIME_MS (180 * 1000)
#define FILE_CONTEXT_LONGEST_EXPIRE_TIME_MS (24 * 60 * 60 * 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)
/*
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
{
uint64_t key;
// node in file_context_common_table_t->lru_list
bool lru_list_node_inserted;
struct list_head lru_list_node;
unsigned long last_access_time;
atomic_t ref_count;
} file_context_common_node_t;
typedef void (*file_contexts_rcu_free_func_t)(struct rcu_head*);
typedef struct
{
file_context_common_node_t common;
// node in file_context_common_table_t->hashtable
struct hlist_node node;
struct rcu_head rcu;
file_contexts_rcu_free_func_t free_func;
} file_context_ht_node_t;
// Abstraction of tables
typedef struct
{
struct list_head lru_list;
unsigned int size;
uint8_t hashbits;
unsigned short clean_count;
unsigned int max_size;
unsigned long expire_time_jiffies;
spinlock_t spinlock;
struct hlist_head hashtable[];
} file_context_common_table_t;
typedef struct
{
struct rb_root tree;
struct list_head lru_list;
unsigned int size;
unsigned short clean_count;
unsigned int max_size;
spinlock_t spinlock;
} file_context_tree_t;
typedef struct file_context_tree_node_s file_context_tree_node_t;
typedef void (*file_contexts_tree_free_func_t)(file_context_tree_node_t*);
struct file_context_tree_node_s
{
file_context_common_node_t common;
// node in file_context_tree_t->tree
union {
struct rb_node node;
struct list_head free_node;
};
file_contexts_tree_free_func_t free_func;
};
// A big hashtable struct to store file_context_open_file_node_t, file_context_rw_node_t, the key is inode ptr
typedef struct
{
atomic_t ref_count;
struct rcu_head rcu;
file_context_common_table_t common_table; /*varsized*/
} file_context_big_table_t;
// Context that is global per file
typedef struct
{
atomic_t flags;
unsigned long deadline;
} file_context_open_file_t;
// Context that is global per file + process
typedef struct
{
atomic_t flags;
unsigned long deadline;
} file_context_open_process_t;
typedef struct
{
interval_set_t interval_set;
spinlock_t spinlock;
atomic_t is_reported;
} file_context_rw_t;
// Node in process_table
typedef struct
{
file_context_tree_node_t node;
file_context_open_process_t data;
} file_context_open_process_node_t;
// Node in open_table
typedef struct
{
file_context_ht_node_t node;
file_context_key_t key;
file_context_open_file_t data;
// pid_version->file_context_open_process_node_t
file_context_tree_t process_lookup;
} file_context_open_file_node_t;
typedef struct
{
uint64_t low;
uint64_t high;
struct rb_node rb;
// node in temporary delete list
union {
struct list_head del_list_node;
struct list_head stack_node;
};
} interval_node_t;
// Node in read_table/write_table
typedef struct
{
file_context_ht_node_t node;
file_context_key_t key;
file_context_rw_t data;
} file_context_rw_node_t;
typedef struct
{
file_context_ht_node_t node;
file_context_key_t key;
// pid_version->file_context_process_node_t
file_context_tree_t process_lookup;
} file_context_file_modify_node_t;
typedef struct
{
uint64_t transport_id;
// 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;
} file_context_tables_t;
typedef struct
{
spinlock_t writer_lock;
file_context_tables_t* tables_for_transport[MAX_TRANSPORT_SIZE];
file_context_big_table_t* close_modified_table;
} file_context_manager_t;