diff options
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/cmd/svc/configd/backend.c | 132 | ||||
-rw-r--r-- | usr/src/cmd/svc/configd/configd.c | 23 | ||||
-rw-r--r-- | usr/src/cmd/svc/configd/configd.h | 2 | ||||
-rw-r--r-- | usr/src/cmd/svc/configd/file_object.c | 33 | ||||
-rw-r--r-- | usr/src/cmd/svc/configd/object.c | 30 | ||||
-rw-r--r-- | usr/src/cmd/svc/svccfg/svccfg_internal.c | 9 | ||||
-rw-r--r-- | usr/src/cmd/svc/svccfg/svccfg_libscf.c | 4 | ||||
-rw-r--r-- | usr/src/lib/libscf/common/lowlevel.c | 12 | ||||
-rw-r--r-- | usr/src/lib/libscf/common/lowlevel_impl.h | 10 |
9 files changed, 215 insertions, 40 deletions
diff --git a/usr/src/cmd/svc/configd/backend.c b/usr/src/cmd/svc/configd/backend.c index 3354b2faee..3c07f41845 100644 --- a/usr/src/cmd/svc/configd/backend.c +++ b/usr/src/cmd/svc/configd/backend.c @@ -135,7 +135,12 @@ int backend_panic_abort = 0; /* abort when panicking */ #define BACKEND_READONLY_CHECK_INTERVAL (2 * (hrtime_t)NANOSEC) /* - * Any change to the below schema should bump the version number + * Any incompatible change to the below schema should bump the version number. + * The schema has been changed to support value ordering, but this change + * is backwards-compatible - i.e. a previous svc.configd can use a + * repository database with the new schema perfectly well. As a result, + * the schema version has not been updated, allowing downgrade of systems + * without losing repository data. */ #define BACKEND_SCHEMA_VERSION 5 @@ -257,13 +262,15 @@ static struct backend_tbl_info tbls_common[] = { /* all backend types */ /* * value_tbl maps a value_id to a set of values. For any given - * value_id, value_type is constant. + * value_id, value_type is constant. The table definition here + * is repeated in backend_check_upgrade(), and must be kept in-sync. */ { "value_tbl", "value_id INTEGER NOT NULL," "value_type CHAR(1) NOT NULL," - "value_value VARCHAR NOT NULL" + "value_value VARCHAR NOT NULL," + "value_order INTEGER DEFAULT 0" }, /* @@ -286,6 +293,10 @@ static struct backend_tbl_info tbls_common[] = { /* all backend types */ { NULL, NULL } }; +/* + * The indexing of value_tbl is repeated in backend_check_upgrade() and + * must be kept in sync with the indexing specification here. + */ static struct backend_idx_info idxs_common[] = { /* all backend types */ { "pg_tbl", "parent", "pg_parent_id" }, { "pg_tbl", "name", "pg_parent_id, pg_name" }, @@ -368,6 +379,29 @@ backend_trace_sql(void *arg, const char *sql) static sqlite_backend_t be_info[BACKEND_TYPE_TOTAL]; static sqlite_backend_t *bes[BACKEND_TYPE_TOTAL]; +/* + * For a native build, repositories are created from scratch, so upgrade + * is not an issue. This variable is implicitly protected by + * bes[BACKEND_TYPE_NORMAL]->be_lock. + */ +#ifdef NATIVE_BUILD +static boolean_t be_normal_upgraded = B_TRUE; +#else +static boolean_t be_normal_upgraded = B_FALSE; +#endif /* NATIVE_BUILD */ + +/* + * Has backend been upgraded? In nonpersistent case, answer is always + * yes. + */ +boolean_t +backend_is_upgraded(backend_tx_t *bt) +{ + if (bt->bt_type == BACKEND_TYPE_NONPERSIST) + return (B_TRUE); + return (be_normal_upgraded); +} + #define BACKEND_PANIC_TIMEOUT (50 * MILLISEC) /* * backend_panic() -- some kind of database problem or corruption has been hit. @@ -953,6 +987,75 @@ out: return (result); } +/* + * Check if value_tbl has been upgraded in the main database, and + * if not (if the value_order column is not present), and do_upgrade is true, + * upgrade value_tbl in repository to contain the additional value_order + * column. The version of sqlite used means ALTER TABLE is not + * available, so we cannot simply use "ALTER TABLE value_tbl ADD COLUMN". + * Rather we need to create a temporary table with the additional column, + * import the value_tbl, drop the original value_tbl, recreate the value_tbl + * with the additional column, import the values from value_tbl_tmp, + * reindex and finally drop value_tbl_tmp. During boot, we wish to check + * if the repository has been upgraded before it is writable, so that + * property value retrieval can use the appropriate form of the SELECT + * statement that retrieves property values. As a result, we need to check + * if the repository has been upgraded prior to the point when we can + * actually carry out the update. + */ +void +backend_check_upgrade(sqlite_backend_t *be, boolean_t do_upgrade) +{ + char *errp; + int r; + + if (be_normal_upgraded) + return; + /* + * Test if upgrade is needed. If value_order column does not exist, + * we need to upgrade the schema. + */ + r = sqlite_exec(be->be_db, "SELECT value_order FROM value_tbl LIMIT 1;", + NULL, NULL, NULL); + if (r == SQLITE_ERROR && do_upgrade) { + /* No value_order column - needs upgrade */ + configd_info("Upgrading SMF repository format..."); + r = sqlite_exec(be->be_db, + "BEGIN TRANSACTION; " + "CREATE TABLE value_tbl_tmp ( " + "value_id INTEGER NOT NULL, " + "value_type CHAR(1) NOT NULL, " + "value_value VARCHAR NOT NULL, " + "value_order INTEGER DEFAULT 0); " + "INSERT INTO value_tbl_tmp " + "(value_id, value_type, value_value) " + "SELECT value_id, value_type, value_value FROM value_tbl; " + "DROP TABLE value_tbl; " + "CREATE TABLE value_tbl( " + "value_id INTEGER NOT NULL, " + "value_type CHAR(1) NOT NULL, " + "value_value VARCHAR NOT NULL, " + "value_order INTEGER DEFAULT 0); " + "INSERT INTO value_tbl SELECT * FROM value_tbl_tmp; " + "CREATE INDEX value_tbl_id ON value_tbl (value_id); " + "DROP TABLE value_tbl_tmp; " + "COMMIT TRANSACTION; " + "VACUUM; ", + NULL, NULL, &errp); + if (r == SQLITE_OK) { + configd_info("SMF repository upgrade is complete."); + } else { + backend_panic("%s: repository upgrade failed: %s", + be->be_path, errp); + /* NOTREACHED */ + } + } + if (r == SQLITE_OK) + be_normal_upgraded = B_TRUE; + else + be_normal_upgraded = B_FALSE; +} + static int backend_check_readonly(sqlite_backend_t *be, int writing, hrtime_t t) { @@ -990,12 +1093,15 @@ backend_check_readonly(sqlite_backend_t *be, int writing, hrtime_t t) /* * We can write! Swap the db handles, mark ourself writable, - * and make a backup. + * upgrade if necessary, and make a backup. */ sqlite_close(be->be_db); be->be_db = new; be->be_readonly = 0; + if (be->be_type == BACKEND_TYPE_NORMAL) + backend_check_upgrade(be, B_TRUE); + if (backend_create_backup_locked(be, REPOSITORY_BOOT_BACKUP) != REP_PROTOCOL_SUCCESS) { configd_critical( @@ -1435,6 +1541,7 @@ backend_create(backend_type_t backend_id, const char *db_file, assert(backend_id >= 0 && backend_id < BACKEND_TYPE_TOTAL); be = &be_info[backend_id]; + assert(be->be_db == NULL); (void) pthread_mutex_init(&be->be_lock, NULL); @@ -1466,7 +1573,6 @@ backend_create(backend_type_t backend_id, const char *db_file, /* * check if we are inited and of the correct schema version * - * Eventually, we'll support schema upgrade here. */ info.rs_out = &val; info.rs_result = REP_PROTOCOL_FAIL_NOT_FOUND; @@ -1598,6 +1704,17 @@ integrity_fail: } /* + * Simply do check if backend has been upgraded. We do not wish + * to actually carry out upgrade here - the main repository may + * not be writable at this point. Actual upgrade is carried out + * via backend_check_readonly(). This check is done so that + * we determine repository state - upgraded or not - and then + * the appropriate SELECT statement (value-ordered or not) + * can be used when retrieving property values early in boot. + */ + if (backend_id == BACKEND_TYPE_NORMAL) + backend_check_upgrade(be, B_FALSE); + /* * check if we are writable */ r = backend_is_readonly(be->be_db, be->be_path); @@ -1614,6 +1731,7 @@ integrity_fail: *bep = be; return (BACKEND_CREATE_READONLY); } + *bep = be; return (BACKEND_CREATE_SUCCESS); @@ -2250,7 +2368,8 @@ backend_init(const char *db_file, const char *npdb_file, int have_np) /* * If we started up with a writable filesystem, but the * non-persistent database needed initialization, we - * are booting a non-global zone, so do a backup. + * are booting a non-global zone, so do a backup, and carry + * out upgrade if necessary. */ if (r == BACKEND_CREATE_NEED_INIT && writable_persist && backend_lock(BACKEND_TYPE_NORMAL, 0, &be) == @@ -2262,6 +2381,7 @@ backend_init(const char *db_file, const char *npdb_file, int have_np) "\"%s\"\n", REPOSITORY_BOOT_BACKUP, be->be_path); } + backend_check_upgrade(be, B_TRUE); backend_unlock(be); } } diff --git a/usr/src/cmd/svc/configd/configd.c b/usr/src/cmd/svc/configd/configd.c index cdbec408c4..563d097310 100644 --- a/usr/src/cmd/svc/configd/configd.c +++ b/usr/src/cmd/svc/configd/configd.c @@ -380,13 +380,15 @@ create_connection(ucred_t *uc, repository_door_request_t *rp, } void -configd_vcritical(const char *message, va_list args) +configd_vlog(int severity, const char *prefix, const char *message, + va_list args) { if (log_to_syslog) - vsyslog(LOG_CRIT, message, args); + vsyslog(severity, message, args); else { flockfile(stderr); - (void) fprintf(stderr, "svc.configd: Fatal error: "); + if (prefix != NULL) + (void) fprintf(stderr, "%s", prefix); (void) vfprintf(stderr, message, args); if (message[0] == 0 || message[strlen(message) - 1] != '\n') (void) fprintf(stderr, "\n"); @@ -395,6 +397,12 @@ configd_vcritical(const char *message, va_list args) } void +configd_vcritical(const char *message, va_list args) +{ + configd_vlog(LOG_CRIT, "svc.configd: Fatal error: ", message, args); +} + +void configd_critical(const char *message, ...) { va_list args; @@ -403,6 +411,15 @@ configd_critical(const char *message, ...) va_end(args); } +void +configd_info(const char *message, ...) +{ + va_list args; + va_start(args, message); + configd_vlog(LOG_INFO, "svc.configd: ", message, args); + va_end(args); +} + static void usage(const char *prog, int ret) { diff --git a/usr/src/cmd/svc/configd/configd.h b/usr/src/cmd/svc/configd/configd.h index a1fdee0d1d..a35239cab4 100644 --- a/usr/src/cmd/svc/configd/configd.h +++ b/usr/src/cmd/svc/configd/configd.h @@ -616,6 +616,7 @@ adt_session_data_t *get_audit_session(void); void configd_critical(const char *, ...); void configd_vcritical(const char *, va_list); +void configd_info(const char *, ...); extern int is_main_repository; extern int max_repository_backups; @@ -752,6 +753,7 @@ void rc_snaplevel_rele(rc_snaplevel_t *); * backend.c */ int backend_init(const char *, const char *, int); +boolean_t backend_is_upgraded(backend_tx_t *); void backend_fini(void); rep_protocol_responseid_t backend_create_backup(const char *); diff --git a/usr/src/cmd/svc/configd/file_object.c b/usr/src/cmd/svc/configd/file_object.c index bbe400e4bf..ad1da04d8f 100644 --- a/usr/src/cmd/svc/configd/file_object.c +++ b/usr/src/cmd/svc/configd/file_object.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -743,9 +742,29 @@ fill_property_callback(void *data, int columns, char **vals, char **names) rep_protocol_responseid_t r; backend_query_t *q = backend_query_alloc(); - backend_query_add(q, - "SELECT value_value FROM value_tbl " - "WHERE (value_id = '%q')", cur); + /* + * Ensure that select operation is reflective + * of repository schema. If the repository has + * been upgraded, make use of value ordering + * by retrieving values in order using the + * value_order column. Otherwise, simply + * run the select with no order specified. + * The order-insensitive select is necessary + * as on first reboot post-upgrade, the repository + * contents need to be read before the repository + * backend is writable (and upgrade is possible). + */ + if (backend_is_upgraded(tx)) { + backend_query_add(q, + "SELECT value_value FROM value_tbl " + "WHERE (value_id = '%q') ORDER BY value_order", + cur); + } else { + backend_query_add(q, + "SELECT value_value FROM value_tbl " + "WHERE (value_id = '%q')", + cur); + } switch (r = backend_tx_run(tx, q, property_value_size_cb, &info)) { diff --git a/usr/src/cmd/svc/configd/object.c b/usr/src/cmd/svc/configd/object.c index 2c7d6a8652..ba4154329a 100644 --- a/usr/src/cmd/svc/configd/object.c +++ b/usr/src/cmd/svc/configd/object.c @@ -194,7 +194,6 @@ tx_process_cmds(tx_commit_data_t *data) backend_query_t *q; int do_delete; - uint32_t nvalues; /* * For persistent pgs, we use backend_fail_if_seen to abort the @@ -283,7 +282,7 @@ tx_process_cmds(tx_commit_data_t *data) data->txc_pg_id, data->txc_gen, elem->tx_prop, type); } else { - uint32_t *v; + uint32_t *v, i = 0; const char *str; val_id = backend_new_id(data->txc_tx, BACKEND_ID_VALUE); @@ -299,16 +298,29 @@ tx_process_cmds(tx_commit_data_t *data) v = elem->tx_values; - nvalues = elem->tx_nvalues; - while (r == REP_PROTOCOL_SUCCESS && - nvalues--) { + for (i = 0; i < elem->tx_nvalues; i++) { str = (const char *)&v[1]; + /* + * Update values in backend, imposing + * ordering via the value_order column. + * This ordering is then used in subseqent + * value retrieval operations. We can + * safely assume that the repository schema + * has been upgraded (and hence has the + * value_order column in value_tbl), since + * it is upgraded as soon as the repository + * is writable. + */ r = backend_tx_run_update(data->txc_tx, - "INSERT INTO value_tbl " - " (value_id, value_type, value_value) " - "VALUES (%d, '%c', '%q');\n", - val_id, elem->tx_cmd->rptc_type, str); + "INSERT INTO value_tbl (value_id, " + "value_type, value_value, " + "value_order) VALUES (%d, '%c', " + "'%q', '%d');\n", + val_id, elem->tx_cmd->rptc_type, + str, i); + if (r != REP_PROTOCOL_SUCCESS) + break; /*LINTED alignment*/ v = (uint32_t *)((caddr_t)str + TX_SIZE(*v)); diff --git a/usr/src/cmd/svc/svccfg/svccfg_internal.c b/usr/src/cmd/svc/svccfg/svccfg_internal.c index 5a4d3515a0..74d206f67a 100644 --- a/usr/src/cmd/svc/svccfg/svccfg_internal.c +++ b/usr/src/cmd/svc/svccfg/svccfg_internal.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -458,7 +458,7 @@ internal_property_new() uu_list_node_init(p, &p->sc_node, property_pool); - p->sc_property_values = uu_list_create(value_pool, p, UU_LIST_SORTED); + p->sc_property_values = uu_list_create(value_pool, p, 0); p->sc_property_name = "<unset>"; return (p); @@ -669,10 +669,7 @@ internal_attach_property(pgroup_t *pgrp, property_t *prop) void internal_attach_value(property_t *prop, value_t *val) { - uu_list_index_t idx; - - (void) uu_list_find(prop->sc_property_values, val, NULL, &idx); - uu_list_insert(prop->sc_property_values, val, idx); + (void) uu_list_append(prop->sc_property_values, val); } /* diff --git a/usr/src/cmd/svc/svccfg/svccfg_libscf.c b/usr/src/cmd/svc/svccfg/svccfg_libscf.c index 098e0ce4ad..c152e2cd10 100644 --- a/usr/src/cmd/svc/svccfg/svccfg_libscf.c +++ b/usr/src/cmd/svc/svccfg/svccfg_libscf.c @@ -11156,7 +11156,7 @@ lscf_setprop(const char *pgname, const char *type, const char *value, assert(values != NULL); walk = uu_list_walk_start((uu_list_t *)values, - UU_WALK_REVERSE); + UU_DEFAULT); if (walk == NULL) uu_die(gettext("Could not walk list")); @@ -11619,7 +11619,7 @@ add_string(uu_list_t *strlist, const char *str) elem = safe_malloc(sizeof (*elem)); uu_list_node_init(elem, &elem->node, string_pool); elem->str = safe_strdup(str); - if (uu_list_prepend(strlist, elem) != 0) + if (uu_list_append(strlist, elem) != 0) uu_die(gettext("libuutil error: %s\n"), uu_strerror(uu_error())); } diff --git a/usr/src/lib/libscf/common/lowlevel.c b/usr/src/lib/libscf/common/lowlevel.c index 4c25197400..6374590467 100644 --- a/usr/src/lib/libscf/common/lowlevel.c +++ b/usr/src/lib/libscf/common/lowlevel.c @@ -3637,6 +3637,7 @@ entry_invalidate(scf_transaction_entry_t *cur, int and_destroy, scf_value_reset_locked(v, and_destroy); } cur->entry_head = NULL; + cur->entry_tail = NULL; } static void @@ -4173,8 +4174,15 @@ scf_entry_add_value(scf_transaction_entry_t *entry, scf_value_t *v) } v->value_tx = entry; - v->value_next = entry->entry_head; - entry->entry_head = v; + v->value_next = NULL; + if (entry->entry_head == NULL) { + entry->entry_head = v; + entry->entry_tail = v; + } else { + entry->entry_tail->value_next = v; + entry->entry_tail = v; + } + (void) pthread_mutex_unlock(&h->rh_lock); return (SCF_SUCCESS); diff --git a/usr/src/lib/libscf/common/lowlevel_impl.h b/usr/src/lib/libscf/common/lowlevel_impl.h index a3bc40aed9..e96ce2ade2 100644 --- a/usr/src/lib/libscf/common/lowlevel_impl.h +++ b/usr/src/lib/libscf/common/lowlevel_impl.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -171,7 +170,8 @@ struct scf_transaction_entry { enum scf_entry_state entry_state; uu_list_node_t entry_link; /* for property name list */ - scf_value_t *entry_head; /* for linked values */ + scf_value_t *entry_head; + scf_value_t *entry_tail; /* for linked values */ enum rep_protocol_transaction_action entry_action; rep_protocol_value_type_t entry_type; |