]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-master: Add refcounting to mmap()ed settings area
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Wed, 4 Jan 2023 20:50:21 +0000 (22:50 +0200)
committerTimo Sirainen <timo.sirainen@open-xchange.com>
Mon, 20 Nov 2023 12:11:40 +0000 (14:11 +0200)
src/lib-master/master-service-private.h
src/lib-master/master-service-settings.c
src/lib-master/master-service-settings.h
src/lib-master/master-service.c

index 484e87c0b3027b6277c1c75a7dea812ef72d1c5f..2f7b2a5870ac98e189a1d46c9fe2df5c3e5f8daa 100644 (file)
@@ -39,8 +39,7 @@ struct master_service {
        const char *version_string;
        char *config_path;
        ARRAY_TYPE(const_string) config_overrides;
-       void *config_mmap_base;
-       size_t config_mmap_size;
+       struct master_settings_mmap *config_mmap;
        int syslog_facility;
        data_stack_frame_t datastack_frame_id;
 
index aba63424d866f97fc95b18215eb50da3aca3ac36..dc1f1d6137ff300376b42a5d4ea208b8cd356cf2 100644 (file)
 #define CONFIG_READ_TIMEOUT_SECS 10
 #define CONFIG_HANDSHAKE "VERSION\tconfig\t3\t0\n"
 
+struct master_settings_mmap {
+       int refcount;
+       void *mmap_base;
+       size_t mmap_size;
+};
+
 #undef DEF
 #define DEF(type, name) \
        SETTING_DEFINE_STRUCT_##type(#name, name, struct master_service_settings)
@@ -544,6 +550,28 @@ master_service_settings_read_mmap(struct setting_parser_context *parser,
        return 0;
 }
 
+void master_settings_mmap_ref(struct master_settings_mmap *mmap)
+{
+       i_assert(mmap->refcount > 0);
+
+       mmap->refcount++;
+}
+
+void master_settings_mmap_unref(struct master_settings_mmap **_mmap)
+{
+       struct master_settings_mmap *mmap = *_mmap;
+       if (mmap == NULL)
+               return;
+       i_assert(mmap->refcount > 0);
+
+       *_mmap = NULL;
+       if (--mmap->refcount > 0)
+               return;
+       if (munmap(mmap->mmap_base, mmap->mmap_size) < 0)
+               i_error("munmap(<config>) failed: %m");
+       i_free(mmap);
+}
+
 int master_service_settings_read(struct master_service *service,
                                 const struct master_service_settings_input *input,
                                 struct master_service_settings_output *output_r,
@@ -552,6 +580,7 @@ int master_service_settings_read(struct master_service *service,
        ARRAY(const struct setting_parser_info *) all_roots;
        const struct setting_parser_info *tmp_root;
        struct setting_parser_context *parser;
+       struct master_settings_mmap *config_mmap = NULL;
        const char *path = NULL, *value, *error;
        unsigned int i;
        int ret, fd = -1;
@@ -559,7 +588,7 @@ int master_service_settings_read(struct master_service *service,
        i_zero(output_r);
        output_r->config_fd = -1;
 
-       if (service->config_mmap_base != NULL && !input->reload_config) {
+       if (service->config_mmap != NULL && !input->reload_config) {
                /* config was already read once */
        } else if ((value = getenv(DOVECOT_CONFIG_FD_ENV)) != NULL) {
                /* doveconf -F parameter already executed us back.
@@ -583,18 +612,19 @@ int master_service_settings_read(struct master_service *service,
                }
        }
        if (fd != -1) {
-               if (service->config_mmap_base != NULL) {
+               if (service->config_mmap != NULL) {
                        i_assert(input->reload_config);
-                       if (munmap(service->config_mmap_base,
-                                  service->config_mmap_size) < 0)
-                               i_error("munmap(<config>) failed: %m");
+                       master_settings_mmap_unref(&service->config_mmap);
                }
 
-               service->config_mmap_base =
-                       mmap_ro_file(fd, &service->config_mmap_size);
-               if (service->config_mmap_base == MAP_FAILED)
+               config_mmap = i_new(struct master_settings_mmap, 1);
+               service->config_mmap = config_mmap;
+               config_mmap->refcount = 1;
+               config_mmap->mmap_base =
+                       mmap_ro_file(fd, &config_mmap->mmap_size);
+               if (config_mmap->mmap_base == MAP_FAILED)
                        i_fatal("Failed to read config: mmap(%s) failed: %m", path);
-               if (service->config_mmap_size == 0)
+               if (config_mmap->mmap_size == 0)
                        i_fatal("Failed to read config: %s file size is empty", path);
 
                if (input->return_config_fd)
@@ -639,11 +669,11 @@ int master_service_settings_read(struct master_service *service,
                        array_front(&all_roots), array_count(&all_roots),
                        SETTINGS_PARSER_FLAG_IGNORE_UNKNOWN_KEYS);
 
-       /* config_mmap_base is NULL only if
-          MASTER_SERVICE_FLAG_NO_CONFIG_SETTINGS is used */
-       if (service->config_mmap_base != NULL) {
+       /* config_mmap is NULL only if MASTER_SERVICE_FLAG_NO_CONFIG_SETTINGS
+          is used */
+       if (config_mmap != NULL) {
                ret = master_service_settings_read_mmap(parser, event,
-                       service->config_mmap_base, service->config_mmap_size,
+                       config_mmap->mmap_base, config_mmap->mmap_size,
                        output_r, &error);
                if (ret < 0) {
                        if (getenv(DOVECOT_CONFIG_FD_ENV) != NULL) {
index 99ea5a6db8980a736c01b24c54f8dad3e1b057bd..fc950e1f49e5de976daa4ef29e36816f1d62f7b0 100644 (file)
@@ -6,6 +6,7 @@
 struct setting_parser_info;
 struct setting_parser_context;
 struct master_service;
+struct master_settings_mmap;
 
 struct master_service_settings {
        const char *base_dir;
@@ -64,6 +65,9 @@ struct master_service_settings_output {
 
 extern const struct setting_parser_info master_service_setting_parser_info;
 
+void master_settings_mmap_ref(struct master_settings_mmap *mmap);
+void master_settings_mmap_unref(struct master_settings_mmap **mmap);
+
 int master_service_settings_read(struct master_service *service,
                                 const struct master_service_settings_input *input,
                                 struct master_service_settings_output *output_r,
index 3665449a1a9d8985b80b3a1763b421f69f2aca01..9087f964d4c9c15f7a06bec8f26cfe0ac5945ad2 100644 (file)
@@ -1591,11 +1591,7 @@ static void master_service_deinit_real(struct master_service **_service)
                settings_parser_unref(&service->set_parser);
                pool_unref(&service->set_pool);
        }
-       if (service->config_mmap_base != NULL) {
-               if (munmap(service->config_mmap_base,
-                          service->config_mmap_size) < 0)
-                       i_error("munmap(<config>) failed: %m");
-       }
+       master_settings_mmap_unref(&service->config_mmap);
        i_free(master_service_category_name);
        master_service_category.name = NULL;
        event_unregister_callback(master_service_event_callback);