/** @file file_contexts.h @brief Store the opened file contexts(inode + pid) @details Copyright (c) 2023 Acronis International GmbH @author Bruce Wang ([email protected]) @since $Id: $ */ #pragma once #include "interval_tree.h" #include "transport.h" #include "transport_id.h" #include "transport_protocol.h" #define FILE_CONTEXT_MAX_FILE_SIZE (100 * 1024 * 1024) typedef struct { long long tv_sec; long tv_nsec; } timespec_compat_t; typedef struct { file_key_t file_key; timespec_compat_t i_mtime; /* last modify time */ timespec_compat_t i_ctime; /* last change time */ } file_context_key_t; // This struct is stored in msg_t, to keep the necessary information typedef struct { file_context_key_t key; transport_id_t skipped_transport_ids[MAX_TRANSPORT_SIZE]; } file_context_msg_info_t; // Particular event properties that are being cached. typedef union { struct { int flags; } open; struct { uint64_t low; uint64_t high; } rw; } file_context_params_t; // This struct used for all request to add to cache from userspace. typedef struct { // You may pass pid_key==0 to apply per inode instead of per process // pid_key could be either unique_pid or pid_version depending on the caching policy. // For 'MODIFY+CLOSE' events it is unique_pid, for everything else pid_version uint64_t pid_key; file_context_params_t params; uint32_t ttl_s; file_context_key_t key; } file_context_add_cache_request_t; // A struct to store the temporary file context information during message creation hence checking. typedef struct { uint64_t pid_key; file_context_params_t params; file_context_msg_info_t msg_info; } file_context_info_t; // Module is loaded/unloaded functions /** * @brief Initialize the file contexts module. * @return 0 on success, negative value on failure. */ int file_contexts_init(void); /** * @brief Frees all resources allocated assuming that module start has failed. */ void file_contexts_init_fail_free(void); /** * @brief Deinitialize the file contexts module and free all resources. */ void file_contexts_deinit(void); // Internal maintainance function that gets called when inode needs to be removed. // Usually this happens when node is unlinked/created or on 'inode_free'. /** * @brief Remove all cache entries associated with a given file key (inode). * @param file_key Pointer to the file key (inode) to remove from cache. */ void remove_common_cache_all(const file_key_t* file_key); // Reserve context id table from transport allocation/deallocation. /** * @brief Reserve a context ID table entry for a given transport ID. * @param id Transport ID to reserve entry for. * @return 0 on success, negative value on failure. */ int acquire_file_context_entry(transport_id_t id); /** * @brief Release a reserved context ID table entry for a given transport ID. * @param id Transport ID to release entry for. */ void release_file_context_entry(transport_id_t id); // Each file context cache has "message" and "client" sides. // When "message" needs to be generated, "check" functions are used with "file_context_info_t", // when client decides to cache, "add" functions are used with "file_context_add_cache_request_t". /* --- OPEN --- */ /** * @brief Check if an open event is cached for the given transport IDs and file context info. * @param ids Pointer to transport IDs. * @param info Pointer to file context info to check. * @return true if cached, false otherwise. */ bool check_open_cache(const transport_ids_t* ids, file_context_info_t* info); /** * @brief Add an open event to the cache for the given transport ID and request. * @param id Transport ID. * @param req Pointer to the cache request. * @return 0 on success, negative value on failure. */ int add_open_cache(transport_id_t id, const file_context_add_cache_request_t* req); /* --- READ/WRITE --- */ /** * @brief Add a read/write event to the cache for the given transport ID, request, and table type. * @param id Transport ID. * @param req Pointer to the cache request. * @param type Table type (read/write). * @return 0 on success, negative value on failure. */ int add_write_cache(transport_id_t id, const file_context_add_cache_request_t* req); /** * @brief Check and update the read cache for the given transport IDs and file context info. * @param ids Pointer to transport IDs. * @param info Pointer to file context info to check and update. * @return true if cache was updated, false otherwise. */ bool check_and_update_read_cache(const transport_ids_t* ids, file_context_info_t *info); /** * @brief Check the write cache for the given transport IDs, file context info, and table type. * @param ids Pointer to transport IDs. * @param info Pointer to file context info to check. * @param type Table type (write). * @return true if cached, false otherwise. */ bool check_write_cache(const transport_ids_t* ids, file_context_info_t *info); // Special cache that is for "file modify" events. // When any modification event happens (fsnotify_modify), an extra node is added in. // On "close" event is being taken from the cache (check_update) to send file modified flag. /** * @brief Reserve an entry for file modification events in the cache. * @return 0 on success, negative value on failure. */ int acquire_file_modify_entry(void); /** * @brief Release a reserved entry for file modification events in the cache. */ void release_file_modify_entry(void); /** * @brief Add a file modification event to the cache on "MODIFY". * @param info Pointer to the cache request. * @return true on success, false otherwise. */ bool add_file_modify_cache(const file_context_add_cache_request_t *info); /** * @brief Check and update the file modification cache for the given file context info on "CLOSE". * @param info Pointer to file context info to check and update. * @return true if cache was updated, false otherwise. */ bool check_update_file_modify_cache(file_context_info_t *info); /** * @brief Allocate a file context table for the given transport ID and table type. * @param id Transport ID. * @param type Table type to allocate. * @return 0 on success, negative value on failure. */ int acquire_file_context_table(transport_id_t id, file_context_table_type_t type);