summaryrefslogtreecommitdiffstats
path: root/src/lib/kdb/kdb_log.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/kdb/kdb_log.c')
-rw-r--r--src/lib/kdb/kdb_log.c136
1 files changed, 96 insertions, 40 deletions
diff --git a/src/lib/kdb/kdb_log.c b/src/lib/kdb/kdb_log.c
index dcc1bcf447..378a497a31 100644
--- a/src/lib/kdb/kdb_log.c
+++ b/src/lib/kdb/kdb_log.c
@@ -72,15 +72,15 @@ sync_update(kdb_hlog_t *ulog, kdb_ent_header_t *upd)
}
/* Sync memory to disk for the update log header. */
-void
-ulog_sync_header(kdb_hlog_t *ulog)
+static void
+sync_header(kdb_hlog_t *ulog)
{
if (!pagesize)
pagesize = getpagesize();
if (msync((caddr_t)ulog, pagesize, MS_SYNC)) {
/* Couldn't sync to disk, let's panic. */
- syslog(LOG_ERR, _("ulog_sync_header: could not sync to disk"));
+ syslog(LOG_ERR, _("could not sync ulog header to disk"));
abort();
}
}
@@ -190,7 +190,7 @@ resize(kdb_hlog_t *ulog, uint32_t ulogentries, int ulogfd,
ulog->db_version_num = KDB_VERSION;
ulog->kdb_state = KDB_STABLE;
ulog->kdb_block = new_block;
- ulog_sync_header(ulog);
+ sync_header(ulog);
/* Expand log considering new block size. */
if (extend_file_to(ulogfd, new_size) < 0)
@@ -210,19 +210,25 @@ reset_header(kdb_hlog_t *ulog)
time_current(&ulog->kdb_last_time);
}
-krb5_error_code
-ulog_lock(krb5_context ctx, int mode)
+/*
+ * If any database operations will be invoked while the ulog lock is held, the
+ * caller must explicitly lock the database before locking the ulog, or
+ * deadlock may result.
+ */
+static krb5_error_code
+lock_ulog(krb5_context context, int mode)
{
kdb_log_context *log_ctx = NULL;
kdb_hlog_t *ulog = NULL;
- if (ctx == NULL)
- return KRB5_LOG_ERROR;
- if (ctx->kdblog_context == NULL ||
- ctx->kdblog_context->iproprole == IPROP_NULL)
- return 0;
- INIT_ULOG(ctx);
- return krb5_lock_file(ctx, log_ctx->ulogfd, mode);
+ INIT_ULOG(context);
+ return krb5_lock_file(context, log_ctx->ulogfd, mode);
+}
+
+static void
+unlock_ulog(krb5_context context)
+{
+ (void)lock_ulog(context, KRB5_LOCKMODE_UNLOCK);
}
/*
@@ -246,7 +252,7 @@ ulog_add_update(krb5_context context, kdb_incr_update_t *upd)
int ulogfd;
INIT_ULOG(context);
- retval = ulog_lock(context, KRB5_LOCKMODE_EXCLUSIVE);
+ retval = lock_ulog(context, KRB5_LOCKMODE_EXCLUSIVE);
if (retval)
return retval;
@@ -317,13 +323,12 @@ ulog_add_update(krb5_context context, kdb_incr_update_t *upd)
ulog->kdb_state = KDB_STABLE;
cleanup:
- ulog_sync_header(ulog);
- ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
+ sync_header(ulog);
+ unlock_ulog(context);
return retval;
}
-/* Used by the slave to update its hash db from* the incr update log. Must be
- * called with lock held. */
+/* Used by the slave to update its hash db from the incr update log. */
krb5_error_code
ulog_replay(krb5_context context, kdb_incr_result_t *incr_ret, char **db_args)
{
@@ -339,6 +344,20 @@ ulog_replay(krb5_context context, kdb_incr_result_t *incr_ret, char **db_args)
INIT_ULOG(context);
+ /* Lock the DB before the ulog to avoid deadlock. */
+ retval = krb5_db_open(context, db_args,
+ KRB5_KDB_OPEN_RW | KRB5_KDB_SRV_TYPE_ADMIN);
+ if (retval)
+ return retval;
+ retval = krb5_db_lock(context, KRB5_DB_LOCKMODE_EXCLUSIVE);
+ if (retval)
+ return retval;
+ retval = lock_ulog(context, KRB5_LOCKMODE_EXCLUSIVE);
+ if (retval) {
+ krb5_db_unlock(context);
+ return retval;
+ }
+
no_of_updates = incr_ret->updates.kdb_ulog_t_len;
upd = incr_ret->updates.kdb_ulog_t_val;
fupd = upd;
@@ -350,11 +369,6 @@ ulog_replay(krb5_context context, kdb_incr_result_t *incr_ret, char **db_args)
errlast.last_time.useconds = (unsigned int)0;
last = &errlast;
- retval = krb5_db_open(context, db_args,
- KRB5_KDB_OPEN_RW | KRB5_KDB_SRV_TYPE_ADMIN);
- if (retval)
- goto cleanup;
-
for (i = 0; i < no_of_updates; i++) {
if (!upd->kdb_commit)
continue;
@@ -401,21 +415,28 @@ cleanup:
/* Record a new last serial number and timestamp in the ulog header. */
ulog->kdb_last_sno = last->last_sno;
ulog->kdb_last_time = last->last_time;
- ulog_sync_header(ulog);
-
+ sync_header(ulog);
+ unlock_ulog(context);
+ krb5_db_unlock(context);
return retval;
}
-/* Reinitialize the log header. Locking is the caller's responsibility. */
-void
+/* Reinitialize the log header. */
+krb5_error_code
ulog_init_header(krb5_context context)
{
+ krb5_error_code ret;
kdb_log_context *log_ctx;
kdb_hlog_t *ulog;
INIT_ULOG(context);
+ ret = lock_ulog(context, KRB5_LOCKMODE_EXCLUSIVE);
+ if (ret)
+ return ret;
reset_header(ulog);
- ulog_sync_header(ulog);
+ sync_header(ulog);
+ unlock_ulog(context);
+ return 0;
}
/*
@@ -519,26 +540,26 @@ ulog_map(krb5_context context, const char *logname, uint32_t ulogentries,
log_ctx->ulogentries = ulogentries;
log_ctx->ulogfd = ulogfd;
- retval = ulog_lock(context, KRB5_LOCKMODE_EXCLUSIVE);
+ retval = lock_ulog(context, KRB5_LOCKMODE_EXCLUSIVE);
if (retval)
return retval;
if (ulog->kdb_hmagic != KDB_ULOG_HDR_MAGIC && ulog->kdb_hmagic != 0) {
- ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
+ unlock_ulog(context);
return KRB5_LOG_CORRUPT;
}
if (ulog->kdb_hmagic != KDB_ULOG_HDR_MAGIC) {
reset_header(ulog);
if (caller != FKPROPLOG)
- ulog_sync_header(ulog);
- ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
+ sync_header(ulog);
+ unlock_ulog(context);
return 0;
}
if (caller == FKPROPLOG || caller == FKPROPD) {
/* kproplog and kpropd don't need to do anything else. */
- ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
+ unlock_ulog(context);
return 0;
}
@@ -551,7 +572,7 @@ ulog_map(krb5_context context, const char *logname, uint32_t ulogentries,
(ulog->kdb_last_sno > ulog->kdb_num ||
ulog->kdb_num > ulogentries)) {
reset_header(ulog);
- ulog_sync_header(ulog);
+ sync_header(ulog);
}
/* Expand ulog if we have specified a greater size. */
@@ -559,12 +580,12 @@ ulog_map(krb5_context context, const char *logname, uint32_t ulogentries,
ulog_filesize += ulogentries * ulog->kdb_block;
if (extend_file_to(ulogfd, ulog_filesize) < 0) {
- ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
+ unlock_ulog(context);
return errno;
}
}
}
- ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
+ unlock_ulog(context);
return 0;
}
@@ -587,7 +608,7 @@ ulog_get_entries(krb5_context context, const kdb_last_t *last,
INIT_ULOG(context);
ulogentries = log_ctx->ulogentries;
- retval = ulog_lock(context, KRB5_LOCKMODE_SHARED);
+ retval = lock_ulog(context, KRB5_LOCKMODE_SHARED);
if (retval)
return retval;
@@ -637,7 +658,7 @@ ulog_get_entries(krb5_context context, const kdb_last_t *last,
ulog_handle->ret = UPDATE_OK;
cleanup:
- (void)ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
+ unlock_ulog(context);
return retval;
}
@@ -658,9 +679,44 @@ ulog_get_sno_status(krb5_context context, const kdb_last_t *last)
{
update_status_t status;
- if (ulog_lock(context, KRB5_LOCKMODE_SHARED) != 0)
+ if (lock_ulog(context, KRB5_LOCKMODE_SHARED) != 0)
return UPDATE_ERROR;
status = get_sno_status(context->kdblog_context, last);
- (void)ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
+ unlock_ulog(context);
return status;
}
+
+krb5_error_code
+ulog_get_last(krb5_context context, kdb_last_t *last_out)
+{
+ krb5_error_code ret;
+ kdb_log_context *log_ctx;
+ kdb_hlog_t *ulog;
+
+ INIT_ULOG(context);
+ ret = lock_ulog(context, KRB5_LOCKMODE_SHARED);
+ if (ret)
+ return ret;
+ last_out->last_sno = log_ctx->ulog->kdb_last_sno;
+ last_out->last_time = log_ctx->ulog->kdb_last_time;
+ unlock_ulog(context);
+ return 0;
+}
+
+krb5_error_code
+ulog_set_last(krb5_context context, const kdb_last_t *last)
+{
+ krb5_error_code ret;
+ kdb_log_context *log_ctx;
+ kdb_hlog_t *ulog;
+
+ INIT_ULOG(context);
+ ret = lock_ulog(context, KRB5_LOCKMODE_EXCLUSIVE);
+ if (ret)
+ return ret;
+ ulog->kdb_last_sno = last->last_sno;
+ ulog->kdb_last_time = last->last_time;
+ sync_header(ulog);
+ unlock_ulog(context);
+ return 0;
+}