/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2023 Red Hat */ #ifndef INDEXER_H #define INDEXER_H #include <linux/mutex.h> #include <linux/sched.h> #include <linux/types.h> #include <linux/wait.h> #include "funnel-queue.h" /* * UDS public API * * The Universal Deduplication System (UDS) is an efficient name-value store. When used for * deduplicating storage, the names are generally hashes of data blocks and the associated data is * where that block is located on the underlying storage medium. The stored names are expected to * be randomly distributed among the space of possible names. If this assumption is violated, the * UDS index will store fewer names than normal but will otherwise continue to work. The data * associated with each name can be any 16-byte value. * * A client must first create an index session to interact with an index. Once created, the session * can be shared among multiple threads or users. When a session is destroyed, it will also close * and save any associated index. * * To make a request, a client must allocate a uds_request structure and set the required fields * before launching it. UDS will invoke the provided callback to complete the request. After the * callback has been called, the uds_request structure can be freed or reused for a new request. * There are five types of requests: * * A UDS_UPDATE request will associate the provided name with the provided data. Any previous data * associated with that name will be discarded. * * A UDS_QUERY request will return the data associated with the provided name, if any. The entry * for the name will also be marked as most recent, as if the data had been updated. * * A UDS_POST request is a combination of UDS_QUERY and UDS_UPDATE. If there is already data * associated with the provided name, that data is returned. If there is no existing association, * the name is associated with the newly provided data. This request is equivalent to a UDS_QUERY * request followed by a UDS_UPDATE request if no data is found, but it is much more efficient. * * A UDS_QUERY_NO_UPDATE request will return the data associated with the provided name, but will * not change the recency of the entry for the name. This request is primarily useful for testing, * to determine whether an entry exists without changing the internal state of the index. * * A UDS_DELETE request removes any data associated with the provided name. This operation is * generally not necessary, because the index will automatically discard its oldest entries once it * becomes full. */ /* General UDS constants and structures */ enum uds_request_type { … }; enum uds_open_index_type { … }; enum { … }; /* * A type representing a UDS memory configuration which is either a positive integer number of * gigabytes or one of the six special constants for configurations smaller than one gigabyte. */ uds_memory_config_size_t; enum { … }; struct uds_record_name { … }; struct uds_record_data { … }; struct uds_volume_record { … }; struct uds_parameters { … }; /* * These statistics capture characteristics of the current index, including resource usage and * requests processed since the index was opened. */ struct uds_index_stats { … }; enum uds_index_region { … } __packed; /* Zone message requests are used to communicate between index zones. */ enum uds_zone_message_type { … } __packed; struct uds_zone_message { … }; struct uds_index_session; struct uds_index; struct uds_request; /* Once this callback has been invoked, the uds_request structure can be reused or freed. */ uds_request_callback_fn; struct uds_request { … }; /* Compute the number of bytes needed to store an index. */ int __must_check uds_compute_index_size(const struct uds_parameters *parameters, u64 *index_size); /* A session is required for most index operations. */ int __must_check uds_create_index_session(struct uds_index_session **session); /* Destroying an index session also closes and saves the associated index. */ int uds_destroy_index_session(struct uds_index_session *session); /* * Create or open an index with an existing session. This operation fails if the index session is * suspended, or if there is already an open index. */ int __must_check uds_open_index(enum uds_open_index_type open_type, const struct uds_parameters *parameters, struct uds_index_session *session); /* * Wait until all callbacks for index operations are complete, and prevent new index operations * from starting. New index operations will fail with EBUSY until the session is resumed. Also * optionally saves the index. */ int __must_check uds_suspend_index_session(struct uds_index_session *session, bool save); /* * Allow new index operations for an index, whether it was suspended or not. If the index is * suspended and the supplied block device differs from the current backing store, the index will * start using the new backing store instead. */ int __must_check uds_resume_index_session(struct uds_index_session *session, struct block_device *bdev); /* Wait until all outstanding index operations are complete. */ int __must_check uds_flush_index_session(struct uds_index_session *session); /* Close an index. This operation fails if the index session is suspended. */ int __must_check uds_close_index(struct uds_index_session *session); /* Get index statistics since the last time the index was opened. */ int __must_check uds_get_index_session_stats(struct uds_index_session *session, struct uds_index_stats *stats); /* This function will fail if any required field of the request is not set. */ int __must_check uds_launch_request(struct uds_request *request); struct cond_var { … }; static inline void uds_init_cond(struct cond_var *cv) { … } static inline void uds_signal_cond(struct cond_var *cv) { … } static inline void uds_broadcast_cond(struct cond_var *cv) { … } void uds_wait_cond(struct cond_var *cv, struct mutex *mutex); #endif /* INDEXER_H */