Currently, the codebase only supports a single instance during the entire running time. This will be extended to allow 3rd-party applications to formally use liberofs with multiple instances simultaneously. Therefore, it is necessary to separate global initialization from per-instance initialization.
Another point is that libcurl will be used for other remote backends, so it also needs to be separated from the current S3 backend. Signed-off-by: Gao Xiang <hsiang...@linux.alibaba.com> --- v2: - update the commit message; - fix non-MT compile error. include/erofs/internal.h | 3 ++ include/erofs/lock.h | 6 ++++ lib/Makefile.am | 5 ++-- lib/global.c | 55 ++++++++++++++++++++++++++++++++++ lib/liberofs_s3.h | 1 + lib/remotes/s3.c | 65 ++++++++++++++++++---------------------- mkfs/main.c | 22 +++++++------- 7 files changed, 109 insertions(+), 48 deletions(-) create mode 100644 lib/global.c diff --git a/include/erofs/internal.h b/include/erofs/internal.h index e9b9099..92e83fd 100644 --- a/include/erofs/internal.h +++ b/include/erofs/internal.h @@ -426,6 +426,9 @@ struct erofs_map_dev { unsigned int m_deviceid; }; +int liberofs_global_init(void); +void liberofs_global_exit(void); + /* super.c */ int erofs_read_superblock(struct erofs_sb_info *sbi); void erofs_put_super(struct erofs_sb_info *sbi); diff --git a/include/erofs/lock.h b/include/erofs/lock.h index f7a4b47..c6e3093 100644 --- a/include/erofs/lock.h +++ b/include/erofs/lock.h @@ -16,6 +16,9 @@ static inline void erofs_mutex_init(erofs_mutex_t *lock) #define erofs_mutex_lock pthread_mutex_lock #define erofs_mutex_unlock pthread_mutex_unlock +#define EROFS_DEFINE_MUTEX(lock) \ + erofs_mutex_t lock = PTHREAD_MUTEX_INITIALIZER + typedef pthread_rwlock_t erofs_rwsem_t; static inline void erofs_init_rwsem(erofs_rwsem_t *lock) @@ -33,6 +36,9 @@ static inline void erofs_mutex_init(erofs_mutex_t *lock) {} static inline void erofs_mutex_lock(erofs_mutex_t *lock) {} static inline void erofs_mutex_unlock(erofs_mutex_t *lock) {} +#define EROFS_DEFINE_MUTEX(lock) \ + erofs_mutex_t lock = {} + typedef struct {} erofs_rwsem_t; static inline void erofs_init_rwsem(erofs_rwsem_t *lock) {} static inline void erofs_down_read(erofs_rwsem_t *lock) {} diff --git a/lib/Makefile.am b/lib/Makefile.am index b079897..a3972b1 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -29,7 +29,8 @@ noinst_HEADERS = $(top_srcdir)/include/erofs_fs.h \ $(top_srcdir)/include/erofs/rebuild.h \ $(top_srcdir)/lib/liberofs_private.h \ $(top_srcdir)/lib/liberofs_xxhash.h \ - $(top_srcdir)/lib/liberofs_metabox.h + $(top_srcdir)/lib/liberofs_metabox.h \ + $(top_srcdir)/lib/liberofs_s3.h noinst_HEADERS += compressor.h liberofs_la_SOURCES = config.c io.c cache.c super.c inode.c xattr.c exclude.c \ @@ -37,7 +38,7 @@ liberofs_la_SOURCES = config.c io.c cache.c super.c inode.c xattr.c exclude.c \ compress_hints.c hashmap.c sha256.c blobchunk.c dir.c \ fragments.c dedupe.c uuid_unparse.c uuid.c tar.c \ block_list.c rebuild.c diskbuf.c bitops.c dedupe_ext.c \ - vmdk.c metabox.c + vmdk.c metabox.c global.c liberofs_la_CFLAGS = -Wall ${libuuid_CFLAGS} -I$(top_srcdir)/include if ENABLE_LZ4 diff --git a/lib/global.c b/lib/global.c new file mode 100644 index 0000000..2f9abd6 --- /dev/null +++ b/lib/global.c @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0+ OR Apache-2.0 +/* + * Copyright (C) 2025 Alibaba Cloud + */ +#include "erofs/lock.h" +#ifdef HAVE_CURL_CURL_H +#include <curl/curl.h> +#endif +#ifdef HAVE_LIBXML_PARSER_H +#include <libxml/parser.h> +#endif +#include "erofs/err.h" +#include "erofs/config.h" + +static EROFS_DEFINE_MUTEX(erofs_global_mutex); +static bool erofs_global_curl_initialized; + +int liberofs_global_init(void) +{ + int err = 0; + + erofs_mutex_lock(&erofs_global_mutex); + erofs_init_configure(); +#ifdef S3EROFS_ENABLED + xmlInitParser(); +#endif +#ifdef HAVE_LIBCURL + if (!erofs_global_curl_initialized) { + if (curl_global_init(CURL_GLOBAL_DEFAULT) != CURLE_OK) { + err = -EFAULT; + goto out_unlock; + } + erofs_global_curl_initialized = true; + } +out_unlock: +#endif + erofs_mutex_unlock(&erofs_global_mutex); + return err; +} + +void liberofs_global_exit(void) +{ + erofs_mutex_lock(&erofs_global_mutex); +#ifdef HAVE_LIBCURL + if (erofs_global_curl_initialized) { + curl_global_cleanup(); + erofs_global_curl_initialized = false; + } +#endif +#ifdef S3EROFS_ENABLED + xmlCleanupParser(); +#endif + erofs_exit_configure(); + erofs_mutex_unlock(&erofs_global_mutex); +} diff --git a/lib/liberofs_s3.h b/lib/liberofs_s3.h index 27b041c..a178c64 100644 --- a/lib/liberofs_s3.h +++ b/lib/liberofs_s3.h @@ -25,6 +25,7 @@ enum s3erofs_signature_version { #define S3_SECRET_KEY_LEN 256 struct erofs_s3 { + void *easy_curl; const char *endpoint; char access_key[S3_ACCESS_KEY_LEN + 1]; char secret_key[S3_SECRET_KEY_LEN + 1]; diff --git a/lib/remotes/s3.c b/lib/remotes/s3.c index 1497b54..f4a364d 100644 --- a/lib/remotes/s3.c +++ b/lib/remotes/s3.c @@ -26,8 +26,6 @@ #define BASE64_ENCODE_LEN(len) (((len + 2) / 3) * 4) -static CURL *easy_curl; - struct s3erofs_query_params { int num; const char *key[S3EROFS_MAX_QUERY_PARAMS]; @@ -213,6 +211,7 @@ static int s3erofs_request_perform(struct erofs_s3 *s3, struct s3erofs_curl_request *req, void *resp) { struct curl_slist *request_headers = NULL; + CURL *curl = s3->easy_curl; long http_code = 0; int ret; @@ -226,11 +225,11 @@ static int s3erofs_request_perform(struct erofs_s3 *s3, } } - curl_easy_setopt(easy_curl, CURLOPT_URL, req->url); - curl_easy_setopt(easy_curl, CURLOPT_WRITEDATA, resp); - curl_easy_setopt(easy_curl, CURLOPT_HTTPHEADER, request_headers); + curl_easy_setopt(curl, CURLOPT_URL, req->url); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, resp); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, request_headers); - ret = curl_easy_perform(easy_curl); + ret = curl_easy_perform(curl); if (ret != CURLE_OK) { erofs_err("curl_easy_perform() failed: %s", curl_easy_strerror(ret)); @@ -238,7 +237,7 @@ static int s3erofs_request_perform(struct erofs_s3 *s3, goto err_header; } - ret = curl_easy_getinfo(easy_curl, CURLINFO_RESPONSE_CODE, &http_code); + ret = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); if (ret != CURLE_OK) { erofs_err("curl_easy_getinfo() failed: %s", curl_easy_strerror(ret)); @@ -473,7 +472,7 @@ static int s3erofs_list_objects(struct s3erofs_object_iterator *it) if (ret < 0) return ret; - if (curl_easy_setopt(easy_curl, CURLOPT_WRITEFUNCTION, + if (curl_easy_setopt(s3->easy_curl, CURLOPT_WRITEFUNCTION, s3erofs_request_write_memory_cb) != CURLE_OK) return -EIO; @@ -547,43 +546,37 @@ s3erofs_get_next_object(struct s3erofs_object_iterator *it) return NULL; } -static int s3erofs_global_init(void) +static int s3erofs_curl_easy_init(struct erofs_s3 *s3) { - if (curl_global_init(CURL_GLOBAL_DEFAULT) != CURLE_OK) - return -EIO; + CURL *curl; - easy_curl = curl_easy_init(); - if (!easy_curl) - goto out_err; + curl = curl_easy_init(); + if (!curl) + return -ENOMEM; - if (curl_easy_setopt(easy_curl, CURLOPT_FOLLOWLOCATION, 1L) != CURLE_OK) - goto out_err; + if (curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L) != CURLE_OK) + goto out_cleanup; - if (curl_easy_setopt(easy_curl, CURLOPT_CONNECTTIMEOUT, 30L) != CURLE_OK) - goto out_err; + if (curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 30L) != CURLE_OK) + goto out_cleanup; - if (curl_easy_setopt(easy_curl, CURLOPT_USERAGENT, + if (curl_easy_setopt(curl, CURLOPT_USERAGENT, "s3erofs/" PACKAGE_VERSION) != CURLE_OK) - goto out_err; + goto out_cleanup; - xmlInitParser(); + s3->easy_curl = curl; return 0; -out_err: - curl_global_cleanup(); - return -EIO; +out_cleanup: + curl_easy_cleanup(curl); + return -EFAULT; } -static void s3erofs_global_exit(void) +static void s3erofs_curl_easy_exit(struct erofs_s3 *s3) { - if (!easy_curl) + if (!s3->easy_curl) return; - - xmlCleanupParser(); - - curl_easy_cleanup(easy_curl); - easy_curl = NULL; - - curl_global_cleanup(); + curl_easy_cleanup(s3->easy_curl); + s3->easy_curl = NULL; } struct s3erofs_curl_getobject_resp { @@ -623,7 +616,7 @@ static int s3erofs_remote_getobject(struct erofs_s3 *s3, if (ret < 0) return ret; - if (curl_easy_setopt(easy_curl, CURLOPT_WRITEFUNCTION, + if (curl_easy_setopt(s3->easy_curl, CURLOPT_WRITEFUNCTION, s3erofs_remote_getobject_cb) != CURLE_OK) return -EIO; @@ -689,7 +682,7 @@ int s3erofs_build_trees(struct erofs_inode *root, struct erofs_s3 *s3, st.st_uid = root->i_uid; st.st_gid = root->i_gid; - ret = s3erofs_global_init(); + ret = s3erofs_curl_easy_init(s3); if (ret) { erofs_err("failed to initialize s3erofs: %s", erofs_strerror(ret)); return ret; @@ -764,6 +757,6 @@ int s3erofs_build_trees(struct erofs_inode *root, struct erofs_s3 *s3, err_iter: s3erofs_destroy_object_iterator(iter); err_global: - s3erofs_global_exit(); + s3erofs_curl_easy_exit(s3); return ret; } diff --git a/mkfs/main.c b/mkfs/main.c index 804d483..b8773fd 100644 --- a/mkfs/main.c +++ b/mkfs/main.c @@ -1481,10 +1481,12 @@ int main(int argc, char **argv) struct timeval t; FILE *blklst = NULL; s64 mkfs_time = 0; - int err = 0; + int err; u32 crc; - erofs_init_configure(); + err = liberofs_global_init(); + if (err) + return 1; erofs_mkfs_default_options(); err = mkfs_parse_options_cfg(argc, argv); @@ -1492,13 +1494,13 @@ int main(int argc, char **argv) if (err) { if (err == -EINVAL) fprintf(stderr, "Try '%s --help' for more information.\n", argv[0]); - return 1; + goto exit; } err = parse_source_date_epoch(); if (err) { fprintf(stderr, "Try '%s --help' for more information.\n", argv[0]); - return 1; + goto exit; } g_sbi.fixed_nsec = 0; @@ -1521,14 +1523,14 @@ int main(int argc, char **argv) (incremental_mode ? 0 : O_TRUNC)); if (err) { fprintf(stderr, "Try '%s --help' for more information.\n", argv[0]); - return 1; + goto exit; } #ifdef WITH_ANDROID if (cfg.fs_config_file && load_canned_fs_config(cfg.fs_config_file) < 0) { erofs_err("failed to load fs config %s", cfg.fs_config_file); - return 1; + goto exit; } #endif erofs_show_config(); @@ -1540,7 +1542,7 @@ int main(int argc, char **argv) if (err) { erofs_err("failed to initialize packedfile: %s", strerror(-err)); - return 1; + goto exit; } } @@ -1549,7 +1551,7 @@ int main(int argc, char **argv) if (err) { erofs_err("failed to initialize metabox: %s", erofs_strerror(err)); - return 1; + goto exit; } } @@ -1687,7 +1689,7 @@ int main(int argc, char **argv) if (cfg.c_chunkbits) { err = erofs_blob_init(cfg.c_blobdev_path, 1 << cfg.c_chunkbits); if (err) - return 1; + goto exit; } if (tar_index_512b || cfg.c_blobdev_path) { @@ -1851,7 +1853,6 @@ exit: erofs_xattr_cleanup_name_prefixes(); erofs_rebuild_cleanup(); erofs_diskbuf_exit(); - erofs_exit_configure(); if (source_mode == EROFS_MKFS_SOURCE_TAR) { erofs_iostream_close(&erofstar.ios); if (erofstar.ios.dumpfd >= 0) @@ -1866,5 +1867,6 @@ exit: erofs_update_progressinfo("Build completed.\n"); erofs_mkfs_showsummaries(); erofs_put_super(&g_sbi); + liberofs_global_exit(); return 0; } -- 2.43.5