diff options
author | stevep <none@none> | 2008-02-19 10:33:55 -0800 |
---|---|---|
committer | stevep <none@none> | 2008-02-19 10:33:55 -0800 |
commit | c0889d7a91fa87e1cb7ef4457629b0cb51d47b50 (patch) | |
tree | 6d61969fd57b6c78ff2948c9d41b3c23f674ca34 | |
parent | 81d97edfb9c61e08bc3e3776a29b9d7d0e87e574 (diff) | |
download | illumos-joyent-c0889d7a91fa87e1cb7ef4457629b0cb51d47b50.tar.gz |
6351623 Initial manifest-import is slow
-rw-r--r-- | usr/src/cmd/svc/configd/backend.c | 418 | ||||
-rw-r--r-- | usr/src/cmd/svc/configd/client.c | 43 | ||||
-rw-r--r-- | usr/src/cmd/svc/configd/configd.h | 7 | ||||
-rw-r--r-- | usr/src/cmd/svc/milestone/manifest-import | 24 | ||||
-rw-r--r-- | usr/src/cmd/svc/svcadm/svcadm.c | 58 | ||||
-rw-r--r-- | usr/src/common/svc/repcache_protocol.h | 16 | ||||
-rw-r--r-- | usr/src/lib/libscf/common/lowlevel.c | 49 | ||||
-rw-r--r-- | usr/src/lib/libscf/common/mapfile-vers | 1 | ||||
-rw-r--r-- | usr/src/lib/libscf/inc/libscf_priv.h | 13 |
9 files changed, 561 insertions, 68 deletions
diff --git a/usr/src/cmd/svc/configd/backend.c b/usr/src/cmd/svc/configd/backend.c index 3f39f068f8..3354b2faee 100644 --- a/usr/src/cmd/svc/configd/backend.c +++ b/usr/src/cmd/svc/configd/backend.c @@ -49,6 +49,7 @@ #include <sys/statvfs.h> #include <unistd.h> #include <zone.h> +#include <libscf_priv.h> #include "configd.h" #include "repcache_protocol.h" @@ -740,13 +741,72 @@ fail: } /* + * This interface is called to perform the actual copy + * + * Return: + * _FAIL_UNKNOWN read/write fails + * _FAIL_NO_RESOURCES out of memory + * _SUCCESS copy succeeds + */ +static rep_protocol_responseid_t +backend_do_copy(const char *src, int srcfd, const char *dst, + int dstfd, size_t *sz) +{ + char *buf; + off_t nrd, nwr, n, r_off = 0, w_off = 0; + + if ((buf = malloc(8192)) == NULL) + return (REP_PROTOCOL_FAIL_NO_RESOURCES); + + while ((nrd = read(srcfd, buf, 8192)) != 0) { + if (nrd < 0) { + if (errno == EINTR) + continue; + + configd_critical( + "Backend copy failed: fails to read from %s " + "at offset %d: %s\n", src, r_off, strerror(errno)); + free(buf); + return (REP_PROTOCOL_FAIL_UNKNOWN); + } + + r_off += nrd; + + nwr = 0; + do { + if ((n = write(dstfd, &buf[nwr], nrd - nwr)) < 0) { + if (errno == EINTR) + continue; + + configd_critical( + "Backend copy failed: fails to write to %s " + "at offset %d: %s\n", dst, w_off, + strerror(errno)); + free(buf); + return (REP_PROTOCOL_FAIL_UNKNOWN); + } + + nwr += n; + w_off += n; + + } while (nwr < nrd); + } + + if (sz) + *sz = w_off; + + free(buf); + return (REP_PROTOCOL_SUCCESS); +} + +/* * Can return: * _BAD_REQUEST name is not valid * _TRUNCATED name is too long for current repository path * _UNKNOWN failed for unknown reason (details written to * console) * _BACKEND_READONLY backend is not writable - * + * _NO_RESOURCES out of memory * _SUCCESS Backup completed successfully. */ static rep_protocol_responseid_t @@ -756,30 +816,35 @@ backend_create_backup_locked(sqlite_backend_t *be, const char *name) ssize_t old_sz; ssize_t old_max = max_repository_backups; ssize_t cur; - char *finalname; - - char finalpath[PATH_MAX]; - char tmppath[PATH_MAX]; - char buf[8192]; + char *finalpath; + char *tmppath; int infd, outfd; size_t len; - off_t inlen, outlen, offset; - time_t now; struct tm now_tm; - rep_protocol_responseid_t result; - if (be->be_readonly) - return (REP_PROTOCOL_FAIL_BACKEND_READONLY); + if ((finalpath = malloc(PATH_MAX)) == NULL) + return (REP_PROTOCOL_FAIL_NO_RESOURCES); + + if ((tmppath = malloc(PATH_MAX)) == NULL) { + free(finalpath); + return (REP_PROTOCOL_FAIL_NO_RESOURCES); + } + + if (be->be_readonly) { + result = REP_PROTOCOL_FAIL_BACKEND_READONLY; + goto out; + } - result = backend_backup_base(be, name, finalpath, sizeof (finalpath)); + result = backend_backup_base(be, name, finalpath, PATH_MAX); if (result != REP_PROTOCOL_SUCCESS) - return (result); + goto out; if (!backend_check_backup_needed(be->be_path, finalpath)) { - return (REP_PROTOCOL_SUCCESS); + result = REP_PROTOCOL_SUCCESS; + goto out; } /* @@ -792,30 +857,33 @@ backend_create_backup_locked(sqlite_backend_t *be, const char *name) else finalname = finalpath; - (void) strlcpy(tmppath, finalpath, sizeof (tmppath)); - if (strlcat(tmppath, "-tmpXXXXXX", sizeof (tmppath)) >= - sizeof (tmppath)) - return (REP_PROTOCOL_FAIL_TRUNCATED); + (void) strlcpy(tmppath, finalpath, PATH_MAX); + if (strlcat(tmppath, "-tmpXXXXXX", PATH_MAX) >= PATH_MAX) { + result = REP_PROTOCOL_FAIL_TRUNCATED; + goto out; + } now = time(NULL); if (localtime_r(&now, &now_tm) == NULL) { configd_critical( "\"%s\" backup failed: localtime(3C) failed: %s\n", name, be->be_path, strerror(errno)); - return (REP_PROTOCOL_FAIL_UNKNOWN); + result = REP_PROTOCOL_FAIL_UNKNOWN; + goto out; } - if (strftime(finalpath + len, sizeof (finalpath) - len, - "-%Y""%m""%d""_""%H""%M""%S", &now_tm) >= - sizeof (finalpath) - len) { - return (REP_PROTOCOL_FAIL_TRUNCATED); + if (strftime(finalpath + len, PATH_MAX - len, + "-%Y""%m""%d""_""%H""%M""%S", &now_tm) >= PATH_MAX - len) { + result = REP_PROTOCOL_FAIL_TRUNCATED; + goto out; } infd = open(be->be_path, O_RDONLY); if (infd < 0) { configd_critical("\"%s\" backup failed: opening %s: %s\n", name, be->be_path, strerror(errno)); - return (REP_PROTOCOL_FAIL_UNKNOWN); + result = REP_PROTOCOL_FAIL_UNKNOWN; + goto out; } outfd = mkstemp(tmppath); @@ -823,40 +891,13 @@ backend_create_backup_locked(sqlite_backend_t *be, const char *name) configd_critical("\"%s\" backup failed: mkstemp(%s): %s\n", name, tmppath, strerror(errno)); (void) close(infd); - return (REP_PROTOCOL_FAIL_UNKNOWN); - } - - for (;;) { - do { - inlen = read(infd, buf, sizeof (buf)); - } while (inlen < 0 && errno == EINTR); - - if (inlen <= 0) - break; - - for (offset = 0; offset < inlen; offset += outlen) { - do { - outlen = write(outfd, buf + offset, - inlen - offset); - } while (outlen < 0 && errno == EINTR); - - if (outlen >= 0) - continue; - - configd_critical( - "\"%s\" backup failed: write to %s: %s\n", - name, tmppath, strerror(errno)); - result = REP_PROTOCOL_FAIL_UNKNOWN; - goto fail; - } + result = REP_PROTOCOL_FAIL_UNKNOWN; + goto out; } - if (inlen < 0) { - configd_critical( - "\"%s\" backup failed: read from %s: %s\n", - name, be->be_path, strerror(errno)); + if ((result = backend_do_copy((const char *)be->be_path, infd, + (const char *)tmppath, outfd, NULL)) != REP_PROTOCOL_SUCCESS) goto fail; - } /* * grab the old list before doing our re-name. @@ -886,7 +927,7 @@ backend_create_backup_locked(sqlite_backend_t *be, const char *name) /* unlink all but the first (old_max - 1) files */ for (cur = old_max - 1; cur < old_sz; cur++) { (void) strlcpy(finalname, old_list[cur], - sizeof (finalpath) - (finalname - finalpath)); + PATH_MAX - (finalname - finalpath)); if (unlink(finalpath) < 0) configd_critical( "\"%s\" backup completed, but removing old " @@ -905,6 +946,10 @@ fail: if (result != REP_PROTOCOL_SUCCESS) (void) unlink(tmppath); +out: + free(finalpath); + free(tmppath); + return (result); } @@ -1074,7 +1119,7 @@ backend_fd_write(int fd, const char *mess) * _UNKNOWN failed for unknown reason (details written to * console) * _BACKEND_READONLY backend is not writable - * + * _NO_RESOURCES out of memory * _SUCCESS Backup completed successfully. */ rep_protocol_responseid_t @@ -1084,8 +1129,7 @@ backend_create_backup(const char *name) sqlite_backend_t *be; result = backend_lock(BACKEND_TYPE_NORMAL, 0, &be); - if (result != REP_PROTOCOL_SUCCESS) - return (result); + assert(result == REP_PROTOCOL_SUCCESS); result = backend_create_backup_locked(be, name); backend_unlock(be); @@ -1093,6 +1137,254 @@ backend_create_backup(const char *name) return (result); } +/* + * Copy the repository. If the sw_back flag is not set, we are + * copying the repository from the default location under /etc/svc to + * the tmpfs /etc/svc/volatile location. If the flag is set, we are + * copying back to the /etc/svc location from the volatile location + * after manifest-import is completed. + * + * Can return: + * + * REP_PROTOCOL_SUCCESS successful copy and rename + * REP_PROTOCOL_FAIL_UNKNOWN file operation error + * REP_PROTOCOL_FAIL_NO_RESOURCES out of memory + */ +static rep_protocol_responseid_t +backend_switch_copy(const char *src, const char *dst, int sw_back) +{ + int srcfd, dstfd; + char *tmppath = malloc(PATH_MAX); + rep_protocol_responseid_t res = REP_PROTOCOL_SUCCESS; + struct stat s_buf; + size_t cpsz, sz; + + if (tmppath == NULL) { + res = REP_PROTOCOL_FAIL_NO_RESOURCES; + goto out; + } + + /* + * Create and open the related db files + */ + (void) strlcpy(tmppath, dst, PATH_MAX); + sz = strlcat(tmppath, "-XXXXXX", PATH_MAX); + assert(sz < PATH_MAX); + if (sz >= PATH_MAX) { + configd_critical( + "Backend copy failed: strlcat %s: overflow\n", tmppath); + abort(); + } + + if ((dstfd = mkstemp(tmppath)) < 0) { + configd_critical("Backend copy failed: mkstemp %s: %s\n", + tmppath, strerror(errno)); + res = REP_PROTOCOL_FAIL_UNKNOWN; + goto out; + } + + if ((srcfd = open(src, O_RDONLY)) < 0) { + configd_critical("Backend copy failed: opening %s: %s\n", + src, strerror(errno)); + res = REP_PROTOCOL_FAIL_UNKNOWN; + goto errexit; + } + + /* + * fstat the backend before copy for sanity check. + */ + if (fstat(srcfd, &s_buf) < 0) { + configd_critical("Backend copy failed: fstat %s: %s\n", + src, strerror(errno)); + res = REP_PROTOCOL_FAIL_UNKNOWN; + goto errexit; + } + + if ((res = backend_do_copy(src, srcfd, dst, dstfd, &cpsz)) != + REP_PROTOCOL_SUCCESS) + goto errexit; + + if (cpsz != s_buf.st_size) { + configd_critical("Backend copy failed: incomplete copy\n"); + res = REP_PROTOCOL_FAIL_UNKNOWN; + goto errexit; + } + + /* + * Rename tmppath to dst + */ + if (rename(tmppath, dst) < 0) { + configd_critical( + "Backend copy failed: rename %s to %s: %s\n", + tmppath, dst, strerror(errno)); + res = REP_PROTOCOL_FAIL_UNKNOWN; + } + +errexit: + if (res != REP_PROTOCOL_SUCCESS && unlink(tmppath) < 0) + configd_critical( + "Backend copy failed: remove %s: %s\n", + tmppath, strerror(errno)); + + (void) close(srcfd); + (void) close(dstfd); + +out: + free(tmppath); + if (sw_back) { + if (unlink(src) < 0) + configd_critical( + "Backend copy failed: remove %s: %s\n", + src, strerror(errno)); + } + + return (res); +} + +/* + * Perform sanity check on the repository. + * Return 0 if check succeeds or -1 if fails. + */ +static int +backend_switch_check(struct sqlite *be_db, char **errp) +{ + struct run_single_int_info info; + uint32_t val = -1UL; + int r; + + info.rs_out = &val; + info.rs_result = REP_PROTOCOL_FAIL_NOT_FOUND; + + r = sqlite_exec(be_db, + "SELECT schema_version FROM schema_version;", + run_single_int_callback, &info, errp); + + if (r == SQLITE_OK && + info.rs_result != REP_PROTOCOL_FAIL_NOT_FOUND && + val == BACKEND_SCHEMA_VERSION) + return (0); + else + return (-1); +} + +/* + * Backend switch entry point. It is called to perform the backend copy and + * switch from src to dst. First, it blocks all other clients from accessing + * the repository by calling backend_lock to lock the repository. Upon + * successful lock, copying and switching of the repository are performed. + * + * Can return: + * REP_PROTOCOL_SUCCESS successful switch + * REP_PROTOCOL_FAIL_BACKEND_ACCESS backen access fails + * REP_PROTOCOL_FAIL_BACKEND_READONLY backend is not writable + * REP_PROTOCOL_FAIL_UNKNOWN file operation error + * REP_PROTOCOL_FAIL_NO_RESOURCES out of memory + */ +rep_protocol_responseid_t +backend_switch(int sw_back) +{ + rep_protocol_responseid_t result; + sqlite_backend_t *be; + struct sqlite *new; + char *errp; + const char *dst; + + result = backend_lock(BACKEND_TYPE_NORMAL, 1, &be); + if (result != REP_PROTOCOL_SUCCESS) + return (result); + + if (sw_back) { + dst = REPOSITORY_DB; + } else { + dst = FAST_REPOSITORY_DB; + } + + /* + * Do the actual copy and rename + */ + result = backend_switch_copy(be->be_path, dst, sw_back); + if (result != REP_PROTOCOL_SUCCESS) { + goto errout; + } + + /* + * Do the backend sanity check and switch + */ + new = sqlite_open(dst, 0600, &errp); + if (new != NULL) { + /* + * Sanity check + */ + if (backend_switch_check(new, &errp) == 0) { + free((char *)be->be_path); + be->be_path = strdup(dst); + if (be->be_path == NULL) { + configd_critical( + "Backend switch failed: strdup %s: %s\n", + dst, strerror(errno)); + result = REP_PROTOCOL_FAIL_NO_RESOURCES; + sqlite_close(new); + } else { + sqlite_close(be->be_db); + be->be_db = new; + } + } else { + configd_critical( + "Backend switch failed: integrity check %s: %s\n", + dst, errp); + result = REP_PROTOCOL_FAIL_BACKEND_ACCESS; + } + } else { + configd_critical("Backend switch failed: sqlite_open %s: %s\n", + dst, errp); + result = REP_PROTOCOL_FAIL_BACKEND_ACCESS; + } + +errout: + backend_unlock(be); + return (result); +} + +/* + * This routine is called to attempt the recovery of + * the most recent valid repository if possible when configd + * is restarted for some reasons or when system crashes + * during the switch operation. The repository databases + * referenced here are indicators of successful switch + * operations. + */ +static void +backend_switch_recovery(void) +{ + const char *fast_db = FAST_REPOSITORY_DB; + char *errp; + struct stat s_buf; + struct sqlite *be_db; + + + /* + * A good transient db containing most recent data can + * exist if system or svc.configd crashes during the + * switch operation. If that is the case, check its + * integrity and use it. + */ + if (stat(fast_db, &s_buf) < 0) { + return; + } + + /* + * Do sanity check on the db + */ + be_db = sqlite_open(fast_db, 0600, &errp); + + if (be_db != NULL) { + if (backend_switch_check(be_db, &errp) == 0) + (void) backend_switch_copy(fast_db, REPOSITORY_DB, 1); + } + + (void) unlink(fast_db); +} + /*ARGSUSED*/ static int backend_integrity_callback(void *private, int narg, char **vals, char **cols) @@ -1890,6 +2182,14 @@ backend_init(const char *db_file, const char *npdb_file, int have_np) sqlite_version, SQLITE_VERSION); return (CONFIGD_EXIT_DATABASE_INIT_FAILED); } + + /* + * If the system crashed during a backend switch, there might + * be a leftover transient database which contains useful + * information which can be used for recovery. + */ + backend_switch_recovery(); + if (db_file == NULL) db_file = REPOSITORY_DB; if (strcmp(db_file, REPOSITORY_DB) != 0) { diff --git a/usr/src/cmd/svc/configd/client.c b/usr/src/cmd/svc/configd/client.c index 2a0b49242d..47a8aefa06 100644 --- a/usr/src/cmd/svc/configd/client.c +++ b/usr/src/cmd/svc/configd/client.c @@ -1762,7 +1762,7 @@ client_wait(repcache_client_t *cp, const void *in, size_t insz, * _UNKNOWN failed for unknown reason (details written to * console) * _BACKEND_READONLY backend is not writable - * + * _NO_RESOURCES out of memory * _SUCCESS Backup completed successfully. */ static rep_protocol_responseid_t @@ -1994,6 +1994,44 @@ start_audit_session(repcache_client_t *cp) ucred_free(cred); } +/* + * Handle switch client request + * + * This routine can return: + * + * _PERMISSION_DENIED not enough privileges to do request. + * _UNKNOWN file operation error (details written to + * the console). + * _SUCCESS switch operation is completed. + * _BACKEND_ACCESS backend access fails. + * _NO_RESOURCES out of memory. + * _BACKEND_READONLY backend is not writable. + */ +static rep_protocol_responseid_t +repository_switch(repcache_client_t *cp, + struct rep_protocol_switch_request *rpr) +{ + rep_protocol_responseid_t result; + ucred_t *uc = get_ucred(); + + if (!client_is_privileged() && (uc == NULL || + ucred_geteuid(uc) != 0)) { + return (REP_PROTOCOL_FAIL_PERMISSION_DENIED); + } + + (void) pthread_mutex_lock(&cp->rc_lock); + if (rpr->rpr_changeid != cp->rc_changeid) { + if ((result = backend_switch(rpr->rpr_flag)) == + REP_PROTOCOL_SUCCESS) + cp->rc_changeid = rpr->rpr_changeid; + } else { + result = REP_PROTOCOL_SUCCESS; + } + (void) pthread_mutex_unlock(&cp->rc_lock); + + return (result); +} + typedef rep_protocol_responseid_t protocol_simple_f(repcache_client_t *cp, const void *rpr); @@ -2168,6 +2206,9 @@ static struct protocol_entry { PROTO(REP_PROTOCOL_SET_AUDIT_ANNOTATION, set_annotation, struct rep_protocol_annotation), + PROTO(REP_PROTOCOL_SWITCH, repository_switch, + struct rep_protocol_switch_request), + PROTO_END() }; #undef PROTO diff --git a/usr/src/cmd/svc/configd/configd.h b/usr/src/cmd/svc/configd/configd.h index 8d53c15c79..a1fdee0d1d 100644 --- a/usr/src/cmd/svc/configd/configd.h +++ b/usr/src/cmd/svc/configd/configd.h @@ -83,12 +83,6 @@ extern int _mutex_held(struct _lwp_mutex_t *); */ #define COMPOSITION_DEPTH 2 -/* - * The default locations of the repository dbs - */ -#define REPOSITORY_DB "/etc/svc/repository.db" -#define NONPERSIST_DB "/etc/svc/volatile/svc_nonpersist.db" - #define CONFIGD_CORE "core.%f.%t.%p" #ifndef NDEBUG @@ -761,6 +755,7 @@ int backend_init(const char *, const char *, int); void backend_fini(void); rep_protocol_responseid_t backend_create_backup(const char *); +rep_protocol_responseid_t backend_switch(int); /* * call on any database inconsistency -- cleans up state as best it can, diff --git a/usr/src/cmd/svc/milestone/manifest-import b/usr/src/cmd/svc/milestone/manifest-import index 363e410179..07f6ba0328 100644 --- a/usr/src/cmd/svc/milestone/manifest-import +++ b/usr/src/cmd/svc/milestone/manifest-import @@ -29,6 +29,8 @@ [ -f /lib/svc/share/smf_include.sh ] || exit 1 +. /lib/svc/share/smf_include.sh + activity=false X= @@ -445,6 +447,13 @@ if [ -n "$nonsite_manifests" -o -n "$site_manifests" ]; then echo "Loading smf(5) service descriptions: \c" > /dev/msglog + # + # Attempt of moving the repository to tmpfs. If that doesn't + # work, reset doswitch so we don't attempt switching back. + # + /usr/sbin/svcadm _smf_repository_switch fast + doswitch=$? + i=1; n=$# while [ $# -gt 0 ]; do printf "%${fwidth}s/%${fwidth}s" $i $n > /dev/msglog @@ -454,6 +463,21 @@ if [ -n "$nonsite_manifests" -o -n "$site_manifests" ]; then echo "$backup\c" > /dev/msglog done + # + # If switch back fails, exit with the fatal error code. + # Normally the failure indicates that there is a serious + # problem on the root file system such as file operation + # failure or repository access failure. + # + if [ $doswitch -eq 0 ]; then + /usr/sbin/svcadm _smf_repository_switch perm || { \ + echo "Repository switch back operation failed, \c" + echo "please check the system log for the" + echo "possible fatal error messages." + exit $SMF_EXIT_ERR_FATAL + } + fi + echo > /dev/msglog echo "Loaded $n smf(5) service descriptions" activity=true diff --git a/usr/src/cmd/svc/svcadm/svcadm.c b/usr/src/cmd/svc/svcadm/svcadm.c index 3e1ccab42c..e9d77475d3 100644 --- a/usr/src/cmd/svc/svcadm/svcadm.c +++ b/usr/src/cmd/svc/svcadm/svcadm.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -2107,6 +2107,7 @@ main(int argc, char *argv[]) { int o; int err; + int sw_back; (void) setlocale(LC_ALL, ""); (void) textdomain(TEXT_DOMAIN); @@ -2388,9 +2389,64 @@ main(int argc, char *argv[]) "unknown error (see console for details)"; break; } + uu_warn("failed to backup repository: %s\n", reason); exit_status = UU_EXIT_FATAL; } + } else if (strcmp(argv[optind], "_smf_repository_switch") == 0) { + const char *reason = NULL; + + ++optind; + + /* + * Check argument and setup scf_switch structure + */ + if (optind != argc - 1) + exit(1); + + if (strcmp(argv[optind], "fast") == 0) { + sw_back = 0; + } else if (strcmp(argv[optind], "perm") == 0) { + sw_back = 1; + } else { + exit(UU_EXIT_USAGE); + } + + /* + * Call into switch primitive + */ + if ((err = _scf_repository_switch(h, sw_back)) != + SCF_SUCCESS) { + /* + * Retrieve per thread SCF error code + */ + switch (scf_error()) { + case SCF_ERROR_NOT_BOUND: + abort(); + /* NOTREACHED */ + + case SCF_ERROR_CONNECTION_BROKEN: + case SCF_ERROR_BACKEND_READONLY: + scfdie(); + /* NOTREACHED */ + + case SCF_ERROR_PERMISSION_DENIED: + case SCF_ERROR_INVALID_ARGUMENT: + reason = scf_strerror(scf_error()); + break; + + case SCF_ERROR_INTERNAL: + reason = "File operation error: (see console)"; + break; + + default: + abort(); + /* NOTREACHED */ + } + + uu_warn("failed to switch repository: %s\n", reason); + exit_status = UU_EXIT_FATAL; + } } else { usage(); } diff --git a/usr/src/common/svc/repcache_protocol.h b/usr/src/common/svc/repcache_protocol.h index 9f76adb816..58bc356c90 100644 --- a/usr/src/common/svc/repcache_protocol.h +++ b/usr/src/common/svc/repcache_protocol.h @@ -359,6 +359,12 @@ * the operation that is being annotated, and file is the file being * processed. This will be used to mark operations which comprise * multiple primitive operations such as svccfg import. + * + * SWITCH(flag) -> result + * The flag is used to indicate the direction of the switch operation. + * When the flag is set to 'fast', move the main repository from the + * default location (/etc/svc) to the tmpfs locationa (/etc/svc/volatile). + * When it is set to 'perm', the switch is reversed. */ #include <door.h> @@ -382,7 +388,7 @@ extern "C" { * This value should be incremented any time the protocol changes. When in * doubt, bump it. */ -#define REPOSITORY_DOOR_VERSION (20 + REPOSITORY_DOOR_BASEVER) +#define REPOSITORY_DOOR_VERSION (21 + REPOSITORY_DOOR_BASEVER) /* * flags for rdr_flags @@ -478,6 +484,8 @@ enum rep_protocol_requestid { REP_PROTOCOL_SET_AUDIT_ANNOTATION, + REP_PROTOCOL_SWITCH, + REP_PROTOCOL_MAX_REQUEST }; @@ -822,6 +830,12 @@ struct rep_protocol_annotation { char rpr_file[MAXPATHLEN]; }; +struct rep_protocol_switch_request { + enum rep_protocol_requestid rpr_request; /* SWITCH */ + uint32_t rpr_changeid; + int rpr_flag; +}; + /* * Response structures */ diff --git a/usr/src/lib/libscf/common/lowlevel.c b/usr/src/lib/libscf/common/lowlevel.c index a9265f9c1c..4c25197400 100644 --- a/usr/src/lib/libscf/common/lowlevel.c +++ b/usr/src/lib/libscf/common/lowlevel.c @@ -6860,6 +6860,55 @@ _scf_request_backup(scf_handle_t *h, const char *name) return (SCF_SUCCESS); } +/* + * Request svc.configd daemon to switch repository database. + * + * Can fail: + * + * _NOT_BOUND handle is not bound + * _CONNECTION_BROKEN server is not reachable + * _INTERNAL file operation error + * the server response is too big + * _PERMISSION_DENIED not enough privileges to do request + * _BACKEND_READONLY backend is not writable + * _BACKEND_ACCESS backend access fails + * _NO_RESOURCES svc.configd is out of memory + */ +int +_scf_repository_switch(scf_handle_t *h, int scf_sw) +{ + struct rep_protocol_switch_request request; + struct rep_protocol_response response; + int r; + + /* + * Setup request protocol and make door call + * Hold rh_lock lock before handle_next_changeid call + */ + (void) pthread_mutex_lock(&h->rh_lock); + + request.rpr_flag = scf_sw; + request.rpr_request = REP_PROTOCOL_SWITCH; + request.rpr_changeid = handle_next_changeid(h); + + r = make_door_call(h, &request, sizeof (request), + &response, sizeof (response)); + + (void) pthread_mutex_unlock(&h->rh_lock); + + if (r < 0) { + DOOR_ERRORS_BLOCK(r); + } + + /* + * Pass protocol error up + */ + if (response.rpr_response != REP_PROTOCOL_SUCCESS) + return (scf_set_error(proto_error(response.rpr_response))); + + return (SCF_SUCCESS); +} + int _scf_pg_is_read_protected(const scf_propertygroup_t *pg, boolean_t *out) { diff --git a/usr/src/lib/libscf/common/mapfile-vers b/usr/src/lib/libscf/common/mapfile-vers index 898e8307ac..315e24d9e8 100644 --- a/usr/src/lib/libscf/common/mapfile-vers +++ b/usr/src/lib/libscf/common/mapfile-vers @@ -234,6 +234,7 @@ SUNWprivate_1.1 { scf_simple_handle_destroy; gen_filenms_from_fmri; _scf_pg_is_read_protected; + _scf_repository_switch; local: *; }; diff --git a/usr/src/lib/libscf/inc/libscf_priv.h b/usr/src/lib/libscf/inc/libscf_priv.h index 39c92d20b7..67c966715f 100644 --- a/usr/src/lib/libscf/inc/libscf_priv.h +++ b/usr/src/lib/libscf/inc/libscf_priv.h @@ -281,6 +281,14 @@ int scf_set_count_property(scf_transaction_t *, char *, uint64_t, boolean_t); #define SCF_WALK_NOINSTANCE 0x10 #define SCF_WALK_EXPLICIT 0x20 +/* + * The default locations of the repository dbs + */ +#define REPOSITORY_DB "/etc/svc/repository.db" +#define NONPERSIST_DB "/etc/svc/volatile/svc_nonpersist.db" +#define FAST_REPOSITORY_DB "/etc/svc/volatile/fast_repository.db" + + typedef struct scf_walkinfo { const char *fmri; scf_scope_t *scope; @@ -308,6 +316,11 @@ scf_error_t scf_walk_fmri(scf_handle_t *, int, char **, int, int _scf_request_backup(scf_handle_t *, const char *); /* + * Repository switch client + */ +int _scf_repository_switch(scf_handle_t *, int); + +/* * Determines whether a property group requires authorization to read; this * does not in any way reflect whether the caller has that authorization. * To determine that, the caller must attempt to read the value of one of the |