diff --git a/lib/ovsdb-error.c b/lib/ovsdb-error.c index d6b4576ea..3b90b1616 100644 --- a/lib/ovsdb-error.c +++ b/lib/ovsdb-error.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, 2010 Nicira Networks +/* Copyright (c) 2009, 2010, 2011 Nicira Networks * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -114,8 +114,16 @@ ovsdb_wrap_error(struct ovsdb_error *error, const char *details, ...) return error; } +/* Returns an ovsdb_error that represents an internal error for file name + * 'file' and line number 'line', with 'details' (formatted as with printf()) + * as the associated message. The caller is responsible for freeing the + * returned error. + * + * If 'inner_error' is nonnull then the returned error is wrapped around + * 'inner_error'. Takes ownership of 'inner_error'. */ struct ovsdb_error * -ovsdb_internal_error(const char *file, int line, const char *details, ...) +ovsdb_internal_error(struct ovsdb_error *inner_error, + const char *file, int line, const char *details, ...) { struct ds ds = DS_EMPTY_INITIALIZER; struct backtrace backtrace; @@ -144,6 +152,14 @@ ovsdb_internal_error(const char *file, int line, const char *details, ...) ds_put_format(&ds, " (%s %s%s)", program_name, VERSION, BUILDNR); + if (inner_error) { + char *s = ovsdb_error_to_string(inner_error); + ds_put_format(&ds, " (generated from: %s)", s); + free(s); + + ovsdb_error_destroy(inner_error); + } + error = ovsdb_error("internal error", "%s", ds_cstr(&ds)); ds_destroy(&ds); diff --git a/lib/ovsdb-error.h b/lib/ovsdb-error.h index 2bff3ae56..89b0c19b2 100644 --- a/lib/ovsdb-error.h +++ b/lib/ovsdb-error.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, 2010 Nicira Networks +/* Copyright (c) 2009, 2010, 2011 Nicira Networks * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,11 +35,25 @@ struct ovsdb_error *ovsdb_wrap_error(struct ovsdb_error *error, const char *details, ...) PRINTF_FORMAT(2, 3); -struct ovsdb_error *ovsdb_internal_error(const char *file, int line, +struct ovsdb_error *ovsdb_internal_error(struct ovsdb_error *error, + const char *file, int line, const char *details, ...) - PRINTF_FORMAT(3, 4) + PRINTF_FORMAT(4, 5) WARN_UNUSED_RESULT; -#define OVSDB_BUG(MSG) ovsdb_internal_error(__FILE__, __LINE__, "%s", MSG) + +/* Returns a pointer to an ovsdb_error that represents an internal error for + * the current file name and line number with MSG as the associated message. + * The caller is responsible for freeing the internal error. */ +#define OVSDB_BUG(MSG) \ + ovsdb_internal_error(NULL, __FILE__, __LINE__, "%s", MSG) + +/* Returns a pointer to an ovsdb_error that represents an internal error for + * the current file name and line number, with MSG as the associated message. + * If ERROR is nonnull then the internal error is wrapped around ERROR. Takes + * ownership of ERROR. The caller is responsible for freeing the returned + * error. */ +#define OVSDB_WRAP_BUG(MSG, ERROR) \ + ovsdb_internal_error(ERROR, __FILE__, __LINE__, "%s", MSG) void ovsdb_error_destroy(struct ovsdb_error *); struct ovsdb_error *ovsdb_error_clone(const struct ovsdb_error *) diff --git a/ovsdb/transaction.c b/ovsdb/transaction.c index b26705a3a..b7c57e57e 100644 --- a/ovsdb/transaction.c +++ b/ovsdb/transaction.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, 2010 Nicira Networks +/* Copyright (c) 2009, 2010, 2011 Nicira Networks * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -218,8 +218,7 @@ update_row_ref_count(struct ovsdb_txn *txn, struct ovsdb_txn_row *r) if (r->old) { error = ovsdb_txn_adjust_row_refs(txn, r->old, column, -1); if (error) { - ovsdb_error_destroy(error); - return OVSDB_BUG("error decreasing refcount"); + return OVSDB_WRAP_BUG("error decreasing refcount", error); } } if (r->new) { @@ -476,8 +475,7 @@ ovsdb_txn_commit(struct ovsdb_txn *txn, bool durable) * was really a no-op. */ error = for_each_txn_row(txn, determine_changes); if (error) { - ovsdb_error_destroy(error); - return OVSDB_BUG("can't happen"); + return OVSDB_WRAP_BUG("can't happen", error); } if (list_is_empty(&txn->txn_tables)) { ovsdb_txn_abort(txn);