From f10863a885eb90e9645bd0fe5ce68435f4ab0cba Mon Sep 17 00:00:00 2001 From: Alberto Maria Fiaschi Date: Wed, 10 Jun 2015 15:26:58 +0200 Subject: [PATCH 001/136] Add --set-nt-hash option to pdbedit to update user password from nt-hash hexstring. Useful to take in sync password from other repository. (Modify MASK_USER_GOOD to include new flag BIT_PWSETNTHASH) pdbedit -vw show also password hashes . Split pdb_set_plaintext_passwd in two function: pdb_set_plaintext_passwd and pdb_update_history. pdb_update_history update password history and is call from pdb_set_plaintext_passwd. Signed-off-by: Alberto Maria Fiaschi --- docs-xml/manpages/pdbedit.8.xml | 20 +++++++++++++++++-- source3/include/passdb.h | 1 + source3/passdb/pdb_get_set.c | 24 +++++++++++++++++------ source3/utils/pdbedit.c | 43 +++++++++++++++++++++++++++++++++++++---- 4 files changed, 76 insertions(+), 12 deletions(-) diff --git a/docs-xml/manpages/pdbedit.8.xml b/docs-xml/manpages/pdbedit.8.xml index 6ed0399..c4ae1a1 100644 --- a/docs-xml/manpages/pdbedit.8.xml +++ b/docs-xml/manpages/pdbedit.8.xml @@ -43,6 +43,7 @@ -r -s configfile -S script + --set-nt-hash -t --time-format -u username @@ -99,7 +100,8 @@ samba:45:Test User -v|--verbose This option enables the verbose listing format. It causes pdbedit to list the users in the database, printing - out the account fields in a descriptive format. + out the account fields in a descriptive format.Used together + with -w also shows passwords hashes. Example: pdbedit -L -v @@ -134,7 +136,9 @@ Profile Path: \\BERSERKER\profile out the account fields in a format compatible with the smbpasswd file format. (see the smbpasswd - 5 for details) + 5 for details). + Instead used together with (-v) displays the passwords + hashes in verbose output. Example: pdbedit -L -w @@ -205,6 +209,18 @@ samba:45:0F2B255F7B67A7A9AAD3B435B51404EE: + --set-nt-hash + This option can be used while modifying + a user account. It will set the user's password using + the nt-hash value given as hexadecimal string. + Useful to synchronize passwords. + + Example: --set-nt-hash 8846F7EAEE8FB117AD06BDD830B7586C + + + + + -p|--profile profile This option can be used while adding or modifying a user account. It will specify the user's profile diff --git a/source3/include/passdb.h b/source3/include/passdb.h index 893d0d0..b78846d 100644 --- a/source3/include/passdb.h +++ b/source3/include/passdb.h @@ -811,6 +811,7 @@ bool pdb_set_nt_passwd(struct samu *sampass, const uint8_t pwd[NT_HASH_LEN], enu bool pdb_set_lanman_passwd(struct samu *sampass, const uint8_t pwd[LM_HASH_LEN], enum pdb_value_state flag); bool pdb_set_pw_history(struct samu *sampass, const uint8_t *pwd, uint32_t historyLen, enum pdb_value_state flag); bool pdb_set_plaintext_pw_only(struct samu *sampass, const char *password, enum pdb_value_state flag); +bool pdb_update_history(struct samu *sampass,const uint8_t new_nt[NT_HASH_LEN]); bool pdb_set_bad_password_count(struct samu *sampass, uint16_t bad_password_count, enum pdb_value_state flag); bool pdb_set_logon_count(struct samu *sampass, uint16_t logon_count, enum pdb_value_state flag); bool pdb_set_country_code(struct samu *sampass, uint16_t country_code, diff --git a/source3/passdb/pdb_get_set.c b/source3/passdb/pdb_get_set.c index 9f27459..74a71cb 100644 --- a/source3/passdb/pdb_get_set.c +++ b/source3/passdb/pdb_get_set.c @@ -999,10 +999,6 @@ bool pdb_set_plaintext_passwd(struct samu *sampass, const char *plaintext) { uchar new_lanman_p16[LM_HASH_LEN]; uchar new_nt_p16[NT_HASH_LEN]; - uchar *pwhistory; - uint32_t pwHistLen; - uint32_t current_history_len; - const uint8_t *current_history; if (!plaintext) return False; @@ -1032,6 +1028,21 @@ bool pdb_set_plaintext_passwd(struct samu *sampass, const char *plaintext) if (!pdb_set_pass_last_set_time (sampass, time(NULL), PDB_CHANGED)) return False; + + return pdb_update_history(sampass, new_nt_p16); +} + +/********************************************************************* + Update password history after change + ********************************************************************/ + +bool pdb_update_history(struct samu *sampass, const uint8_t new_nt[NT_HASH_LEN]) +{ + uchar *pwhistory; + uint32_t pwHistLen; + uint32_t current_history_len; + const uint8_t *current_history; + if ((pdb_get_acct_ctrl(sampass) & ACB_NORMAL) == 0) { /* * No password history for non-user accounts @@ -1055,7 +1066,7 @@ bool pdb_set_plaintext_passwd(struct samu *sampass, const char *plaintext) */ current_history = pdb_get_pw_history(sampass, ¤t_history_len); if ((current_history_len != 0) && (current_history == NULL)) { - DEBUG(1, ("pdb_set_plaintext_passwd: pwhistory == NULL!\n")); + DEBUG(1, ("pdb_update_history: pwhistory == NULL!\n")); return false; } @@ -1096,11 +1107,12 @@ bool pdb_set_plaintext_passwd(struct samu *sampass, const char *plaintext) * The old format was to store the md5 hash of * the salt+newpw. */ - memcpy(&pwhistory[PW_HISTORY_SALT_LEN], new_nt_p16, SALTED_MD5_HASH_LEN); + memcpy(&pwhistory[PW_HISTORY_SALT_LEN], new_nt, SALTED_MD5_HASH_LEN); pdb_set_pw_history(sampass, pwhistory, pwHistLen, PDB_CHANGED); return True; + } /* check for any PDB_SET/CHANGED field and fill the appropriate mask bit */ diff --git a/source3/utils/pdbedit.c b/source3/utils/pdbedit.c index 1f44fb0..202758e 100644 --- a/source3/utils/pdbedit.c +++ b/source3/utils/pdbedit.c @@ -55,9 +55,10 @@ #define BIT_LOGONHOURS 0x10000000 #define BIT_KICKOFFTIME 0x20000000 #define BIT_DESCRIPTION 0x40000000 +#define BIT_PWSETNTHASH 0x80000000 #define MASK_ALWAYS_GOOD 0x0000001F -#define MASK_USER_GOOD 0x60405FE0 +#define MASK_USER_GOOD 0xE0405FE0 static int get_sid_from_cli_string(struct dom_sid *sid, const char *str_sid) { @@ -317,6 +318,12 @@ static int print_sam_info (struct samu *sam_pwent, bool verbosity, bool smbpwdst hours = pdb_get_hours(sam_pwent); pdb_sethexhours(temp, hours); printf ("Logon hours : %s\n", temp); + if (smbpwdstyle){ + pdb_sethexpwd(temp, pdb_get_lanman_passwd(sam_pwent), pdb_get_acct_ctrl(sam_pwent)); + printf ("LM hash : %s\n", temp); + pdb_sethexpwd(temp, pdb_get_nt_passwd(sam_pwent), pdb_get_acct_ctrl(sam_pwent)); + printf ("NT hash : %s\n", temp); + } } else if (smbpwdstyle) { char lm_passwd[33]; @@ -499,7 +506,7 @@ static int set_user_info(const char *username, const char *fullname, const char *profile, const char *account_control, const char *user_sid, const char *user_domain, const bool badpw, const bool hours, - const char *kickoff_time) + const char *kickoff_time, const char *str_hex_pwd) { bool updated_autolock = False, updated_badpw = False; struct samu *sam_pwent; @@ -601,9 +608,33 @@ static int set_user_info(const char *username, const char *fullname, pdb_set_kickoff_time(sam_pwent, value, PDB_CHANGED); } + if (str_hex_pwd) { + unsigned char new_nt_p16[NT_HASH_LEN]; + if(strlen(str_hex_pwd) != (NT_HASH_LEN *2)){ + fprintf(stderr, "Invalid hash\n"); + return -1; + } + + pdb_gethexpwd(str_hex_pwd, new_nt_p16); + + if (!pdb_set_nt_passwd (sam_pwent, new_nt_p16 , PDB_CHANGED)) { + fprintf(stderr, "Failed to set password from nt-hash\n"); + return -1; + } + + if (!pdb_set_pass_last_set_time (sam_pwent, time(NULL), PDB_CHANGED)){ + fprintf(stderr, "Failed to set last password set time\n"); + return -1; + } + if (!pdb_update_history(sam_pwent, new_nt_p16)){ + fprintf(stderr, "Failed to update password history\n"); + return -1; + } + } if (NT_STATUS_IS_OK(pdb_update_sam_account(sam_pwent))) { - print_user_info(username, True, False); + + print_user_info(username, True, (str_hex_pwd != NULL )); } else { fprintf (stderr, "Unable to modify entry!\n"); TALLOC_FREE(sam_pwent); @@ -1021,6 +1052,7 @@ int main(int argc, const char **argv) static int pw_from_stdin = False; struct pdb_methods *bin, *bout; static char *kickoff_time = NULL; + static char *str_hex_pwd = NULL; TALLOC_CTX *frame = talloc_stackframe(); NTSTATUS status; poptContext pc; @@ -1058,6 +1090,7 @@ int main(int argc, const char **argv) {"time-format", 0, POPT_ARG_STRING, &pwd_time_format, 0, "The time format for time parameters", NULL }, {"password-from-stdin", 't', POPT_ARG_NONE, &pw_from_stdin, 0, "get password from standard in", NULL}, {"kickoff-time", 'K', POPT_ARG_STRING, &kickoff_time, 0, "set the kickoff time", NULL}, + {"set-nt-hash", 0, POPT_ARG_STRING, &str_hex_pwd, 0, "set password from nt-hash", NULL}, POPT_COMMON_SAMBA POPT_TABLEEND }; @@ -1118,7 +1151,9 @@ int main(int argc, const char **argv) (badpw_reset ? BIT_BADPWRESET : 0) + (hours_reset ? BIT_LOGONHOURS : 0) + (kickoff_time ? BIT_KICKOFFTIME : 0) + + (str_hex_pwd ? BIT_PWSETNTHASH : 0 ) + (acct_desc ? BIT_DESCRIPTION : 0); + if (setparms & BIT_BACKEND) { /* HACK: set the global passdb backend by overwriting globals. @@ -1315,7 +1350,7 @@ int main(int argc, const char **argv) profile_path, account_control, user_sid, user_domain, badpw_reset, hours_reset, - kickoff_time); + kickoff_time,str_hex_pwd); } } } From 036203e02a4926d8d465a3f83f6bc565ae451483 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Tue, 5 Aug 2014 15:35:57 +1000 Subject: [PATCH 002/136] ctdb-freeze: Do an early exit if freeze is pending Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/server/ctdb_freeze.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/ctdb/server/ctdb_freeze.c b/ctdb/server/ctdb_freeze.c index ced2cca..db235c5 100644 --- a/ctdb/server/ctdb_freeze.c +++ b/ctdb/server/ctdb_freeze.c @@ -139,25 +139,28 @@ void ctdb_start_freeze(struct ctdb_context *ctdb, uint32_t priority) return; } + if (ctdb->freeze_handles[priority] != NULL) { + /* already trying to freeze */ + return; + } + DEBUG(DEBUG_ERR, ("Freeze priority %u\n", priority)); /* Stop any vacuuming going on: we don't want to wait. */ ctdb_stop_vacuuming(ctdb); - /* if there isn't a freeze lock child then create one */ - if (ctdb->freeze_handles[priority] == NULL) { - h = talloc_zero(ctdb, struct ctdb_freeze_handle); - CTDB_NO_MEMORY_FATAL(ctdb, h); - h->ctdb = ctdb; - h->priority = priority; - talloc_set_destructor(h, ctdb_freeze_handle_destructor); - - h->lreq = ctdb_lock_alldb_prio(h, ctdb, priority, false, - ctdb_freeze_lock_handler, h); - CTDB_NO_MEMORY_FATAL(ctdb, h->lreq); - ctdb->freeze_handles[priority] = h; - ctdb->freeze_mode[priority] = CTDB_FREEZE_PENDING; - } + /* create freeze lock child */ + h = talloc_zero(ctdb, struct ctdb_freeze_handle); + CTDB_NO_MEMORY_FATAL(ctdb, h); + h->ctdb = ctdb; + h->priority = priority; + talloc_set_destructor(h, ctdb_freeze_handle_destructor); + + h->lreq = ctdb_lock_alldb_prio(h, ctdb, priority, false, + ctdb_freeze_lock_handler, h); + CTDB_NO_MEMORY_FATAL(ctdb, h->lreq); + ctdb->freeze_handles[priority] = h; + ctdb->freeze_mode[priority] = CTDB_FREEZE_PENDING; } /* From b15a65ecc8646f4bd65012005ee28d4aaf272836 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Tue, 5 Aug 2014 16:23:47 +1000 Subject: [PATCH 003/136] ctdb-freeze: Remove commented test code Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/server/ctdb_freeze.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/ctdb/server/ctdb_freeze.c b/ctdb/server/ctdb_freeze.c index db235c5..0d587ef 100644 --- a/ctdb/server/ctdb_freeze.c +++ b/ctdb/server/ctdb_freeze.c @@ -251,16 +251,6 @@ static void thaw_priority(struct ctdb_context *ctdb, uint32_t priority) } ctdb->freeze_transaction_started = false; -#if 0 - /* this hack can be used to get a copy of the databases at the end of a recovery */ - system("mkdir -p /var/ctdb.saved; /usr/bin/rsync --delete -a /var/ctdb/ /var/ctdb.saved/$$ 2>&1 > /dev/null"); -#endif - -#if 0 - /* and this one for local testing */ - system("mkdir -p test.db.saved; /usr/bin/rsync --delete -a test.db/ test.db.saved/$$ 2>&1 > /dev/null"); -#endif - if (ctdb->freeze_handles[priority] != NULL) { talloc_free(ctdb->freeze_handles[priority]); ctdb->freeze_handles[priority] = NULL; From 8df0916520f2cf938cbdece28d83c8a7b1824934 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Tue, 5 Aug 2014 16:37:43 +1000 Subject: [PATCH 004/136] ctdb-locking: Remove unused priority argument from db_handler_t Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/server/ctdb_lock.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/ctdb/server/ctdb_lock.c b/ctdb/server/ctdb_lock.c index 82295ea..92e9284 100644 --- a/ctdb/server/ctdb_lock.c +++ b/ctdb/server/ctdb_lock.c @@ -114,7 +114,6 @@ static bool later_db(struct ctdb_context *ctdb, const char *name) } typedef int (*db_handler_t)(struct ctdb_db_context *ctdb_db, - uint32_t priority, void *private_data); static int ctdb_db_iterator(struct ctdb_context *ctdb, uint32_t priority, @@ -130,7 +129,7 @@ static int ctdb_db_iterator(struct ctdb_context *ctdb, uint32_t priority, if (later_db(ctdb, ctdb_db->db_name)) { continue; } - ret = handler(ctdb_db, priority, private_data); + ret = handler(ctdb_db, private_data); if (ret != 0) { return -1; } @@ -145,7 +144,7 @@ static int ctdb_db_iterator(struct ctdb_context *ctdb, uint32_t priority, if (!later_db(ctdb, ctdb_db->db_name)) { continue; } - ret = handler(ctdb_db, priority, private_data); + ret = handler(ctdb_db, private_data); if (ret != 0) { return -1; } @@ -158,13 +157,12 @@ static int ctdb_db_iterator(struct ctdb_context *ctdb, uint32_t priority, /* * lock all databases - mark only */ -static int db_lock_mark_handler(struct ctdb_db_context *ctdb_db, uint32_t priority, +static int db_lock_mark_handler(struct ctdb_db_context *ctdb_db, void *private_data) { int tdb_transaction_write_lock_mark(struct tdb_context *); - DEBUG(DEBUG_INFO, ("marking locked database %s, priority:%u\n", - ctdb_db->db_name, priority)); + DEBUG(DEBUG_INFO, ("marking locked database %s\n", ctdb_db->db_name)); if (tdb_transaction_write_lock_mark(ctdb_db->ltdb->tdb) != 0) { DEBUG(DEBUG_ERR, ("Failed to mark (transaction lock) database %s\n", @@ -215,13 +213,12 @@ static int ctdb_lockall_mark(struct ctdb_context *ctdb) /* * lock all databases - unmark only */ -static int db_lock_unmark_handler(struct ctdb_db_context *ctdb_db, uint32_t priority, +static int db_lock_unmark_handler(struct ctdb_db_context *ctdb_db, void *private_data) { int tdb_transaction_write_lock_unmark(struct tdb_context *); - DEBUG(DEBUG_INFO, ("unmarking locked database %s, priority:%u\n", - ctdb_db->db_name, priority)); + DEBUG(DEBUG_INFO, ("unmarking locked database %s\n", ctdb_db->db_name)); if (tdb_transaction_write_lock_unmark(ctdb_db->ltdb->tdb) != 0) { DEBUG(DEBUG_ERR, ("Failed to unmark (transaction lock) database %s\n", @@ -558,8 +555,7 @@ static void ctdb_lock_timeout_handler(struct tevent_context *ev, } -static int db_count_handler(struct ctdb_db_context *ctdb_db, uint32_t priority, - void *private_data) +static int db_count_handler(struct ctdb_db_context *ctdb_db, void *private_data) { int *count = (int *)private_data; @@ -585,8 +581,7 @@ struct db_namelist { int n; }; -static int db_name_handler(struct ctdb_db_context *ctdb_db, uint32_t priority, - void *private_data) +static int db_name_handler(struct ctdb_db_context *ctdb_db, void *private_data) { struct db_namelist *list = (struct db_namelist *)private_data; From b1f468017750c4c91f80c5239a364546a1d35e72 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Tue, 5 Aug 2014 16:43:11 +1000 Subject: [PATCH 005/136] ctdb-locking: Rename ctdb_db_iterator to ctdb_db_prio_iterator This iterator only iterates through databases of specified priority. Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/server/ctdb_lock.c | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/ctdb/server/ctdb_lock.c b/ctdb/server/ctdb_lock.c index 92e9284..cfc0e6c 100644 --- a/ctdb/server/ctdb_lock.c +++ b/ctdb/server/ctdb_lock.c @@ -116,8 +116,8 @@ static bool later_db(struct ctdb_context *ctdb, const char *name) typedef int (*db_handler_t)(struct ctdb_db_context *ctdb_db, void *private_data); -static int ctdb_db_iterator(struct ctdb_context *ctdb, uint32_t priority, - db_handler_t handler, void *private_data) +static int ctdb_db_prio_iterator(struct ctdb_context *ctdb, uint32_t priority, + db_handler_t handler, void *private_data) { struct ctdb_db_context *ctdb_db; int ret; @@ -193,7 +193,7 @@ int ctdb_lockall_mark_prio(struct ctdb_context *ctdb, uint32_t priority) return -1; } - return ctdb_db_iterator(ctdb, priority, db_lock_mark_handler, NULL); + return ctdb_db_prio_iterator(ctdb, priority, db_lock_mark_handler, NULL); } static int ctdb_lockall_mark(struct ctdb_context *ctdb) @@ -201,7 +201,11 @@ static int ctdb_lockall_mark(struct ctdb_context *ctdb) uint32_t priority; for (priority=1; priority<=NUM_DB_PRIORITIES; priority++) { - if (ctdb_db_iterator(ctdb, priority, db_lock_mark_handler, NULL) != 0) { + int ret; + + ret = ctdb_db_prio_iterator(ctdb, priority, + db_lock_mark_handler, NULL); + if (ret != 0) { return -1; } } @@ -249,7 +253,8 @@ int ctdb_lockall_unmark_prio(struct ctdb_context *ctdb, uint32_t priority) return -1; } - return ctdb_db_iterator(ctdb, priority, db_lock_unmark_handler, NULL); + return ctdb_db_prio_iterator(ctdb, priority, db_lock_unmark_handler, + NULL); } static int ctdb_lockall_unmark(struct ctdb_context *ctdb) @@ -257,7 +262,11 @@ static int ctdb_lockall_unmark(struct ctdb_context *ctdb) uint32_t priority; for (priority=NUM_DB_PRIORITIES; priority>0; priority--) { - if (ctdb_db_iterator(ctdb, priority, db_lock_unmark_handler, NULL) != 0) { + int ret; + + ret = ctdb_db_prio_iterator(ctdb, priority, + db_lock_unmark_handler, NULL); + if (ret != 0) { return -1; } } @@ -614,13 +623,15 @@ static bool lock_helper_args(TALLOC_CTX *mem_ctx, case LOCK_ALLDB_PRIO: nargs = 3; - ctdb_db_iterator(ctdb, lock_ctx->priority, db_count_handler, &nargs); + ctdb_db_prio_iterator(ctdb, lock_ctx->priority, + db_count_handler, &nargs); break; case LOCK_ALLDB: nargs = 3; for (priority=1; prioritypriority, db_name_handler, &list); + ctdb_db_prio_iterator(ctdb, lock_ctx->priority, + db_name_handler, &list); break; case LOCK_ALLDB: @@ -668,7 +680,8 @@ static bool lock_helper_args(TALLOC_CTX *mem_ctx, list.names = args; list.n = 3; for (priority=1; priority Date: Tue, 5 Aug 2014 16:45:34 +1000 Subject: [PATCH 006/136] ctdb-locking: Expose ctdb_db_prio_iterator function Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/include/ctdb_private.h | 6 ++++++ ctdb/server/ctdb_lock.c | 7 ++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/ctdb/include/ctdb_private.h b/ctdb/include/ctdb_private.h index 42b87ca..fad09d1 100644 --- a/ctdb/include/ctdb_private.h +++ b/ctdb/include/ctdb_private.h @@ -1459,6 +1459,12 @@ int32_t ctdb_control_reload_public_ips(struct ctdb_context *ctdb, struct ctdb_re /* from server/ctdb_lock.c */ struct lock_request; +typedef int (*ctdb_db_handler_t)(struct ctdb_db_context *ctdb_db, + void *private_data); + +int ctdb_db_prio_iterator(struct ctdb_context *ctdb, uint32_t priority, + ctdb_db_handler_t handler, void *private_data); + int ctdb_lockall_mark_prio(struct ctdb_context *ctdb, uint32_t priority); int ctdb_lockall_unmark_prio(struct ctdb_context *ctdb, uint32_t priority); diff --git a/ctdb/server/ctdb_lock.c b/ctdb/server/ctdb_lock.c index cfc0e6c..63652b5 100644 --- a/ctdb/server/ctdb_lock.c +++ b/ctdb/server/ctdb_lock.c @@ -113,11 +113,8 @@ static bool later_db(struct ctdb_context *ctdb, const char *name) return false; } -typedef int (*db_handler_t)(struct ctdb_db_context *ctdb_db, - void *private_data); - -static int ctdb_db_prio_iterator(struct ctdb_context *ctdb, uint32_t priority, - db_handler_t handler, void *private_data) +int ctdb_db_prio_iterator(struct ctdb_context *ctdb, uint32_t priority, + ctdb_db_handler_t handler, void *private_data) { struct ctdb_db_context *ctdb_db; int ret; From fb237608d7bdb3faf471a7be8a96176a42826811 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Tue, 5 Aug 2014 16:49:06 +1000 Subject: [PATCH 007/136] ctdb-locking: Add ctdb_db_iterator to iterate through all databases Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/include/ctdb_private.h | 2 ++ ctdb/server/ctdb_lock.c | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/ctdb/include/ctdb_private.h b/ctdb/include/ctdb_private.h index fad09d1..8a906e5 100644 --- a/ctdb/include/ctdb_private.h +++ b/ctdb/include/ctdb_private.h @@ -1464,6 +1464,8 @@ typedef int (*ctdb_db_handler_t)(struct ctdb_db_context *ctdb_db, int ctdb_db_prio_iterator(struct ctdb_context *ctdb, uint32_t priority, ctdb_db_handler_t handler, void *private_data); +int ctdb_db_iterator(struct ctdb_context *ctdb, ctdb_db_handler_t handler, + void *private_data); int ctdb_lockall_mark_prio(struct ctdb_context *ctdb, uint32_t priority); int ctdb_lockall_unmark_prio(struct ctdb_context *ctdb, uint32_t priority); diff --git a/ctdb/server/ctdb_lock.c b/ctdb/server/ctdb_lock.c index 63652b5..2ef5b21 100644 --- a/ctdb/server/ctdb_lock.c +++ b/ctdb/server/ctdb_lock.c @@ -150,6 +150,21 @@ int ctdb_db_prio_iterator(struct ctdb_context *ctdb, uint32_t priority, return 0; } +int ctdb_db_iterator(struct ctdb_context *ctdb, ctdb_db_handler_t handler, + void *private_data) +{ + struct ctdb_db_context *ctdb_db; + int ret; + + for (ctdb_db = ctdb->db_list; ctdb_db; ctdb_db = ctdb_db->next) { + ret = handler(ctdb_db, private_data); + if (ret != 0) { + return -1; + } + } + + return 0; +} /* * lock all databases - mark only From 74f7eebc7911a4ec5f6ee68266b027a661579c68 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Tue, 5 Aug 2014 16:23:21 +1000 Subject: [PATCH 008/136] ctdb-freeze: Use ctdb_db_prio_iterator to cancel transaction on databases Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/server/ctdb_freeze.c | 50 ++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/ctdb/server/ctdb_freeze.c b/ctdb/server/ctdb_freeze.c index 0d587ef..002f148 100644 --- a/ctdb/server/ctdb_freeze.c +++ b/ctdb/server/ctdb_freeze.c @@ -26,6 +26,26 @@ #include "lib/tdb_wrap/tdb_wrap.h" #include "../common/rb_tree.h" + +/** + * Cancel a transaction on database + */ +static int db_transaction_cancel_handler(struct ctdb_db_context *ctdb_db, + void *private_data) +{ + int ret; + + tdb_add_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK); + ret = tdb_transaction_cancel(ctdb_db->ltdb->tdb); + if (ret != 0) { + DEBUG(DEBUG_ERR, ("Failed to cancel transaction for db %s\n", + ctdb_db->db_name)); + } + tdb_remove_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK); + return 0; +} + + /* a list of control requests waiting for a freeze lock child to get the database locks @@ -48,27 +68,17 @@ struct ctdb_freeze_handle { /* destroy a freeze handle - */ + */ static int ctdb_freeze_handle_destructor(struct ctdb_freeze_handle *h) { struct ctdb_context *ctdb = h->ctdb; - struct ctdb_db_context *ctdb_db; DEBUG(DEBUG_ERR,("Release freeze handler for prio %u\n", h->priority)); /* cancel any pending transactions */ if (ctdb->freeze_transaction_started) { - for (ctdb_db=ctdb->db_list;ctdb_db;ctdb_db=ctdb_db->next) { - if (ctdb_db->priority != h->priority) { - continue; - } - tdb_add_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK); - if (tdb_transaction_cancel(ctdb_db->ltdb->tdb) != 0) { - DEBUG(DEBUG_ERR,(__location__ " Failed to cancel transaction for db '%s'\n", - ctdb_db->db_name)); - } - tdb_remove_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK); - } + ctdb_db_prio_iterator(ctdb, h->priority, + db_transaction_cancel_handler, NULL); ctdb->freeze_transaction_started = false; } @@ -238,18 +248,10 @@ static void thaw_priority(struct ctdb_context *ctdb, uint32_t priority) /* cancel any pending transactions */ if (ctdb->freeze_transaction_started) { - struct ctdb_db_context *ctdb_db; - - for (ctdb_db=ctdb->db_list;ctdb_db;ctdb_db=ctdb_db->next) { - tdb_add_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK); - if (tdb_transaction_cancel(ctdb_db->ltdb->tdb) != 0) { - DEBUG(DEBUG_ERR,(__location__ " Failed to cancel transaction for db '%s'\n", - ctdb_db->db_name)); - } - tdb_remove_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK); - } + ctdb_db_prio_iterator(ctdb, priority, + db_transaction_cancel_handler, NULL); + ctdb->freeze_transaction_started = false; } - ctdb->freeze_transaction_started = false; if (ctdb->freeze_handles[priority] != NULL) { talloc_free(ctdb->freeze_handles[priority]); From 457618888a80d3f5733a9e3dd41d3ab64ace4ae5 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Tue, 5 Aug 2014 17:02:07 +1000 Subject: [PATCH 009/136] ctdb-freeze: Use ctdb_db_iterator to cancel transaction on databases Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/server/ctdb_freeze.c | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/ctdb/server/ctdb_freeze.c b/ctdb/server/ctdb_freeze.c index 002f148..5c20253 100644 --- a/ctdb/server/ctdb_freeze.c +++ b/ctdb/server/ctdb_freeze.c @@ -341,21 +341,9 @@ int32_t ctdb_control_transaction_start(struct ctdb_context *ctdb, uint32_t id) */ int32_t ctdb_control_transaction_cancel(struct ctdb_context *ctdb) { - struct ctdb_db_context *ctdb_db; - DEBUG(DEBUG_ERR,(__location__ " recovery transaction cancelled called\n")); - for (ctdb_db=ctdb->db_list;ctdb_db;ctdb_db=ctdb_db->next) { - tdb_add_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK); - - if (tdb_transaction_cancel(ctdb_db->ltdb->tdb) != 0) { - DEBUG(DEBUG_ERR,(__location__ " Failed to cancel transaction for db '%s'\n", ctdb_db->db_name)); - /* not a fatal error */ - } - - tdb_remove_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK); - } - + ctdb_db_iterator(ctdb, db_transaction_cancel_handler, NULL); ctdb->freeze_transaction_started = false; return 0; @@ -425,14 +413,7 @@ int32_t ctdb_control_transaction_commit(struct ctdb_context *ctdb, uint32_t id) fail: /* cancel any pending transactions */ - for (ctdb_db=ctdb->db_list;ctdb_db;ctdb_db=ctdb_db->next) { - tdb_add_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK); - if (tdb_transaction_cancel(ctdb_db->ltdb->tdb) != 0) { - DEBUG(DEBUG_ERR,(__location__ " Failed to cancel transaction for db '%s'\n", - ctdb_db->db_name)); - } - tdb_remove_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK); - } + ctdb_db_iterator(ctdb, db_transaction_cancel_handler, NULL); ctdb->freeze_transaction_started = false; return -1; From bc9a68592e15068332a915270c6ebdc46f4542d0 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Tue, 5 Aug 2014 17:02:28 +1000 Subject: [PATCH 010/136] ctdb-freeze: Use ctdb_db_iterator to start transaction on databases Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/server/ctdb_freeze.c | 57 +++++++++++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/ctdb/server/ctdb_freeze.c b/ctdb/server/ctdb_freeze.c index 5c20253..8243fab 100644 --- a/ctdb/server/ctdb_freeze.c +++ b/ctdb/server/ctdb_freeze.c @@ -45,6 +45,34 @@ static int db_transaction_cancel_handler(struct ctdb_db_context *ctdb_db, return 0; } +/** + * Start a transaction on database + */ +static int db_transaction_start_handler(struct ctdb_db_context *ctdb_db, + void *private_data) +{ + bool freeze_transaction_started = *(bool *)private_data; + int ret; + + tdb_add_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK); + if (freeze_transaction_started) { + ret = tdb_transaction_cancel(ctdb_db->ltdb->tdb); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Failed to cancel transaction for db %s\n", + ctdb_db->db_name)); + } + } + ret = tdb_transaction_start(ctdb_db->ltdb->tdb); + tdb_remove_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK); + if (ret != 0) { + DEBUG(DEBUG_ERR, ("Failed to start transaction for db %s\n", + ctdb_db->db_name)); + return -1; + } + return 0; +} + /* a list of control requests waiting for a freeze lock child to get @@ -296,8 +324,7 @@ int32_t ctdb_control_thaw(struct ctdb_context *ctdb, uint32_t priority, */ int32_t ctdb_control_transaction_start(struct ctdb_context *ctdb, uint32_t id) { - struct ctdb_db_context *ctdb_db; - int i; + int i, ret; for (i=1;i<=NUM_DB_PRIORITIES; i++) { if (ctdb->freeze_mode[i] != CTDB_FREEZE_FROZEN) { @@ -306,28 +333,10 @@ int32_t ctdb_control_transaction_start(struct ctdb_context *ctdb, uint32_t id) } } - for (ctdb_db=ctdb->db_list;ctdb_db;ctdb_db=ctdb_db->next) { - int ret; - - tdb_add_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK); - - if (ctdb->freeze_transaction_started) { - if (tdb_transaction_cancel(ctdb_db->ltdb->tdb) != 0) { - DEBUG(DEBUG_ERR,(__location__ " Failed to cancel transaction for db '%s'\n", - ctdb_db->db_name)); - /* not a fatal error */ - } - } - - ret = tdb_transaction_start(ctdb_db->ltdb->tdb); - - tdb_remove_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK); - - if (ret != 0) { - DEBUG(DEBUG_ERR,(__location__ " Failed to start transaction for db '%s'\n", - ctdb_db->db_name)); - return -1; - } + ret = ctdb_db_iterator(ctdb, db_transaction_start_handler, + &ctdb->freeze_transaction_started); + if (ret != 0) { + return -1; } ctdb->freeze_transaction_started = true; From 2116c55b08288b3c59613ed0d088eeba1c29d682 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Tue, 5 Aug 2014 17:13:22 +1000 Subject: [PATCH 011/136] ctdb-freeze: Use ctdb_db_iterator to commit transaction on databases Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/server/ctdb_freeze.c | 53 +++++++++++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/ctdb/server/ctdb_freeze.c b/ctdb/server/ctdb_freeze.c index 8243fab..ec0a970 100644 --- a/ctdb/server/ctdb_freeze.c +++ b/ctdb/server/ctdb_freeze.c @@ -73,6 +73,33 @@ static int db_transaction_start_handler(struct ctdb_db_context *ctdb_db, return 0; } +/** + * Commit a transaction on database + */ +static int db_transaction_commit_handler(struct ctdb_db_context *ctdb_db, + void *private_data) +{ + int healthy_nodes = *(int *)private_data; + int ret; + + tdb_add_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK); + ret = tdb_transaction_commit(ctdb_db->ltdb->tdb); + tdb_remove_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK); + if (ret != 0) { + DEBUG(DEBUG_ERR, ("Failed to commit transaction for db %s\n", + ctdb_db->db_name)); + return -1; + } + + ret = ctdb_update_persistent_health(ctdb_db->ctdb, ctdb_db, NULL, + healthy_nodes); + if (ret != 0) { + DEBUG(DEBUG_ERR, ("Failed to update persistent health for db %s\n", + ctdb_db->db_name)); + } + return ret; +} + /* a list of control requests waiting for a freeze lock child to get @@ -363,9 +390,9 @@ int32_t ctdb_control_transaction_cancel(struct ctdb_context *ctdb) */ int32_t ctdb_control_transaction_commit(struct ctdb_context *ctdb, uint32_t id) { - struct ctdb_db_context *ctdb_db; int i; int healthy_nodes = 0; + int ret; for (i=1;i<=NUM_DB_PRIORITIES; i++) { if (ctdb->freeze_mode[i] != CTDB_FREEZE_FROZEN) { @@ -394,25 +421,11 @@ int32_t ctdb_control_transaction_commit(struct ctdb_context *ctdb, uint32_t id) } DEBUG(DEBUG_INFO,(__location__ " healthy_nodes[%d]\n", healthy_nodes)); - for (ctdb_db=ctdb->db_list;ctdb_db;ctdb_db=ctdb_db->next) { - int ret; - - tdb_add_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK); - ret = tdb_transaction_commit(ctdb_db->ltdb->tdb); - if (ret != 0) { - DEBUG(DEBUG_ERR,(__location__ " Failed to commit transaction for db '%s'. Cancel all transactions and resetting transaction_started to false.\n", - ctdb_db->db_name)); - goto fail; - } - tdb_remove_flags(ctdb_db->ltdb->tdb, TDB_NOLOCK); - - ret = ctdb_update_persistent_health(ctdb, ctdb_db, NULL, healthy_nodes); - if (ret != 0) { - DEBUG(DEBUG_CRIT,(__location__ " Failed to update persistent health for db '%s'. " - "Cancel all remaining transactions and resetting transaction_started to false.\n", - ctdb_db->db_name)); - goto fail; - } + ret = ctdb_db_iterator(ctdb, db_transaction_commit_handler, + &healthy_nodes); + if (ret != 0) { + DEBUG(DEBUG_ERR, ("Cancel all transactions\n")); + goto fail; } ctdb->freeze_transaction_started = false; From 6a212d13d046d9f3ff6a2423d55b24b8068498e3 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Tue, 5 Aug 2014 14:42:00 +1000 Subject: [PATCH 012/136] ctdb-call: Convert pending calls list to per database list The pending calls are migration requests received from clients (over unix domain socket) which are under processing. After a recovery is finished, any requests which are under processing will be dropped since they do not belong to the current generation. All the pending call requests are resent with new generation to restart record migrations. This is in preparation for parallel database recovery. Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/include/ctdb_private.h | 4 +++- ctdb/server/ctdb_call.c | 18 ++++++++++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/ctdb/include/ctdb_private.h b/ctdb/include/ctdb_private.h index 8a906e5..b8ca020 100644 --- a/ctdb/include/ctdb_private.h +++ b/ctdb/include/ctdb_private.h @@ -489,7 +489,6 @@ struct ctdb_context { struct ctdb_vnn_map *vnn_map; uint32_t num_clients; uint32_t recovery_master; - struct ctdb_call_state *pending_calls; struct ctdb_client_ip *client_ip_list; bool do_checkpublicip; struct trbt_tree *server_ids; @@ -584,6 +583,8 @@ struct ctdb_db_context { struct lock_context *lock_current; struct lock_context *lock_pending; int lock_num_current; + + struct ctdb_call_state *pending_calls; }; @@ -1016,6 +1017,7 @@ int32_t ctdb_run_eventscripts(struct ctdb_context *ctdb, struct ctdb_req_control void ctdb_daemon_cancel_controls(struct ctdb_context *ctdb, struct ctdb_node *node); +void ctdb_call_resend_db(struct ctdb_db_context *ctdb); void ctdb_call_resend_all(struct ctdb_context *ctdb); void ctdb_node_dead(struct ctdb_node *node); void ctdb_node_connected(struct ctdb_node *node); diff --git a/ctdb/server/ctdb_call.c b/ctdb/server/ctdb_call.c index 391dfb1..a158d26 100644 --- a/ctdb/server/ctdb_call.c +++ b/ctdb/server/ctdb_call.c @@ -1301,7 +1301,7 @@ void ctdb_reply_error(struct ctdb_context *ctdb, struct ctdb_req_header *hdr) */ static int ctdb_call_destructor(struct ctdb_call_state *state) { - DLIST_REMOVE(state->ctdb_db->ctdb->pending_calls, state); + DLIST_REMOVE(state->ctdb_db->pending_calls, state); ctdb_reqid_remove(state->ctdb_db->ctdb, state->reqid); return 0; } @@ -1334,15 +1334,25 @@ static void ctdb_call_resend(struct ctdb_call_state *state) /* resend all pending calls on recovery */ -void ctdb_call_resend_all(struct ctdb_context *ctdb) +void ctdb_call_resend_db(struct ctdb_db_context *ctdb_db) { struct ctdb_call_state *state, *next; - for (state=ctdb->pending_calls;state;state=next) { + + for (state = ctdb_db->pending_calls; state; state = next) { next = state->next; ctdb_call_resend(state); } } +void ctdb_call_resend_all(struct ctdb_context *ctdb) +{ + struct ctdb_db_context *ctdb_db; + + for (ctdb_db = ctdb->db_list; ctdb_db; ctdb_db = ctdb_db->next) { + ctdb_call_resend_db(ctdb_db); + } +} + /* this allows the caller to setup a async.fn */ @@ -1445,7 +1455,7 @@ struct ctdb_call_state *ctdb_daemon_call_send_remote(struct ctdb_db_context *ctd state->state = CTDB_CALL_WAIT; state->generation = ctdb->vnn_map->generation; - DLIST_ADD(ctdb->pending_calls, state); + DLIST_ADD(ctdb_db->pending_calls, state); ctdb_queue_packet(ctdb, &state->c->hdr); From 056c44fda3f3d84dc3eb9766e0ee04bdb6387ea5 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Thu, 21 Aug 2014 12:26:58 +1000 Subject: [PATCH 013/136] ctdb-freeze: Refactor code to check if databases are frozen Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/include/ctdb_private.h | 2 ++ ctdb/server/ctdb_freeze.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/ctdb/include/ctdb_private.h b/ctdb/include/ctdb_private.h index b8ca020..83b8bd2 100644 --- a/ctdb/include/ctdb_private.h +++ b/ctdb/include/ctdb_private.h @@ -997,6 +997,8 @@ void ctdb_request_control_reply(struct ctdb_context *ctdb, struct ctdb_req_contr int32_t ctdb_control_freeze(struct ctdb_context *ctdb, struct ctdb_req_control *c, bool *async_reply); int32_t ctdb_control_thaw(struct ctdb_context *ctdb, uint32_t priority, bool check_recmode); +bool ctdb_db_prio_frozen(struct ctdb_context *ctdb, uint32_t priority); +bool ctdb_db_all_frozen(struct ctdb_context *ctdb); int ctdb_start_recoverd(struct ctdb_context *ctdb); void ctdb_stop_recoverd(struct ctdb_context *ctdb); diff --git a/ctdb/server/ctdb_freeze.c b/ctdb/server/ctdb_freeze.c index ec0a970..9f9710f 100644 --- a/ctdb/server/ctdb_freeze.c +++ b/ctdb/server/ctdb_freeze.c @@ -488,3 +488,32 @@ int32_t ctdb_control_wipe_database(struct ctdb_context *ctdb, TDB_DATA indata) return 0; } + +bool ctdb_db_prio_frozen(struct ctdb_context *ctdb, uint32_t priority) +{ + if (priority == 0) { + priority = 1; + } + if (priority > NUM_DB_PRIORITIES) { + DEBUG(DEBUG_ERR, ("Invalid DB priority specified\n")); + return false; + } + + if (ctdb->freeze_mode[priority] != CTDB_FREEZE_FROZEN) { + return false; + } + + return true; +} + +bool ctdb_db_all_frozen(struct ctdb_context *ctdb) +{ + int i; + + for (i=1; i<=NUM_DB_PRIORITIES; i++) { + if (ctdb->freeze_mode[i] != CTDB_FREEZE_FROZEN) { + return false; + } + } + return true; +} From 8c58c7392fe342fb39fcaf81c2465762f1823b51 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Thu, 21 Aug 2014 12:32:02 +1000 Subject: [PATCH 014/136] ctdb-daemon: Avoid the use of ctdb->freeze_mode variable Use ctdb->freeze_mode only in ctdb_freeze.c and use the functions to check if databases are frozen everywhere else. Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/server/ctdb_banning.c | 10 +--------- ctdb/server/ctdb_control.c | 8 +------- ctdb/server/ctdb_freeze.c | 20 +++++++++----------- ctdb/server/ctdb_lock.c | 10 ++++------ ctdb/server/ctdb_recover.c | 13 +++++-------- 5 files changed, 20 insertions(+), 41 deletions(-) diff --git a/ctdb/server/ctdb_banning.c b/ctdb/server/ctdb_banning.c index d8f7ab1..91064b4 100644 --- a/ctdb/server/ctdb_banning.c +++ b/ctdb/server/ctdb_banning.c @@ -31,17 +31,9 @@ ctdb_ban_node_event(struct event_context *ev, struct timed_event *te, struct timeval t, void *private_data) { struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context); - bool freeze_failed = false; - int i; /* Make sure we were able to freeze databases during banning */ - for (i=1; i<=NUM_DB_PRIORITIES; i++) { - if (ctdb->freeze_mode[i] != CTDB_FREEZE_FROZEN) { - freeze_failed = true; - break; - } - } - if (freeze_failed) { + if (!ctdb_db_all_frozen(ctdb)) { DEBUG(DEBUG_ERR, ("Banning timedout, but still unable to freeze databases\n")); ctdb_ban_self(ctdb); return; diff --git a/ctdb/server/ctdb_control.c b/ctdb/server/ctdb_control.c index 2335f06..7b26ff9 100644 --- a/ctdb/server/ctdb_control.c +++ b/ctdb/server/ctdb_control.c @@ -110,16 +110,10 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb, } case CTDB_CONTROL_STATISTICS: { - int i; CHECK_CONTROL_DATA_SIZE(0); ctdb->statistics.memory_used = talloc_total_size(NULL); ctdb->statistics.num_clients = ctdb->num_clients; - ctdb->statistics.frozen = 0; - for (i=1; i<= NUM_DB_PRIORITIES; i++) { - if (ctdb->freeze_mode[i] == CTDB_FREEZE_FROZEN) { - ctdb->statistics.frozen = 1; - } - } + ctdb->statistics.frozen = (ctdb_db_all_frozen(ctdb) ? 1 : 0); ctdb->statistics.recovering = (ctdb->recovery_mode == CTDB_RECOVERY_ACTIVE); ctdb->statistics.statistics_current_time = timeval_current(); diff --git a/ctdb/server/ctdb_freeze.c b/ctdb/server/ctdb_freeze.c index 9f9710f..6b6a712 100644 --- a/ctdb/server/ctdb_freeze.c +++ b/ctdb/server/ctdb_freeze.c @@ -351,13 +351,12 @@ int32_t ctdb_control_thaw(struct ctdb_context *ctdb, uint32_t priority, */ int32_t ctdb_control_transaction_start(struct ctdb_context *ctdb, uint32_t id) { - int i, ret; + int ret; - for (i=1;i<=NUM_DB_PRIORITIES; i++) { - if (ctdb->freeze_mode[i] != CTDB_FREEZE_FROZEN) { - DEBUG(DEBUG_ERR,(__location__ " Failed transaction_start while not frozen\n")); - return -1; - } + if (!ctdb_db_all_frozen(ctdb)) { + DEBUG(DEBUG_ERR, (__location__ + " failing transaction start while not frozen\n")); + return -1; } ret = ctdb_db_iterator(ctdb, db_transaction_start_handler, @@ -394,11 +393,10 @@ int32_t ctdb_control_transaction_commit(struct ctdb_context *ctdb, uint32_t id) int healthy_nodes = 0; int ret; - for (i=1;i<=NUM_DB_PRIORITIES; i++) { - if (ctdb->freeze_mode[i] != CTDB_FREEZE_FROZEN) { - DEBUG(DEBUG_ERR,(__location__ " Failed transaction_start while not frozen\n")); - return -1; - } + if (!ctdb_db_all_frozen(ctdb)) { + DEBUG(DEBUG_ERR, (__location__ + " failing transaction commit while not frozen\n")); + return -1; } if (!ctdb->freeze_transaction_started) { diff --git a/ctdb/server/ctdb_lock.c b/ctdb/server/ctdb_lock.c index 2ef5b21..9494f9f 100644 --- a/ctdb/server/ctdb_lock.c +++ b/ctdb/server/ctdb_lock.c @@ -196,11 +196,10 @@ int ctdb_lockall_mark_prio(struct ctdb_context *ctdb, uint32_t priority) /* * This function is only used by the main dameon during recovery. * At this stage, the databases have already been locked, by a - * dedicated child process. The freeze_mode variable is used to track - * whether the actual locks are held by the child process or not. + * dedicated child process. */ - if (ctdb->freeze_mode[priority] != CTDB_FREEZE_FROZEN) { + if (!ctdb_db_prio_frozen(ctdb, priority)) { DEBUG(DEBUG_ERR, ("Attempt to mark all databases locked when not frozen\n")); return -1; } @@ -256,11 +255,10 @@ int ctdb_lockall_unmark_prio(struct ctdb_context *ctdb, uint32_t priority) /* * This function is only used by the main daemon during recovery. * At this stage, the databases have already been locked, by a - * dedicated child process. The freeze_mode variable is used to track - * whether the actual locks are held by the child process or not. + * dedicated child process. */ - if (ctdb->freeze_mode[priority] != CTDB_FREEZE_FROZEN) { + if (!ctdb_db_prio_frozen(ctdb, priority)) { DEBUG(DEBUG_ERR, ("Attempt to unmark all databases locked when not frozen\n")); return -1; } diff --git a/ctdb/server/ctdb_recover.c b/ctdb/server/ctdb_recover.c index 23f793b..3a638fa 100644 --- a/ctdb/server/ctdb_recover.c +++ b/ctdb/server/ctdb_recover.c @@ -54,13 +54,10 @@ int ctdb_control_setvnnmap(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA indata, TDB_DATA *outdata) { struct ctdb_vnn_map_wire *map = (struct ctdb_vnn_map_wire *)indata.dptr; - int i; - for(i=1; i<=NUM_DB_PRIORITIES; i++) { - if (ctdb->freeze_mode[i] != CTDB_FREEZE_FROZEN) { - DEBUG(DEBUG_ERR,("Attempt to set vnnmap when not frozen\n")); - return -1; - } + if (!ctdb_db_all_frozen(ctdb)) { + DEBUG(DEBUG_ERR,("Attempt to set vnnmap when not frozen\n")); + return -1; } talloc_free(ctdb->vnn_map); @@ -252,7 +249,7 @@ int32_t ctdb_control_pull_db(struct ctdb_context *ctdb, TDB_DATA indata, TDB_DAT return -1; } - if (ctdb->freeze_mode[ctdb_db->priority] != CTDB_FREEZE_FROZEN) { + if (!ctdb_db_prio_frozen(ctdb, ctdb_db->priority)) { DEBUG(DEBUG_DEBUG,("rejecting ctdb_control_pull_db when not frozen\n")); return -1; } @@ -324,7 +321,7 @@ int32_t ctdb_control_push_db(struct ctdb_context *ctdb, TDB_DATA indata) return -1; } - if (ctdb->freeze_mode[ctdb_db->priority] != CTDB_FREEZE_FROZEN) { + if (!ctdb_db_prio_frozen(ctdb, ctdb_db->priority)) { DEBUG(DEBUG_DEBUG,("rejecting ctdb_control_push_db when not frozen\n")); return -1; } From 7afabb1285f6778b5b2862e178315b03f54eb8ef Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Tue, 15 Sep 2015 12:22:17 +1000 Subject: [PATCH 015/136] ctdb-daemon: Avoid the use of ctdb->freeze_handle variable These variables are used for state information related to freezing databases. Instead use the API functions to check if the databases are frozen. Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/server/ctdb_monitor.c | 12 ++++-------- ctdb/server/ctdb_recover.c | 2 +- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/ctdb/server/ctdb_monitor.c b/ctdb/server/ctdb_monitor.c index 6dd7c1e..edaae48 100644 --- a/ctdb/server/ctdb_monitor.c +++ b/ctdb/server/ctdb_monitor.c @@ -368,14 +368,10 @@ static void ctdb_check_health(struct event_context *ev, struct timed_event *te, ctdb->monitor->monitoring_mode == CTDB_MONITORING_DISABLED) { skip_monitoring = true; } else { - int i; - for (i=1; i<=NUM_DB_PRIORITIES; i++) { - if (ctdb->freeze_handles[i] != NULL) { - DEBUG(DEBUG_ERR, - ("Skip monitoring since databases are frozen\n")); - skip_monitoring = true; - break; - } + if (ctdb_db_all_frozen(ctdb)) { + DEBUG(DEBUG_ERR, + ("Skip monitoring since databases are frozen\n")); + skip_monitoring = true; } } diff --git a/ctdb/server/ctdb_recover.c b/ctdb/server/ctdb_recover.c index 3a638fa..0df7f58 100644 --- a/ctdb/server/ctdb_recover.c +++ b/ctdb/server/ctdb_recover.c @@ -558,7 +558,7 @@ int32_t ctdb_control_set_recmode(struct ctdb_context *ctdb, /* force the databases to thaw */ for (i=1; i<=NUM_DB_PRIORITIES; i++) { - if (ctdb->freeze_handles[i] != NULL) { + if (ctdb_db_prio_frozen(ctdb, i)) { ctdb_control_thaw(ctdb, i, false); } } From 5447864e5d31d433f9a54924f3bb01f1384620fd Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Tue, 5 Aug 2014 14:16:29 +1000 Subject: [PATCH 016/136] ctdb-daemon: Add controls to freeze/thaw a single database Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/include/ctdb_private.h | 11 +++ ctdb/include/ctdb_protocol.h | 2 + ctdb/server/ctdb_control.c | 9 +++ ctdb/server/ctdb_freeze.c | 182 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 204 insertions(+) diff --git a/ctdb/include/ctdb_private.h b/ctdb/include/ctdb_private.h index 83b8bd2..b6f7263 100644 --- a/ctdb/include/ctdb_private.h +++ b/ctdb/include/ctdb_private.h @@ -585,6 +585,11 @@ struct ctdb_db_context { int lock_num_current; struct ctdb_call_state *pending_calls; + + enum ctdb_freeze_mode freeze_mode; + struct ctdb_db_freeze_handle *freeze_handle; + bool freeze_transaction_started; + uint32_t freeze_transaction_id; }; @@ -994,9 +999,15 @@ int32_t ctdb_control_set_recmode(struct ctdb_context *ctdb, void ctdb_request_control_reply(struct ctdb_context *ctdb, struct ctdb_req_control *c, TDB_DATA *outdata, int32_t status, const char *errormsg); +int32_t ctdb_control_db_freeze(struct ctdb_context *ctdb, + struct ctdb_req_control *c, + uint32_t db_id, bool *async_reply); +int32_t ctdb_control_db_thaw(struct ctdb_context *ctdb, uint32_t db_id); + int32_t ctdb_control_freeze(struct ctdb_context *ctdb, struct ctdb_req_control *c, bool *async_reply); int32_t ctdb_control_thaw(struct ctdb_context *ctdb, uint32_t priority, bool check_recmode); +bool ctdb_db_frozen(struct ctdb_db_context *ctdb_db); bool ctdb_db_prio_frozen(struct ctdb_context *ctdb, uint32_t priority); bool ctdb_db_all_frozen(struct ctdb_context *ctdb); diff --git a/ctdb/include/ctdb_protocol.h b/ctdb/include/ctdb_protocol.h index d9cad7c..6169c8f 100644 --- a/ctdb/include/ctdb_protocol.h +++ b/ctdb/include/ctdb_protocol.h @@ -415,6 +415,8 @@ enum ctdb_controls {CTDB_CONTROL_PROCESS_EXISTS = 0, CTDB_CONTROL_GET_RUNSTATE = 138, CTDB_CONTROL_DB_DETACH = 139, CTDB_CONTROL_GET_NODES_FILE = 140, + CTDB_CONTROL_DB_FREEZE = 141, + CTDB_CONTROL_DB_THAW = 142, }; /* diff --git a/ctdb/server/ctdb_control.c b/ctdb/server/ctdb_control.c index 7b26ff9..e7c7620 100644 --- a/ctdb/server/ctdb_control.c +++ b/ctdb/server/ctdb_control.c @@ -683,6 +683,15 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb, case CTDB_CONTROL_DB_DETACH: return ctdb_control_db_detach(ctdb, indata, client_id); + case CTDB_CONTROL_DB_FREEZE: + CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t)); + return ctdb_control_db_freeze(ctdb, c, *(uint32_t *)indata.dptr, + async_reply); + + case CTDB_CONTROL_DB_THAW: + CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t)); + return ctdb_control_db_thaw(ctdb, *(uint32_t *)indata.dptr); + default: DEBUG(DEBUG_CRIT,(__location__ " Unknown CTDB control opcode %u\n", opcode)); return -1; diff --git a/ctdb/server/ctdb_freeze.c b/ctdb/server/ctdb_freeze.c index 6b6a712..5dc1b7c 100644 --- a/ctdb/server/ctdb_freeze.c +++ b/ctdb/server/ctdb_freeze.c @@ -101,6 +101,179 @@ static int db_transaction_commit_handler(struct ctdb_db_context *ctdb_db, } +/* a list of control requests waiting for db freeze */ +struct ctdb_db_freeze_waiter { + struct ctdb_db_freeze_waiter *next, *prev; + struct ctdb_context *ctdb; + void *private_data; + int32_t status; +}; + +/* a handle to a db freeze lock child process */ +struct ctdb_db_freeze_handle { + struct ctdb_db_context *ctdb_db; + struct lock_request *lreq; + struct ctdb_db_freeze_waiter *waiters; +}; + +/** + * Called when freeing database freeze handle + */ +static int ctdb_db_freeze_handle_destructor(struct ctdb_db_freeze_handle *h) +{ + struct ctdb_db_context *ctdb_db = h->ctdb_db; + + DEBUG(DEBUG_ERR, ("Release freeze handle for db %s\n", + ctdb_db->db_name)); + + /* Cancel any pending transactions */ + if (ctdb_db->freeze_transaction_started) { + db_transaction_cancel_handler(ctdb_db, NULL); + ctdb_db->freeze_transaction_started = false; + } + ctdb_db->freeze_mode = CTDB_FREEZE_NONE; + ctdb_db->freeze_handle = NULL; + + talloc_free(h->lreq); + return 0; +} + +/** + * Called when a database is frozen + */ +static void ctdb_db_freeze_handler(void *private_data, bool locked) +{ + struct ctdb_db_freeze_handle *h = talloc_get_type_abort( + private_data, struct ctdb_db_freeze_handle); + struct ctdb_db_freeze_waiter *w; + + if (h->ctdb_db->freeze_mode == CTDB_FREEZE_FROZEN) { + DEBUG(DEBUG_ERR, ("Freeze db child died - unfreezing\n")); + h->ctdb_db->freeze_mode = CTDB_FREEZE_NONE; + talloc_free(h); + return; + } + + if (!locked) { + DEBUG(DEBUG_ERR, ("Failed to get db lock for %s\n", + h->ctdb_db->db_name)); + h->ctdb_db->freeze_mode = CTDB_FREEZE_NONE; + talloc_free(h); + return; + } + + h->ctdb_db->freeze_mode = CTDB_FREEZE_FROZEN; + + /* notify the waiters */ + while ((w = h->waiters) != NULL) { + w->status = 0; + DLIST_REMOVE(h->waiters, w); + talloc_free(w); + } +} + +/** + * Start freeze process for a database + */ +static void ctdb_start_db_freeze(struct ctdb_db_context *ctdb_db) +{ + struct ctdb_db_freeze_handle *h; + + if (ctdb_db->freeze_mode == CTDB_FREEZE_FROZEN) { + return; + } + + if (ctdb_db->freeze_handle != NULL) { + return; + } + + DEBUG(DEBUG_ERR, ("Freeze db: %s\n", ctdb_db->db_name)); + + ctdb_stop_vacuuming(ctdb_db->ctdb); + + h = talloc_zero(ctdb_db, struct ctdb_db_freeze_handle); + CTDB_NO_MEMORY_FATAL(ctdb_db->ctdb, h); + + h->ctdb_db = ctdb_db; + h->lreq = ctdb_lock_db(h, ctdb_db, false, ctdb_db_freeze_handler, h); + CTDB_NO_MEMORY_FATAL(ctdb_db->ctdb, h->lreq); + talloc_set_destructor(h, ctdb_db_freeze_handle_destructor); + + ctdb_db->freeze_handle = h; + ctdb_db->freeze_mode = CTDB_FREEZE_PENDING; +} + +/** + * Reply to a waiter for db freeze + */ +static int ctdb_db_freeze_waiter_destructor(struct ctdb_db_freeze_waiter *w) +{ + /* 'c' pointer is talloc_memdup(), so cannot use talloc_get_type */ + struct ctdb_req_control *c = + (struct ctdb_req_control *)w->private_data; + + ctdb_request_control_reply(w->ctdb, c, NULL, w->status, NULL); + return 0; +} + +/** + * freeze a database + */ +int32_t ctdb_control_db_freeze(struct ctdb_context *ctdb, + struct ctdb_req_control *c, + uint32_t db_id, + bool *async_reply) +{ + struct ctdb_db_context *ctdb_db; + struct ctdb_db_freeze_waiter *w; + + ctdb_db = find_ctdb_db(ctdb, db_id); + if (ctdb_db == NULL) { + DEBUG(DEBUG_ERR, ("Freeze db for unknown dbid 0x%08x\n", db_id)); + return -1; + } + + if (ctdb_db->freeze_mode == CTDB_FREEZE_FROZEN) { + DEBUG(DEBUG_ERR, ("Freeze db: %s frozen\n", ctdb_db->db_name)); + return 0; + } + + ctdb_start_db_freeze(ctdb_db); + + /* add ourselves to the list of waiters */ + w = talloc(ctdb_db->freeze_handle, struct ctdb_db_freeze_waiter); + CTDB_NO_MEMORY(ctdb, w); + w->ctdb = ctdb; + w->private_data = talloc_steal(w, c); + w->status = -1; + talloc_set_destructor(w, ctdb_db_freeze_waiter_destructor); + DLIST_ADD(ctdb_db->freeze_handle->waiters, w); + + *async_reply = true; + return 0; +} + +/** + * Thaw a database + */ +int32_t ctdb_control_db_thaw(struct ctdb_context *ctdb, uint32_t db_id) +{ + struct ctdb_db_context *ctdb_db; + + ctdb_db = find_ctdb_db(ctdb, db_id); + if (ctdb_db == NULL) { + DEBUG(DEBUG_ERR, ("Thaw db for unknown dbid 0x%08x\n", db_id)); + return -1; + } + + DEBUG(DEBUG_ERR, ("Thaw db: %s\n", ctdb_db->db_name)); + + TALLOC_FREE(ctdb_db->freeze_handle); + ctdb_call_resend_db(ctdb_db); + return 0; +} + + /* a list of control requests waiting for a freeze lock child to get the database locks @@ -487,6 +660,15 @@ int32_t ctdb_control_wipe_database(struct ctdb_context *ctdb, TDB_DATA indata) return 0; } +bool ctdb_db_frozen(struct ctdb_db_context *ctdb_db) +{ + if (ctdb_db->freeze_mode != CTDB_FREEZE_FROZEN) { + return false; + } + + return true; +} + bool ctdb_db_prio_frozen(struct ctdb_context *ctdb, uint32_t priority) { if (priority == 0) { From fd7ceaf3ac59fc7dc70d34e81cfd75a171a2e6c0 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Thu, 28 Aug 2014 15:30:39 +1000 Subject: [PATCH 017/136] ctdb-freeze: Move destructor closer to where it is used Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/server/ctdb_freeze.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/ctdb/server/ctdb_freeze.c b/ctdb/server/ctdb_freeze.c index 5dc1b7c..5acae6e 100644 --- a/ctdb/server/ctdb_freeze.c +++ b/ctdb/server/ctdb_freeze.c @@ -352,15 +352,6 @@ static void ctdb_freeze_lock_handler(void *private_data, bool locked) } /* - destroy a waiter for a freeze mode change - */ -static int ctdb_freeze_waiter_destructor(struct ctdb_freeze_waiter *w) -{ - ctdb_request_control_reply(w->ctdb, w->c, NULL, w->status, NULL); - return 0; -} - -/* start the freeze process for a certain priority */ void ctdb_start_freeze(struct ctdb_context *ctdb, uint32_t priority) @@ -402,6 +393,15 @@ void ctdb_start_freeze(struct ctdb_context *ctdb, uint32_t priority) } /* + destroy a waiter for a freeze mode change + */ +static int ctdb_freeze_waiter_destructor(struct ctdb_freeze_waiter *w) +{ + ctdb_request_control_reply(w->ctdb, w->c, NULL, w->status, NULL); + return 0; +} + +/* freeze the databases */ int32_t ctdb_control_freeze(struct ctdb_context *ctdb, struct ctdb_req_control *c, bool *async_reply) From d139f87718e06aaae73652fdf52f2c1dd2dcbe99 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Thu, 28 Aug 2014 15:28:34 +1000 Subject: [PATCH 018/136] ctdb-freeze: Use single database freeze/thaw code for existing controls This changes the locking behaviour when the databases are frozen. Instead of a single lock helper locking all databases with a priority, a lock helper is launched for every database. Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/server/ctdb_freeze.c | 114 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 107 insertions(+), 7 deletions(-) diff --git a/ctdb/server/ctdb_freeze.c b/ctdb/server/ctdb_freeze.c index 5acae6e..7733f42 100644 --- a/ctdb/server/ctdb_freeze.c +++ b/ctdb/server/ctdb_freeze.c @@ -290,10 +290,16 @@ struct ctdb_freeze_waiter { struct ctdb_freeze_handle { struct ctdb_context *ctdb; uint32_t priority; - struct lock_request *lreq; + unsigned int num_total, num_locked, num_failed; struct ctdb_freeze_waiter *waiters; }; +static int db_thaw(struct ctdb_db_context *ctdb_db, void *private_data) +{ + talloc_free(ctdb_db->freeze_handle); + return 0; +} + /* destroy a freeze handle */ @@ -310,6 +316,8 @@ static int ctdb_freeze_handle_destructor(struct ctdb_freeze_handle *h) ctdb->freeze_transaction_started = false; } + ctdb_db_prio_iterator(ctdb, h->priority, db_thaw, NULL); + ctdb->freeze_mode[h->priority] = CTDB_FREEZE_NONE; ctdb->freeze_handles[h->priority] = NULL; @@ -351,12 +359,85 @@ static void ctdb_freeze_lock_handler(void *private_data, bool locked) } } +/** + * When single database is frozen + */ +static int db_freeze_waiter_destructor(struct ctdb_db_freeze_waiter *w) +{ + struct ctdb_freeze_handle *h = talloc_get_type_abort( + w->private_data, struct ctdb_freeze_handle); + + if (w->status == 0) { + h->num_locked += 1; + } else { + h->num_failed += 1; + } + + /* Call ctdb_freeze_lock_handler() only when the status of all + * databases is known. + */ + if (h->num_locked + h->num_failed == h->num_total) { + bool locked; + + if (h->num_locked == h->num_total) { + locked = true; + } else { + locked = false; + } + ctdb_freeze_lock_handler(h, locked); + } + return 0; +} + +/** + * Count the number of databases + */ +static int db_count(struct ctdb_db_context *ctdb_db, void *private_data) +{ + int *count = (int *)private_data; + + *count += 1; + + return 0; +} + +/** + * Freeze a single database + */ +static int db_freeze(struct ctdb_db_context *ctdb_db, void *private_data) +{ + struct ctdb_freeze_handle *h = talloc_get_type_abort( + private_data, struct ctdb_freeze_handle); + struct ctdb_db_freeze_waiter *w; + + ctdb_start_db_freeze(ctdb_db); + + w = talloc(ctdb_db->freeze_handle, struct ctdb_db_freeze_waiter); + CTDB_NO_MEMORY(h->ctdb, w); + w->ctdb = h->ctdb; + w->private_data = h; + w->status = -1; + talloc_set_destructor(w, db_freeze_waiter_destructor); + + if (ctdb_db->freeze_mode == CTDB_FREEZE_FROZEN) { + /* Early return if already frozen */ + w->status = 0; + talloc_free(w); + return 0; + } + + DLIST_ADD(ctdb_db->freeze_handle->waiters, w); + + return 0; +} + /* start the freeze process for a certain priority */ void ctdb_start_freeze(struct ctdb_context *ctdb, uint32_t priority) { struct ctdb_freeze_handle *h; + int ret; if ((priority < 1) || (priority > NUM_DB_PRIORITIES)) { DEBUG(DEBUG_ERR,(__location__ " Invalid db priority : %u\n", priority)); @@ -378,18 +459,31 @@ void ctdb_start_freeze(struct ctdb_context *ctdb, uint32_t priority) /* Stop any vacuuming going on: we don't want to wait. */ ctdb_stop_vacuuming(ctdb); - /* create freeze lock child */ + /* create freeze lock children for each database */ h = talloc_zero(ctdb, struct ctdb_freeze_handle); CTDB_NO_MEMORY_FATAL(ctdb, h); h->ctdb = ctdb; h->priority = priority; talloc_set_destructor(h, ctdb_freeze_handle_destructor); - h->lreq = ctdb_lock_alldb_prio(h, ctdb, priority, false, - ctdb_freeze_lock_handler, h); - CTDB_NO_MEMORY_FATAL(ctdb, h->lreq); - ctdb->freeze_handles[priority] = h; + ret = ctdb_db_prio_iterator(ctdb, priority, db_count, &h->num_total); + if (ret != 0) { + talloc_free(h); + return; + } + ctdb->freeze_mode[priority] = CTDB_FREEZE_PENDING; + + ret = ctdb_db_prio_iterator(ctdb, priority, db_freeze, h); + if (ret != 0) { + talloc_free(h); + return; + } + + ctdb->freeze_handles[priority] = h; + if (h->num_total == 0) { + ctdb->freeze_mode[priority] = CTDB_FREEZE_FROZEN; + } } /* @@ -429,12 +523,17 @@ int32_t ctdb_control_freeze(struct ctdb_context *ctdb, struct ctdb_req_control * ctdb_start_freeze(ctdb, priority); - /* add ourselves to list of waiters */ if (ctdb->freeze_handles[priority] == NULL) { DEBUG(DEBUG_ERR,("No freeze lock handle when adding a waiter\n")); return -1; } + /* If there are no databases, we are done. */ + if (ctdb->freeze_handles[priority]->num_total == 0) { + return 0; + } + + /* add ourselves to list of waiters */ w = talloc(ctdb->freeze_handles[priority], struct ctdb_freeze_waiter); CTDB_NO_MEMORY(ctdb, w); w->ctdb = ctdb; @@ -481,6 +580,7 @@ static void thaw_priority(struct ctdb_context *ctdb, uint32_t priority) ctdb->freeze_transaction_started = false; } + ctdb_db_prio_iterator(ctdb, priority, db_thaw, NULL); if (ctdb->freeze_handles[priority] != NULL) { talloc_free(ctdb->freeze_handles[priority]); ctdb->freeze_handles[priority] = NULL; From e170bd4f1b3fcf988867d1dd00b49e8813c6ca7f Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Thu, 10 Sep 2015 13:24:43 +1000 Subject: [PATCH 019/136] ctdb-locking: Add mark/unmark functions for a single database Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/include/ctdb_private.h | 3 +++ ctdb/server/ctdb_lock.c | 26 ++++++++++++++++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/ctdb/include/ctdb_private.h b/ctdb/include/ctdb_private.h index b6f7263..61d5c9f 100644 --- a/ctdb/include/ctdb_private.h +++ b/ctdb/include/ctdb_private.h @@ -1485,6 +1485,9 @@ int ctdb_db_iterator(struct ctdb_context *ctdb, ctdb_db_handler_t handler, int ctdb_lockall_mark_prio(struct ctdb_context *ctdb, uint32_t priority); int ctdb_lockall_unmark_prio(struct ctdb_context *ctdb, uint32_t priority); +int ctdb_lockdb_mark(struct ctdb_db_context *ctdb_db); +int ctdb_lockdb_unmark(struct ctdb_db_context *ctdb_db); + struct lock_request *ctdb_lock_record(TALLOC_CTX *mem_ctx, struct ctdb_db_context *ctdb_db, TDB_DATA key, diff --git a/ctdb/server/ctdb_lock.c b/ctdb/server/ctdb_lock.c index 9494f9f..d8d4f5a 100644 --- a/ctdb/server/ctdb_lock.c +++ b/ctdb/server/ctdb_lock.c @@ -191,6 +191,17 @@ static int db_lock_mark_handler(struct ctdb_db_context *ctdb_db, return 0; } +int ctdb_lockdb_mark(struct ctdb_db_context *ctdb_db) +{ + if (!ctdb_db_frozen(ctdb_db)) { + DEBUG(DEBUG_ERR, + ("Attempt to mark database locked when not frozen\n")); + return -1; + } + + return db_lock_mark_handler(ctdb_db, NULL); +} + int ctdb_lockall_mark_prio(struct ctdb_context *ctdb, uint32_t priority) { /* @@ -250,6 +261,17 @@ static int db_lock_unmark_handler(struct ctdb_db_context *ctdb_db, return 0; } +int ctdb_lockdb_unmark(struct ctdb_db_context *ctdb_db) +{ + if (!ctdb_db_frozen(ctdb_db)) { + DEBUG(DEBUG_ERR, + ("Attempt to unmark database locked when not frozen\n")); + return -1; + } + + return db_lock_unmark_handler(ctdb_db, NULL); +} + int ctdb_lockall_unmark_prio(struct ctdb_context *ctdb, uint32_t priority) { /* @@ -359,7 +381,7 @@ static void process_callbacks(struct lock_context *lock_ctx, bool locked) break; case LOCK_DB: - tdb_lockall_mark(lock_ctx->ctdb_db->ltdb->tdb); + ctdb_lockdb_mark(lock_ctx->ctdb_db); break; case LOCK_ALLDB_PRIO: @@ -396,7 +418,7 @@ static void process_callbacks(struct lock_context *lock_ctx, bool locked) break; case LOCK_DB: - tdb_lockall_unmark(lock_ctx->ctdb_db->ltdb->tdb); + ctdb_lockdb_unmark(lock_ctx->ctdb_db); break; case LOCK_ALLDB_PRIO: From e0fa182d9362537f7081e215250ce2052a9a34c8 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Tue, 15 Sep 2015 14:01:49 +1000 Subject: [PATCH 020/136] ctdb-daemon: Use database specific freeze check routine Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/server/ctdb_recover.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ctdb/server/ctdb_recover.c b/ctdb/server/ctdb_recover.c index 0df7f58..f869252 100644 --- a/ctdb/server/ctdb_recover.c +++ b/ctdb/server/ctdb_recover.c @@ -249,7 +249,7 @@ int32_t ctdb_control_pull_db(struct ctdb_context *ctdb, TDB_DATA indata, TDB_DAT return -1; } - if (!ctdb_db_prio_frozen(ctdb, ctdb_db->priority)) { + if (!ctdb_db_frozen(ctdb_db)) { DEBUG(DEBUG_DEBUG,("rejecting ctdb_control_pull_db when not frozen\n")); return -1; } @@ -321,7 +321,7 @@ int32_t ctdb_control_push_db(struct ctdb_context *ctdb, TDB_DATA indata) return -1; } - if (!ctdb_db_prio_frozen(ctdb, ctdb_db->priority)) { + if (!ctdb_db_frozen(ctdb_db)) { DEBUG(DEBUG_DEBUG,("rejecting ctdb_control_push_db when not frozen\n")); return -1; } From 66c7bcc777ff5cbc625da86384d8c29d34c66bf9 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Mon, 14 Sep 2015 14:53:45 +1000 Subject: [PATCH 021/136] ctdb-daemon: Use database specific mark/unmark routines Instead of marking all the databases with priority, mark only the database which is currently being processed. Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/server/ctdb_recover.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/ctdb/server/ctdb_recover.c b/ctdb/server/ctdb_recover.c index f869252..d5973a9 100644 --- a/ctdb/server/ctdb_recover.c +++ b/ctdb/server/ctdb_recover.c @@ -242,7 +242,7 @@ int32_t ctdb_control_pull_db(struct ctdb_context *ctdb, TDB_DATA indata, TDB_DAT struct ctdb_marshall_buffer *reply; pull = (struct ctdb_control_pulldb *)indata.dptr; - + ctdb_db = find_ctdb_db(ctdb, pull->db_id); if (!ctdb_db) { DEBUG(DEBUG_ERR,(__location__ " Unknown db 0x%08x\n", pull->db_id)); @@ -250,7 +250,8 @@ int32_t ctdb_control_pull_db(struct ctdb_context *ctdb, TDB_DATA indata, TDB_DAT } if (!ctdb_db_frozen(ctdb_db)) { - DEBUG(DEBUG_DEBUG,("rejecting ctdb_control_pull_db when not frozen\n")); + DEBUG(DEBUG_ERR, + ("rejecting ctdb_control_pull_db when not frozen\n")); return -1; } @@ -272,19 +273,19 @@ int32_t ctdb_control_pull_db(struct ctdb_context *ctdb, TDB_DATA indata, TDB_DAT ctdb_db->db_name, ctdb_db->unhealthy_reason)); } - if (ctdb_lockall_mark_prio(ctdb, ctdb_db->priority) != 0) { - DEBUG(DEBUG_ERR,(__location__ " Failed to get lock on entired db - failing\n")); + if (ctdb_lockdb_mark(ctdb_db) != 0) { + DEBUG(DEBUG_ERR,(__location__ " Failed to get lock on entire db - failing\n")); return -1; } if (tdb_traverse_read(ctdb_db->ltdb->tdb, traverse_pulldb, ¶ms) == -1) { DEBUG(DEBUG_ERR,(__location__ " Failed to get traverse db '%s'\n", ctdb_db->db_name)); - ctdb_lockall_unmark_prio(ctdb, ctdb_db->priority); + ctdb_lockdb_unmark(ctdb_db); talloc_free(params.pulldata); return -1; } - ctdb_lockall_unmark_prio(ctdb, ctdb_db->priority); + ctdb_lockdb_unmark(ctdb_db); outdata->dptr = (uint8_t *)params.pulldata; outdata->dsize = params.len; @@ -322,12 +323,13 @@ int32_t ctdb_control_push_db(struct ctdb_context *ctdb, TDB_DATA indata) } if (!ctdb_db_frozen(ctdb_db)) { - DEBUG(DEBUG_DEBUG,("rejecting ctdb_control_push_db when not frozen\n")); + DEBUG(DEBUG_ERR, + ("rejecting ctdb_control_push_db when not frozen\n")); return -1; } - if (ctdb_lockall_mark_prio(ctdb, ctdb_db->priority) != 0) { - DEBUG(DEBUG_ERR,(__location__ " Failed to get lock on entired db - failing\n")); + if (ctdb_lockdb_mark(ctdb_db) != 0) { + DEBUG(DEBUG_ERR,(__location__ " Failed to get lock on entire db - failing\n")); return -1; } @@ -385,11 +387,11 @@ int32_t ctdb_control_push_db(struct ctdb_context *ctdb, TDB_DATA indata) } } - ctdb_lockall_unmark_prio(ctdb, ctdb_db->priority); + ctdb_lockdb_unmark(ctdb_db); return 0; failed: - ctdb_lockall_unmark_prio(ctdb, ctdb_db->priority); + ctdb_lockdb_unmark(ctdb_db); return -1; } From 979f1c5ea116b8aac536ebe29d584730e8fe9a4b Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Thu, 28 Aug 2014 16:58:56 +1000 Subject: [PATCH 022/136] ctdb-freeze: Improve log message to indicate subsequent freeze operation Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/server/ctdb_freeze.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ctdb/server/ctdb_freeze.c b/ctdb/server/ctdb_freeze.c index 7733f42..e5f9cab 100644 --- a/ctdb/server/ctdb_freeze.c +++ b/ctdb/server/ctdb_freeze.c @@ -516,7 +516,7 @@ int32_t ctdb_control_freeze(struct ctdb_context *ctdb, struct ctdb_req_control * } if (ctdb->freeze_mode[priority] == CTDB_FREEZE_FROZEN) { - DEBUG(DEBUG_ERR, ("Freeze priority %u\n", priority)); + DEBUG(DEBUG_ERR, ("Freeze priority %u: frozen\n", priority)); /* we're already frozen */ return 0; } From 9f779f130fa275dcc43adcab03d4704663776dce Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Thu, 28 Aug 2014 16:59:52 +1000 Subject: [PATCH 023/136] ctdb-freeze: simplify code with TALLOC_FREE Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/server/ctdb_freeze.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/ctdb/server/ctdb_freeze.c b/ctdb/server/ctdb_freeze.c index e5f9cab..f911207 100644 --- a/ctdb/server/ctdb_freeze.c +++ b/ctdb/server/ctdb_freeze.c @@ -581,10 +581,7 @@ static void thaw_priority(struct ctdb_context *ctdb, uint32_t priority) } ctdb_db_prio_iterator(ctdb, priority, db_thaw, NULL); - if (ctdb->freeze_handles[priority] != NULL) { - talloc_free(ctdb->freeze_handles[priority]); - ctdb->freeze_handles[priority] = NULL; - } + TALLOC_FREE(ctdb->freeze_handles[priority]); } /* From 4f155e77a8210e43456239391c03a5804d01b828 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Wed, 9 Sep 2015 15:02:49 +1000 Subject: [PATCH 024/136] ctdb-daemon: Rename ctdb_control_wipe_database to ctdb_control_transdb The same structure is required in new controls for database transactions. Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/include/ctdb_private.h | 2 +- ctdb/server/ctdb_control.c | 2 +- ctdb/server/ctdb_freeze.c | 2 +- ctdb/server/ctdb_recoverd.c | 2 +- ctdb/tools/ctdb.c | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ctdb/include/ctdb_private.h b/ctdb/include/ctdb_private.h index 61d5c9f..20ea281 100644 --- a/ctdb/include/ctdb_private.h +++ b/ctdb/include/ctdb_private.h @@ -936,7 +936,7 @@ struct ctdb_control_list_tunable { }; -struct ctdb_control_wipe_database { +struct ctdb_control_transdb { uint32_t db_id; uint32_t transaction_id; }; diff --git a/ctdb/server/ctdb_control.c b/ctdb/server/ctdb_control.c index e7c7620..33fbe21 100644 --- a/ctdb/server/ctdb_control.c +++ b/ctdb/server/ctdb_control.c @@ -442,7 +442,7 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb, return ctdb_control_transaction_commit(ctdb, *(uint32_t *)indata.dptr); case CTDB_CONTROL_WIPE_DATABASE: - CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_control_wipe_database)); + CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_control_transdb)); return ctdb_control_wipe_database(ctdb, indata); case CTDB_CONTROL_UPTIME: diff --git a/ctdb/server/ctdb_freeze.c b/ctdb/server/ctdb_freeze.c index f911207..bbdcda3 100644 --- a/ctdb/server/ctdb_freeze.c +++ b/ctdb/server/ctdb_freeze.c @@ -714,7 +714,7 @@ int32_t ctdb_control_transaction_commit(struct ctdb_context *ctdb, uint32_t id) */ int32_t ctdb_control_wipe_database(struct ctdb_context *ctdb, TDB_DATA indata) { - struct ctdb_control_wipe_database w = *(struct ctdb_control_wipe_database *)indata.dptr; + struct ctdb_control_transdb w = *(struct ctdb_control_transdb *)indata.dptr; struct ctdb_db_context *ctdb_db; ctdb_db = find_ctdb_db(ctdb, w.db_id); diff --git a/ctdb/server/ctdb_recoverd.c b/ctdb/server/ctdb_recoverd.c index be53de6..ea3a857 100644 --- a/ctdb/server/ctdb_recoverd.c +++ b/ctdb/server/ctdb_recoverd.c @@ -1490,7 +1490,7 @@ static int recover_database(struct ctdb_recoverd *rec, int ret; struct ctdb_context *ctdb = rec->ctdb; TDB_DATA data; - struct ctdb_control_wipe_database w; + struct ctdb_control_transdb w; uint32_t *nodes; recdb = create_recdb(ctdb, mem_ctx); diff --git a/ctdb/tools/ctdb.c b/ctdb/tools/ctdb.c index 69f881f..0d00687 100644 --- a/ctdb/tools/ctdb.c +++ b/ctdb/tools/ctdb.c @@ -5581,7 +5581,7 @@ static int control_restoredb(struct ctdb_context *ctdb, int argc, const char **a struct ctdb_node_map *nodemap=NULL; struct ctdb_vnn_map *vnnmap=NULL; int i, fh; - struct ctdb_control_wipe_database w; + struct ctdb_control_transdb w; uint32_t *nodes; uint32_t generation; struct tm *tm; @@ -5861,7 +5861,7 @@ static int control_wipedb(struct ctdb_context *ctdb, int argc, struct ctdb_node_map *nodemap = NULL; struct ctdb_vnn_map *vnnmap = NULL; int i; - struct ctdb_control_wipe_database w; + struct ctdb_control_transdb w; uint32_t *nodes; uint32_t generation; uint8_t flags; From 3d325e7fa1de48ec88487d31a657e6a876d2dd81 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Wed, 9 Sep 2015 15:38:36 +1000 Subject: [PATCH 025/136] ctdb-daemon: Add controls for transactions on a single database Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/include/ctdb_private.h | 7 ++ ctdb/include/ctdb_protocol.h | 3 + ctdb/server/ctdb_control.c | 12 +++ ctdb/server/ctdb_freeze.c | 177 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 199 insertions(+) diff --git a/ctdb/include/ctdb_private.h b/ctdb/include/ctdb_private.h index 20ea281..8c29928 100644 --- a/ctdb/include/ctdb_private.h +++ b/ctdb/include/ctdb_private.h @@ -1275,6 +1275,13 @@ int32_t ctdb_control_trans3_commit(struct ctdb_context *ctdb, void ctdb_persistent_finish_trans3_commits(struct ctdb_context *ctdb); +int32_t ctdb_control_db_transaction_start(struct ctdb_context *ctdb, + TDB_DATA indata); +int32_t ctdb_control_db_transaction_commit(struct ctdb_context *ctdb, + TDB_DATA indata); +int32_t ctdb_control_db_transaction_cancel(struct ctdb_context *ctdb, + TDB_DATA indata); + int32_t ctdb_control_transaction_start(struct ctdb_context *ctdb, uint32_t id); int32_t ctdb_control_transaction_commit(struct ctdb_context *ctdb, uint32_t id); int32_t ctdb_control_transaction_cancel(struct ctdb_context *ctdb); diff --git a/ctdb/include/ctdb_protocol.h b/ctdb/include/ctdb_protocol.h index 6169c8f..d49a641 100644 --- a/ctdb/include/ctdb_protocol.h +++ b/ctdb/include/ctdb_protocol.h @@ -417,6 +417,9 @@ enum ctdb_controls {CTDB_CONTROL_PROCESS_EXISTS = 0, CTDB_CONTROL_GET_NODES_FILE = 140, CTDB_CONTROL_DB_FREEZE = 141, CTDB_CONTROL_DB_THAW = 142, + CTDB_CONTROL_DB_TRANSACTION_START = 143, + CTDB_CONTROL_DB_TRANSACTION_COMMIT = 144, + CTDB_CONTROL_DB_TRANSACTION_CANCEL = 145, }; /* diff --git a/ctdb/server/ctdb_control.c b/ctdb/server/ctdb_control.c index 33fbe21..2df14b7 100644 --- a/ctdb/server/ctdb_control.c +++ b/ctdb/server/ctdb_control.c @@ -692,6 +692,18 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb, CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t)); return ctdb_control_db_thaw(ctdb, *(uint32_t *)indata.dptr); + case CTDB_CONTROL_DB_TRANSACTION_START: + CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_control_transdb)); + return ctdb_control_db_transaction_start(ctdb, indata); + + case CTDB_CONTROL_DB_TRANSACTION_COMMIT: + CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_control_transdb)); + return ctdb_control_db_transaction_commit(ctdb, indata); + + case CTDB_CONTROL_DB_TRANSACTION_CANCEL: + CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t)); + return ctdb_control_db_transaction_cancel(ctdb, indata); + default: DEBUG(DEBUG_CRIT,(__location__ " Unknown CTDB control opcode %u\n", opcode)); return -1; diff --git a/ctdb/server/ctdb_freeze.c b/ctdb/server/ctdb_freeze.c index bbdcda3..df4d81d 100644 --- a/ctdb/server/ctdb_freeze.c +++ b/ctdb/server/ctdb_freeze.c @@ -615,6 +615,183 @@ int32_t ctdb_control_thaw(struct ctdb_context *ctdb, uint32_t priority, return 0; } +/** + * Database transaction wrappers + * + * These functions are wrappers around transaction start/cancel/commit handlers. + */ + +struct db_start_transaction_state { + uint32_t transaction_id; + bool transaction_started; +}; + +static int db_start_transaction(struct ctdb_db_context *ctdb_db, + void *private_data) +{ + struct db_start_transaction_state *state = + (struct db_start_transaction_state *)private_data; + int ret; + bool transaction_started; + + if (ctdb_db->freeze_mode != CTDB_FREEZE_FROZEN) { + DEBUG(DEBUG_ERR, + ("Database %s not frozen, cannot start transaction\n", + ctdb_db->db_name)); + return -1; + } + + transaction_started = state->transaction_started & + ctdb_db->freeze_transaction_started; + + ret = db_transaction_start_handler(ctdb_db, + &transaction_started); + if (ret != 0) { + return -1; + } + + ctdb_db->freeze_transaction_started = true; + ctdb_db->freeze_transaction_id = state->transaction_id; + + return 0; +} + +static int db_cancel_transaction(struct ctdb_db_context *ctdb_db, + void *private_data) +{ + int ret; + + ret = db_transaction_cancel_handler(ctdb_db, private_data); + if (ret != 0) { + return ret; + } + + ctdb_db->freeze_transaction_started = false; + + return 0; +} + +struct db_commit_transaction_state { + uint32_t transaction_id; + int healthy_nodes; +}; + +static int db_commit_transaction(struct ctdb_db_context *ctdb_db, + void *private_data) +{ + struct db_commit_transaction_state *state = + (struct db_commit_transaction_state *)private_data; + int ret; + + if (ctdb_db->freeze_mode != CTDB_FREEZE_FROZEN) { + DEBUG(DEBUG_ERR, + ("Database %s not frozen, cannot commit transaction\n", + ctdb_db->db_name)); + return -1; + } + + if (!ctdb_db->freeze_transaction_started) { + DEBUG(DEBUG_ERR, ("Transaction not started on %s\n", + ctdb_db->db_name)); + return -1; + } + + if (ctdb_db->freeze_transaction_id != state->transaction_id) { + DEBUG(DEBUG_ERR, + ("Incorrect transaction commit id 0x%08x for %s\n", + state->transaction_id, ctdb_db->db_name)); + return -1; + } + + ret = db_transaction_commit_handler(ctdb_db, &state->healthy_nodes); + if (ret != 0) { + return -1; + } + + ctdb_db->freeze_transaction_started = false; + ctdb_db->freeze_transaction_id = 0; + return 0; +} + +/** + * Start a transaction on a database - used for db recovery + */ +int32_t ctdb_control_db_transaction_start(struct ctdb_context *ctdb, + TDB_DATA indata) +{ + struct ctdb_control_transdb *w = + (struct ctdb_control_transdb *)indata.dptr; + struct ctdb_db_context *ctdb_db; + struct db_start_transaction_state state; + + ctdb_db = find_ctdb_db(ctdb, w->db_id); + if (ctdb_db == NULL) { + DEBUG(DEBUG_ERR, + ("Transaction start for unknown dbid 0x%08x\n", + w->db_id)); + return -1; + } + + state.transaction_id = w->transaction_id; + state.transaction_started = true; + + return db_start_transaction(ctdb_db, &state); +} + +/** + * Cancel a transaction on a database - used for db recovery + */ +int32_t ctdb_control_db_transaction_cancel(struct ctdb_context *ctdb, + TDB_DATA indata) +{ + uint32_t db_id = *(uint32_t *)indata.dptr; + struct ctdb_db_context *ctdb_db; + + ctdb_db = find_ctdb_db(ctdb, db_id); + if (ctdb_db == NULL) { + DEBUG(DEBUG_ERR, + ("Transaction cancel for unknown dbid 0x%08x\n", db_id)); + return -1; + } + + DEBUG(DEBUG_ERR, ("Recovery db transaction cancelled for %s\n", + ctdb_db->db_name)); + + return db_cancel_transaction(ctdb_db, NULL); +} + +/** + * Commit a transaction on a database - used for db recovery + */ +int32_t ctdb_control_db_transaction_commit(struct ctdb_context *ctdb, + TDB_DATA indata) +{ + struct ctdb_control_transdb *w = + (struct ctdb_control_transdb *)indata.dptr; + struct ctdb_db_context *ctdb_db; + struct db_commit_transaction_state state; + int healthy_nodes, i; + + ctdb_db = find_ctdb_db(ctdb, w->db_id); + if (ctdb_db == NULL) { + DEBUG(DEBUG_ERR, + ("Transaction commit for unknown dbid 0x%08x\n", + w->db_id)); + return -1; + } + + healthy_nodes = 0; + for (i=0; i < ctdb->num_nodes; i++) { + if (ctdb->nodes[i]->flags == 0) { + healthy_nodes += 1; + } + } + + state.transaction_id = w->transaction_id; + state.healthy_nodes = healthy_nodes; + + return db_commit_transaction(ctdb_db, &state); +} /* start a transaction on all databases - used for recovery From 858056263a0000663c0b50da6f080a845dc4d766 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Tue, 15 Sep 2015 15:13:50 +1000 Subject: [PATCH 026/136] ctdb-freeze: Use single database transactions for global transactions This cascades the global transaction controls to individual database transaction operations. This ensures that the individual database state is correctly set when processing global transaction controls. Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/server/ctdb_freeze.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/ctdb/server/ctdb_freeze.c b/ctdb/server/ctdb_freeze.c index df4d81d..2d5f07b 100644 --- a/ctdb/server/ctdb_freeze.c +++ b/ctdb/server/ctdb_freeze.c @@ -798,6 +798,7 @@ int32_t ctdb_control_db_transaction_commit(struct ctdb_context *ctdb, */ int32_t ctdb_control_transaction_start(struct ctdb_context *ctdb, uint32_t id) { + struct db_start_transaction_state state; int ret; if (!ctdb_db_all_frozen(ctdb)) { @@ -806,8 +807,10 @@ int32_t ctdb_control_transaction_start(struct ctdb_context *ctdb, uint32_t id) return -1; } - ret = ctdb_db_iterator(ctdb, db_transaction_start_handler, - &ctdb->freeze_transaction_started); + state.transaction_id = id; + state.transaction_started = ctdb->freeze_transaction_started; + + ret = ctdb_db_iterator(ctdb, db_start_transaction, &state); if (ret != 0) { return -1; } @@ -825,7 +828,8 @@ int32_t ctdb_control_transaction_cancel(struct ctdb_context *ctdb) { DEBUG(DEBUG_ERR,(__location__ " recovery transaction cancelled called\n")); - ctdb_db_iterator(ctdb, db_transaction_cancel_handler, NULL); + ctdb_db_iterator(ctdb, db_cancel_transaction, NULL); + ctdb->freeze_transaction_started = false; return 0; @@ -836,6 +840,7 @@ int32_t ctdb_control_transaction_cancel(struct ctdb_context *ctdb) */ int32_t ctdb_control_transaction_commit(struct ctdb_context *ctdb, uint32_t id) { + struct db_commit_transaction_state state; int i; int healthy_nodes = 0; int ret; @@ -866,8 +871,10 @@ int32_t ctdb_control_transaction_commit(struct ctdb_context *ctdb, uint32_t id) } DEBUG(DEBUG_INFO,(__location__ " healthy_nodes[%d]\n", healthy_nodes)); - ret = ctdb_db_iterator(ctdb, db_transaction_commit_handler, - &healthy_nodes); + state.transaction_id = id; + state.healthy_nodes = healthy_nodes; + + ret = ctdb_db_iterator(ctdb, db_commit_transaction, &state); if (ret != 0) { DEBUG(DEBUG_ERR, ("Cancel all transactions\n")); goto fail; @@ -880,7 +887,7 @@ int32_t ctdb_control_transaction_commit(struct ctdb_context *ctdb, uint32_t id) fail: /* cancel any pending transactions */ - ctdb_db_iterator(ctdb, db_transaction_cancel_handler, NULL); + ctdb_db_iterator(ctdb, db_cancel_transaction, NULL); ctdb->freeze_transaction_started = false; return -1; From d14ff2d87e95c4c8c9faef800fc81b8c049d16da Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Tue, 15 Sep 2015 14:16:21 +1000 Subject: [PATCH 027/136] ctdb-freeze: Use database specific information in wipe database Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/server/ctdb_freeze.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ctdb/server/ctdb_freeze.c b/ctdb/server/ctdb_freeze.c index 2d5f07b..d90444a 100644 --- a/ctdb/server/ctdb_freeze.c +++ b/ctdb/server/ctdb_freeze.c @@ -907,17 +907,17 @@ int32_t ctdb_control_wipe_database(struct ctdb_context *ctdb, TDB_DATA indata) return -1; } - if (ctdb->freeze_mode[ctdb_db->priority] != CTDB_FREEZE_FROZEN) { + if (ctdb_db->freeze_mode != CTDB_FREEZE_FROZEN) { DEBUG(DEBUG_ERR,(__location__ " Failed transaction_start while not frozen\n")); return -1; } - if (!ctdb->freeze_transaction_started) { + if (!ctdb_db->freeze_transaction_started) { DEBUG(DEBUG_ERR,(__location__ " transaction not started\n")); return -1; } - if (w.transaction_id != ctdb->freeze_transaction_id) { + if (w.transaction_id != ctdb_db->freeze_transaction_id) { DEBUG(DEBUG_ERR,(__location__ " incorrect transaction id 0x%x in commit\n", w.transaction_id)); return -1; } From fafd35b68f8af41095cb41cd604c27495fa2b6a1 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Tue, 15 Sep 2015 16:13:10 +1000 Subject: [PATCH 028/136] ctdb-freeze: Fix a log message Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/server/ctdb_freeze.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ctdb/server/ctdb_freeze.c b/ctdb/server/ctdb_freeze.c index d90444a..0f971e7 100644 --- a/ctdb/server/ctdb_freeze.c +++ b/ctdb/server/ctdb_freeze.c @@ -307,7 +307,7 @@ static int ctdb_freeze_handle_destructor(struct ctdb_freeze_handle *h) { struct ctdb_context *ctdb = h->ctdb; - DEBUG(DEBUG_ERR,("Release freeze handler for prio %u\n", h->priority)); + DEBUG(DEBUG_ERR,("Release freeze handle for prio %u\n", h->priority)); /* cancel any pending transactions */ if (ctdb->freeze_transaction_started) { From b4357a79d916b1f8ade8fa78563fbef0ce670aa9 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Wed, 16 Sep 2015 18:20:31 +1000 Subject: [PATCH 029/136] ctdb-banning: Do not freeze databases on ban in the daemon Once the node is marked as banned, the recovery daemon on that node will start freezing the databases anyway. This check happens every second in recovery daemon, so the delay in freezing the databases on ban would be a second. The main reason for freezing databases is to prevent any database access from samba clients. However, banning code also drops the public IPs and thus disconnecting the clients. In addition, the generation gets set to INVALID_GENERATION, thus database record migration requests on that node will not be processed. Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/server/ctdb_banning.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/ctdb/server/ctdb_banning.c b/ctdb/server/ctdb_banning.c index 91064b4..92026fd 100644 --- a/ctdb/server/ctdb_banning.c +++ b/ctdb/server/ctdb_banning.c @@ -50,10 +50,7 @@ ctdb_ban_node_event(struct event_context *ev, struct timed_event *te, void ctdb_local_node_got_banned(struct ctdb_context *ctdb) { - uint32_t i; - - /* make sure we are frozen */ - DEBUG(DEBUG_NOTICE,("This node has been banned - forcing freeze and recovery\n")); + DEBUG(DEBUG_NOTICE,("This node has been banned - forcing recovery\n")); /* Reset the generation id to 1 to make us ignore any REQ/REPLY CALL/DMASTER someone sends to us. @@ -62,10 +59,9 @@ void ctdb_local_node_got_banned(struct ctdb_context *ctdb) */ ctdb->vnn_map->generation = INVALID_GENERATION; + /* make sure we get frozen */ ctdb->recovery_mode = CTDB_RECOVERY_ACTIVE; - for (i=1; i<=NUM_DB_PRIORITIES; i++) { - ctdb_start_freeze(ctdb, i); - } + ctdb_release_all_ips(ctdb); } From 8a5039d96390742be5563e74b7e2778f7d388ed2 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Wed, 16 Sep 2015 18:23:23 +1000 Subject: [PATCH 030/136] ctdb-freeze: Make function ctdb_start_freeze static Since the banning code does not call this function anymore, it can be made static. Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/include/ctdb_private.h | 2 -- ctdb/server/ctdb_freeze.c | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/ctdb/include/ctdb_private.h b/ctdb/include/ctdb_private.h index 8c29928..8ca8d4b 100644 --- a/ctdb/include/ctdb_private.h +++ b/ctdb/include/ctdb_private.h @@ -1207,8 +1207,6 @@ int ctdb_ctrl_get_all_tunables(struct ctdb_context *ctdb, uint32_t destnode, struct ctdb_tunable *tunables); -void ctdb_start_freeze(struct ctdb_context *ctdb, uint32_t priority); - bool parse_ip_mask(const char *s, const char *iface, ctdb_sock_addr *addr, unsigned *mask); bool parse_ip_port(const char *s, ctdb_sock_addr *addr); bool parse_ip(const char *s, const char *iface, unsigned port, ctdb_sock_addr *addr); diff --git a/ctdb/server/ctdb_freeze.c b/ctdb/server/ctdb_freeze.c index 0f971e7..5a2061d 100644 --- a/ctdb/server/ctdb_freeze.c +++ b/ctdb/server/ctdb_freeze.c @@ -434,7 +434,7 @@ static int db_freeze(struct ctdb_db_context *ctdb_db, void *private_data) /* start the freeze process for a certain priority */ -void ctdb_start_freeze(struct ctdb_context *ctdb, uint32_t priority) +static void ctdb_start_freeze(struct ctdb_context *ctdb, uint32_t priority) { struct ctdb_freeze_handle *h; int ret; From 5d9dd4d400296a4182dadc70cb4ddf9ca0681a60 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Wed, 16 Sep 2015 18:49:00 +1000 Subject: [PATCH 031/136] ctdb-freeze: Ensure all databases get frozen during freeze It's possible that the databases can get attached after initial freeze. This typically happens during startup as CTDB will only attach persistent databases and go in to startup freeze. During recovery, the recovery master will attach all the missing databases and then send freeze controls. Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/server/ctdb_freeze.c | 49 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/ctdb/server/ctdb_freeze.c b/ctdb/server/ctdb_freeze.c index 5a2061d..9d72d87 100644 --- a/ctdb/server/ctdb_freeze.c +++ b/ctdb/server/ctdb_freeze.c @@ -445,7 +445,48 @@ static void ctdb_start_freeze(struct ctdb_context *ctdb, uint32_t priority) } if (ctdb->freeze_mode[priority] == CTDB_FREEZE_FROZEN) { - /* we're already frozen */ + int count = 0; + + /* + * Check if all the databases are frozen + * + * It's possible that the databases can get attached after + * initial freeze. This typically happens during startup as + * CTDB will only attach persistent databases and go in to + * startup freeze. The recovery master during recovery will + * attach all the missing databases. + */ + + h = ctdb->freeze_handles[priority]; + if (h == NULL) { + ctdb->freeze_mode[priority] = CTDB_FREEZE_NONE; + return; + } + + ret = ctdb_db_prio_iterator(ctdb, priority, db_count, &count); + if (ret != 0) { + TALLOC_FREE(ctdb->freeze_handles[priority]); + ctdb->freeze_mode[priority] = CTDB_FREEZE_NONE; + return; + } + + if (count != h->num_total) { + DEBUG(DEBUG_ERR, ("Freeze priority %u: incremental\n", + priority)); + + h->num_total = count; + h->num_locked = 0; + h->num_failed = 0; + + ctdb->freeze_mode[priority] = CTDB_FREEZE_PENDING; + + ret = ctdb_db_prio_iterator(ctdb, priority, + db_freeze, h); + if (ret != 0) { + TALLOC_FREE(ctdb->freeze_handles[priority]); + ctdb->freeze_mode[priority] = CTDB_FREEZE_NONE; + } + } return; } @@ -465,6 +506,7 @@ static void ctdb_start_freeze(struct ctdb_context *ctdb, uint32_t priority) h->ctdb = ctdb; h->priority = priority; talloc_set_destructor(h, ctdb_freeze_handle_destructor); + ctdb->freeze_handles[priority] = h; ret = ctdb_db_prio_iterator(ctdb, priority, db_count, &h->num_total); if (ret != 0) { @@ -480,7 +522,6 @@ static void ctdb_start_freeze(struct ctdb_context *ctdb, uint32_t priority) return; } - ctdb->freeze_handles[priority] = h; if (h->num_total == 0) { ctdb->freeze_mode[priority] = CTDB_FREEZE_FROZEN; } @@ -515,14 +556,14 @@ int32_t ctdb_control_freeze(struct ctdb_context *ctdb, struct ctdb_req_control * return -1; } + ctdb_start_freeze(ctdb, priority); + if (ctdb->freeze_mode[priority] == CTDB_FREEZE_FROZEN) { DEBUG(DEBUG_ERR, ("Freeze priority %u: frozen\n", priority)); /* we're already frozen */ return 0; } - ctdb_start_freeze(ctdb, priority); - if (ctdb->freeze_handles[priority] == NULL) { DEBUG(DEBUG_ERR,("No freeze lock handle when adding a waiter\n")); return -1; From b81d4ccc770fc0f691fb87becd991350d91d2bd6 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Thu, 17 Sep 2015 12:57:51 +1000 Subject: [PATCH 032/136] ctdb-freeze: Use individual database freeze in blocking freeze Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/server/ctdb_freeze.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/ctdb/server/ctdb_freeze.c b/ctdb/server/ctdb_freeze.c index 9d72d87..761ed8e 100644 --- a/ctdb/server/ctdb_freeze.c +++ b/ctdb/server/ctdb_freeze.c @@ -590,20 +590,33 @@ int32_t ctdb_control_freeze(struct ctdb_context *ctdb, struct ctdb_req_control * } +static int db_freeze_block(struct ctdb_db_context *ctdb_db, void *private_data) +{ + struct tevent_context *ev = (struct tevent_context *)private_data; + + ctdb_start_db_freeze(ctdb_db); + + while (ctdb_db->freeze_mode == CTDB_FREEZE_PENDING) { + tevent_loop_once(ev); + } + + if (ctdb_db->freeze_mode != CTDB_FREEZE_FROZEN) { + return -1; + } + + return 0; +} + /* block until we are frozen, used during daemon startup */ bool ctdb_blocking_freeze(struct ctdb_context *ctdb) { - int i; - - for (i=1; i<=NUM_DB_PRIORITIES; i++) { - ctdb_start_freeze(ctdb, i); + int ret; - /* block until frozen */ - while (ctdb->freeze_mode[i] == CTDB_FREEZE_PENDING) { - event_loop_once(ctdb->ev); - } + ret = ctdb_db_iterator(ctdb, db_freeze_block, ctdb->ev); + if (ret != 0) { + return false; } return true; From 1df25943866e1644d0f48c8980c7eafdea0b6366 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Fri, 11 Sep 2015 14:20:44 +1000 Subject: [PATCH 033/136] ctdb-daemon: Introduce per database generation The database generation for each database is updated only during recovery. After recovery is complete the database generation would be the same as the global generation. The database generation is required for parallel database recovery. Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/include/ctdb_private.h | 1 + ctdb/server/ctdb_banning.c | 5 +++++ ctdb/server/ctdb_freeze.c | 5 +++-- ctdb/server/ctdb_ltdb_server.c | 1 + ctdb/server/ctdb_recoverd.c | 7 ++++++- 5 files changed, 16 insertions(+), 3 deletions(-) diff --git a/ctdb/include/ctdb_private.h b/ctdb/include/ctdb_private.h index 8ca8d4b..975a7aa 100644 --- a/ctdb/include/ctdb_private.h +++ b/ctdb/include/ctdb_private.h @@ -590,6 +590,7 @@ struct ctdb_db_context { struct ctdb_db_freeze_handle *freeze_handle; bool freeze_transaction_started; uint32_t freeze_transaction_id; + uint32_t generation; }; diff --git a/ctdb/server/ctdb_banning.c b/ctdb/server/ctdb_banning.c index 92026fd..a86b78b 100644 --- a/ctdb/server/ctdb_banning.c +++ b/ctdb/server/ctdb_banning.c @@ -50,6 +50,8 @@ ctdb_ban_node_event(struct event_context *ev, struct timed_event *te, void ctdb_local_node_got_banned(struct ctdb_context *ctdb) { + struct ctdb_db_context *ctdb_db; + DEBUG(DEBUG_NOTICE,("This node has been banned - forcing recovery\n")); /* Reset the generation id to 1 to make us ignore any @@ -58,6 +60,9 @@ void ctdb_local_node_got_banned(struct ctdb_context *ctdb) anymore. */ ctdb->vnn_map->generation = INVALID_GENERATION; + for (ctdb_db = ctdb->db_list; ctdb_db != NULL; ctdb_db = ctdb_db->next) { + ctdb_db->generation = INVALID_GENERATION; + } /* make sure we get frozen */ ctdb->recovery_mode = CTDB_RECOVERY_ACTIVE; diff --git a/ctdb/server/ctdb_freeze.c b/ctdb/server/ctdb_freeze.c index 761ed8e..5a688d3 100644 --- a/ctdb/server/ctdb_freeze.c +++ b/ctdb/server/ctdb_freeze.c @@ -100,7 +100,6 @@ static int db_transaction_commit_handler(struct ctdb_db_context *ctdb_db, return ret; } - /* a list of control requests waiting for db freeze */ struct ctdb_db_freeze_waiter { struct ctdb_db_freeze_waiter *next, *prev; @@ -266,7 +265,8 @@ int32_t ctdb_control_db_thaw(struct ctdb_context *ctdb, uint32_t db_id) return -1; } - DEBUG(DEBUG_ERR, ("Thaw db: %s\n", ctdb_db->db_name)); + DEBUG(DEBUG_ERR, ("Thaw db: %s generation %u\n", ctdb_db->db_name, + ctdb_db->generation)); TALLOC_FREE(ctdb_db->freeze_handle); ctdb_call_resend_db(ctdb_db); @@ -764,6 +764,7 @@ static int db_commit_transaction(struct ctdb_db_context *ctdb_db, ctdb_db->freeze_transaction_started = false; ctdb_db->freeze_transaction_id = 0; + ctdb_db->generation = state->transaction_id; return 0; } diff --git a/ctdb/server/ctdb_ltdb_server.c b/ctdb/server/ctdb_ltdb_server.c index ad61f14..440ca7b 100644 --- a/ctdb/server/ctdb_ltdb_server.c +++ b/ctdb/server/ctdb_ltdb_server.c @@ -1009,6 +1009,7 @@ static int ctdb_local_attach(struct ctdb_context *ctdb, const char *db_name, return -1; } + ctdb_db->generation = ctdb->vnn_map->generation; DEBUG(DEBUG_NOTICE,("Attached to database '%s' with flags 0x%x\n", ctdb_db->db_path, tdb_flags)); diff --git a/ctdb/server/ctdb_recoverd.c b/ctdb/server/ctdb_recoverd.c index ea3a857..8fe955d 100644 --- a/ctdb/server/ctdb_recoverd.c +++ b/ctdb/server/ctdb_recoverd.c @@ -1960,6 +1960,12 @@ static int do_recovery(struct ctdb_recoverd *rec, goto fail; } + /* Database generations are updated when the transaction is commited to + * the databases. So make sure to use the final generation as the + * transaction id + */ + generation = new_generation(); + data.dptr = (void *)&generation; data.dsize = sizeof(uint32_t); @@ -2019,7 +2025,6 @@ static int do_recovery(struct ctdb_recoverd *rec, /* build a new vnn map with all the currently active and unbanned nodes */ - generation = new_generation(); vnnmap = talloc(mem_ctx, struct ctdb_vnn_map); CTDB_NO_MEMORY(ctdb, vnnmap); vnnmap->generation = generation; From 3d11efe3c63c884ebb78c5488c565d9ab5afb963 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Tue, 15 Sep 2015 16:50:19 +1000 Subject: [PATCH 034/136] ctdb-daemon: Use database generation in packet headers for database requests Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/server/ctdb_call.c | 15 ++++++++++----- ctdb/server/ctdb_ltdb_server.c | 6 ++++-- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/ctdb/server/ctdb_call.c b/ctdb/server/ctdb_call.c index a158d26..9a43b9a 100644 --- a/ctdb/server/ctdb_call.c +++ b/ctdb/server/ctdb_call.c @@ -190,6 +190,7 @@ static void ctdb_send_dmaster_reply(struct ctdb_db_context *ctdb_db, r->hdr.destnode = new_dmaster; r->hdr.reqid = reqid; + r->hdr.generation = ctdb_db->generation; r->rsn = header->rsn; r->keylen = key.dsize; r->datalen = data.dsize; @@ -242,6 +243,7 @@ static void ctdb_call_send_dmaster(struct ctdb_db_context *ctdb_db, CTDB_NO_MEMORY_FATAL(ctdb, r); r->hdr.destnode = lmaster; r->hdr.reqid = c->hdr.reqid; + r->hdr.generation = ctdb_db->generation; r->db_id = c->db_id; r->rsn = header->rsn; r->dmaster = c->hdr.srcnode; @@ -416,7 +418,7 @@ struct dmaster_defer_call { }; struct dmaster_defer_queue { - struct ctdb_context *ctdb; + struct ctdb_db_context *ctdb_db; uint32_t generation; struct dmaster_defer_call *deferred_calls; }; @@ -436,7 +438,7 @@ static void dmaster_defer_reprocess(struct tevent_context *ev, static int dmaster_defer_queue_destructor(struct dmaster_defer_queue *ddq) { /* Ignore requests, if database recovery happens in-between. */ - if (ddq->generation != ddq->ctdb->vnn_map->generation) { + if (ddq->generation != ddq->ctdb_db->generation) { return 0; } @@ -490,7 +492,7 @@ static int dmaster_defer_setup(struct ctdb_db_context *ctdb_db, talloc_free(k); return -1; } - ddq->ctdb = ctdb_db->ctdb; + ddq->ctdb_db = ctdb_db; ddq->generation = hdr->generation; ddq->deferred_calls = NULL; @@ -1024,6 +1026,7 @@ void ctdb_request_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr) CTDB_NO_MEMORY_FATAL(ctdb, r); r->hdr.destnode = c->hdr.srcnode; r->hdr.reqid = c->hdr.reqid; + r->hdr.generation = ctdb_db->generation; r->status = 0; r->datalen = data.dsize + sizeof(struct ctdb_ltdb_header); header.rsn -= 2; @@ -1108,6 +1111,7 @@ void ctdb_request_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr) CTDB_NO_MEMORY_FATAL(ctdb, r); r->hdr.destnode = hdr->srcnode; r->hdr.reqid = hdr->reqid; + r->hdr.generation = ctdb_db->generation; r->status = call->status; r->datalen = call->reply_data.dsize; if (call->reply_data.dsize) { @@ -1314,7 +1318,7 @@ static void ctdb_call_resend(struct ctdb_call_state *state) { struct ctdb_context *ctdb = state->ctdb_db->ctdb; - state->generation = ctdb->vnn_map->generation; + state->generation = state->ctdb_db->generation; /* use a new reqid, in case the old reply does eventually come in */ ctdb_reqid_remove(ctdb, state->reqid); @@ -1439,6 +1443,7 @@ struct ctdb_call_state *ctdb_daemon_call_send_remote(struct ctdb_db_context *ctd /* this limits us to 16k outstanding messages - not unreasonable */ state->c->hdr.reqid = state->reqid; + state->c->hdr.generation = ctdb_db->generation; state->c->flags = call->flags; state->c->db_id = ctdb_db->db_id; state->c->callid = call->call_id; @@ -1453,7 +1458,7 @@ struct ctdb_call_state *ctdb_daemon_call_send_remote(struct ctdb_db_context *ctd state->call->key.dptr = &state->c->data[0]; state->state = CTDB_CALL_WAIT; - state->generation = ctdb->vnn_map->generation; + state->generation = ctdb_db->generation; DLIST_ADD(ctdb_db->pending_calls, state); diff --git a/ctdb/server/ctdb_ltdb_server.c b/ctdb/server/ctdb_ltdb_server.c index 440ca7b..b387adb 100644 --- a/ctdb/server/ctdb_ltdb_server.c +++ b/ctdb/server/ctdb_ltdb_server.c @@ -241,6 +241,7 @@ static int ctdb_ltdb_store_server(struct ctdb_db_context *ctdb_db, struct lock_fetch_state { struct ctdb_context *ctdb; + struct ctdb_db_context *ctdb_db; void (*recv_pkt)(void *, struct ctdb_req_header *); void *recv_context; struct ctdb_req_header *hdr; @@ -255,7 +256,7 @@ static void lock_fetch_callback(void *p, bool locked) { struct lock_fetch_state *state = talloc_get_type(p, struct lock_fetch_state); if (!state->ignore_generation && - state->generation != state->ctdb->vnn_map->generation) { + state->generation != state->ctdb_db->generation) { DEBUG(DEBUG_NOTICE,("Discarding previous generation lockwait packet\n")); talloc_free(state->hdr); return; @@ -321,10 +322,11 @@ int ctdb_ltdb_lock_requeue(struct ctdb_db_context *ctdb_db, state = talloc(hdr, struct lock_fetch_state); state->ctdb = ctdb_db->ctdb; + state->ctdb_db = ctdb_db; state->hdr = hdr; state->recv_pkt = recv_pkt; state->recv_context = recv_context; - state->generation = ctdb_db->ctdb->vnn_map->generation; + state->generation = ctdb_db->generation; state->ignore_generation = ignore_generation; /* now the contended path */ From d701072c3e2309019a729c908b28c6657b28a2ca Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Wed, 23 Sep 2015 14:47:58 +1000 Subject: [PATCH 035/136] ctdb-call: Delete old defer queue if recovery occurs Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/server/ctdb_call.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/ctdb/server/ctdb_call.c b/ctdb/server/ctdb_call.c index 9a43b9a..39aac7e 100644 --- a/ctdb/server/ctdb_call.c +++ b/ctdb/server/ctdb_call.c @@ -482,8 +482,15 @@ static int dmaster_defer_setup(struct ctdb_db_context *ctdb_db, /* Already exists */ ddq = trbt_lookuparray32(ctdb_db->defer_dmaster, k[0], k); if (ddq != NULL) { - talloc_free(k); - return 0; + if (ddq->generation == ctdb_db->generation) { + talloc_free(k); + return 0; + } + + /* Recovery ocurred - get rid of old queue. All the deferred + * requests will be resent anyway from ctdb_call_resend_db. + */ + talloc_free(ddq); } ddq = talloc(hdr, struct dmaster_defer_queue); From 0ff90f4fac74e61192aff100b168e38ce0adfabb Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Tue, 15 Sep 2015 16:50:19 +1000 Subject: [PATCH 036/136] ctdb-daemon: Check packet generation against database generation CTDB verifies the generation in the packet header matches that of the current generation. However, that check now needs to be done where database context is available. So add in the check in handlers for database requests (CTDB_REQ_CALL, CTDB_REQ_DMASTER, CTDB_REPLY_DMASTER and CTDB_REPLY_CALL). Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/server/ctdb_call.c | 59 +++++++++++++++++++++++++++++++++++++---------- ctdb/server/ctdb_server.c | 21 ++++------------- 2 files changed, 52 insertions(+), 28 deletions(-) diff --git a/ctdb/server/ctdb_call.c b/ctdb/server/ctdb_call.c index 39aac7e..4a59094 100644 --- a/ctdb/server/ctdb_call.c +++ b/ctdb/server/ctdb_call.c @@ -569,6 +569,23 @@ void ctdb_request_dmaster(struct ctdb_context *ctdb, struct ctdb_req_header *hdr size_t len; int ret; + ctdb_db = find_ctdb_db(ctdb, c->db_id); + if (!ctdb_db) { + ctdb_send_error(ctdb, hdr, -1, + "Unknown database in request. db_id==0x%08x", + c->db_id); + return; + } + + if (hdr->generation != ctdb_db->generation) { + DEBUG(DEBUG_DEBUG, + ("ctdb operation %u request %u from node %u to %u had an" + " invalid generation:%u while our generation is:%u\n", + hdr->operation, hdr->reqid, hdr->srcnode, hdr->destnode, + hdr->generation, ctdb_db->generation)); + return; + } + key.dptr = c->data; key.dsize = c->keylen; data.dptr = c->data + c->keylen; @@ -580,14 +597,6 @@ void ctdb_request_dmaster(struct ctdb_context *ctdb, struct ctdb_req_header *hdr sizeof(record_flags)); } - ctdb_db = find_ctdb_db(ctdb, c->db_id); - if (!ctdb_db) { - ctdb_send_error(ctdb, hdr, -1, - "Unknown database in request. db_id==0x%08x", - c->db_id); - return; - } - dmaster_defer_setup(ctdb_db, hdr, key); /* fetch the current record */ @@ -616,7 +625,7 @@ void ctdb_request_dmaster(struct ctdb_context *ctdb, struct ctdb_req_header *hdr if (header.dmaster != hdr->srcnode) { DEBUG(DEBUG_ALERT,("pnn %u dmaster request for new-dmaster %u from non-master %u real-dmaster=%u key %08x dbid 0x%08x gen=%u curgen=%u c->rsn=%llu header.rsn=%llu reqid=%u keyval=0x%08x\n", ctdb->pnn, c->dmaster, hdr->srcnode, header.dmaster, ctdb_hash(&key), - ctdb_db->db_id, hdr->generation, ctdb->vnn_map->generation, + ctdb_db->db_id, hdr->generation, ctdb_db->generation, (unsigned long long)c->rsn, (unsigned long long)header.rsn, c->hdr.reqid, (key.dsize >= 4)?(*(uint32_t *)key.dptr):0)); if (header.rsn != 0 || header.dmaster != ctdb->pnn) { @@ -631,7 +640,7 @@ void ctdb_request_dmaster(struct ctdb_context *ctdb, struct ctdb_req_header *hdr if (header.rsn > c->rsn) { DEBUG(DEBUG_ALERT,("pnn %u dmaster request with older RSN new-dmaster %u from %u real-dmaster=%u key %08x dbid 0x%08x gen=%u curgen=%u c->rsn=%llu header.rsn=%llu reqid=%u\n", ctdb->pnn, c->dmaster, hdr->srcnode, header.dmaster, ctdb_hash(&key), - ctdb_db->db_id, hdr->generation, ctdb->vnn_map->generation, + ctdb_db->db_id, hdr->generation, ctdb_db->generation, (unsigned long long)c->rsn, (unsigned long long)header.rsn, c->hdr.reqid)); } @@ -871,7 +880,6 @@ void ctdb_request_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr) return; } - ctdb_db = find_ctdb_db(ctdb, c->db_id); if (!ctdb_db) { ctdb_send_error(ctdb, hdr, -1, @@ -880,6 +888,15 @@ void ctdb_request_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr) return; } + if (hdr->generation != ctdb_db->generation) { + DEBUG(DEBUG_DEBUG, + ("ctdb operation %u request %u from node %u to %u had an" + " invalid generation:%u while our generation is:%u\n", + hdr->operation, hdr->reqid, hdr->srcnode, hdr->destnode, + hdr->generation, ctdb_db->generation)); + return; + } + call = talloc(hdr, struct ctdb_call); CTDB_NO_MEMORY_FATAL(ctdb, call); @@ -1154,6 +1171,15 @@ void ctdb_reply_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr) return; } + if (hdr->generation != state->generation) { + DEBUG(DEBUG_DEBUG, + ("ctdb operation %u request %u from node %u to %u had an" + " invalid generation:%u while our generation is:%u\n", + hdr->operation, hdr->reqid, hdr->srcnode, hdr->destnode, + hdr->generation, state->generation)); + return; + } + /* read only delegation processing */ /* If we got a FETCH_WITH_HEADER we should check if this is a ro @@ -1248,7 +1274,16 @@ void ctdb_reply_dmaster(struct ctdb_context *ctdb, struct ctdb_req_header *hdr) DEBUG(DEBUG_ERR,("Unknown db_id 0x%x in ctdb_reply_dmaster\n", c->db_id)); return; } - + + if (hdr->generation != ctdb_db->generation) { + DEBUG(DEBUG_DEBUG, + ("ctdb operation %u request %u from node %u to %u had an" + " invalid generation:%u while our generation is:%u\n", + hdr->operation, hdr->reqid, hdr->srcnode, hdr->destnode, + hdr->generation, ctdb_db->generation)); + return; + } + key.dptr = c->data; key.dsize = c->keylen; data.dptr = &c->data[key.dsize]; diff --git a/ctdb/server/ctdb_server.c b/ctdb/server/ctdb_server.c index 81ef361..75aec16 100644 --- a/ctdb/server/ctdb_server.c +++ b/ctdb/server/ctdb_server.c @@ -215,22 +215,11 @@ void ctdb_input_pkt(struct ctdb_context *ctdb, struct ctdb_req_header *hdr) goto done; } - /* for ctdb_call inter-node operations verify that the - remote node that sent us the call is running in the - same generation instance as this node - */ - if (ctdb->vnn_map->generation != hdr->generation) { - DEBUG(DEBUG_DEBUG,(__location__ " ctdb operation %u" - " request %u" - " length %u from node %u to %u had an" - " invalid generation id:%u while our" - " generation id is:%u\n", - hdr->operation, hdr->reqid, - hdr->length, - hdr->srcnode, hdr->destnode, - hdr->generation, ctdb->vnn_map->generation)); - goto done; - } + /* Push the check for generation in the handlers for these + * operations. Check database generation instead of global + * generation. Since the database context is not available + * here, push the check in the operations. + */ } switch (hdr->operation) { From 3cbd0409f398828ee6415229b3c23781405176ea Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Fri, 11 Sep 2015 16:14:12 +1000 Subject: [PATCH 037/136] ctdb-daemon: Add a check for database generation consistency Before setting recovery mode to normal, confirm that all the databases are recovered by matching the database generation with the global generation. Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/server/ctdb_recover.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ctdb/server/ctdb_recover.c b/ctdb/server/ctdb_recover.c index d5973a9..422e160 100644 --- a/ctdb/server/ctdb_recover.c +++ b/ctdb/server/ctdb_recover.c @@ -532,6 +532,7 @@ int32_t ctdb_control_set_recmode(struct ctdb_context *ctdb, int i, ret; struct ctdb_set_recmode_state *state; pid_t parent = getpid(); + struct ctdb_db_context *ctdb_db; /* if we enter recovery but stay in recovery for too long we will eventually drop all our ip addresses @@ -558,6 +559,16 @@ int32_t ctdb_control_set_recmode(struct ctdb_context *ctdb, /* some special handling when ending recovery mode */ + for (ctdb_db = ctdb->db_list; ctdb_db != NULL; ctdb_db = ctdb_db->next) { + if (ctdb_db->generation != ctdb->vnn_map->generation) { + DEBUG(DEBUG_ERR, + ("Inconsistent DB generation %u for %s\n", + ctdb_db->generation, ctdb_db->db_name)); + DEBUG(DEBUG_ERR, ("Recovery mode set to ACTIVE\n")); + return -1; + } + } + /* force the databases to thaw */ for (i=1; i<=NUM_DB_PRIORITIES; i++) { if (ctdb_db_prio_frozen(ctdb, i)) { From 42f772215178050a3f465440e79e1ec9bce0e34f Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Mon, 14 Sep 2015 13:49:05 +1000 Subject: [PATCH 038/136] ctdb-daemon: Remove freeze requirement for updating vnnmap In the parallel database recovery model, all the database will not remain frozen at the same time. So relax the condition to check if recovery is active. Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/server/ctdb_recover.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ctdb/server/ctdb_recover.c b/ctdb/server/ctdb_recover.c index 422e160..b57aa8e 100644 --- a/ctdb/server/ctdb_recover.c +++ b/ctdb/server/ctdb_recover.c @@ -50,13 +50,13 @@ ctdb_control_getvnnmap(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA inda return 0; } -int +int ctdb_control_setvnnmap(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA indata, TDB_DATA *outdata) { struct ctdb_vnn_map_wire *map = (struct ctdb_vnn_map_wire *)indata.dptr; - if (!ctdb_db_all_frozen(ctdb)) { - DEBUG(DEBUG_ERR,("Attempt to set vnnmap when not frozen\n")); + if (ctdb->recovery_mode != CTDB_RECOVERY_ACTIVE) { + DEBUG(DEBUG_ERR, ("Attempt to set vnnmap when not in recovery\n")); return -1; } From 90b633ea79291c85248f63493af64be7868763af Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Wed, 30 Sep 2015 11:38:52 +1000 Subject: [PATCH 039/136] ctdb-build: Do not mark ctdb private headers public These headers are used by the server code and should not be marked public. Samba builds against the in-tree version of the headers and should not be built with externally installed CTDB. Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/packaging/RPM/ctdb.spec.in | 6 ------ ctdb/wscript | 6 ------ 2 files changed, 12 deletions(-) diff --git a/ctdb/packaging/RPM/ctdb.spec.in b/ctdb/packaging/RPM/ctdb.spec.in index bc5ec0c..d9d4125 100644 --- a/ctdb/packaging/RPM/ctdb.spec.in +++ b/ctdb/packaging/RPM/ctdb.spec.in @@ -225,12 +225,6 @@ development libraries for ctdb %files devel %defattr(-,root,root) -%{_includedir}/ctdb.h -%{_includedir}/ctdb_client.h -%{_includedir}/ctdb_protocol.h -%{_includedir}/ctdb_private.h -%{_includedir}/ctdb_typesafe_cb.h -%{_includedir}/ctdb_version.h %package tests Summary: CTDB test suite diff --git a/ctdb/wscript b/ctdb/wscript index eea25e9..d815cd9 100755 --- a/ctdb/wscript +++ b/ctdb/wscript @@ -334,7 +334,6 @@ def build(bld): bld.SAMBA_SUBSYSTEM('ctdb-client', source=bld.SUBDIR('client', 'ctdb_client.c'), includes='include include/internal', - public_headers='include/ctdb_client.h', deps='''replace popt talloc tevent tdb samba-util tdb-wrap''') @@ -358,11 +357,6 @@ def build(bld): ctdb_update_record.c ctdb_lock.c'''), includes='include include/internal', - public_headers='''include/ctdb_version.h - include/ctdb.h - include/ctdb_private.h - include/ctdb_protocol.h - include/ctdb_typesafe_cb.h''', deps='replace popt talloc tevent tdb talloc_report') bld.SAMBA_BINARY('ctdbd', From 3f287ec47934225be5a72e9c7bf51421d22895a6 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Mon, 3 Aug 2015 15:38:32 +1000 Subject: [PATCH 040/136] ctdb-build: Do not split ctdb-system subsystem The functions defined in common/system_*.c depend on the functions defined in common/system_common.c. So keep them together. Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/tests/src/ctdb_test.c | 1 - ctdb/tests/src/ctdbd_test.c | 1 - ctdb/wscript | 43 ++++++++++++++++++++----------------------- 3 files changed, 20 insertions(+), 25 deletions(-) diff --git a/ctdb/tests/src/ctdb_test.c b/ctdb/tests/src/ctdb_test.c index 38f5a06..85f4813 100644 --- a/ctdb/tests/src/ctdb_test.c +++ b/ctdb/tests/src/ctdb_test.c @@ -175,7 +175,6 @@ ctdb_get_capabilities(struct ctdb_context *ctdb, #include "common/ctdb_ltdb.c" #include "common/ctdb_message.c" #include "common/rb_tree.c" -#include "common/system_common.c" #include "common/ctdb_logging.c" #include "common/ctdb_fork.c" #include "common/system_util.c" diff --git a/ctdb/tests/src/ctdbd_test.c b/ctdb/tests/src/ctdbd_test.c index b62429e..439512a 100644 --- a/ctdb/tests/src/ctdbd_test.c +++ b/ctdb/tests/src/ctdbd_test.c @@ -38,7 +38,6 @@ bool fast_start; #include "common/ctdb_message.c" #include "common/cmdline.c" #include "common/rb_tree.c" -#include "common/system_common.c" #include "common/ctdb_logging.c" #include "common/ctdb_fork.c" #include "common/system_util.c" diff --git a/ctdb/wscript b/ctdb/wscript index d815cd9..8b357fc 100755 --- a/ctdb/wscript +++ b/ctdb/wscript @@ -299,20 +299,6 @@ def build(bld): deps='replace') ib_deps = ' ctdb-ib rdmacm ibverbs' - bld.SAMBA_SUBSYSTEM('ctdb-common', - source=bld.SUBDIR('common', - '''ctdb_io.c ctdb_util.c ctdb_ltdb.c - ctdb_message.c cmdline.c rb_tree.c - system_common.c ctdb_fork.c'''), - includes='include include/internal common .', - deps='replace popt talloc tevent tdb popt') - - bld.SAMBA_SUBSYSTEM('ctdb-common-util', - source=bld.SUBDIR('common', - 'system_util.c ctdb_logging.c'), - includes='include include/internal', - deps='replace tevent tdb') - if sys.platform.startswith('linux'): CTDB_SYSTEM_SRC = bld.SUBDIR('common', 'system_linux.c') elif sys.platform.startswith('aix'): @@ -327,10 +313,24 @@ def build(bld): Logs.error("Platform %s not supported" % sys.platform) bld.SAMBA_SUBSYSTEM('ctdb-system', - source=CTDB_SYSTEM_SRC, + source='common/system_common.c ' + CTDB_SYSTEM_SRC, includes='include include/internal', deps='replace talloc tevent tdb pcap') + bld.SAMBA_SUBSYSTEM('ctdb-common', + source=bld.SUBDIR('common', + '''ctdb_io.c ctdb_util.c ctdb_ltdb.c + ctdb_message.c cmdline.c rb_tree.c + ctdb_fork.c'''), + includes='include include/internal common .', + deps='replace popt talloc tevent tdb popt ctdb-system') + + bld.SAMBA_SUBSYSTEM('ctdb-common-util', + source=bld.SUBDIR('common', + 'system_util.c ctdb_logging.c'), + includes='include include/internal', + deps='replace tevent tdb') + bld.SAMBA_SUBSYSTEM('ctdb-client', source=bld.SUBDIR('client', 'ctdb_client.c'), includes='include include/internal', @@ -362,15 +362,14 @@ def build(bld): bld.SAMBA_BINARY('ctdbd', source='', deps='''ctdb-server ctdb-client ctdb-common - ctdb-common-util ctdb-system ctdb-tcp''' + + ctdb-common-util ctdb-tcp''' + ib_deps, install_path='${SBINDIR}', manpages='ctdbd.1') bld.SAMBA_BINARY('ctdb', source='tools/ctdb.c tools/ctdb_vacuum.c', - deps='''ctdb-client ctdb-common ctdb-common-util - ctdb-system''', + deps='ctdb-client ctdb-common ctdb-common-util', includes='include include/internal', install_path='${BINDIR}', manpages='ctdb.1') @@ -428,7 +427,7 @@ def build(bld): bld.SAMBA_BINARY('pmdactdb', source='utils/pmda/pmda_ctdb.c', includes='include include/internal', - deps='''ctdb-client ctdb-common ctdb-system + deps='''ctdb-client ctdb-common ctdb-common-util pcp_pmda pcp''', install_path='${CTDB_PMDADIR}') bld.INSTALL_FILES('${CTDB_PMDADIR}', 'utils/pmda/Install', @@ -592,8 +591,7 @@ def build(bld): bld.SAMBA_BINARY(target, source=src, includes='include include/internal', - deps='''ctdb-client ctdb-common ctdb-common-util - ctdb-system''', + deps='ctdb-client ctdb-common ctdb-common-util', install_path='${CTDB_TEST_LIBDIR}') bld.SAMBA_BINARY('ctdb_takeover_tests', @@ -622,8 +620,7 @@ def build(bld): bld.SAMBA_BINARY('ibwrapper_test', source='ib/ibwrapper_test.c', includes='include include/internal', - deps='''replace talloc ctdb-client ctdb-common - ctdb-system''' + + deps='replace talloc ctdb-client ctdb-common ' + ib_deps, install_path='${CTDB_TEST_LIBDIR}') From ba56d852cb156585e34b758f3065df7adcdb73ba Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Wed, 8 Apr 2015 14:24:31 +1000 Subject: [PATCH 041/136] ctdb-daemon: Remove ctdb from traverse_callback Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/client/ctdb_client.c | 8 ++++---- ctdb/include/ctdb_client.h | 5 +++-- ctdb/tests/src/ctdb_traverse.c | 2 +- ctdb/tools/ctdb.c | 7 +++++-- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/ctdb/client/ctdb_client.c b/ctdb/client/ctdb_client.c index 9c7571f..57f2017 100644 --- a/ctdb/client/ctdb_client.c +++ b/ctdb/client/ctdb_client.c @@ -2213,7 +2213,7 @@ static void traverse_handler(struct ctdb_context *ctdb, uint64_t srvid, TDB_DATA return; } - if (state->fn(ctdb, key, data, state->private_data) != 0) { + if (state->fn(key, data, state->private_data) != 0) { state->done = true; } @@ -2296,7 +2296,7 @@ int ctdb_traverse(struct ctdb_db_context *ctdb_db, ctdb_traverse_func fn, void * /* called on each key during a catdb */ -int ctdb_dumpdb_record(struct ctdb_context *ctdb, TDB_DATA key, TDB_DATA data, void *p) +int ctdb_dumpdb_record(TDB_DATA key, TDB_DATA data, void *p) { int i; struct ctdb_dump_db_context *c = (struct ctdb_dump_db_context *)p; @@ -2316,8 +2316,8 @@ int ctdb_dumpdb_record(struct ctdb_context *ctdb, TDB_DATA key, TDB_DATA data, v fprintf(f, "dmaster: %u\n", h->dmaster); fprintf(f, "rsn: %llu\n", (unsigned long long)h->rsn); - if (c->printlmaster && ctdb->vnn_map != NULL) { - fprintf(f, "lmaster: %u\n", ctdb_lmaster(ctdb, &key)); + if (c->printlmaster && c->ctdb->vnn_map != NULL) { + fprintf(f, "lmaster: %u\n", ctdb_lmaster(c->ctdb, &key)); } if (c->printhash) { diff --git a/ctdb/include/ctdb_client.h b/ctdb/include/ctdb_client.h index 74887a7..528ea46 100644 --- a/ctdb/include/ctdb_client.h +++ b/ctdb/include/ctdb_client.h @@ -324,10 +324,11 @@ uint32_t *ctdb_get_connected_nodes(struct ctdb_context *ctdb, int ctdb_statistics_reset(struct ctdb_context *ctdb, uint32_t destnode); -typedef int (*ctdb_traverse_func)(struct ctdb_context *, TDB_DATA, TDB_DATA, void *); +typedef int (*ctdb_traverse_func)(TDB_DATA, TDB_DATA, void *); int ctdb_traverse(struct ctdb_db_context *ctdb_db, ctdb_traverse_func fn, void *private_data); struct ctdb_dump_db_context { + struct ctdb_context *ctdb; FILE *f; bool printemptyrecords; bool printdatasize; @@ -336,7 +337,7 @@ struct ctdb_dump_db_context { bool printrecordflags; }; -int ctdb_dumpdb_record(struct ctdb_context *ctdb, TDB_DATA key, TDB_DATA data, void *p); +int ctdb_dumpdb_record(TDB_DATA key, TDB_DATA data, void *p); int ctdb_dump_db(struct ctdb_db_context *ctdb_db, struct ctdb_dump_db_context *ctx); diff --git a/ctdb/tests/src/ctdb_traverse.c b/ctdb/tests/src/ctdb_traverse.c index 5b37ed9..67a0c61 100644 --- a/ctdb/tests/src/ctdb_traverse.c +++ b/ctdb/tests/src/ctdb_traverse.c @@ -28,7 +28,7 @@ static const char *dbname = "test.tdb"; -static int traverse_callback(struct ctdb_context *ctdb, TDB_DATA key, TDB_DATA data, void *private_data) +static int traverse_callback(TDB_DATA key, TDB_DATA data, void *private_data) { uint32_t *count = private_data; diff --git a/ctdb/tools/ctdb.c b/ctdb/tools/ctdb.c index 0d00687..989b94c 100644 --- a/ctdb/tools/ctdb.c +++ b/ctdb/tools/ctdb.c @@ -3772,6 +3772,7 @@ static int control_catdb(struct ctdb_context *ctdb, int argc, const char **argv) } ZERO_STRUCT(c); + c.ctdb = ctdb; c.f = stdout; c.printemptyrecords = (bool)options.printemptyrecords; c.printdatasize = (bool)options.printdatasize; @@ -3807,6 +3808,7 @@ static int cattdb_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, d->count++; ZERO_STRUCT(c); + c.ctdb = d->ctdb; c.f = stdout; c.printemptyrecords = (bool)options.printemptyrecords; c.printdatasize = (bool)options.printdatasize; @@ -3814,7 +3816,7 @@ static int cattdb_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, c.printhash = (bool)options.printhash; c.printrecordflags = true; - return ctdb_dumpdb_record(d->ctdb, key, data, &c); + return ctdb_dumpdb_record(key, data, &c); } /* @@ -5824,6 +5826,7 @@ static int control_dumpdbbackup(struct ctdb_context *ctdb, int argc, const char dbhdr.name, m->db_id, tbuf); ZERO_STRUCT(c); + c.ctdb = ctdb; c.f = stdout; c.printemptyrecords = (bool)options.printemptyrecords; c.printdatasize = (bool)options.printdatasize; @@ -5839,7 +5842,7 @@ static int control_dumpdbbackup(struct ctdb_context *ctdb, int argc, const char rec = ctdb_marshall_loop_next(m, rec, &reqid, NULL, &key, &data); - ctdb_dumpdb_record(ctdb, key, data, &c); + ctdb_dumpdb_record(key, data, &c); } printf("Dumped %d records\n", i); From 6672deea13b663dd43e82df76a3152887ddac1dd Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Wed, 8 Apr 2015 14:25:01 +1000 Subject: [PATCH 042/136] ctdb-daemon: formatting fix Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/client/ctdb_client.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ctdb/client/ctdb_client.c b/ctdb/client/ctdb_client.c index 57f2017..1d832fa 100644 --- a/ctdb/client/ctdb_client.c +++ b/ctdb/client/ctdb_client.c @@ -2188,9 +2188,9 @@ static void traverse_handler(struct ctdb_context *ctdb, uint64_t srvid, TDB_DATA struct ctdb_rec_data *d = (struct ctdb_rec_data *)data.dptr; TDB_DATA key; - if (data.dsize < sizeof(uint32_t) || - d->length != data.dsize) { - DEBUG(DEBUG_ERR,("Bad data size %u in traverse_handler\n", (unsigned)data.dsize)); + if (data.dsize < sizeof(uint32_t) || d->length != data.dsize) { + DEBUG(DEBUG_ERR, ("Bad data size %u in traverse_handler\n", + (unsigned)data.dsize)); state->done = true; return; } From acf5ebfa906b226d7db2051c9716dd9091d7ecb7 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Wed, 8 Apr 2015 14:25:12 +1000 Subject: [PATCH 043/136] ctdb-daemon: whitespace fix Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/tests/src/ctdb_traverse.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ctdb/tests/src/ctdb_traverse.c b/ctdb/tests/src/ctdb_traverse.c index 67a0c61..8ca76a3 100644 --- a/ctdb/tests/src/ctdb_traverse.c +++ b/ctdb/tests/src/ctdb_traverse.c @@ -31,7 +31,7 @@ static const char *dbname = "test.tdb"; static int traverse_callback(TDB_DATA key, TDB_DATA data, void *private_data) { uint32_t *count = private_data; - + (*count)++; return 0; } From e5592f9fc018b4b22fbdba4f45526210f5f41692 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Tue, 17 Mar 2015 12:35:31 +1100 Subject: [PATCH 044/136] ctdb-common: Add db_hash abstraction A hash table implemented using in-memory tdb backend. Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/common/db_hash.c | 268 +++++++++++++++++++++++++++++++++++ ctdb/common/db_hash.h | 159 +++++++++++++++++++++ ctdb/tests/cunit/db_hash_test_001.sh | 7 + ctdb/tests/run_tests.sh | 2 +- ctdb/tests/src/db_hash_test.c | 102 +++++++++++++ ctdb/wscript | 19 +++ 6 files changed, 556 insertions(+), 1 deletion(-) create mode 100644 ctdb/common/db_hash.c create mode 100644 ctdb/common/db_hash.h create mode 100755 ctdb/tests/cunit/db_hash_test_001.sh create mode 100644 ctdb/tests/src/db_hash_test.c diff --git a/ctdb/common/db_hash.c b/ctdb/common/db_hash.c new file mode 100644 index 0000000..6a23337 --- /dev/null +++ b/ctdb/common/db_hash.c @@ -0,0 +1,268 @@ +/* + Using tdb as a hash table + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include "replace.h" +#include "system/filesys.h" + +#include +#include + +#include "common/db_hash.h" + +struct db_hash_context { + struct tdb_context *db; +}; + + +static int db_hash_destructor(struct db_hash_context *dh) +{ + if (dh->db != NULL) { + tdb_close(dh->db); + dh->db = NULL; + } + return 0; +} + +int db_hash_init(TALLOC_CTX *mem_ctx, const char *name, int hash_size, + enum db_hash_type type, struct db_hash_context **result) +{ + struct db_hash_context *dh; + int tdb_flags = TDB_INTERNAL | TDB_DISALLOW_NESTING; + + dh = talloc_zero(mem_ctx, struct db_hash_context); + if (dh == NULL) { + return ENOMEM; + } + + if (type == DB_HASH_COMPLEX) { + tdb_flags |= TDB_INCOMPATIBLE_HASH; + } + + dh->db = tdb_open(name, hash_size, tdb_flags, O_RDWR|O_CREAT, 0); + if (dh->db == NULL) { + talloc_free(dh); + return ENOMEM; + } + + talloc_set_destructor(dh, db_hash_destructor); + *result = dh; + return 0; +} + +static int db_hash_map_tdb_error(struct db_hash_context *dh) +{ + enum TDB_ERROR tdb_err; + int ret; + + tdb_err = tdb_error(dh->db); + switch (tdb_err) { + case TDB_SUCCESS: + ret = 0; break; + case TDB_ERR_OOM: + ret = ENOMEM; break; + case TDB_ERR_EXISTS: + ret = EEXIST; break; + case TDB_ERR_NOEXIST: + ret = ENOENT; break; + case TDB_ERR_EINVAL: + ret = EINVAL; break; + default: + ret = EIO; break; + } + return ret; +} + +int db_hash_insert(struct db_hash_context *dh, uint8_t *keybuf, size_t keylen, + uint8_t *databuf, size_t datalen) +{ + TDB_DATA key, data; + int ret; + + if (dh == NULL) { + return EINVAL; + } + + key.dptr = keybuf; + key.dsize = keylen; + + data.dptr = databuf; + data.dsize = datalen; + + ret = tdb_store(dh->db, key, data, TDB_INSERT); + if (ret != 0) { + ret = db_hash_map_tdb_error(dh); + } + return ret; +} + +int db_hash_add(struct db_hash_context *dh, uint8_t *keybuf, size_t keylen, + uint8_t *databuf, size_t datalen) +{ + TDB_DATA key, data; + int ret; + + if (dh == NULL) { + return EINVAL; + } + + key.dptr = keybuf; + key.dsize = keylen; + + data.dptr = databuf; + data.dsize = datalen; + + ret = tdb_store(dh->db, key, data, TDB_REPLACE); + if (ret != 0) { + ret = db_hash_map_tdb_error(dh); + } + return ret; +} + +int db_hash_delete(struct db_hash_context *dh, uint8_t *keybuf, size_t keylen) +{ + TDB_DATA key; + int ret; + + key.dptr = keybuf; + key.dsize = keylen; + + if (dh == NULL) { + return EINVAL; + } + + ret = tdb_delete(dh->db, key); + if (ret != 0) { + ret = db_hash_map_tdb_error(dh); + } + return ret; +} + +struct db_hash_fetch_state { + db_hash_record_parser_fn parser; + void *private_data; +}; + +static int db_hash_fetch_parser(TDB_DATA key, TDB_DATA data, void *private_data) +{ + struct db_hash_fetch_state *state = + (struct db_hash_fetch_state *)private_data; + int ret; + + ret = state->parser(key.dptr, key.dsize, data.dptr, data.dsize, + state->private_data); + return ret; +} + +int db_hash_fetch(struct db_hash_context *dh, uint8_t *keybuf, size_t keylen, + db_hash_record_parser_fn parser, void *private_data) +{ + struct db_hash_fetch_state state; + TDB_DATA key; + int ret; + + if (dh == NULL || parser == NULL) { + return EINVAL; + } + + state.parser = parser; + state.private_data = private_data; + + key.dptr = keybuf; + key.dsize = keylen; + + ret = tdb_parse_record(dh->db, key, db_hash_fetch_parser, &state); + if (ret == -1) { + return ENOENT; + } + return ret; +} + +int db_hash_exists(struct db_hash_context *dh, uint8_t *keybuf, size_t keylen) +{ + TDB_DATA key; + int ret; + + if (dh == NULL) { + return EINVAL; + } + + key.dptr = keybuf; + key.dsize = keylen; + + ret = tdb_exists(dh->db, key); + if (ret == 1) { + /* Key found */ + ret = 0; + } else { + ret = db_hash_map_tdb_error(dh); + if (ret == 0) { + ret = ENOENT; + } + } + return ret; +} + +struct db_hash_traverse_state { + db_hash_record_parser_fn parser; + void *private_data; +}; + +static int db_hash_traverse_parser(struct tdb_context *tdb, + TDB_DATA key, TDB_DATA data, + void *private_data) +{ + struct db_hash_traverse_state *state = + (struct db_hash_traverse_state *)private_data; + + return state->parser(key.dptr, key.dsize, data.dptr, data.dsize, + state->private_data); +} + +int db_hash_traverse(struct db_hash_context *dh, + db_hash_record_parser_fn parser, void *private_data, + int *count) +{ + struct db_hash_traverse_state state; + int ret; + + if (dh == NULL) { + return EINVAL; + } + + /* Special case, for counting records */ + if (parser == NULL) { + ret = tdb_traverse_read(dh->db, NULL, NULL); + } else { + state.parser = parser; + state.private_data = private_data; + + ret = tdb_traverse_read(dh->db, db_hash_traverse_parser, &state); + } + + if (ret == -1) { + ret = db_hash_map_tdb_error(dh); + } else { + if (count != NULL) { + *count = ret; + } + ret = 0; + } + + return ret; +} diff --git a/ctdb/common/db_hash.h b/ctdb/common/db_hash.h new file mode 100644 index 0000000..8f0e50b --- /dev/null +++ b/ctdb/common/db_hash.h @@ -0,0 +1,159 @@ +/* + Using tdb as a hash table + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#ifndef __CTDB_DB_HASH_H__ +#define __CTDB_DB_HASH_H__ + +#include +#include + +/** + * @file db_hash.h + * + * @brief Use tdb database as a hash table + * + * This uses in-memory tdb databases to create a fixed sized hash table. + */ + +/** + * @brief Hash type to indicate the hashing function to use. + * + * DB_HASH_SIMPLE uses default hashing function + * DB_HASH_COMPLEX uses jenkins hashing function + */ +enum db_hash_type { + DB_HASH_SIMPLE, + DB_HASH_COMPLEX, +}; + +/** + * @brief Parser callback function called when fetching a record + * + * This function is called when fetching a record. This function should + * not modify key and data arguments. + * + * The function should return 0 on success and errno on error. + */ +typedef int (*db_hash_record_parser_fn)(uint8_t *keybuf, size_t keylen, + uint8_t *databuf, size_t datalen, + void *private_data); + +/** + * @brief Abstract structure representing tdb hash table + */ +struct db_hash_context; + +/** + * @brief Initialize tdb hash table + * + * This returns a new tdb hash table context which is a talloc context. Freeing + * this context will free all the memory associated with the hash table. + * + * @param[in] mem_ctx Talloc memory context + * @param[in] name The name for the hash table + * @param[in] hash_size The size of the hash table + * @param[in] type The type of hashing function to use + * @param[out] result The new db_hash_context structure + * @return 0 on success, errno on failure + */ +int db_hash_init(TALLOC_CTX *mem_ctx, const char *name, int hash_size, + enum db_hash_type type, struct db_hash_context **result); + +/** + * @brief Insert a record into the hash table + * + * The key and data can be any binary data. Insert only if the record does not + * exist. If the record already exists, return error. + * + * @param[in] dh The tdb hash table context + * @param[in] keybuf The key buffer + * @param[in] keylen The key length + * @param[in] databuf The data buffer + * @param[in] datalen The data length + * @return 0 on success, errno on failure + */ +int db_hash_insert(struct db_hash_context *dh, uint8_t *keybuf, size_t keylen, + uint8_t *databuf, size_t datalen); + +/** + * @brief Add a record into the hash table + * + * The key and data can be any binary data. If the record does not exist, + * insert the record. If the record already exists, replace the record. + * + * @param[in] dh The tdb hash table context + * @param[in] keybuf The key buffer + * @param[in] keylen The key length + * @param[in] databuf The data buffer + * @param[in] datalen The data length + * @return 0 on success, errno on failure + */ +int db_hash_add(struct db_hash_context *dh, uint8_t *keybuf, size_t keylen, + uint8_t *databuf, size_t datalen); +/** + * @brief Delete a record from the hash table + * + * @param[in] dh The tdb hash table context + * @param[in] keybuf The key buffer + * @param[in] keylen The key length + * @return 0 on success, errno on failure + */ +int db_hash_delete(struct db_hash_context *dh, uint8_t *keybuf, size_t keylen); + +/** + * @brief Fetch a record from the hash table + * + * The key and data can be any binary data. + * + * @param[in] dh The tdb hash table context + * @param[in] keybuf The key buffer + * @param[in] keylen The key length + * @param[in] parser Function called when the matching record is found + * @param[in] private_data Private data to parser function + * @return 0 on success, errno on failure + */ +int db_hash_fetch(struct db_hash_context *dh, uint8_t *keybuf, size_t keylen, + db_hash_record_parser_fn parser, void *private_data); + +/** + * @brief Check if a record exists in the hash table + * + * @param[in] dh The tdb hash table context + * @param[in] keybuf The key buffer + * @param[in] keylen The key length + * @return 0 if the record exists, errno on failure + */ +int db_hash_exists(struct db_hash_context *dh, uint8_t *keybuf, size_t keylen); + +/** + * @brief Traverse the database + * + * The parser function should non-zero value to stop traverse. + * + * @param[in] dh The tdb hash table context + * @param[in] parser Function called for each record + * @param[in] private_data Private data to parser function + * @param[out] count Number of records traversed + * @return 0 on success, errno on failure + */ +int db_hash_traverse(struct db_hash_context *dh, + db_hash_record_parser_fn parser, void *private_data, + int *count); + +#endif /* __CTDB_DB_HASH_H__ */ diff --git a/ctdb/tests/cunit/db_hash_test_001.sh b/ctdb/tests/cunit/db_hash_test_001.sh new file mode 100755 index 0000000..76c38fe --- /dev/null +++ b/ctdb/tests/cunit/db_hash_test_001.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +. "${TEST_SCRIPTS_DIR}/unit.sh" + +ok_null + +unit_test db_hash_test diff --git a/ctdb/tests/run_tests.sh b/ctdb/tests/run_tests.sh index d705ac1..2af2daf 100755 --- a/ctdb/tests/run_tests.sh +++ b/ctdb/tests/run_tests.sh @@ -255,7 +255,7 @@ export TEST_SCRIPTS_DIR="${test_dir}/scripts" # If no tests specified then run some defaults if [ -z "$1" ] ; then if [ -n "$TEST_LOCAL_DAEMONS" ] ; then - set -- onnode takeover tool eventscripts simple + set -- onnode takeover tool eventscripts cunit simple else set -- simple complex fi diff --git a/ctdb/tests/src/db_hash_test.c b/ctdb/tests/src/db_hash_test.c new file mode 100644 index 0000000..e05d116 --- /dev/null +++ b/ctdb/tests/src/db_hash_test.c @@ -0,0 +1,102 @@ +/* + db_hash tests + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include "replace.h" + +#include + +#include "common/db_hash.c" + +static void do_test(enum db_hash_type type) +{ + struct db_hash_context *dh; + TALLOC_CTX *mem_ctx = talloc_new(NULL); + TALLOC_CTX *tmp_ctx = talloc_new(NULL); + uint8_t *key = (uint8_t *)talloc_strdup(tmp_ctx, "This is a long key"); + uint8_t *value = (uint8_t *)talloc_strdup(tmp_ctx, "This is a long value"); + int ret; + + ret = db_hash_init(mem_ctx, "foobar", 1024, type, &dh); + assert(ret == 0); + + ret = db_hash_insert(dh, key, sizeof(key), value, sizeof(value)); + assert(ret == 0); + + ret = db_hash_exists(dh, key, sizeof(key)); + assert(ret == 0); + + ret = db_hash_insert(dh, key, sizeof(key), value, sizeof(value)); + assert(ret == EEXIST); + + ret = db_hash_delete(dh, key, sizeof(key)); + assert(ret == 0); + + ret = db_hash_exists(dh, key, sizeof(key)); + assert(ret == ENOENT); + + ret = db_hash_delete(dh, key, sizeof(key)); + assert(ret == ENOENT); + + ret = db_hash_add(dh, key, sizeof(key), key, sizeof(key)); + assert(ret == 0); + + ret = db_hash_add(dh, key, sizeof(key), value, sizeof(value)); + assert(ret == 0); + + talloc_free(dh); + ret = talloc_get_size(mem_ctx); + assert(ret == 0); + + talloc_free(mem_ctx); +} + +static void do_traverse_test(enum db_hash_type type) +{ + struct db_hash_context *dh; + TALLOC_CTX *mem_ctx = talloc_new(NULL); + char key[] = "keyXXXX"; + char value[] = "This is some test value"; + int count, ret, i; + + ret = db_hash_init(mem_ctx, "foobar", 1024, type, &dh); + assert(ret == 0); + + for (i=0; i<2000; i++) { + sprintf(key, "key%04d", i); + ret = db_hash_insert(dh, (uint8_t *)key, sizeof(key), + (uint8_t *)value, sizeof(value)); + assert(ret == 0); + } + + ret = db_hash_traverse(dh, NULL, NULL, &count); + assert(ret == 0); + assert(count == 2000); + + talloc_free(dh); + talloc_free(mem_ctx); +} + +int main(void) +{ + do_test(DB_HASH_SIMPLE); + do_test(DB_HASH_COMPLEX); + do_traverse_test(DB_HASH_SIMPLE); + do_traverse_test(DB_HASH_COMPLEX); + return 0; +} diff --git a/ctdb/wscript b/ctdb/wscript index 8b357fc..afd4d0e 100755 --- a/ctdb/wscript +++ b/ctdb/wscript @@ -331,6 +331,11 @@ def build(bld): includes='include include/internal', deps='replace tevent tdb') + bld.SAMBA_SUBSYSTEM('ctdb-util', + source=bld.SUBDIR('common', + '''db_hash.c'''), + deps='replace talloc tevent tdb') + bld.SAMBA_SUBSYSTEM('ctdb-client', source=bld.SUBDIR('client', 'ctdb_client.c'), includes='include include/internal', @@ -565,6 +570,19 @@ def build(bld): t.env.VERSION = VERSION bld.INSTALL_FILES('${LIBDIR}/pkgconfig', 'ctdb.pc') + # Unit tests + ctdb_unit_tests = [ + 'db_hash_test', + ] + + for target in ctdb_unit_tests: + src = 'tests/src/' + target + '.c' + + bld.SAMBA_BINARY(target, + source=src, + deps='talloc tevent tdb', + install_path='${CTDB_TEST_LIBDIR}') + # Test binaries ctdb_tests = [ 'rb_test', @@ -626,6 +644,7 @@ def build(bld): test_subdirs = [ 'complex', + 'cunit', 'events.d', 'eventscripts', 'onnode', From 6272ef0d09930ffbff43c6223ea35858d13efffa Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Mon, 16 Mar 2015 23:25:27 +1100 Subject: [PATCH 045/136] ctdb-common: Add srvid abstraction Attempt to make common code independent and free from ctdb_context. Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/common/srvid.c | 269 +++++++++++++++++++++++++++++++++++++ ctdb/common/srvid.h | 115 ++++++++++++++++ ctdb/tests/cunit/srvid_test_001.sh | 7 + ctdb/tests/src/srvid_test.c | 78 +++++++++++ ctdb/wscript | 3 +- 5 files changed, 471 insertions(+), 1 deletion(-) create mode 100644 ctdb/common/srvid.c create mode 100644 ctdb/common/srvid.h create mode 100755 ctdb/tests/cunit/srvid_test_001.sh create mode 100644 ctdb/tests/src/srvid_test.c diff --git a/ctdb/common/srvid.c b/ctdb/common/srvid.c new file mode 100644 index 0000000..f9cd49b --- /dev/null +++ b/ctdb/common/srvid.c @@ -0,0 +1,269 @@ +/* + Message handler database based on srvid + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include "replace.h" +#include "system/filesys.h" + +#include + +#include "lib/util/dlinklist.h" +#include "common/db_hash.h" +#include "common/srvid.h" + +struct srvid_handler_list; + +struct srvid_context { + struct db_hash_context *dh; + struct srvid_handler_list *list; +}; + +struct srvid_handler { + struct srvid_handler *prev, *next; + struct srvid_handler_list *list; + srvid_handler_fn handler; + void *private_data; +}; + +struct srvid_handler_list { + struct srvid_handler_list *prev, *next; + struct srvid_context *srv; + uint64_t srvid; + struct srvid_handler *h; +}; + + +/* + * Initialise message srvid context and database + */ +int srvid_init(TALLOC_CTX *mem_ctx, struct srvid_context **result) +{ + struct srvid_context *srv; + int ret; + + srv = talloc_zero(mem_ctx, struct srvid_context); + if (srv == NULL) { + return ENOMEM; + } + + ret = db_hash_init(srv, "messagedb", 8192, DB_HASH_SIMPLE, &srv->dh); + if (ret != 0) { + talloc_free(srv); + return ret; + } + + *result = srv; + return 0; +} + +/* + * Wrapper functions to insert/delete/fetch srvid_hander_list + */ + +static int srvid_insert(struct srvid_context *srv, uint64_t srvid, + struct srvid_handler_list *list) +{ + return db_hash_insert(srv->dh, (uint8_t *)&srvid, sizeof(uint64_t), + (uint8_t *)&list, sizeof(list)); +} + +static int srvid_delete(struct srvid_context *srv, uint64_t srvid) +{ + return db_hash_delete(srv->dh, (uint8_t *)&srvid, sizeof(uint64_t)); +} + +static int srvid_fetch_parser(uint8_t *keybuf, size_t keylen, + uint8_t *databuf, size_t datalen, + void *private_data) +{ + struct srvid_handler_list **list = + (struct srvid_handler_list **)private_data; + + if (datalen != sizeof(*list)) { + return EIO; + } + + *list = *(struct srvid_handler_list **)databuf; + return 0; +} + +static int srvid_fetch(struct srvid_context *srv, uint64_t srvid, + struct srvid_handler_list **list) +{ + return db_hash_fetch(srv->dh, (uint8_t *)&srvid, sizeof(uint64_t), + srvid_fetch_parser, list); +} + +/* + * When a handler is freed, remove it from the list + */ +static int srvid_handler_destructor(struct srvid_handler *h) +{ + struct srvid_handler_list *list = h->list; + + DLIST_REMOVE(list->h, h); + if (list->h == NULL) { + talloc_free(list); + } + return 0; +} + +/* + * When a list is freed, remove all handlers and remove db entry + */ +static int srvid_handler_list_destructor(struct srvid_handler_list *list) +{ + struct srvid_handler *h; + + while (list->h != NULL) { + h = list->h; + DLIST_REMOVE(list->h, h); + TALLOC_FREE(h); + } + + srvid_delete(list->srv, list->srvid); + DLIST_REMOVE(list->srv->list, list); + return 0; +} + +/* + * Register a message handler + */ +int srvid_register(struct srvid_context *srv, TALLOC_CTX *mem_ctx, + uint64_t srvid, srvid_handler_fn handler, + void *private_data) +{ + struct srvid_handler_list *list; + struct srvid_handler *h; + int ret; + + if (srv == NULL) { + return EINVAL; + } + + h = talloc_zero(mem_ctx, struct srvid_handler); + if (h == NULL) { + return ENOMEM; + } + + h->handler = handler; + h->private_data = private_data; + + ret = srvid_fetch(srv, srvid, &list); + if (ret != 0) { + /* srvid not yet registered */ + list = talloc_zero(srv, struct srvid_handler_list); + if (list == NULL) { + talloc_free(h); + return ENOMEM; + } + + list->srv = srv; + list->srvid = srvid; + + ret = srvid_insert(srv, srvid, list); + if (ret != 0) { + talloc_free(h); + talloc_free(list); + return ret; + } + + DLIST_ADD(srv->list, list); + talloc_set_destructor(list, srvid_handler_list_destructor); + } + + h->list = list; + DLIST_ADD(list->h, h); + talloc_set_destructor(h, srvid_handler_destructor); + return 0; +} + +/* + * Deregister a message handler + */ +int srvid_deregister(struct srvid_context *srv, uint64_t srvid, + void *private_data) +{ + struct srvid_handler_list *list; + struct srvid_handler *h; + int ret; + + ret = srvid_fetch(srv, srvid, &list); + if (ret != 0) { + return ret; + } + + for (h = list->h; h != NULL; h = h->next) { + if (h->private_data == private_data) { + talloc_free(h); + return 0; + } + } + + return ENOENT; +} + +/* + * Check if a message handler exists + */ +int srvid_exists(struct srvid_context *srv, uint64_t srvid) +{ + struct srvid_handler_list *list; + int ret; + + ret = srvid_fetch(srv, srvid, &list); + if (ret != 0) { + return ret; + } + if (list->h == NULL) { + return ENOENT; + } + + return 0; +} + +/* + * Send a message to registered srvid and srvid_all + */ +int srvid_dispatch(struct srvid_context *srv, uint64_t srvid, + uint64_t srvid_all, TDB_DATA data) +{ + struct srvid_handler_list *list; + struct srvid_handler *h; + int ret; + + ret = srvid_fetch(srv, srvid, &list); + if (ret == 0) { + for (h = list->h; h != NULL; h = h->next) { + h->handler(srvid, data, h->private_data); + } + } + + if (srvid_all == 0) { + return ret; + } + + ret = srvid_fetch(srv, srvid_all, &list); + if (ret == 0) { + for (h = list->h; h != NULL; h = h->next) { + h->handler(srvid, data, h->private_data); + } + } + + return ret; +} diff --git a/ctdb/common/srvid.h b/ctdb/common/srvid.h new file mode 100644 index 0000000..f048b5c --- /dev/null +++ b/ctdb/common/srvid.h @@ -0,0 +1,115 @@ +/* + Message handler database based on srvid + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#ifndef __CTDB_SRVID_H__ +#define __CTDB_SRVID_H__ + +#include +#include + +/** + * @file srvid.h + * + * @brief Database of message handlers based on srvid + * + * CTDB can be used to send messages between clients across nodes using + * CTDB_REQ_MESSAGE. Clients register for mesages based on srvid. CTDB itself + * uses a small set of srvid messages. A large range (2^56) of srvid messages + * is reserved for Samba. + */ + +/** + * @brief Message handler function + * + * To receive messages for a specific srvid, register a message handler function + * for the srvid. + */ +typedef void (*srvid_handler_fn)(uint64_t srvid, TDB_DATA data, + void *private_data); + +/** + * @brief Abstract struct to store srvid message handler database + */ +struct srvid_context; + +/** + * @brief Initialize srvid message handler database + * + * This returns a new srvid message handler database context. Freeing + * this context will free all the memory associated with the hash table. + * + * @param[in] mem_ctx Talloc memory context + * @param[out] result The new db_hash_context structure + * @return 0 on success, errno on failure + */ +int srvid_init(TALLOC_CTX *mem_ctx, struct srvid_context **result); + +/** + * @brief Register a message handler for a srvid + * + * The message handler is allocated using the specified talloc context. Freeing + * this talloc context, removes the message handler. + * + * @param[in] srv The srvid message handler database context + * @param[in] mem_ctx Talloc memory context for message handler + * @param[in] srvid The srvid + * @param[in] handler The message handler function for srvid + * @param[in] private_data Private data for message handler function + * @return 0 on success, errno on failure + */ +int srvid_register(struct srvid_context *srv, TALLOC_CTX *mem_ctx, + uint64_t srvid, srvid_handler_fn handler, + void *private_data); + +/** + * @brief Unregister a message handler for a srvid + * + * @param[in] srv The srvid message handler database context + * @param[in] srvid The srvid + * @param[in] private_data Private data of message handler function + * @return 0 on success, errno on failure + */ +int srvid_deregister(struct srvid_context *srv, uint64_t srvid, + void *private_data); + +/** + * @brief Check if any message handler is registered for srvid + * + * @param[in] srv The srvid message handler database context + * @param[in] srvid The srvid + * @return 0 on success, errno on failure + */ +int srvid_exists(struct srvid_context *srv, uint64_t srvid); + +/** + * @brief Call message handlers for given srvid + * + * @param[in] srv The srvid message handler database context + * @param[in] srvid The srvid + * @param[in] srvid_all The srvid that gets all messages + * @param[in] data The data passed to each message handler + * @return 0 on success, errno on failure + * + * If srvid_all passed is 0, the message is not sent to message handlers + * registered with special srvid to receive all messages. + */ +int srvid_dispatch(struct srvid_context *srv, uint64_t srvid, + uint64_t srvid_all, TDB_DATA data); + +#endif /* __CTDB_SRVID_H__ */ diff --git a/ctdb/tests/cunit/srvid_test_001.sh b/ctdb/tests/cunit/srvid_test_001.sh new file mode 100755 index 0000000..ed09535 --- /dev/null +++ b/ctdb/tests/cunit/srvid_test_001.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +. "${TEST_SCRIPTS_DIR}/unit.sh" + +ok_null + +unit_test srvid_test diff --git a/ctdb/tests/src/srvid_test.c b/ctdb/tests/src/srvid_test.c new file mode 100644 index 0000000..f5e94ac --- /dev/null +++ b/ctdb/tests/src/srvid_test.c @@ -0,0 +1,78 @@ +/* + srvid tests + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include "replace.h" + +#include + +#include "common/db_hash.c" +#include "common/srvid.c" + +#define TEST_SRVID 0xFE11223344556677 + +static void test_handler(uint64_t srvid, TDB_DATA data, void *private_data) +{ + int *count = (int *)private_data; + (*count)++; +} + +int main(void) +{ + struct srvid_context *srv; + TALLOC_CTX *mem_ctx = talloc_new(NULL); + TALLOC_CTX *tmp_ctx = talloc_new(NULL); + int ret; + int count = 0; + + ret = srvid_init(mem_ctx, &srv); + assert(ret == 0); + + ret = srvid_register(srv, tmp_ctx, TEST_SRVID, test_handler, &count); + assert(ret == 0); + + ret = srvid_exists(srv, TEST_SRVID); + assert(ret == 0); + + ret = srvid_dispatch(srv, TEST_SRVID, 0, tdb_null); + assert(ret == 0); + assert(count == 1); + + ret = srvid_deregister(srv, TEST_SRVID, NULL); + assert(ret == ENOENT); + + ret = srvid_deregister(srv, TEST_SRVID, &count); + assert(ret == 0); + + ret = srvid_register(srv, tmp_ctx, TEST_SRVID, test_handler, &count); + assert(ret == 0); + + talloc_free(tmp_ctx); + ret = srvid_exists(srv, TEST_SRVID); + assert(ret == ENOENT); + + ret = srvid_dispatch(srv, TEST_SRVID, 0, tdb_null); + assert(ret == ENOENT); + + talloc_free(srv); + assert(talloc_get_size(mem_ctx) == 0); + + talloc_free(mem_ctx); + + return 0; +} diff --git a/ctdb/wscript b/ctdb/wscript index afd4d0e..aaefad3 100755 --- a/ctdb/wscript +++ b/ctdb/wscript @@ -333,7 +333,7 @@ def build(bld): bld.SAMBA_SUBSYSTEM('ctdb-util', source=bld.SUBDIR('common', - '''db_hash.c'''), + '''db_hash.c srvid.c'''), deps='replace talloc tevent tdb') bld.SAMBA_SUBSYSTEM('ctdb-client', @@ -573,6 +573,7 @@ def build(bld): # Unit tests ctdb_unit_tests = [ 'db_hash_test', + 'srvid_test', ] for target in ctdb_unit_tests: From 62f1e2579a6e97e7e33f68be779694d5eceb36c0 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Wed, 8 Apr 2015 14:38:26 +1000 Subject: [PATCH 046/136] ctdb-daemon: Replace ctdb_message with srvid abstraction Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/client/ctdb_client.c | 31 ++++- ctdb/common/ctdb_message.c | 286 --------------------------------------- ctdb/include/common/srvid.h | 1 + ctdb/include/ctdb_client.h | 12 +- ctdb/include/ctdb_private.h | 22 +-- ctdb/include/internal/includes.h | 1 + ctdb/server/ctdb_daemon.c | 31 +++-- ctdb/server/ctdb_recoverd.c | 105 +++++++------- ctdb/server/ctdb_traverse.c | 2 +- ctdb/tests/src/ctdb_bench.c | 88 +++++++----- ctdb/tests/src/ctdb_fetch.c | 59 +++++--- ctdb/tests/src/ctdb_test.c | 5 +- ctdb/tests/src/ctdb_test_stubs.c | 5 +- ctdb/tests/src/ctdbd_test.c | 3 +- ctdb/tools/ctdb.c | 11 +- ctdb/wscript | 12 +- 16 files changed, 223 insertions(+), 451 deletions(-) delete mode 100644 ctdb/common/ctdb_message.c create mode 120000 ctdb/include/common/srvid.h diff --git a/ctdb/client/ctdb_client.c b/ctdb/client/ctdb_client.c index 1d832fa..d4ef327 100644 --- a/ctdb/client/ctdb_client.c +++ b/ctdb/client/ctdb_client.c @@ -178,6 +178,22 @@ static void ctdb_client_reply_call(struct ctdb_context *ctdb, struct ctdb_req_he } } +void ctdb_request_message(struct ctdb_context *ctdb, + struct ctdb_req_header *hdr) +{ + struct ctdb_req_message *c = (struct ctdb_req_message *)hdr; + TDB_DATA data; + + data.dsize = c->datalen; + data.dptr = talloc_memdup(c, &c->data[0], c->datalen); + if (data.dptr == NULL) { + DEBUG(DEBUG_ERR, (__location__ " Memory allocation failure\n")); + return; + } + + srvid_dispatch(ctdb->srv, c->srvid, CTDB_SRVID_ALL, data); +} + static void ctdb_client_reply_control(struct ctdb_context *ctdb, struct ctdb_req_header *hdr); /* @@ -472,7 +488,7 @@ int ctdb_call(struct ctdb_db_context *ctdb_db, struct ctdb_call *call) handler function in the client */ int ctdb_client_set_message_handler(struct ctdb_context *ctdb, uint64_t srvid, - ctdb_msg_fn_t handler, + srvid_handler_fn handler, void *private_data) { int res; @@ -486,7 +502,7 @@ int ctdb_client_set_message_handler(struct ctdb_context *ctdb, uint64_t srvid, } /* also need to register the handler with our own ctdb structure */ - return ctdb_register_message_handler(ctdb, ctdb, srvid, handler, private_data); + return srvid_register(ctdb->srv, ctdb, srvid, handler, private_data); } /* @@ -505,7 +521,7 @@ int ctdb_client_remove_message_handler(struct ctdb_context *ctdb, uint64_t srvid } /* also need to register the handler with our own ctdb structure */ - ctdb_deregister_message_handler(ctdb, srvid, private_data); + srvid_deregister(ctdb->srv, srvid, private_data); return 0; } @@ -2182,7 +2198,7 @@ struct traverse_state { /* called on each key during a ctdb_traverse */ -static void traverse_handler(struct ctdb_context *ctdb, uint64_t srvid, TDB_DATA data, void *p) +static void traverse_handler(uint64_t srvid, TDB_DATA data, void *p) { struct traverse_state *state = (struct traverse_state *)p; struct ctdb_rec_data *d = (struct ctdb_rec_data *)data.dptr; @@ -3295,6 +3311,13 @@ struct ctdb_context *ctdb_init(struct event_context *ev) ctdb->lastid = INT_MAX-200; CTDB_NO_MEMORY_NULL(ctdb, ctdb->idr); + ret = srvid_init(ctdb, &ctdb->srv); + if (ret != 0) { + DEBUG(DEBUG_ERR, ("srvid_init failed (%s)\n", strerror(ret))); + talloc_free(ctdb); + return NULL; + } + ret = ctdb_set_socketname(ctdb, CTDB_SOCKET); if (ret != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_set_socketname failed.\n")); diff --git a/ctdb/common/ctdb_message.c b/ctdb/common/ctdb_message.c deleted file mode 100644 index 0e19761..0000000 --- a/ctdb/common/ctdb_message.c +++ /dev/null @@ -1,286 +0,0 @@ -/* - ctdb_message protocol code - - Copyright (C) Andrew Tridgell 2007 - Copyright (C) Amitay Isaacs 2013 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, see . -*/ -/* - see http://wiki.samba.org/index.php/Samba_%26_Clustering for - protocol design and packet details -*/ -#include "includes.h" -#include "tdb.h" -#include "system/network.h" -#include "system/filesys.h" -#include "../include/ctdb_private.h" -#include "lib/util/dlinklist.h" - -static int message_list_db_init(struct ctdb_context *ctdb) -{ - ctdb->message_list_indexdb = tdb_open("messagedb", 8192, - TDB_INTERNAL| - TDB_INCOMPATIBLE_HASH| - TDB_DISALLOW_NESTING, - O_RDWR|O_CREAT, 0); - if (ctdb->message_list_indexdb == NULL) { - DEBUG(DEBUG_ERR, ("Failed to create message list indexdb\n")); - return -1; - } - - return 0; -} - -static int message_list_db_add(struct ctdb_context *ctdb, uint64_t srvid, - struct ctdb_message_list_header *h) -{ - int ret; - TDB_DATA key, data; - - if (ctdb->message_list_indexdb == NULL) { - ret = message_list_db_init(ctdb); - if (ret < 0) { - return -1; - } - } - - key.dptr = (uint8_t *)&srvid; - key.dsize = sizeof(uint64_t); - - data.dptr = (uint8_t *)&h; - data.dsize = sizeof(struct ctdb_message_list_header *); - - ret = tdb_store(ctdb->message_list_indexdb, key, data, TDB_INSERT); - if (ret < 0) { - DEBUG(DEBUG_ERR, ("Failed to add message list handler (%s)\n", - tdb_errorstr(ctdb->message_list_indexdb))); - return -1; - } - - return 0; -} - -static int message_list_db_delete(struct ctdb_context *ctdb, uint64_t srvid) -{ - int ret; - TDB_DATA key; - - if (ctdb->message_list_indexdb == NULL) { - return -1; - } - - key.dptr = (uint8_t *)&srvid; - key.dsize = sizeof(uint64_t); - - ret = tdb_delete(ctdb->message_list_indexdb, key); - if (ret < 0) { - DEBUG(DEBUG_ERR, ("Failed to delete message list handler (%s)\n", - tdb_errorstr(ctdb->message_list_indexdb))); - return -1; - } - - return 0; -} - -static int message_list_db_fetch_parser(TDB_DATA key, TDB_DATA data, - void *private_data) -{ - struct ctdb_message_list_header **h = - (struct ctdb_message_list_header **)private_data; - - if (data.dsize != sizeof(struct ctdb_message_list_header *)) { - return -1; - } - - *h = *(struct ctdb_message_list_header **)data.dptr; - return 0; -} - -static int message_list_db_fetch(struct ctdb_context *ctdb, uint64_t srvid, - struct ctdb_message_list_header **h) -{ - TDB_DATA key; - - if (ctdb->message_list_indexdb == NULL) { - return -1; - } - - key.dptr = (uint8_t *)&srvid; - key.dsize = sizeof(uint64_t); - - return tdb_parse_record(ctdb->message_list_indexdb, key, - message_list_db_fetch_parser, h); -} - -/* - this dispatches the messages to the registered ctdb message handler -*/ -int ctdb_dispatch_message(struct ctdb_context *ctdb, uint64_t srvid, TDB_DATA data) -{ - struct ctdb_message_list_header *h; - struct ctdb_message_list *m; - uint64_t srvid_all = CTDB_SRVID_ALL; - int ret; - - ret = message_list_db_fetch(ctdb, srvid, &h); - if (ret == 0) { - for (m=h->m; m; m=m->next) { - m->message_handler(ctdb, srvid, data, m->message_private); - } - } - - ret = message_list_db_fetch(ctdb, srvid_all, &h); - if (ret == 0) { - for(m=h->m; m; m=m->next) { - m->message_handler(ctdb, srvid, data, m->message_private); - } - } - - return 0; -} - -/* - called when a CTDB_REQ_MESSAGE packet comes in -*/ -void ctdb_request_message(struct ctdb_context *ctdb, struct ctdb_req_header *hdr) -{ - struct ctdb_req_message *c = (struct ctdb_req_message *)hdr; - TDB_DATA data; - - data.dsize = c->datalen; - data.dptr = talloc_memdup(c, &c->data[0], c->datalen); - - ctdb_dispatch_message(ctdb, c->srvid, data); -} - -/* - * When header is freed, remove all the srvid handlers - */ -static int message_header_destructor(struct ctdb_message_list_header *h) -{ - struct ctdb_message_list *m; - - while (h->m != NULL) { - m = h->m; - DLIST_REMOVE(h->m, m); - TALLOC_FREE(m); - } - - message_list_db_delete(h->ctdb, h->srvid); - DLIST_REMOVE(h->ctdb->message_list_header, h); - - return 0; -} - -/* - when a client goes away, we need to remove its srvid handler from the list - */ -static int message_handler_destructor(struct ctdb_message_list *m) -{ - struct ctdb_message_list_header *h = m->h; - - DLIST_REMOVE(h->m, m); - if (h->m == NULL) { - talloc_free(h); - } - return 0; -} - -/* - setup handler for receipt of ctdb messages from ctdb_send_message() -*/ -int ctdb_register_message_handler(struct ctdb_context *ctdb, - TALLOC_CTX *mem_ctx, - uint64_t srvid, - ctdb_msg_fn_t handler, - void *private_data) -{ - struct ctdb_message_list_header *h; - struct ctdb_message_list *m; - int ret; - - m = talloc_zero(mem_ctx, struct ctdb_message_list); - CTDB_NO_MEMORY(ctdb, m); - - m->message_handler = handler; - m->message_private = private_data; - - ret = message_list_db_fetch(ctdb, srvid, &h); - if (ret != 0) { - /* srvid not registered yet */ - h = talloc_zero(ctdb, struct ctdb_message_list_header); - CTDB_NO_MEMORY(ctdb, h); - - h->ctdb = ctdb; - h->srvid = srvid; - - ret = message_list_db_add(ctdb, srvid, h); - if (ret < 0) { - talloc_free(m); - talloc_free(h); - return -1; - } - - DLIST_ADD(ctdb->message_list_header, h); - talloc_set_destructor(h, message_header_destructor); - } - - m->h = h; - DLIST_ADD(h->m, m); - talloc_set_destructor(m, message_handler_destructor); - return 0; -} - - -/* - setup handler for receipt of ctdb messages from ctdb_send_message() -*/ -int ctdb_deregister_message_handler(struct ctdb_context *ctdb, uint64_t srvid, void *private_data) -{ - struct ctdb_message_list_header *h; - struct ctdb_message_list *m; - int ret; - - ret = message_list_db_fetch(ctdb, srvid, &h); - if (ret != 0) { - return -1; - } - - for (m=h->m; m; m=m->next) { - if (m->message_private == private_data) { - talloc_free(m); - return 0; - } - } - - return -1; -} - - -/* - * check if the given srvid exists - */ -bool ctdb_check_message_handler(struct ctdb_context *ctdb, uint64_t srvid) -{ - struct ctdb_message_list_header *h; - int ret; - - ret = message_list_db_fetch(ctdb, srvid, &h); - if (ret != 0 || h->m == NULL) { - return false; - } - - return true; -} diff --git a/ctdb/include/common/srvid.h b/ctdb/include/common/srvid.h new file mode 120000 index 0000000..5a36c27 --- /dev/null +++ b/ctdb/include/common/srvid.h @@ -0,0 +1 @@ +../../common/srvid.h \ No newline at end of file diff --git a/ctdb/include/ctdb_client.h b/ctdb/include/ctdb_client.h index 528ea46..2f03b14 100644 --- a/ctdb/include/ctdb_client.h +++ b/ctdb/include/ctdb_client.h @@ -19,6 +19,8 @@ #ifndef _CTDB_CLIENT_H #define _CTDB_CLIENT_H + +#include "common/srvid.h" #include "ctdb_protocol.h" enum control_state {CTDB_CONTROL_WAIT, CTDB_CONTROL_DONE, CTDB_CONTROL_ERROR, CTDB_CONTROL_TIMEOUT}; @@ -127,8 +129,8 @@ uint32_t ctdb_get_pnn(struct ctdb_context *ctdb); typedef void (*ctdb_msg_fn_t)(struct ctdb_context *, uint64_t srvid, TDB_DATA data, void *); int ctdb_client_set_message_handler(struct ctdb_context *ctdb, uint64_t srvid, - ctdb_msg_fn_t handler, - void *private_data); + srvid_handler_fn handler, + void *private_data); int ctdb_client_remove_message_handler(struct ctdb_context *ctdb, uint64_t srvid, void *private_data); int ctdb_client_check_message_handlers(struct ctdb_context *ctdb, @@ -159,12 +161,6 @@ int ctdb_record_store(struct ctdb_record_handle *h, TDB_DATA data); int ctdb_fetch(struct ctdb_db_context *ctdb_db, TALLOC_CTX *mem_ctx, TDB_DATA key, TDB_DATA *data); -int ctdb_register_message_handler(struct ctdb_context *ctdb, - TALLOC_CTX *mem_ctx, - uint64_t srvid, - ctdb_msg_fn_t handler, - void *private_data); - struct ctdb_db_context *find_ctdb_db(struct ctdb_context *ctdb, uint32_t id); diff --git a/ctdb/include/ctdb_private.h b/ctdb/include/ctdb_private.h index 975a7aa..b9965df 100644 --- a/ctdb/include/ctdb_private.h +++ b/ctdb/include/ctdb_private.h @@ -264,21 +264,6 @@ struct ctdb_upcalls { void (*node_connected)(struct ctdb_node *); }; -/* list of message handlers - needs to be changed to a more efficient data - structure so we can find a message handler given a srvid quickly */ -struct ctdb_message_list_header { - struct ctdb_message_list_header *next, *prev; - struct ctdb_context *ctdb; - uint64_t srvid; - struct ctdb_message_list *m; -}; -struct ctdb_message_list { - struct ctdb_message_list *next, *prev; - struct ctdb_message_list_header *h; - ctdb_msg_fn_t message_handler; - void *message_private; -}; - /* additional data required for the daemon mode */ struct ctdb_daemon_data { int sd; @@ -479,8 +464,7 @@ struct ctdb_context { const struct ctdb_upcalls *upcalls; /* transport upcalls */ void *private_data; /* private to transport */ struct ctdb_db_context *db_list; - struct ctdb_message_list_header *message_list_header; - struct tdb_context *message_list_indexdb; + struct srvid_context *srv; struct ctdb_daemon_data daemon; struct ctdb_statistics statistics; struct ctdb_statistics statistics_current; @@ -970,11 +954,7 @@ int32_t ctdb_control_traverse_data(struct ctdb_context *ctdb, TDB_DATA data, TDB int32_t ctdb_control_traverse_kill(struct ctdb_context *ctdb, TDB_DATA indata, TDB_DATA *outdata, uint32_t srcnode); -int ctdb_dispatch_message(struct ctdb_context *ctdb, uint64_t srvid, TDB_DATA data); -bool ctdb_check_message_handler(struct ctdb_context *ctdb, uint64_t srvid); - int daemon_register_message_handler(struct ctdb_context *ctdb, uint32_t client_id, uint64_t srvid); -int ctdb_deregister_message_handler(struct ctdb_context *ctdb, uint64_t srvid, void *private_data); int daemon_deregister_message_handler(struct ctdb_context *ctdb, uint32_t client_id, uint64_t srvid); int daemon_check_srvids(struct ctdb_context *ctdb, TDB_DATA indata, TDB_DATA *outdata); diff --git a/ctdb/include/internal/includes.h b/ctdb/include/internal/includes.h index 6c00c03..74c11ba 100644 --- a/ctdb/include/internal/includes.h +++ b/ctdb/include/internal/includes.h @@ -18,6 +18,7 @@ #include "lib/util/debug.h" #include "lib/util/samba_util.h" +#include "common/srvid.h" #include "ctdb_client.h" #include "ctdb_logging.h" diff --git a/ctdb/server/ctdb_daemon.c b/ctdb/server/ctdb_daemon.c index 563370a..4e68606 100644 --- a/ctdb/server/ctdb_daemon.c +++ b/ctdb/server/ctdb_daemon.c @@ -127,8 +127,8 @@ static int daemon_queue_send(struct ctdb_client *client, struct ctdb_req_header message handler for when we are in daemon mode. This redirects the message to the right client */ -static void daemon_message_handler(struct ctdb_context *ctdb, uint64_t srvid, - TDB_DATA data, void *private_data) +static void daemon_message_handler(uint64_t srvid, TDB_DATA data, + void *private_data) { struct ctdb_client *client = talloc_get_type(private_data, struct ctdb_client); struct ctdb_req_message *r; @@ -136,9 +136,9 @@ static void daemon_message_handler(struct ctdb_context *ctdb, uint64_t srvid, /* construct a message to send to the client containing the data */ len = offsetof(struct ctdb_req_message, data) + data.dsize; - r = ctdbd_allocate_pkt(ctdb, ctdb, CTDB_REQ_MESSAGE, + r = ctdbd_allocate_pkt(client->ctdb, client->ctdb, CTDB_REQ_MESSAGE, len, struct ctdb_req_message); - CTDB_NO_MEMORY_VOID(ctdb, r); + CTDB_NO_MEMORY_VOID(client->ctdb, r); talloc_set_name_const(r, "req_message packet"); @@ -163,7 +163,8 @@ int daemon_register_message_handler(struct ctdb_context *ctdb, uint32_t client_i DEBUG(DEBUG_ERR,("Bad client_id in daemon_request_register_message_handler\n")); return -1; } - res = ctdb_register_message_handler(ctdb, client, srvid, daemon_message_handler, client); + res = srvid_register(ctdb->srv, client, srvid, daemon_message_handler, + client); if (res != 0) { DEBUG(DEBUG_ERR,(__location__ " Failed to register handler %llu in daemon\n", (unsigned long long)srvid)); @@ -186,7 +187,7 @@ int daemon_deregister_message_handler(struct ctdb_context *ctdb, uint32_t client DEBUG(DEBUG_ERR,("Bad client_id in daemon_request_deregister_message_handler\n")); return -1; } - return ctdb_deregister_message_handler(ctdb, srvid, client); + return srvid_deregister(ctdb->srv, srvid, client); } int daemon_check_srvids(struct ctdb_context *ctdb, TDB_DATA indata, @@ -211,7 +212,7 @@ int daemon_check_srvids(struct ctdb_context *ctdb, TDB_DATA indata, return -1; } for (i=0; isrv, ids[i]) == 0) { results[i/8] |= (1 << (i%8)); } } @@ -1257,6 +1258,11 @@ int ctdb_start_daemon(struct ctdb_context *ctdb, bool do_fork) ctdb_set_child_logging(ctdb); + if (srvid_init(ctdb, &ctdb->srv) != 0) { + DEBUG(DEBUG_CRIT,("Failed to setup message srvid context\n")); + exit(1); + } + /* initialize statistics collection */ ctdb_statistics_init(ctdb); @@ -1558,15 +1564,10 @@ struct ctdb_local_message { static void ctdb_local_message_trigger(struct event_context *ev, struct timed_event *te, struct timeval t, void *private_data) { - struct ctdb_local_message *m = talloc_get_type(private_data, - struct ctdb_local_message); - int res; + struct ctdb_local_message *m = talloc_get_type( + private_data, struct ctdb_local_message); - res = ctdb_dispatch_message(m->ctdb, m->srvid, m->data); - if (res != 0) { - DEBUG(DEBUG_ERR, (__location__ " Failed to dispatch message for srvid=%llu\n", - (unsigned long long)m->srvid)); - } + srvid_dispatch(m->ctdb->srv, m->srvid, CTDB_SRVID_ALL, m->data); talloc_free(m); } diff --git a/ctdb/server/ctdb_recoverd.c b/ctdb/server/ctdb_recoverd.c index 8fe955d..ac920d5 100644 --- a/ctdb/server/ctdb_recoverd.c +++ b/ctdb/server/ctdb_recoverd.c @@ -1063,10 +1063,12 @@ static bool vacuum_fetch_process_one(struct ctdb_db_context *ctdb_db, /* handler for vacuum fetch */ -static void vacuum_fetch_handler(struct ctdb_context *ctdb, uint64_t srvid, - TDB_DATA data, void *private_data) +static void vacuum_fetch_handler(uint64_t srvid, TDB_DATA data, + void *private_data) { - struct ctdb_recoverd *rec = talloc_get_type(private_data, struct ctdb_recoverd); + struct ctdb_recoverd *rec = talloc_get_type( + private_data, struct ctdb_recoverd); + struct ctdb_context *ctdb = rec->ctdb; struct ctdb_marshall_buffer *recs; int ret, i; TALLOC_CTX *tmp_ctx = talloc_new(ctdb); @@ -1134,9 +1136,12 @@ static void vacuum_fetch_handler(struct ctdb_context *ctdb, uint64_t srvid, /* * handler for database detach */ -static void detach_database_handler(struct ctdb_context *ctdb, uint64_t srvid, - TDB_DATA data, void *private_data) +static void detach_database_handler(uint64_t srvid, TDB_DATA data, + void *private_data) { + struct ctdb_recoverd *rec = talloc_get_type( + private_data, struct ctdb_recoverd); + struct ctdb_context *ctdb = rec->ctdb; uint32_t db_id; struct ctdb_db_context *ctdb_db; @@ -2339,9 +2344,11 @@ static void election_send_request(struct event_context *ev, struct timed_event * /* handler for memory dumps */ -static void mem_dump_handler(struct ctdb_context *ctdb, uint64_t srvid, - TDB_DATA data, void *private_data) +static void mem_dump_handler(uint64_t srvid, TDB_DATA data, void *private_data) { + struct ctdb_recoverd *rec = talloc_get_type( + private_data, struct ctdb_recoverd); + struct ctdb_context *ctdb = rec->ctdb; TALLOC_CTX *tmp_ctx = talloc_new(ctdb); TDB_DATA *dump; int ret; @@ -2382,10 +2389,11 @@ DEBUG(DEBUG_ERR, ("recovery master memory dump\n")); /* handler for reload_nodes */ -static void reload_nodes_handler(struct ctdb_context *ctdb, uint64_t srvid, - TDB_DATA data, void *private_data) +static void reload_nodes_handler(uint64_t srvid, TDB_DATA data, + void *private_data) { - struct ctdb_recoverd *rec = talloc_get_type(private_data, struct ctdb_recoverd); + struct ctdb_recoverd *rec = talloc_get_type( + private_data, struct ctdb_recoverd); DEBUG(DEBUG_ERR, (__location__ " Reload nodes file from recovery daemon\n")); @@ -2410,16 +2418,17 @@ static void ctdb_rebalance_timeout(struct event_context *ev, do_takeover_run(rec, rec->nodemap, false); } - -static void recd_node_rebalance_handler(struct ctdb_context *ctdb, - uint64_t srvid, - TDB_DATA data, void *private_data) + +static void recd_node_rebalance_handler(uint64_t srvid, TDB_DATA data, + void *private_data) { + struct ctdb_recoverd *rec = talloc_get_type( + private_data, struct ctdb_recoverd); + struct ctdb_context *ctdb = rec->ctdb; uint32_t pnn; uint32_t *t; int len; uint32_t deferred_rebalance; - struct ctdb_recoverd *rec = talloc_get_type(private_data, struct ctdb_recoverd); if (rec->recmaster != ctdb_get_pnn(ctdb)) { return; @@ -2475,10 +2484,11 @@ static void recd_node_rebalance_handler(struct ctdb_context *ctdb, -static void recd_update_ip_handler(struct ctdb_context *ctdb, uint64_t srvid, - TDB_DATA data, void *private_data) +static void recd_update_ip_handler(uint64_t srvid, TDB_DATA data, + void *private_data) { - struct ctdb_recoverd *rec = talloc_get_type(private_data, struct ctdb_recoverd); + struct ctdb_recoverd *rec = talloc_get_type( + private_data, struct ctdb_recoverd); struct ctdb_public_ip *ip; if (rec->recmaster != rec->ctdb->pnn) { @@ -2533,22 +2543,21 @@ static void srvid_disable_and_reply(struct ctdb_context *ctdb, srvid_request_reply(ctdb, (struct srvid_request *)r, result); } -static void disable_takeover_runs_handler(struct ctdb_context *ctdb, - uint64_t srvid, TDB_DATA data, +static void disable_takeover_runs_handler(uint64_t srvid, TDB_DATA data, void *private_data) { - struct ctdb_recoverd *rec = talloc_get_type(private_data, - struct ctdb_recoverd); + struct ctdb_recoverd *rec = talloc_get_type( + private_data, struct ctdb_recoverd); - srvid_disable_and_reply(ctdb, data, rec->takeover_run); + srvid_disable_and_reply(rec->ctdb, data, rec->takeover_run); } /* Backward compatibility for this SRVID */ -static void disable_ip_check_handler(struct ctdb_context *ctdb, uint64_t srvid, - TDB_DATA data, void *private_data) +static void disable_ip_check_handler(uint64_t srvid, TDB_DATA data, + void *private_data) { - struct ctdb_recoverd *rec = talloc_get_type(private_data, - struct ctdb_recoverd); + struct ctdb_recoverd *rec = talloc_get_type( + private_data, struct ctdb_recoverd); uint32_t timeout; if (data.dsize != sizeof(uint32_t)) { @@ -2564,17 +2573,16 @@ static void disable_ip_check_handler(struct ctdb_context *ctdb, uint64_t srvid, timeout = *((uint32_t *)data.dptr); - ctdb_op_disable(rec->takeover_run, ctdb->ev, timeout); + ctdb_op_disable(rec->takeover_run, rec->ctdb->ev, timeout); } -static void disable_recoveries_handler(struct ctdb_context *ctdb, - uint64_t srvid, TDB_DATA data, +static void disable_recoveries_handler(uint64_t srvid, TDB_DATA data, void *private_data) { - struct ctdb_recoverd *rec = talloc_get_type(private_data, - struct ctdb_recoverd); + struct ctdb_recoverd *rec = talloc_get_type( + private_data, struct ctdb_recoverd); - srvid_disable_and_reply(ctdb, data, rec->recovery); + srvid_disable_and_reply(rec->ctdb, data, rec->recovery); } /* @@ -2582,12 +2590,12 @@ static void disable_recoveries_handler(struct ctdb_context *ctdb, handle this later in the monitor_cluster loop so we do not recurse with other requests to takeover_run() */ -static void ip_reallocate_handler(struct ctdb_context *ctdb, uint64_t srvid, - TDB_DATA data, void *private_data) +static void ip_reallocate_handler(uint64_t srvid, TDB_DATA data, + void *private_data) { struct srvid_request *request; - struct ctdb_recoverd *rec = talloc_get_type(private_data, - struct ctdb_recoverd); + struct ctdb_recoverd *rec = talloc_get_type( + private_data, struct ctdb_recoverd); if (data.dsize != sizeof(struct srvid_request)) { DEBUG(DEBUG_ERR, (__location__ " Wrong size of return address.\n")); @@ -2596,7 +2604,7 @@ static void ip_reallocate_handler(struct ctdb_context *ctdb, uint64_t srvid, request = (struct srvid_request *)data.dptr; - srvid_request_add(ctdb, &rec->reallocate_requests, request); + srvid_request_add(rec->ctdb, &rec->reallocate_requests, request); } static void process_ipreallocate_requests(struct ctdb_context *ctdb, @@ -2644,10 +2652,11 @@ static void process_ipreallocate_requests(struct ctdb_context *ctdb, /* handler for recovery master elections */ -static void election_handler(struct ctdb_context *ctdb, uint64_t srvid, - TDB_DATA data, void *private_data) +static void election_handler(uint64_t srvid, TDB_DATA data, void *private_data) { - struct ctdb_recoverd *rec = talloc_get_type(private_data, struct ctdb_recoverd); + struct ctdb_recoverd *rec = talloc_get_type( + private_data, struct ctdb_recoverd); + struct ctdb_context *ctdb = rec->ctdb; int ret; struct election_message *em = (struct election_message *)data.dptr; @@ -2740,15 +2749,16 @@ static void force_election(struct ctdb_recoverd *rec, uint32_t pnn, /* handler for when a node changes its flags */ -static void monitor_handler(struct ctdb_context *ctdb, uint64_t srvid, - TDB_DATA data, void *private_data) +static void monitor_handler(uint64_t srvid, TDB_DATA data, void *private_data) { + struct ctdb_recoverd *rec = talloc_get_type( + private_data, struct ctdb_recoverd); + struct ctdb_context *ctdb = rec->ctdb; int ret; struct ctdb_node_flag_change *c = (struct ctdb_node_flag_change *)data.dptr; struct ctdb_node_map *nodemap=NULL; TALLOC_CTX *tmp_ctx; int i; - struct ctdb_recoverd *rec = talloc_get_type(private_data, struct ctdb_recoverd); int disabled_flag_changed; if (data.dsize != sizeof(*c)) { @@ -2814,9 +2824,12 @@ static void monitor_handler(struct ctdb_context *ctdb, uint64_t srvid, /* handler for when we need to push out flag changes ot all other nodes */ -static void push_flags_handler(struct ctdb_context *ctdb, uint64_t srvid, - TDB_DATA data, void *private_data) +static void push_flags_handler(uint64_t srvid, TDB_DATA data, + void *private_data) { + struct ctdb_recoverd *rec = talloc_get_type( + private_data, struct ctdb_recoverd); + struct ctdb_context *ctdb = rec->ctdb; int ret; struct ctdb_node_flag_change *c = (struct ctdb_node_flag_change *)data.dptr; struct ctdb_node_map *nodemap=NULL; diff --git a/ctdb/server/ctdb_traverse.c b/ctdb/server/ctdb_traverse.c index d19305a..939e534 100644 --- a/ctdb/server/ctdb_traverse.c +++ b/ctdb/server/ctdb_traverse.c @@ -674,7 +674,7 @@ static void traverse_start_callback(void *p, TDB_DATA key, TDB_DATA data) cdata.dptr = (uint8_t *)d; cdata.dsize = d->length; - ctdb_dispatch_message(state->ctdb, state->srvid, cdata); + srvid_dispatch(state->ctdb->srv, state->srvid, 0, cdata); if (key.dsize == 0 && data.dsize == 0) { DEBUG(DEBUG_NOTICE, ("Ending traverse on DB %s (id %d), records %d\n", state->h->ctdb_db->db_name, state->h->reqid, diff --git a/ctdb/tests/src/ctdb_bench.c b/ctdb/tests/src/ctdb_bench.c index 3323589..10253a2 100644 --- a/ctdb/tests/src/ctdb_bench.c +++ b/ctdb/tests/src/ctdb_bench.c @@ -78,26 +78,31 @@ static int fetch_func(struct ctdb_call_info *call) } -static int msg_count; -static int msg_plus, msg_minus; +struct bench_data { + struct ctdb_context *ctdb; + struct tevent_context *ev; + int msg_count; + int msg_plus, msg_minus; +}; /* handler for messages in bench_ring() */ -static void ring_message_handler(struct ctdb_context *ctdb, uint64_t srvid, - TDB_DATA data, void *private_data) +static void ring_message_handler(uint64_t srvid, TDB_DATA data, + void *private_data) { + struct bench_data *bdata = talloc_get_type_abort( + private_data, struct bench_data); int incr = *(int *)data.dptr; - int *count = (int *)private_data; int dest; - (*count)++; - dest = (ctdb_get_pnn(ctdb) + num_nodes + incr) % num_nodes; - ctdb_client_send_message(ctdb, dest, srvid, data); + bdata->msg_count++; + dest = (ctdb_get_pnn(bdata->ctdb) + num_nodes + incr) % num_nodes; + ctdb_client_send_message(bdata->ctdb, dest, srvid, data); if (incr == 1) { - msg_plus++; + bdata->msg_plus++; } else { - msg_minus++; + bdata->msg_minus++; } } @@ -116,10 +121,11 @@ static void send_start_messages(struct ctdb_context *ctdb, int incr) ctdb_client_send_message(ctdb, dest, 0, data); } -static void each_second(struct event_context *ev, struct timed_event *te, - struct timeval t, void *private_data) +static void each_second(struct event_context *ev, struct timed_event *te, + struct timeval t, void *private_data) { - struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context); + struct bench_data *bdata = talloc_get_type_abort( + private_data, struct bench_data); /* we kickstart the ring into action by inserting messages from node with pnn 0. @@ -127,49 +133,57 @@ static void each_second(struct event_context *ev, struct timed_event *te, running in which case the ring is broken and the messages are lost. if so, once every second try again to restart the ring */ - if (msg_plus == 0) { + if (bdata->msg_plus == 0) { // printf("no messages recevied, try again to kickstart the ring in forward direction...\n"); - send_start_messages(ctdb, 1); + send_start_messages(bdata->ctdb, 1); } - if (msg_minus == 0) { + if (bdata->msg_minus == 0) { // printf("no messages recevied, try again to kickstart the ring in reverse direction...\n"); - send_start_messages(ctdb, -1); + send_start_messages(bdata->ctdb, -1); } - event_add_timed(ctdb->ev, ctdb, timeval_current_ofs(1, 0), each_second, ctdb); + event_add_timed(bdata->ev, bdata, timeval_current_ofs(1, 0), + each_second, bdata); } static void dummy_event(struct event_context *ev, struct timed_event *te, struct timeval t, void *private_data) { - struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context); - event_add_timed(ctdb->ev, ctdb, timeval_current_ofs(1, 0), dummy_event, ctdb); + struct bench_data *bdata = talloc_get_type_abort( + private_data, struct bench_data); + + event_add_timed(bdata->ev, bdata, timeval_current_ofs(1, 0), + dummy_event, bdata); } /* benchmark sending messages in a ring around the nodes */ -static void bench_ring(struct ctdb_context *ctdb, struct event_context *ev) +static void bench_ring(struct bench_data *bdata) { - int pnn=ctdb_get_pnn(ctdb); + int pnn = ctdb_get_pnn(bdata->ctdb); if (pnn == 0) { - event_add_timed(ctdb->ev, ctdb, timeval_current_ofs(1, 0), each_second, ctdb); + event_add_timed(bdata->ev, bdata, timeval_current_ofs(1, 0), + each_second, bdata); } else { - event_add_timed(ctdb->ev, ctdb, timeval_current_ofs(1, 0), dummy_event, ctdb); + event_add_timed(bdata->ev, bdata, timeval_current_ofs(1, 0), + dummy_event, bdata); } start_timer(); while (end_timer() < timelimit) { - if (pnn == 0 && msg_count % 10000 == 0 && end_timer() > 0) { - printf("Ring: %.2f msgs/sec (+ve=%d -ve=%d)\r", - msg_count/end_timer(), msg_plus, msg_minus); + if (pnn == 0 && bdata->msg_count % 10000 == 0 && end_timer() > 0) { + printf("Ring: %.2f msgs/sec (+ve=%d -ve=%d)\r", + bdata->msg_count/end_timer(), + bdata->msg_plus, bdata->msg_minus); fflush(stdout); } - event_loop_once(ev); + event_loop_once(bdata->ev); } - printf("Ring: %.2f msgs/sec (+ve=%d -ve=%d)\n", - msg_count/end_timer(), msg_plus, msg_minus); + printf("Ring: %.2f msgs/sec (+ve=%d -ve=%d)\n", + bdata->msg_count/end_timer(), + bdata->msg_plus, bdata->msg_minus); } /* @@ -194,6 +208,7 @@ int main(int argc, const char *argv[]) int ret; poptContext pc; struct event_context *ev; + struct bench_data *bdata; pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST); @@ -244,7 +259,14 @@ int main(int argc, const char *argv[]) DEBUG(DEBUG_DEBUG,("ctdb_set_call() failed, ignoring return code %d\n", ret)); } - if (ctdb_client_set_message_handler(ctdb, 0, ring_message_handler,&msg_count)) + bdata = talloc_zero(ctdb, struct bench_data); + if (bdata == NULL) { + goto error; + } + bdata->ctdb = ctdb; + bdata->ev = ev; + + if (ctdb_client_set_message_handler(ctdb, 0, ring_message_handler, bdata)) goto error; printf("Waiting for cluster\n"); @@ -255,8 +277,8 @@ int main(int argc, const char *argv[]) event_loop_once(ev); } - bench_ring(ctdb, ev); - + bench_ring(bdata); + error: return 0; } diff --git a/ctdb/tests/src/ctdb_fetch.c b/ctdb/tests/src/ctdb_fetch.c index b900efa..1d8bd3e 100644 --- a/ctdb/tests/src/ctdb_fetch.c +++ b/ctdb/tests/src/ctdb_fetch.c @@ -43,7 +43,12 @@ static double end_timer(void) static int timelimit = 10; static int num_records = 10; static int num_nodes; -static int msg_count; + +struct bench_data { + struct ctdb_context *ctdb; + struct tevent_context *ev; + int msg_count; +}; #define TESTKEY "testkey" @@ -52,8 +57,9 @@ static int msg_count; store a expanded record send a message to next node to tell it to do the same */ -static void bench_fetch_1node(struct ctdb_context *ctdb) +static void bench_fetch_1node(struct bench_data *bdata) { + struct ctdb_context *ctdb = bdata->ctdb; TDB_DATA key, data, nulldata; struct ctdb_db_context *ctdb_db; TALLOC_CTX *tmp_ctx = talloc_new(ctdb); @@ -82,7 +88,8 @@ static void bench_fetch_1node(struct ctdb_context *ctdb) } data.dptr = (uint8_t *)talloc_asprintf_append((char *)data.dptr, "msg_count=%d on node %d\n", - msg_count, ctdb_get_pnn(ctdb)); + bdata->msg_count, + ctdb_get_pnn(ctdb)); if (data.dptr == NULL) { printf("Failed to create record\n"); talloc_free(tmp_ctx); @@ -109,11 +116,13 @@ static void bench_fetch_1node(struct ctdb_context *ctdb) /* handler for messages in bench_ring() */ -static void message_handler(struct ctdb_context *ctdb, uint64_t srvid, - TDB_DATA data, void *private_data) +static void message_handler(uint64_t srvid, TDB_DATA data, void *private_data) { - msg_count++; - bench_fetch_1node(ctdb); + struct bench_data *bdata = talloc_get_type_abort( + private_data, struct bench_data); + + bdata->msg_count++; + bench_fetch_1node(bdata); } @@ -134,36 +143,38 @@ static void timeout_handler(struct event_context *ev, struct timed_event *timer, send a message to next node to tell it to do the same */ -static void bench_fetch(struct ctdb_context *ctdb, struct event_context *ev) +static void bench_fetch(struct bench_data *bdata) { + struct ctdb_context *ctdb = bdata->ctdb; int pnn=ctdb_get_pnn(ctdb); if (pnn == num_nodes - 1) { - bench_fetch_1node(ctdb); + bench_fetch_1node(bdata); } - + start_timer(); - event_add_timed(ev, ctdb, timeval_current_ofs(timelimit,0), timeout_handler, NULL); + event_add_timed(bdata->ev, bdata, timeval_current_ofs(timelimit,0), + timeout_handler, NULL); while (end_timer() < timelimit) { - if (pnn == 0 && msg_count % 100 == 0 && end_timer() > 0) { - printf("Fetch: %.2f msgs/sec\r", msg_count/end_timer()); + if (pnn == 0 && bdata->msg_count % 100 == 0 && end_timer() > 0) { + printf("Fetch: %.2f msgs/sec\r", bdata->msg_count/end_timer()); fflush(stdout); } - if (event_loop_once(ev) != 0) { + if (event_loop_once(bdata->ev) != 0) { printf("Event loop failed!\n"); break; } } - printf("Fetch: %.2f msgs/sec\n", msg_count/end_timer()); + printf("Fetch: %.2f msgs/sec\n", bdata->msg_count/end_timer()); } /* handler for reconfigure message */ -static void reconfigure_handler(struct ctdb_context *ctdb, uint64_t srvid, - TDB_DATA data, void *private_data) +static void reconfigure_handler(uint64_t srvid, TDB_DATA data, + void *private_data) { int *ready = (int *)private_data; *ready = 1; @@ -193,6 +204,7 @@ int main(int argc, const char *argv[]) TDB_DATA key, data; struct ctdb_record_handle *h; int cluster_ready=0; + struct bench_data *bdata; pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST); @@ -240,7 +252,16 @@ int main(int argc, const char *argv[]) exit(1); } - ctdb_client_set_message_handler(ctdb, 0, message_handler, &msg_count); + bdata = talloc_zero(ctdb, struct bench_data); + if (bdata == NULL) { + printf("memory allocation error\n"); + exit(1); + } + + bdata->ctdb = ctdb; + bdata->ev = ev; + + ctdb_client_set_message_handler(ctdb, 0, message_handler, bdata); printf("Waiting for cluster\n"); while (1) { @@ -257,7 +278,7 @@ int main(int argc, const char *argv[]) */ printf("Sleeping for %d seconds\n", num_nodes); sleep(num_nodes); - bench_fetch(ctdb, ev); + bench_fetch(bdata); key.dptr = discard_const(TESTKEY); key.dsize = strlen(TESTKEY); diff --git a/ctdb/tests/src/ctdb_test.c b/ctdb/tests/src/ctdb_test.c index 85f4813..3a3b2a7 100644 --- a/ctdb/tests/src/ctdb_test.c +++ b/ctdb/tests/src/ctdb_test.c @@ -132,7 +132,7 @@ int ctdb_ctrl_getdbseqnum(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t dbid, uint64_t *seqnum); int ctdb_client_set_message_handler(struct ctdb_context *ctdb, uint64_t srvid, - ctdb_msg_fn_t handler, + srvid_handler_fn handler, void *private_data); int ctdb_client_remove_message_handler(struct ctdb_context *ctdb, uint64_t srvid, @@ -173,7 +173,8 @@ ctdb_get_capabilities(struct ctdb_context *ctdb, #include "common/ctdb_io.c" #include "common/ctdb_util.c" #include "common/ctdb_ltdb.c" -#include "common/ctdb_message.c" +#include "common/db_hash.c" +#include "common/srvid.c" #include "common/rb_tree.c" #include "common/ctdb_logging.c" #include "common/ctdb_fork.c" diff --git a/ctdb/tests/src/ctdb_test_stubs.c b/ctdb/tests/src/ctdb_test_stubs.c index 93516fd..38fe016 100644 --- a/ctdb/tests/src/ctdb_test_stubs.c +++ b/ctdb/tests/src/ctdb_test_stubs.c @@ -610,7 +610,7 @@ ctdb_ctrl_get_ifaces_stub(struct ctdb_context *ctdb, * the ctdb tool only registers one at a time so keep this simple. */ static struct { uint64_t srvid; - ctdb_msg_fn_t message_handler; + srvid_handler_fn message_handler; void *message_private; } ctdb_message_list_fake = { .srvid = 0, @@ -620,7 +620,7 @@ static struct { int ctdb_client_set_message_handler_stub(struct ctdb_context *ctdb, uint64_t srvid, - ctdb_msg_fn_t handler, + srvid_handler_fn handler, void *private_data) { ctdb_message_list_fake.srvid = srvid; @@ -649,7 +649,6 @@ static void ctdb_fake_handler_pnn_reply(struct ctdb_context *ctdb, reply_data.dsize = sizeof(pnn); reply_data.dptr = (uint8_t *)&pnn; ctdb_message_list_fake.message_handler( - ctdb, ctdb_message_list_fake.srvid, reply_data, ctdb_message_list_fake.message_private); diff --git a/ctdb/tests/src/ctdbd_test.c b/ctdb/tests/src/ctdbd_test.c index 439512a..d505267 100644 --- a/ctdb/tests/src/ctdbd_test.c +++ b/ctdb/tests/src/ctdbd_test.c @@ -35,7 +35,8 @@ bool fast_start; #include "common/ctdb_io.c" #include "common/ctdb_util.c" #include "common/ctdb_ltdb.c" -#include "common/ctdb_message.c" +#include "common/db_hash.c" +#include "common/srvid.c" #include "common/cmdline.c" #include "common/rb_tree.c" #include "common/ctdb_logging.c" diff --git a/ctdb/tools/ctdb.c b/ctdb/tools/ctdb.c index 989b94c..fa41412 100644 --- a/ctdb/tools/ctdb.c +++ b/ctdb/tools/ctdb.c @@ -2189,9 +2189,7 @@ struct srvid_reply_handler_data { const char *srvid_str; }; -static void srvid_broadcast_reply_handler(struct ctdb_context *ctdb, - uint64_t srvid, - TDB_DATA data, +static void srvid_broadcast_reply_handler(uint64_t srvid, TDB_DATA data, void *private_data) { struct srvid_reply_handler_data *d = @@ -6036,8 +6034,7 @@ static int control_dumpmemory(struct ctdb_context *ctdb, int argc, const char ** /* handler for memory dumps */ -static void mem_dump_handler(struct ctdb_context *ctdb, uint64_t srvid, - TDB_DATA data, void *private_data) +static void mem_dump_handler(uint64_t srvid, TDB_DATA data, void *private_data) { sys_write(1, data.dptr, data.dsize); exit(0); @@ -6108,8 +6105,8 @@ static int control_msgsend(struct ctdb_context *ctdb, int argc, const char **arg /* handler for msglisten */ -static void msglisten_handler(struct ctdb_context *ctdb, uint64_t srvid, - TDB_DATA data, void *private_data) +static void msglisten_handler(uint64_t srvid, TDB_DATA data, + void *private_data) { int i; diff --git a/ctdb/wscript b/ctdb/wscript index aaefad3..786ae18 100755 --- a/ctdb/wscript +++ b/ctdb/wscript @@ -320,7 +320,7 @@ def build(bld): bld.SAMBA_SUBSYSTEM('ctdb-common', source=bld.SUBDIR('common', '''ctdb_io.c ctdb_util.c ctdb_ltdb.c - ctdb_message.c cmdline.c rb_tree.c + cmdline.c rb_tree.c ctdb_fork.c'''), includes='include include/internal common .', deps='replace popt talloc tevent tdb popt ctdb-system') @@ -340,7 +340,7 @@ def build(bld): source=bld.SUBDIR('client', 'ctdb_client.c'), includes='include include/internal', deps='''replace popt talloc tevent tdb - samba-util tdb-wrap''') + samba-util tdb-wrap ctdb-util''') bld.SAMBA_SUBSYSTEM('ctdb-server', source='server/ctdbd.c ' + @@ -367,14 +367,15 @@ def build(bld): bld.SAMBA_BINARY('ctdbd', source='', deps='''ctdb-server ctdb-client ctdb-common - ctdb-common-util ctdb-tcp''' + + ctdb-common-util ctdb-tcp ctdb-util''' + ib_deps, install_path='${SBINDIR}', manpages='ctdbd.1') bld.SAMBA_BINARY('ctdb', source='tools/ctdb.c tools/ctdb_vacuum.c', - deps='ctdb-client ctdb-common ctdb-common-util', + deps='''ctdb-client ctdb-common ctdb-common-util + ctdb-util''', includes='include include/internal', install_path='${BINDIR}', manpages='ctdb.1') @@ -610,7 +611,8 @@ def build(bld): bld.SAMBA_BINARY(target, source=src, includes='include include/internal', - deps='ctdb-client ctdb-common ctdb-common-util', + deps='''ctdb-client ctdb-common ctdb-common-util + ctdb-util''', install_path='${CTDB_TEST_LIBDIR}') bld.SAMBA_BINARY('ctdb_takeover_tests', From 9d75bf3a9ffaa1e0cd25f7ada57f9eef7de614c3 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Wed, 8 Apr 2015 14:41:12 +1000 Subject: [PATCH 047/136] ctdb-daemon: formatting fix Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/client/ctdb_client.c | 23 +++++++++++++++-------- ctdb/server/ctdb_daemon.c | 3 ++- ctdb/tests/src/ctdb_fetch.c | 4 ++-- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/ctdb/client/ctdb_client.c b/ctdb/client/ctdb_client.c index d4ef327..1d4374d 100644 --- a/ctdb/client/ctdb_client.c +++ b/ctdb/client/ctdb_client.c @@ -487,17 +487,20 @@ int ctdb_call(struct ctdb_db_context *ctdb_db, struct ctdb_call *call) tell the daemon what messaging srvid we will use, and register the message handler function in the client */ -int ctdb_client_set_message_handler(struct ctdb_context *ctdb, uint64_t srvid, - srvid_handler_fn handler, - void *private_data) +int ctdb_client_set_message_handler(struct ctdb_context *ctdb, uint64_t srvid, + srvid_handler_fn handler, + void *private_data) { int res; int32_t status; - res = ctdb_control(ctdb, CTDB_CURRENT_NODE, srvid, CTDB_CONTROL_REGISTER_SRVID, 0, + res = ctdb_control(ctdb, CTDB_CURRENT_NODE, srvid, + CTDB_CONTROL_REGISTER_SRVID, 0, tdb_null, NULL, NULL, &status, NULL, NULL); if (res != 0 || status != 0) { - DEBUG(DEBUG_ERR,("Failed to register srvid %llu\n", (unsigned long long)srvid)); + DEBUG(DEBUG_ERR, + ("Failed to register srvid %llu\n", + (unsigned long long)srvid)); return -1; } @@ -508,15 +511,19 @@ int ctdb_client_set_message_handler(struct ctdb_context *ctdb, uint64_t srvid, /* tell the daemon we no longer want a srvid */ -int ctdb_client_remove_message_handler(struct ctdb_context *ctdb, uint64_t srvid, void *private_data) +int ctdb_client_remove_message_handler(struct ctdb_context *ctdb, + uint64_t srvid, void *private_data) { int res; int32_t status; - res = ctdb_control(ctdb, CTDB_CURRENT_NODE, srvid, CTDB_CONTROL_DEREGISTER_SRVID, 0, + res = ctdb_control(ctdb, CTDB_CURRENT_NODE, srvid, + CTDB_CONTROL_DEREGISTER_SRVID, 0, tdb_null, NULL, NULL, &status, NULL, NULL); if (res != 0 || status != 0) { - DEBUG(DEBUG_ERR,("Failed to deregister srvid %llu\n", (unsigned long long)srvid)); + DEBUG(DEBUG_ERR, + ("Failed to deregister srvid %llu\n", + (unsigned long long)srvid)); return -1; } diff --git a/ctdb/server/ctdb_daemon.c b/ctdb/server/ctdb_daemon.c index 4e68606..4d8deda 100644 --- a/ctdb/server/ctdb_daemon.c +++ b/ctdb/server/ctdb_daemon.c @@ -1561,7 +1561,8 @@ struct ctdb_local_message { TDB_DATA data; }; -static void ctdb_local_message_trigger(struct event_context *ev, struct timed_event *te, +static void ctdb_local_message_trigger(struct event_context *ev, + struct timed_event *te, struct timeval t, void *private_data) { struct ctdb_local_message *m = talloc_get_type( diff --git a/ctdb/tests/src/ctdb_fetch.c b/ctdb/tests/src/ctdb_fetch.c index 1d8bd3e..dff9fe2 100644 --- a/ctdb/tests/src/ctdb_fetch.c +++ b/ctdb/tests/src/ctdb_fetch.c @@ -241,8 +241,8 @@ int main(int argc, const char *argv[]) exit(1); } - ctdb_client_set_message_handler(ctdb, CTDB_SRVID_RECONFIGURE, reconfigure_handler, - &cluster_ready); + ctdb_client_set_message_handler(ctdb, CTDB_SRVID_RECONFIGURE, + reconfigure_handler, &cluster_ready); /* attach to a specific database */ ctdb_db = ctdb_attach(ctdb, timeval_current_ofs(2, 0), "test.tdb", From 7c6115e11b2112f5b4003be862f709cc9ffea615 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Wed, 8 Apr 2015 14:41:59 +1000 Subject: [PATCH 048/136] ctdb-daemon: whitespace fix Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/tests/src/ctdb_bench.c | 2 +- ctdb/tests/src/ctdb_fetch.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ctdb/tests/src/ctdb_bench.c b/ctdb/tests/src/ctdb_bench.c index 10253a2..09cb8ab 100644 --- a/ctdb/tests/src/ctdb_bench.c +++ b/ctdb/tests/src/ctdb_bench.c @@ -145,7 +145,7 @@ static void each_second(struct event_context *ev, struct timed_event *te, each_second, bdata); } -static void dummy_event(struct event_context *ev, struct timed_event *te, +static void dummy_event(struct event_context *ev, struct timed_event *te, struct timeval t, void *private_data) { struct bench_data *bdata = talloc_get_type_abort( diff --git a/ctdb/tests/src/ctdb_fetch.c b/ctdb/tests/src/ctdb_fetch.c index dff9fe2..2b11bad 100644 --- a/ctdb/tests/src/ctdb_fetch.c +++ b/ctdb/tests/src/ctdb_fetch.c @@ -86,7 +86,7 @@ static void bench_fetch_1node(struct bench_data *bdata) if (data.dsize == 0) { data.dptr = (uint8_t *)talloc_asprintf(tmp_ctx, "Test data\n"); } - data.dptr = (uint8_t *)talloc_asprintf_append((char *)data.dptr, + data.dptr = (uint8_t *)talloc_asprintf_append((char *)data.dptr, "msg_count=%d on node %d\n", bdata->msg_count, ctdb_get_pnn(ctdb)); From a7ea6b094e60a41e28df5a8f17b98bb3bd1058d9 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Tue, 17 Mar 2015 13:41:36 +1100 Subject: [PATCH 049/136] ctdb-include: Remove unused definition Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/include/ctdb_private.h | 1 - 1 file changed, 1 deletion(-) diff --git a/ctdb/include/ctdb_private.h b/ctdb/include/ctdb_private.h index b9965df..a7af80d 100644 --- a/ctdb/include/ctdb_private.h +++ b/ctdb/include/ctdb_private.h @@ -813,7 +813,6 @@ int ctdb_call_local(struct ctdb_db_context *ctdb_db, struct ctdb_call *call, int ctdb_socket_connect(struct ctdb_context *ctdb); void ctdb_client_read_cb(uint8_t *data, size_t cnt, void *args); -#define CTDB_BAD_REQID ((uint32_t)-1) uint32_t ctdb_reqid_new(struct ctdb_context *ctdb, void *state); void *_ctdb_reqid_find(struct ctdb_context *ctdb, uint32_t reqid, const char *type, const char *location); void ctdb_reqid_remove(struct ctdb_context *ctdb, uint32_t reqid); From 9fd4d07ca60e2e4a40662988ce8136efa6452ced Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Tue, 17 Mar 2015 13:29:44 +1100 Subject: [PATCH 050/136] ctdb-common: Add request id abstraction Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/common/reqid.c | 89 ++++++++++++++++++++++++++++++++++++++ ctdb/common/reqid.h | 89 ++++++++++++++++++++++++++++++++++++++ ctdb/tests/cunit/reqid_test_001.sh | 13 ++++++ ctdb/tests/src/reqid_test.c | 72 ++++++++++++++++++++++++++++++ ctdb/wscript | 7 ++- 5 files changed, 269 insertions(+), 1 deletion(-) create mode 100644 ctdb/common/reqid.c create mode 100644 ctdb/common/reqid.h create mode 100755 ctdb/tests/cunit/reqid_test_001.sh create mode 100644 ctdb/tests/src/reqid_test.c diff --git a/ctdb/common/reqid.c b/ctdb/common/reqid.c new file mode 100644 index 0000000..0e651cf --- /dev/null +++ b/ctdb/common/reqid.c @@ -0,0 +1,89 @@ +/* + ctdb request id handling code + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include "replace.h" + +#include + +#include "lib/util/idtree.h" +#include "reqid.h" + +struct reqid_context { + struct idr_context *idr; + uint32_t lastid; +}; + +int reqid_init(TALLOC_CTX *mem_ctx, int start_id, + struct reqid_context **result) +{ + struct reqid_context *reqid_ctx; + + reqid_ctx = talloc_zero(mem_ctx, struct reqid_context); + if (reqid_ctx == NULL) { + return ENOMEM; + } + + reqid_ctx->idr = idr_init(reqid_ctx); + if (reqid_ctx->idr == NULL) { + talloc_free(reqid_ctx); + return ENOMEM; + } + + if (start_id <= 0) { + start_id = 1; + } + reqid_ctx->lastid = start_id; + + *result = reqid_ctx; + return 0; +} + +uint32_t reqid_new(struct reqid_context *reqid_ctx, void *private_data) +{ + int id; + + id = idr_get_new_above(reqid_ctx->idr, private_data, + reqid_ctx->lastid+1, INT_MAX); + if (id < 0) { + /* reqid wrapped */ + id = idr_get_new(reqid_ctx->idr, private_data, INT_MAX); + } + if (id == -1) { + return REQID_INVALID; + } + + reqid_ctx->lastid = id; + return id; +} + +void *_reqid_find(struct reqid_context *reqid_ctx, uint32_t reqid) +{ + return idr_find(reqid_ctx->idr, reqid); +} + +int reqid_remove(struct reqid_context *reqid_ctx, uint32_t reqid) +{ + int ret; + + ret = idr_remove(reqid_ctx->idr, reqid); + if (ret < 0) { + return ENOENT; + } + return 0; +} diff --git a/ctdb/common/reqid.h b/ctdb/common/reqid.h new file mode 100644 index 0000000..736e5b3 --- /dev/null +++ b/ctdb/common/reqid.h @@ -0,0 +1,89 @@ +/* + Request id database + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#ifndef __CTDB_REQID_H__ +#define __CTDB_REQID_H__ + +#include + +/** + * @file reqid.h + * + * @brief Request id database + * + * CTDB tracks messsages using request id. CTDB stores client state for each + * request id to process the replies correctly. + */ + +/** + * @brief Abstract struct to store request id database + */ +struct reqid_context; + +#define REQID_INVALID 0xffffffff + +/** + * @brief Initialize request id database + * + * This returns a new request id context. Freeing this context will free + * all the memory associated with request id database. + * + * @param[in] mem_ctx Talloc memory context + * @param[in] start_id The initial id + * @param[out] result The new talloc_context structure + * @return 0 on success, errno on failure + */ +int reqid_init(TALLOC_CTX *mem_ctx, int start_id, + struct reqid_context **result); + +/** + * @brief Generate new request id and associate given data with the request id + * + * @param[in] reqid_ctx The request id context + * @param[in] private_data The state to associate with new request id + * @return new request id, REQID_INVALID on failure + */ +uint32_t reqid_new(struct reqid_context *reqid_ctx, void *private_data); + +#ifdef DOXYGEN +/** + * @brief Fetch the data associated with the request id + * + * @param[in] reqid_ctx The request id context + * @param[in] reqid The request id + * @param[in] type The data type of the stored data + * @return the data stored for the reqid, NULL on failure + */ +type *reqid_find(struct reqid_context *reqid_ctx, uint32_t reqid, #type); +#else +void *_reqid_find(struct reqid_context *reqid_ctx, uint32_t reqid); +#define reqid_find(ctx, reqid, type) \ + (type *)talloc_check_name(_reqid_find(ctx, reqid), #type) +#endif + +/** + * @brief Remove the data associated with the request id + * + * @param[in] reqid_ctx The request id context + * @param[in] reqid The request id + * @return 0 on success, errno on failure + */ +int reqid_remove(struct reqid_context *reqid_ctx, uint32_t reqid); + +#endif /* __CTDB_REQID_H__ */ diff --git a/ctdb/tests/cunit/reqid_test_001.sh b/ctdb/tests/cunit/reqid_test_001.sh new file mode 100755 index 0000000..06259ba --- /dev/null +++ b/ctdb/tests/cunit/reqid_test_001.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +. "${TEST_SCRIPTS_DIR}/unit.sh" + +output=$( +for i in $(seq 0 1023) ; do + echo "WARNING: attempt to remove unset id $i in idtree" +done +) + +ok "$output" + +unit_test reqid_test diff --git a/ctdb/tests/src/reqid_test.c b/ctdb/tests/src/reqid_test.c new file mode 100644 index 0000000..ec0c4a5 --- /dev/null +++ b/ctdb/tests/src/reqid_test.c @@ -0,0 +1,72 @@ +/* + reqid tests + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include "replace.h" + +#include + +#include "common/reqid.c" + + +int main(void) +{ + struct reqid_context *reqid_ctx; + TALLOC_CTX *mem_ctx = talloc_new(NULL); + int i, ret; + uint32_t reqid; + int *data, *tmp; + + ret = reqid_init(mem_ctx, INT_MAX-200, &reqid_ctx); + assert(ret == 0); + + data = talloc_zero(mem_ctx, int); + assert(data != 0); + + for (i=0; i<1024*1024; i++) { + reqid = reqid_new(reqid_ctx, data); + assert(reqid != -1); + } + + for (i=0; i<1024; i++) { + tmp = reqid_find(reqid_ctx, i, int); + assert(tmp == data); + } + + for (i=0; i<1024; i++) { + ret = reqid_remove(reqid_ctx, i); + assert(ret == 0); + } + + for (i=0; i<1024; i++) { + tmp = reqid_find(reqid_ctx, i, int); + assert(tmp == NULL); + } + + for (i=0; i<1024; i++) { + ret = reqid_remove(reqid_ctx, i); + assert(ret == ENOENT); + } + + talloc_free(reqid_ctx); + assert(talloc_get_size(mem_ctx) == 0); + + talloc_free(mem_ctx); + + return 0; +} diff --git a/ctdb/wscript b/ctdb/wscript index 786ae18..467b51e 100755 --- a/ctdb/wscript +++ b/ctdb/wscript @@ -333,7 +333,7 @@ def build(bld): bld.SAMBA_SUBSYSTEM('ctdb-util', source=bld.SUBDIR('common', - '''db_hash.c srvid.c'''), + '''db_hash.c srvid.c reqid.c'''), deps='replace talloc tevent tdb') bld.SAMBA_SUBSYSTEM('ctdb-client', @@ -585,6 +585,11 @@ def build(bld): deps='talloc tevent tdb', install_path='${CTDB_TEST_LIBDIR}') + bld.SAMBA_BINARY('reqid_test', + source='tests/src/reqid_test.c', + deps='samba-util', + install_path='${CTDB_TEST_LIBDIR}') + # Test binaries ctdb_tests = [ 'rb_test', From b25c1135a74f5d61da00847149587835bc2102c9 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Tue, 17 Mar 2015 14:30:18 +1100 Subject: [PATCH 051/136] ctdb-daemon: Use reqid abstraction Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/client/ctdb_client.c | 26 ++++++++++++---------- ctdb/common/ctdb_util.c | 49 +----------------------------------------- ctdb/include/ctdb_private.h | 7 +----- ctdb/server/ctdb_call.c | 15 +++++++------ ctdb/server/ctdb_control.c | 7 +++--- ctdb/server/ctdb_daemon.c | 17 ++++++++------- ctdb/server/ctdb_ltdb_server.c | 5 +++-- ctdb/server/ctdb_persistent.c | 7 +++--- ctdb/server/ctdb_serverids.c | 3 ++- ctdb/server/ctdb_takeover.c | 9 ++++---- ctdb/server/ctdb_traverse.c | 9 ++++---- ctdb/server/ctdbd.c | 8 ++++++- ctdb/tests/src/ctdb_test.c | 1 + ctdb/tests/src/ctdbd_test.c | 1 + 14 files changed, 66 insertions(+), 98 deletions(-) diff --git a/ctdb/client/ctdb_client.c b/ctdb/client/ctdb_client.c index 1d4374d..b8e7e10 100644 --- a/ctdb/client/ctdb_client.c +++ b/ctdb/client/ctdb_client.c @@ -28,6 +28,7 @@ #include #include "../include/ctdb_private.h" #include "lib/util/dlinklist.h" +#include "common/reqid.h" /* allocate a packet for use in client<->daemon communication @@ -153,7 +154,7 @@ static void ctdb_client_reply_call(struct ctdb_context *ctdb, struct ctdb_req_he struct ctdb_reply_call *c = (struct ctdb_reply_call *)hdr; struct ctdb_client_call_state *state; - state = ctdb_reqid_find(ctdb, hdr->reqid, struct ctdb_client_call_state); + state = reqid_find(ctdb->idr, hdr->reqid, struct ctdb_client_call_state); if (state == NULL) { DEBUG(DEBUG_ERR,(__location__ " reqid %u not found\n", hdr->reqid)); return; @@ -344,7 +345,7 @@ int ctdb_call_recv(struct ctdb_client_call_state *state, struct ctdb_call *call) */ static int ctdb_client_call_destructor(struct ctdb_client_call_state *state) { - ctdb_reqid_remove(state->ctdb_db->ctdb, state->reqid); + reqid_remove(state->ctdb_db->ctdb->idr, state->reqid); return 0; } @@ -444,7 +445,7 @@ struct ctdb_client_call_state *ctdb_call_send(struct ctdb_db_context *ctdb_db, return NULL; } - state->reqid = ctdb_reqid_new(ctdb, state); + state->reqid = reqid_new(ctdb->idr, state); state->ctdb_db = ctdb_db; talloc_set_destructor(state, ctdb_client_call_destructor); @@ -978,7 +979,7 @@ static void ctdb_client_reply_control(struct ctdb_context *ctdb, struct ctdb_reply_control *c = (struct ctdb_reply_control *)hdr; struct ctdb_client_control_state *state; - state = ctdb_reqid_find(ctdb, hdr->reqid, struct ctdb_client_control_state); + state = reqid_find(ctdb->idr, hdr->reqid, struct ctdb_client_control_state); if (state == NULL) { DEBUG(DEBUG_ERR,(__location__ " reqid %u not found\n", hdr->reqid)); return; @@ -1020,7 +1021,7 @@ static void ctdb_client_reply_control(struct ctdb_context *ctdb, */ static int ctdb_client_control_destructor(struct ctdb_client_control_state *state) { - ctdb_reqid_remove(state->ctdb, state->reqid); + reqid_remove(state->ctdb->idr, state->reqid); return 0; } @@ -1071,7 +1072,7 @@ struct ctdb_client_control_state *ctdb_control_send(struct ctdb_context *ctdb, CTDB_NO_MEMORY_NULL(ctdb, state); state->ctdb = ctdb; - state->reqid = ctdb_reqid_new(ctdb, state); + state->reqid = reqid_new(ctdb->idr, state); state->state = CTDB_CONTROL_WAIT; state->errormsg = NULL; @@ -3313,10 +3314,13 @@ struct ctdb_context *ctdb_init(struct event_context *ev) return NULL; } ctdb->ev = ev; - ctdb->idr = idr_init(ctdb); /* Wrap early to exercise code. */ - ctdb->lastid = INT_MAX-200; - CTDB_NO_MEMORY_NULL(ctdb, ctdb->idr); + ret = reqid_init(ctdb, INT_MAX-200, &ctdb->idr); + if (ret != 0) { + DEBUG(DEBUG_ERR, ("reqid_init failed (%s)\n", strerror(ret))); + talloc_free(ctdb); + return NULL; + } ret = srvid_init(ctdb, &ctdb->srv); if (ret != 0) { @@ -4101,7 +4105,7 @@ struct ctdb_transaction_handle { static int ctdb_transaction_destructor(struct ctdb_transaction_handle *h) { g_lock_unlock(h, h->g_lock_db, h->lock_name, h->reqid); - ctdb_reqid_remove(h->ctdb_db->ctdb, h->reqid); + reqid_remove(h->ctdb_db->ctdb->idr, h->reqid); return 0; } @@ -4149,7 +4153,7 @@ struct ctdb_transaction_handle *ctdb_transaction_start(struct ctdb_db_context *c return NULL; } - h->reqid = ctdb_reqid_new(h->ctdb_db->ctdb, h); + h->reqid = reqid_new(h->ctdb_db->ctdb->idr, h); if (!g_lock_lock(h, h->g_lock_db, h->lock_name, h->reqid)) { DEBUG(DEBUG_ERR, (__location__ " Error locking g_lock.tdb\n")); diff --git a/ctdb/common/ctdb_util.c b/ctdb/common/ctdb_util.c index 709c7a1..2864834 100644 --- a/ctdb/common/ctdb_util.c +++ b/ctdb/common/ctdb_util.c @@ -23,6 +23,7 @@ #include "system/filesys.h" #include "system/wait.h" #include "../include/ctdb_private.h" +#include "common/reqid.h" /* return error string for last error @@ -199,54 +200,6 @@ uint32_t ctdb_hash(const TDB_DATA *key) return tdb_jenkins_hash(discard_const(key)); } -/* - a type checking varient of idr_find - */ -static void *_idr_find_type(struct idr_context *idp, int id, const char *type, const char *location) -{ - void *p = idr_find(idp, id); - if (p && talloc_check_name(p, type) == NULL) { - DEBUG(DEBUG_ERR,("%s idr_find_type expected type %s but got %s\n", - location, type, talloc_get_name(p))); - return NULL; - } - return p; -} - -uint32_t ctdb_reqid_new(struct ctdb_context *ctdb, void *state) -{ - int id = idr_get_new_above(ctdb->idr, state, ctdb->lastid+1, INT_MAX); - if (id < 0) { - DEBUG(DEBUG_DEBUG, ("Reqid wrap!\n")); - id = idr_get_new(ctdb->idr, state, INT_MAX); - } - ctdb->lastid = id; - return id; -} - -void *_ctdb_reqid_find(struct ctdb_context *ctdb, uint32_t reqid, const char *type, const char *location) -{ - void *p; - - p = _idr_find_type(ctdb->idr, reqid, type, location); - if (p == NULL) { - DEBUG(DEBUG_WARNING, ("Could not find idr:%u\n",reqid)); - } - - return p; -} - - -void ctdb_reqid_remove(struct ctdb_context *ctdb, uint32_t reqid) -{ - int ret; - - ret = idr_remove(ctdb->idr, reqid); - if (ret != 0) { - DEBUG(DEBUG_ERR, ("Removing idr that does not exist\n")); - } -} - static uint32_t ctdb_marshall_record_size(TDB_DATA key, struct ctdb_ltdb_header *header, diff --git a/ctdb/include/ctdb_private.h b/ctdb/include/ctdb_private.h index a7af80d..5702ad1 100644 --- a/ctdb/include/ctdb_private.h +++ b/ctdb/include/ctdb_private.h @@ -453,8 +453,7 @@ struct ctdb_context { uint32_t num_connected; unsigned flags; uint32_t capabilities; - struct idr_context *idr; - int lastid; + struct reqid_context *idr; struct ctdb_node **nodes; /* array of nodes in the cluster - indexed by vnn */ struct ctdb_vnn *vnn; /* list of public ip addresses and interfaces */ struct ctdb_vnn *single_ip_vnn; /* a structure for the single ip */ @@ -813,10 +812,6 @@ int ctdb_call_local(struct ctdb_db_context *ctdb_db, struct ctdb_call *call, int ctdb_socket_connect(struct ctdb_context *ctdb); void ctdb_client_read_cb(uint8_t *data, size_t cnt, void *args); -uint32_t ctdb_reqid_new(struct ctdb_context *ctdb, void *state); -void *_ctdb_reqid_find(struct ctdb_context *ctdb, uint32_t reqid, const char *type, const char *location); -void ctdb_reqid_remove(struct ctdb_context *ctdb, uint32_t reqid); - void ctdb_request_control(struct ctdb_context *ctdb, struct ctdb_req_header *hdr); void ctdb_reply_control(struct ctdb_context *ctdb, struct ctdb_req_header *hdr); diff --git a/ctdb/server/ctdb_call.c b/ctdb/server/ctdb_call.c index 4a59094..a591ae5 100644 --- a/ctdb/server/ctdb_call.c +++ b/ctdb/server/ctdb_call.c @@ -27,6 +27,7 @@ #include "system/filesys.h" #include "../include/ctdb_private.h" #include "../common/rb_tree.h" +#include "common/reqid.h" struct ctdb_sticky_record { struct ctdb_context *ctdb; @@ -334,7 +335,7 @@ static void ctdb_become_dmaster(struct ctdb_db_context *ctdb_db, header.dmaster = ctdb->pnn; header.flags = record_flags; - state = ctdb_reqid_find(ctdb, hdr->reqid, struct ctdb_call_state); + state = reqid_find(ctdb->idr, hdr->reqid, struct ctdb_call_state); if (state) { if (state->call->flags & CTDB_CALL_FLAG_VACUUM_MIGRATION) { @@ -1159,7 +1160,7 @@ void ctdb_reply_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr) struct ctdb_reply_call *c = (struct ctdb_reply_call *)hdr; struct ctdb_call_state *state; - state = ctdb_reqid_find(ctdb, hdr->reqid, struct ctdb_call_state); + state = reqid_find(ctdb->idr, hdr->reqid, struct ctdb_call_state); if (state == NULL) { DEBUG(DEBUG_ERR, (__location__ " reqid %u not found\n", hdr->reqid)); return; @@ -1319,7 +1320,7 @@ void ctdb_reply_error(struct ctdb_context *ctdb, struct ctdb_req_header *hdr) struct ctdb_reply_error *c = (struct ctdb_reply_error *)hdr; struct ctdb_call_state *state; - state = ctdb_reqid_find(ctdb, hdr->reqid, struct ctdb_call_state); + state = reqid_find(ctdb->idr, hdr->reqid, struct ctdb_call_state); if (state == NULL) { DEBUG(DEBUG_ERR,("pnn %u Invalid reqid %u in ctdb_reply_error\n", ctdb->pnn, hdr->reqid)); @@ -1348,7 +1349,7 @@ void ctdb_reply_error(struct ctdb_context *ctdb, struct ctdb_req_header *hdr) static int ctdb_call_destructor(struct ctdb_call_state *state) { DLIST_REMOVE(state->ctdb_db->pending_calls, state); - ctdb_reqid_remove(state->ctdb_db->ctdb, state->reqid); + reqid_remove(state->ctdb_db->ctdb->idr, state->reqid); return 0; } @@ -1363,8 +1364,8 @@ static void ctdb_call_resend(struct ctdb_call_state *state) state->generation = state->ctdb_db->generation; /* use a new reqid, in case the old reply does eventually come in */ - ctdb_reqid_remove(ctdb, state->reqid); - state->reqid = ctdb_reqid_new(ctdb, state); + reqid_remove(ctdb->idr, state->reqid); + state->reqid = reqid_new(ctdb->idr, state); state->c->hdr.reqid = state->reqid; /* update the generation count for this request, so its valid with the new vnn_map */ @@ -1473,7 +1474,7 @@ struct ctdb_call_state *ctdb_daemon_call_send_remote(struct ctdb_db_context *ctd state->call = talloc(state, struct ctdb_call); CTDB_NO_MEMORY_NULL(ctdb, state->call); - state->reqid = ctdb_reqid_new(ctdb, state); + state->reqid = reqid_new(ctdb->idr, state); state->ctdb_db = ctdb_db; talloc_set_destructor(state, ctdb_call_destructor); diff --git a/ctdb/server/ctdb_control.c b/ctdb/server/ctdb_control.c index 2df14b7..03e19df 100644 --- a/ctdb/server/ctdb_control.c +++ b/ctdb/server/ctdb_control.c @@ -25,6 +25,7 @@ #include "lib/util/dlinklist.h" #include "lib/tdb_wrap/tdb_wrap.h" #include "lib/util/talloc_report.h" +#include "common/reqid.h" struct ctdb_control_state { @@ -785,7 +786,7 @@ void ctdb_reply_control(struct ctdb_context *ctdb, struct ctdb_req_header *hdr) struct ctdb_control_state *state; const char *errormsg = NULL; - state = ctdb_reqid_find(ctdb, hdr->reqid, struct ctdb_control_state); + state = reqid_find(ctdb->idr, hdr->reqid, struct ctdb_control_state); if (state == NULL) { DEBUG(DEBUG_ERR,("pnn %u Invalid reqid %u in ctdb_reply_control\n", ctdb->pnn, hdr->reqid)); @@ -814,7 +815,7 @@ void ctdb_reply_control(struct ctdb_context *ctdb, struct ctdb_req_header *hdr) static int ctdb_control_destructor(struct ctdb_control_state *state) { - ctdb_reqid_remove(state->ctdb, state->reqid); + reqid_remove(state->ctdb->idr, state->reqid); return 0; } @@ -881,7 +882,7 @@ int ctdb_daemon_send_control(struct ctdb_context *ctdb, uint32_t destnode, state = talloc(private_data?private_data:ctdb, struct ctdb_control_state); CTDB_NO_MEMORY(ctdb, state); - state->reqid = ctdb_reqid_new(ctdb, state); + state->reqid = reqid_new(ctdb->idr, state); state->callback = callback; state->private_data = private_data; state->ctdb = ctdb; diff --git a/ctdb/server/ctdb_daemon.c b/ctdb/server/ctdb_daemon.c index 4d8deda..0287a67 100644 --- a/ctdb/server/ctdb_daemon.c +++ b/ctdb/server/ctdb_daemon.c @@ -29,6 +29,7 @@ #include "../include/ctdb_private.h" #include "../common/rb_tree.h" #include +#include "common/reqid.h" struct ctdb_client_pid_list { struct ctdb_client_pid_list *next, *prev; @@ -157,7 +158,7 @@ static void daemon_message_handler(uint64_t srvid, TDB_DATA data, */ int daemon_register_message_handler(struct ctdb_context *ctdb, uint32_t client_id, uint64_t srvid) { - struct ctdb_client *client = ctdb_reqid_find(ctdb, client_id, struct ctdb_client); + struct ctdb_client *client = reqid_find(ctdb->idr, client_id, struct ctdb_client); int res; if (client == NULL) { DEBUG(DEBUG_ERR,("Bad client_id in daemon_request_register_message_handler\n")); @@ -182,7 +183,7 @@ int daemon_register_message_handler(struct ctdb_context *ctdb, uint32_t client_i */ int daemon_deregister_message_handler(struct ctdb_context *ctdb, uint32_t client_id, uint64_t srvid) { - struct ctdb_client *client = ctdb_reqid_find(ctdb, client_id, struct ctdb_client); + struct ctdb_client *client = reqid_find(ctdb->idr, client_id, struct ctdb_client); if (client == NULL) { DEBUG(DEBUG_ERR,("Bad client_id in daemon_request_deregister_message_handler\n")); return -1; @@ -229,7 +230,7 @@ static int ctdb_client_destructor(struct ctdb_client *client) struct ctdb_db_context *ctdb_db; ctdb_takeover_client_destructor_hook(client); - ctdb_reqid_remove(client->ctdb, client->client_id); + reqid_remove(client->ctdb->idr, client->client_id); client->ctdb->num_clients--; if (client->num_persistent_updates != 0) { @@ -387,7 +388,7 @@ static void daemon_incoming_packet_wrap(void *p, struct ctdb_req_header *hdr) return; } - client = ctdb_reqid_find(w->ctdb, w->client_id, struct ctdb_client); + client = reqid_find(w->ctdb->idr, w->client_id, struct ctdb_client); if (client == NULL) { DEBUG(DEBUG_ERR,(__location__ " Packet for disconnected client %u\n", w->client_id)); @@ -448,7 +449,7 @@ static int deferred_fetch_queue_destructor(struct ctdb_deferred_fetch_queue *dfq DLIST_REMOVE(dfq->deferred_calls, dfc); - client = ctdb_reqid_find(dfc->w->ctdb, dfc->w->client_id, struct ctdb_client); + client = reqid_find(dfc->w->ctdb->idr, dfc->w->client_id, struct ctdb_client); if (client == NULL) { DEBUG(DEBUG_ERR,(__location__ " Packet for disconnected client %u\n", dfc->w->client_id)); @@ -931,7 +932,7 @@ static void ctdb_accept_client(struct event_context *ev, struct fd_event *fde, client->ctdb = ctdb; client->fd = fd; - client->client_id = ctdb_reqid_new(ctdb, client); + client->client_id = reqid_new(ctdb->idr, client); client->pid = peer_pid; client_pid = talloc(client, struct ctdb_client_pid_list); @@ -1654,7 +1655,7 @@ static int ctdb_client_notify_destructor(struct ctdb_client_notify_list *nl) int32_t ctdb_control_register_notify(struct ctdb_context *ctdb, uint32_t client_id, TDB_DATA indata) { struct ctdb_client_notify_register *notify = (struct ctdb_client_notify_register *)indata.dptr; - struct ctdb_client *client = ctdb_reqid_find(ctdb, client_id, struct ctdb_client); + struct ctdb_client *client = reqid_find(ctdb->idr, client_id, struct ctdb_client); struct ctdb_client_notify_list *nl; DEBUG(DEBUG_INFO,("Register srvid %llu for client %d\n", (unsigned long long)notify->srvid, client_id)); @@ -1703,7 +1704,7 @@ int32_t ctdb_control_register_notify(struct ctdb_context *ctdb, uint32_t client_ int32_t ctdb_control_deregister_notify(struct ctdb_context *ctdb, uint32_t client_id, TDB_DATA indata) { struct ctdb_client_notify_deregister *notify = (struct ctdb_client_notify_deregister *)indata.dptr; - struct ctdb_client *client = ctdb_reqid_find(ctdb, client_id, struct ctdb_client); + struct ctdb_client *client = reqid_find(ctdb->idr, client_id, struct ctdb_client); struct ctdb_client_notify_list *nl; DEBUG(DEBUG_INFO,("Deregister srvid %llu for client %d\n", (unsigned long long)notify->srvid, client_id)); diff --git a/ctdb/server/ctdb_ltdb_server.c b/ctdb/server/ctdb_ltdb_server.c index b387adb..93e9041 100644 --- a/ctdb/server/ctdb_ltdb_server.c +++ b/ctdb/server/ctdb_ltdb_server.c @@ -28,6 +28,7 @@ #include "lib/tdb_wrap/tdb_wrap.h" #include "lib/util/dlinklist.h" #include +#include "common/reqid.h" #define PERSISTENT_HEALTH_TDB "persistent_health.tdb" @@ -1096,7 +1097,7 @@ int32_t ctdb_control_db_attach(struct ctdb_context *ctdb, TDB_DATA indata, * recovery daemons. */ if (client_id != 0) { - client = ctdb_reqid_find(ctdb, client_id, struct ctdb_client); + client = reqid_find(ctdb->idr, client_id, struct ctdb_client); } if (client != NULL) { /* If the node is inactive it is not part of the cluster @@ -1236,7 +1237,7 @@ int32_t ctdb_control_db_detach(struct ctdb_context *ctdb, TDB_DATA indata, * Do the actual detach only if the control comes from other daemons. */ if (client_id != 0) { - client = ctdb_reqid_find(ctdb, client_id, struct ctdb_client); + client = reqid_find(ctdb->idr, client_id, struct ctdb_client); if (client != NULL) { /* forward the control to all the nodes */ ctdb_daemon_send_control(ctdb, CTDB_BROADCAST_ALL, 0, diff --git a/ctdb/server/ctdb_persistent.c b/ctdb/server/ctdb_persistent.c index 5c54b9e..759421f 100644 --- a/ctdb/server/ctdb_persistent.c +++ b/ctdb/server/ctdb_persistent.c @@ -24,6 +24,7 @@ #include "lib/tdb_wrap/tdb_wrap.h" #include "tdb.h" #include "../include/ctdb_private.h" +#include "common/reqid.h" struct ctdb_persistent_state { struct ctdb_context *ctdb; @@ -174,7 +175,7 @@ int32_t ctdb_control_trans3_commit(struct ctdb_context *ctdb, return -1; } - client = ctdb_reqid_find(ctdb, c->client_id, struct ctdb_client); + client = reqid_find(ctdb->idr, c->client_id, struct ctdb_client); if (client == NULL) { DEBUG(DEBUG_ERR,(__location__ " can not match persistent_store " "to a client. Returning error\n")); @@ -277,7 +278,7 @@ int32_t ctdb_control_start_persistent_update(struct ctdb_context *ctdb, struct ctdb_req_control *c, TDB_DATA recdata) { - struct ctdb_client *client = ctdb_reqid_find(ctdb, c->client_id, struct ctdb_client); + struct ctdb_client *client = reqid_find(ctdb->idr, c->client_id, struct ctdb_client); if (client == NULL) { DEBUG(DEBUG_ERR,(__location__ " can not match start_persistent_update to a client. Returning error\n")); @@ -298,7 +299,7 @@ int32_t ctdb_control_cancel_persistent_update(struct ctdb_context *ctdb, struct ctdb_req_control *c, TDB_DATA recdata) { - struct ctdb_client *client = ctdb_reqid_find(ctdb, c->client_id, struct ctdb_client); + struct ctdb_client *client = reqid_find(ctdb->idr, c->client_id, struct ctdb_client); if (client == NULL) { DEBUG(DEBUG_ERR,(__location__ " can not match cancel_persistent_update to a client. Returning error\n")); diff --git a/ctdb/server/ctdb_serverids.c b/ctdb/server/ctdb_serverids.c index dba25ed..d264a1f 100644 --- a/ctdb/server/ctdb_serverids.c +++ b/ctdb/server/ctdb_serverids.c @@ -19,6 +19,7 @@ #include "includes.h" #include "../include/ctdb_private.h" #include "../common/rb_tree.h" +#include "common/reqid.h" #define SERVER_ID_KEY_SIZE 3 @@ -58,7 +59,7 @@ int32_t ctdb_control_register_server_id(struct ctdb_context *ctdb, TDB_DATA indata) { struct ctdb_server_id *server_id; - struct ctdb_client *client = ctdb_reqid_find(ctdb, client_id, struct ctdb_client); + struct ctdb_client *client = reqid_find(ctdb->idr, client_id, struct ctdb_client); if (client == NULL) { diff --git a/ctdb/server/ctdb_takeover.c b/ctdb/server/ctdb_takeover.c index 2f4874b..098cfe7 100644 --- a/ctdb/server/ctdb_takeover.c +++ b/ctdb/server/ctdb_takeover.c @@ -26,6 +26,7 @@ #include "system/wait.h" #include "../include/ctdb_private.h" #include "../common/rb_tree.h" +#include "common/reqid.h" #define TAKEOVER_TIMEOUT() timeval_current_ofs(ctdb->tunable.takeover_timeout,0) @@ -820,9 +821,9 @@ static void release_kill_clients(struct ctdb_context *ctdb, ctdb_sock_addr *addr ctdb_addr_to_str(&ip->addr))); if (ctdb_same_ip(&tmp_addr, addr)) { - struct ctdb_client *client = ctdb_reqid_find(ctdb, - ip->client_id, - struct ctdb_client); + struct ctdb_client *client = reqid_find(ctdb->idr, + ip->client_id, + struct ctdb_client); DEBUG(DEBUG_INFO,("matched client %u with IP %s and pid %u\n", ip->client_id, ctdb_addr_to_str(&ip->addr), @@ -2799,7 +2800,7 @@ static int ctdb_client_ip_destructor(struct ctdb_client_ip *ip) int32_t ctdb_control_tcp_client(struct ctdb_context *ctdb, uint32_t client_id, TDB_DATA indata) { - struct ctdb_client *client = ctdb_reqid_find(ctdb, client_id, struct ctdb_client); + struct ctdb_client *client = reqid_find(ctdb->idr, client_id, struct ctdb_client); struct ctdb_control_tcp_addr *tcp_sock = NULL; struct ctdb_tcp_list *tcp; struct ctdb_tcp_connection t; diff --git a/ctdb/server/ctdb_traverse.c b/ctdb/server/ctdb_traverse.c index 939e534..88528c5 100644 --- a/ctdb/server/ctdb_traverse.c +++ b/ctdb/server/ctdb_traverse.c @@ -24,6 +24,7 @@ #include "tdb.h" #include "../include/ctdb_private.h" #include "lib/util/dlinklist.h" +#include "common/reqid.h" typedef void (*ctdb_traverse_fn_t)(void *private_data, TDB_DATA key, TDB_DATA data); @@ -286,7 +287,7 @@ struct ctdb_traverse_all_handle { */ static int ctdb_traverse_all_destructor(struct ctdb_traverse_all_handle *state) { - ctdb_reqid_remove(state->ctdb, state->reqid); + reqid_remove(state->ctdb->idr, state->reqid); return 0; } @@ -360,7 +361,7 @@ static struct ctdb_traverse_all_handle *ctdb_daemon_traverse_all(struct ctdb_db_ state->ctdb = ctdb; state->ctdb_db = ctdb_db; - state->reqid = ctdb_reqid_new(ctdb_db->ctdb, state); + state->reqid = reqid_new(ctdb_db->ctdb->idr, state); state->callback = callback; state->private_data = start_state; state->null_count = 0; @@ -574,7 +575,7 @@ int32_t ctdb_control_traverse_data(struct ctdb_context *ctdb, TDB_DATA data, TDB return -1; } - state = ctdb_reqid_find(ctdb, d->reqid, struct ctdb_traverse_all_handle); + state = reqid_find(ctdb->idr, d->reqid, struct ctdb_traverse_all_handle); if (state == NULL || d->reqid != state->reqid) { /* traverse might have been terminated already */ return -1; @@ -707,7 +708,7 @@ int32_t ctdb_control_traverse_start_ext(struct ctdb_context *ctdb, struct ctdb_traverse_start_ext *d = (struct ctdb_traverse_start_ext *)data.dptr; struct traverse_start_state *state; struct ctdb_db_context *ctdb_db; - struct ctdb_client *client = ctdb_reqid_find(ctdb, client_id, struct ctdb_client); + struct ctdb_client *client = reqid_find(ctdb->idr, client_id, struct ctdb_client); if (client == NULL) { DEBUG(DEBUG_ERR,(__location__ " No client found\n")); diff --git a/ctdb/server/ctdbd.c b/ctdb/server/ctdbd.c index ec285c0..d057ed6 100644 --- a/ctdb/server/ctdbd.c +++ b/ctdb/server/ctdbd.c @@ -25,6 +25,7 @@ #include "system/network.h" #include "cmdline.h" #include "../include/ctdb_private.h" +#include "common/reqid.h" static struct { const char *nlist; @@ -185,9 +186,14 @@ int main(int argc, const char *argv[]) ctdb->recovery_mode = CTDB_RECOVERY_NORMAL; ctdb->recovery_master = (uint32_t)-1; ctdb->upcalls = &ctdb_upcalls; - ctdb->idr = idr_init(ctdb); ctdb->recovery_lock_fd = -1; + ret = reqid_init(ctdb, 0, &ctdb->idr);; + if (ret != 0) { + DEBUG(DEBUG_ALERT, ("reqid_init failed (%s)\n", strerror(ret))); + exit(1); + } + ctdb_tunables_set_defaults(ctdb); ret = ctdb_set_recovery_lock_file(ctdb, options.recovery_lock_file); diff --git a/ctdb/tests/src/ctdb_test.c b/ctdb/tests/src/ctdb_test.c index 3a3b2a7..1ebd02b 100644 --- a/ctdb/tests/src/ctdb_test.c +++ b/ctdb/tests/src/ctdb_test.c @@ -179,6 +179,7 @@ ctdb_get_capabilities(struct ctdb_context *ctdb, #include "common/ctdb_logging.c" #include "common/ctdb_fork.c" #include "common/system_util.c" +#include "common/reqid.c" /* CTDB_CLIENT_OBJ */ #include "client/ctdb_client.c" diff --git a/ctdb/tests/src/ctdbd_test.c b/ctdb/tests/src/ctdbd_test.c index d505267..6a81cbd 100644 --- a/ctdb/tests/src/ctdbd_test.c +++ b/ctdb/tests/src/ctdbd_test.c @@ -42,6 +42,7 @@ bool fast_start; #include "common/ctdb_logging.c" #include "common/ctdb_fork.c" #include "common/system_util.c" +#include "common/reqid.c" /* CTDB_SERVER_OBJ */ #include "server/ctdb_daemon.c" From 100917b169765821bc79ef322663948c5edd34ca Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Tue, 8 Sep 2015 17:58:25 +1000 Subject: [PATCH 052/136] ctdb-packaging: Install header files in ctdb subdirectory Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/packaging/RPM/ctdb.spec.in | 1 + 1 file changed, 1 insertion(+) diff --git a/ctdb/packaging/RPM/ctdb.spec.in b/ctdb/packaging/RPM/ctdb.spec.in index d9d4125..1bdae58 100644 --- a/ctdb/packaging/RPM/ctdb.spec.in +++ b/ctdb/packaging/RPM/ctdb.spec.in @@ -95,6 +95,7 @@ CFLAGS="$RPM_OPT_FLAGS $EXTRA -D_GNU_SOURCE" ./buildtools/bin/waf configure \ --enable-pmda \ %endif --prefix=%{_prefix} \ + --includedir=%{_includedir}/ctdb \ --libdir=%{_libdir} \ --sysconfdir=%{_sysconfdir} \ --mandir=%{_mandir} \ From 9c16fe43fc37d0804e5a0337726fccf4e1ab73f3 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Tue, 8 Sep 2015 18:15:35 +1000 Subject: [PATCH 053/136] ctdb-build: Set PKGCONFIGDIR for public libraries in standalone build Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/wscript | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ctdb/wscript b/ctdb/wscript index 467b51e..d075ad0 100755 --- a/ctdb/wscript +++ b/ctdb/wscript @@ -260,6 +260,8 @@ def build(bld): dep_vars=['VERSION']) t.env.VERSION = VERSION + bld.env.PKGCONFIGDIR = '${LIBDIR}/pkgconfig' + bld.RECURSE('lib/replace') if bld.CHECK_FOR_THIRD_PARTY(): bld.RECURSE('third_party/popt') From 670db6ac1d678babd25dd82c4467c0f094cfabc5 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Tue, 8 Sep 2015 10:34:21 +1000 Subject: [PATCH 054/136] lib/util: Create a new library for tevent_unix.c This is required for ctdb. This avoids adding dependency on wstatus and ntstatus to ctdb build. Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- lib/util/wscript_build | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/util/wscript_build b/lib/util/wscript_build index 47d64c1..e3bf073 100755 --- a/lib/util/wscript_build +++ b/lib/util/wscript_build @@ -69,6 +69,15 @@ bld.SAMBA_SUBSYSTEM('samba-util-core', tevent execinfo pthread''', local_include=False) +bld.SAMBA_LIBRARY('tevent-unix-util', + source='tevent_unix.c', + local_include=False, + deps='tevent', + public_headers='tevent_unix.h', + header_path=[ ('*', 'util') ], + pc_files=[], + vnum='0.0.1') + if not bld.env.SAMBA_UTIL_CORE_ONLY: bld.env.public_headers_skip.append('charset_compat.h') @@ -127,10 +136,10 @@ if not bld.env.SAMBA_UTIL_CORE_ONLY: ) bld.SAMBA_LIBRARY('tevent-util', - source='tevent_unix.c tevent_ntstatus.c tevent_werror.c', + source='tevent_ntstatus.c tevent_werror.c', local_include=False, - public_deps='tevent errors', - public_headers='tevent_ntstatus.h tevent_unix.h tevent_werror.h', + public_deps='tevent errors tevent-unix-util', + public_headers='tevent_ntstatus.h tevent_werror.h', header_path=[ ('*', 'util') ], pc_files=[], vnum='0.0.1' From 606b909310fc49a5f793c5031372a08c3848685b Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Tue, 8 Sep 2015 18:16:08 +1000 Subject: [PATCH 055/136] ctdb-build: Placeholder for public headers from lib/util Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/include/public/util/README.txt | 6 ++++++ ctdb/wscript | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 ctdb/include/public/util/README.txt diff --git a/ctdb/include/public/util/README.txt b/ctdb/include/public/util/README.txt new file mode 100644 index 0000000..534e9b7 --- /dev/null +++ b/ctdb/include/public/util/README.txt @@ -0,0 +1,6 @@ +DO NOT REMOVE + +This is a placeholder to allow for build rules putting public headers +in this directory. Using this directory allows us to ensure that our +public headers will work with external applications that make use of +Samba libraries diff --git a/ctdb/wscript b/ctdb/wscript index d075ad0..12779bc 100755 --- a/ctdb/wscript +++ b/ctdb/wscript @@ -213,7 +213,7 @@ def configure(conf): # Allow unified compilation and separate compilation of utilities # to find includes if not conf.env.standalone_ctdb: - conf.ADD_EXTRA_INCLUDES('#ctdb/include') + conf.ADD_EXTRA_INCLUDES('#include/public #ctdb/include') else: if srcdir == '.': # Building from tarball From facd3c864e0a2db29e6b838389111ba731e02078 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Tue, 8 Sep 2015 17:58:54 +1000 Subject: [PATCH 056/136] ctdb-packaging: Package public library and header for tevent-unix-util Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/packaging/RPM/ctdb.spec.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ctdb/packaging/RPM/ctdb.spec.in b/ctdb/packaging/RPM/ctdb.spec.in index 1bdae58..5db2e3a 100644 --- a/ctdb/packaging/RPM/ctdb.spec.in +++ b/ctdb/packaging/RPM/ctdb.spec.in @@ -204,6 +204,7 @@ rm -rf $RPM_BUILD_ROOT %{_bindir}/onnode %dir %{_libdir} %{_libdir}/ctdb/lib* +%{_libdir}/libtevent-unix-util.so.0* %{_mandir}/man1/ctdb.1.gz %{_mandir}/man1/ctdbd.1.gz %{_mandir}/man1/ctdbd_wrapper.1.gz @@ -226,6 +227,8 @@ development libraries for ctdb %files devel %defattr(-,root,root) +%{_includedir}/ctdb/util/*.h +%{_libdir}/libtevent-unix-util.so %package tests Summary: CTDB test suite From c77d3bb183a6e8109db8e4f5494adf899b01ccea Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Wed, 2 Sep 2015 22:32:50 +1000 Subject: [PATCH 057/136] ctdb-common: Add packet read abstraction Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/common/pkt_read.c | 190 ++++++++++++++++++++++++++++++ ctdb/common/pkt_read.h | 98 ++++++++++++++++ ctdb/tests/cunit/pkt_read_001.sh | 7 ++ ctdb/tests/src/pkt_read_test.c | 242 +++++++++++++++++++++++++++++++++++++++ ctdb/wscript | 8 +- 5 files changed, 542 insertions(+), 3 deletions(-) create mode 100644 ctdb/common/pkt_read.c create mode 100644 ctdb/common/pkt_read.h create mode 100755 ctdb/tests/cunit/pkt_read_001.sh create mode 100644 ctdb/tests/src/pkt_read_test.c diff --git a/ctdb/common/pkt_read.c b/ctdb/common/pkt_read.c new file mode 100644 index 0000000..212ace5 --- /dev/null +++ b/ctdb/common/pkt_read.c @@ -0,0 +1,190 @@ +/* + Reading packets using fixed and dynamic buffer + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +/* This is similar to read_packet abstraction. The main different is that + * tevent fd event is created only once. + */ + +#include "replace.h" +#include "system/network.h" + +#include +#include + +#include "lib/util/tevent_unix.h" + +#include "pkt_read.h" + +/* + * Read a packet using fixed buffer + */ + +struct pkt_read_state { + int fd; + uint8_t *buf; + size_t buflen; + size_t nread, total; + bool use_fixed; + ssize_t (*more)(uint8_t *buf, size_t buflen, void *private_data); + void *private_data; +}; + +struct tevent_req *pkt_read_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + int fd, size_t initial, + uint8_t *buf, size_t buflen, + ssize_t (*more)(uint8_t *buf, + size_t buflen, + void *private_data), + void *private_data) +{ + struct tevent_req *req; + struct pkt_read_state *state; + + req = tevent_req_create(mem_ctx, &state, struct pkt_read_state); + if (req == NULL) { + return NULL; + } + + state->fd = fd; + + if (buf == NULL || buflen == 0) { + state->use_fixed = false; + state->buf = talloc_array(state, uint8_t, initial); + if (state->buf == NULL) { + talloc_free(req); + return NULL; + } + state->buflen = initial; + } else { + state->use_fixed = true; + state->buf = buf; + state->buflen = buflen; + } + + state->nread = 0; + state->total = initial; + + state->more = more; + state->private_data = private_data; + + return req; +} + +void pkt_read_handler(struct tevent_context *ev, struct tevent_fd *fde, + uint16_t flags, struct tevent_req *req) +{ + struct pkt_read_state *state = tevent_req_data( + req, struct pkt_read_state); + ssize_t nread, more; + uint8_t *tmp; + + nread = read(state->fd, state->buf + state->nread, + state->total - state->nread); + if ((nread == -1) && (errno == EINTR)) { + /* retry */ + return; + } + if (nread == -1) { + tevent_req_error(req, errno); + return; + } + if (nread == 0) { + /* fd closed */ + tevent_req_error(req, EPIPE); + return; + } + + state->nread += nread; + if (state->nread < state->total) { + /* come back later */ + return; + } + + /* Check if "more" asks for more data */ + if (state->more == NULL) { + tevent_req_done(req); + return; + } + + more = state->more(state->buf, state->nread, state->private_data); + if (more == -1) { + /* invalid packet */ + tevent_req_error(req, EIO); + return; + } + if (more == 0) { + tevent_req_done(req); + return; + } + + if (state->total + more < state->total) { + /* int wrapped */ + tevent_req_error(req, EMSGSIZE); + return; + } + + if (state->total + more < state->buflen) { + /* continue using fixed buffer */ + state->total += more; + return; + } + + if (state->use_fixed) { + /* switch to dynamic buffer */ + tmp = talloc_array(state, uint8_t, state->total + more); + if (tevent_req_nomem(tmp, req)) { + return; + } + + memcpy(tmp, state->buf, state->total); + state->use_fixed = false; + } else { + tmp = talloc_realloc(state, state->buf, uint8_t, + state->total + more); + if (tevent_req_nomem(tmp, req)) { + return; + } + } + + state->buf = tmp; + state->buflen = state->total + more; + state->total += more; +} + +ssize_t pkt_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + uint8_t **pbuf, bool *free_buf, int *perrno) +{ + struct pkt_read_state *state = tevent_req_data( + req, struct pkt_read_state); + + if (tevent_req_is_unix_error(req, perrno)) { + return -1; + } + + if (state->use_fixed) { + *pbuf = state->buf; + *free_buf = false; + } else { + *pbuf = talloc_steal(mem_ctx, state->buf); + *free_buf = true; + } + + return state->total; +} diff --git a/ctdb/common/pkt_read.h b/ctdb/common/pkt_read.h new file mode 100644 index 0000000..25d4a51 --- /dev/null +++ b/ctdb/common/pkt_read.h @@ -0,0 +1,98 @@ +/* + API for reading packets using fixed and dynamic buffer + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#ifndef __CTDB_PKT_READ_H__ +#define __CTDB_PKT_READ_H__ + +#include +#include + +/** + * @file pkt_read.h + * + * @brief Read a packet using fixed size buffer or allocated memory. + * + * CTDB communication uses lots of small packets. This abstraction avoids the + * need to allocate memory for small packets. Only if the received packet is + * larger than the fixed memory buffer, use talloc to allocate memory. + */ + +/** + * @brief Start async computation to read a packet + * + * This returns a tevent request to read a packet from given fd. The fd + * should be nonblocking. Freeing this request will free all the memory + * associated with the request. + * + * @param[in] mem_ctx Talloc memory context + * @param[in] ev Tevent context + * @param[in] fd The non-blocking file/socket descriptor to read from + * @param[in] initial Initial amount of data to read + * @param[in] buf The static buffer to read data in + * @param[in] buflen The size of the static buffer + * @param[in] more The function to check if the bytes read forms a packet + * @param[in] private_data Private data to pass to more function + * @return new tevent request or NULL on failure + */ +struct tevent_req *pkt_read_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + int fd, size_t initial, + uint8_t *buf, size_t buflen, + ssize_t (*more)(uint8_t *buf, + size_t buflen, + void *private_data), + void *private_data); + +/** + * @brief Function to actually read data from the socket + * + * This function should be called, when tevent fd event is triggered. This + * function has the syntax of tevent_fd_handler_t. The private_data for this + * function is the tevent request created by pkt_read_send function. + * + * @param[in] ev Tevent context + * @param[in] fde Tevent fd context + * @param[in] flags Tevent fd flags + * @param[in] req The active tevent request + */ +void pkt_read_handler(struct tevent_context *ev, struct tevent_fd *fde, + uint16_t flags, struct tevent_req *req); + +/** + * @brief Retrieve a packet + * + * This function returns the pkt read from fd. + * + * @param[in] req Tevent request + * @param[in] mem_ctx Talloc memory context + * @param[out] pbuf The pointer to the buffer + * @param[out] free_buf Boolean to indicate that caller should free buffer + * @param[out] perrno errno in case of failure + * @return the size of the pkt, or -1 on failure + * + * If the pkt data is dynamically allocated, then it is moved under the + * specified talloc memory context and free_buf is set to true. It is the + * responsibility of the caller to the free the memory returned. + * + * If the pkt data is stored in the fixed buffer, then free_buf is set to false. + */ +ssize_t pkt_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + uint8_t **pbuf, bool *free_buf, int *perrno); + +#endif /* __CTDB_PKT_READ_H__ */ diff --git a/ctdb/tests/cunit/pkt_read_001.sh b/ctdb/tests/cunit/pkt_read_001.sh new file mode 100755 index 0000000..c951f39 --- /dev/null +++ b/ctdb/tests/cunit/pkt_read_001.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +. "${TEST_SCRIPTS_DIR}/unit.sh" + +ok_null + +unit_test pkt_read_test diff --git a/ctdb/tests/src/pkt_read_test.c b/ctdb/tests/src/pkt_read_test.c new file mode 100644 index 0000000..6dfd5a0 --- /dev/null +++ b/ctdb/tests/src/pkt_read_test.c @@ -0,0 +1,242 @@ +/* + packet read tests + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include "replace.h" +#include "system/filesys.h" + +#include + +#include "common/pkt_read.c" + +static void writer(int fd) +{ + uint8_t buf[1024*1024]; + size_t buflen; + size_t pkt_size[4] = { 100, 500, 1024, 1024*1024 }; + int i, j; + int ret; + + for (i=0; i<1024*1024; i++) { + buf[i] = i%256; + } + + for (i=0; i<1000; i++) { + for (j=0; j<4; j++) { + buflen = pkt_size[j]; + *(uint32_t *)buf = buflen; + + ret = write(fd, buf, buflen); + if (ret < 0) { + printf("write error: %s\n", strerror(errno)); + assert(ret > 0); + } + } + } + + close(fd); +} + +struct reader_state { + struct tevent_context *ev; + int fd; + uint8_t buf[1024]; + struct tevent_req *subreq; +}; + +static ssize_t reader_more(uint8_t *buf, size_t buflen, void *private_data); +static void reader_done(struct tevent_req *subreq); + +static struct tevent_req *reader_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + int fd) +{ + struct tevent_req *req, *subreq; + struct reader_state *state; + + req = tevent_req_create(mem_ctx, &state, struct reader_state); + if (req == NULL) { + return NULL; + } + + state->ev = ev; + state->fd = fd; + + subreq = pkt_read_send(state, state->ev, state->fd, 4, + state->buf, 1024, reader_more, NULL); + if (tevent_req_nomem(subreq, req)) { + tevent_req_post(req, ev); + } + + state->subreq = subreq; + tevent_req_set_callback(subreq, reader_done, req); + return req; +} + +static ssize_t reader_more(uint8_t *buf, size_t buflen, void *private_data) +{ + uint32_t pkt_len; + + if (buflen < sizeof(pkt_len)) { + return sizeof(pkt_len) - buflen; + } + + pkt_len = *(uint32_t *)buf; + return pkt_len - buflen; +} + +static void reader_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct reader_state *state = tevent_req_data( + req, struct reader_state); + ssize_t nread; + uint8_t *buf; + bool free_buf; + int err; + + nread = pkt_read_recv(subreq, state, &buf, &free_buf, &err); + TALLOC_FREE(subreq); + state->subreq = NULL; + if (nread == -1) { + if (err == EPIPE) { + tevent_req_done(req); + } else { + tevent_req_error(req, err); + } + return; + } + + if (free_buf) { + talloc_free(buf); + } + + subreq = pkt_read_send(state, state->ev, state->fd, 4, + state->buf, 1024, reader_more, NULL); + if (tevent_req_nomem(subreq, req)) { + return; + } + + state->subreq = subreq; + tevent_req_set_callback(subreq, reader_done, req); +} + +static void reader_recv(struct tevent_req *req, int *perr) +{ + struct reader_state *state = tevent_req_data( + req, struct reader_state); + int err = 0; + + if (state->subreq != NULL) { + *perr = -1; + } + + if (tevent_req_is_unix_error(req, &err)) { + *perr = err; + return; + } + + *perr = 0; +} + +static void reader_handler(struct tevent_context *ev, struct tevent_fd *fde, + uint16_t flags, void *private_data) +{ + struct tevent_req *req = talloc_get_type_abort( + private_data, struct tevent_req); + struct reader_state *state = tevent_req_data( + req, struct reader_state); + + assert(state->subreq != NULL); + pkt_read_handler(ev, fde, flags, state->subreq); +} + +static void reader(int fd) +{ + TALLOC_CTX *mem_ctx; + struct tevent_context *ev; + struct tevent_fd *fde; + struct tevent_req *req; + int err; + + mem_ctx = talloc_new(NULL); + assert(mem_ctx != NULL); + + ev = tevent_context_init(mem_ctx); + assert(ev != NULL); + + req = reader_send(mem_ctx, ev, fd); + assert(req != NULL); + + fde = tevent_add_fd(ev, mem_ctx, fd, TEVENT_FD_READ, + reader_handler, req); + assert(fde != NULL); + + tevent_req_poll(req, ev); + + reader_recv(req, &err); + assert(err == 0); + + close(fd); + + talloc_free(mem_ctx); +} + +static bool set_nonblocking(int fd) +{ + int v; + + v = fcntl(fd, F_GETFL, 0); + if (v == -1) { + return false; + } + if (fcntl(fd, F_SETFL, v | O_NONBLOCK) == -1) { + return false; + } + return true; +} + +int main(void) +{ + int fd[2]; + int ret; + pid_t pid; + + ret = pipe(fd); + assert(ret == 0); + + pid = fork(); + assert(pid != -1); + + if (pid == 0) { + /* Child process */ + close(fd[0]); + writer(fd[1]); + exit(0); + } + + close(fd[1]); + if (!set_nonblocking(fd[0])) { + exit(1); + } + + reader(fd[0]); + + return 0; +} diff --git a/ctdb/wscript b/ctdb/wscript index 12779bc..a4523d8 100755 --- a/ctdb/wscript +++ b/ctdb/wscript @@ -335,8 +335,9 @@ def build(bld): bld.SAMBA_SUBSYSTEM('ctdb-util', source=bld.SUBDIR('common', - '''db_hash.c srvid.c reqid.c'''), - deps='replace talloc tevent tdb') + '''db_hash.c srvid.c reqid.c + pkt_read.c'''), + deps='replace talloc tevent tdb tevent-unix-util') bld.SAMBA_SUBSYSTEM('ctdb-client', source=bld.SUBDIR('client', 'ctdb_client.c'), @@ -577,6 +578,7 @@ def build(bld): ctdb_unit_tests = [ 'db_hash_test', 'srvid_test', + 'pkt_read_test', ] for target in ctdb_unit_tests: @@ -584,7 +586,7 @@ def build(bld): bld.SAMBA_BINARY(target, source=src, - deps='talloc tevent tdb', + deps='talloc tevent tdb tevent-unix-util', install_path='${CTDB_TEST_LIBDIR}') bld.SAMBA_BINARY('reqid_test', From e01c0eed38335e7b421ab4f79410f08ab1d31482 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Mon, 6 Apr 2015 17:26:29 +1000 Subject: [PATCH 058/136] ctdb-common: Add packet write abstraction Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/common/pkt_write.c | 101 +++++++++++ ctdb/common/pkt_write.h | 79 ++++++++ ctdb/tests/cunit/pkt_write_001.sh | 7 + ctdb/tests/src/pkt_write_test.c | 370 ++++++++++++++++++++++++++++++++++++++ ctdb/wscript | 3 +- 5 files changed, 559 insertions(+), 1 deletion(-) create mode 100644 ctdb/common/pkt_write.c create mode 100644 ctdb/common/pkt_write.h create mode 100755 ctdb/tests/cunit/pkt_write_001.sh create mode 100644 ctdb/tests/src/pkt_write_test.c diff --git a/ctdb/common/pkt_write.c b/ctdb/common/pkt_write.c new file mode 100644 index 0000000..b1c1730 --- /dev/null +++ b/ctdb/common/pkt_write.c @@ -0,0 +1,101 @@ +/* + Write a packet + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include "replace.h" +#include "system/network.h" + +#include +#include + +#include "lib/util/tevent_unix.h" + +#include "pkt_write.h" + +/* + * Write a packet + */ + +struct pkt_write_state { + int fd; + uint8_t *buf; + size_t buflen, offset; +}; + +struct tevent_req *pkt_write_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + int fd, uint8_t *buf, size_t buflen) +{ + struct tevent_req *req; + struct pkt_write_state *state; + + req = tevent_req_create(mem_ctx, &state, struct pkt_write_state); + if (req == NULL) { + return NULL; + } + + state->fd = fd; + state->buf = buf; + state->buflen = buflen; + state->offset = 0; + + return req; +} + +void pkt_write_handler(struct tevent_context *ev, struct tevent_fd *fde, + uint16_t flags, struct tevent_req *req) +{ + struct pkt_write_state *state = tevent_req_data( + req, struct pkt_write_state); + ssize_t nwritten; + + nwritten = write(state->fd, state->buf + state->offset, + state->buflen - state->offset); + if ((nwritten == -1) && (errno == EINTR)) { + /* retry */ + return; + } + if (nwritten == -1) { + tevent_req_error(req, errno); + return; + } + if (nwritten == 0) { + /* retry */ + return; + } + + state->offset += nwritten; + if (state->offset < state->buflen) { + /* come back later */ + return; + } + + tevent_req_done(req); +} + +ssize_t pkt_write_recv(struct tevent_req *req, int *perrno) +{ + struct pkt_write_state *state = tevent_req_data( + req, struct pkt_write_state); + + if (tevent_req_is_unix_error(req, perrno)) { + return -1; + } + + return state->offset; +} diff --git a/ctdb/common/pkt_write.h b/ctdb/common/pkt_write.h new file mode 100644 index 0000000..19d8045 --- /dev/null +++ b/ctdb/common/pkt_write.h @@ -0,0 +1,79 @@ +/* + API for writing a packet + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#ifndef __CTDB_PKT_WRITE_H__ +#define __CTDB_PKT_WRITE_H__ + +#include +#include + +/** + * @file pkt_write.h + * + * @brief Write a packet. + * + * Write a complete packet with possibly multiple system calls. + */ + +/** + * @brief Start async computation to write a packet + * + * This returns a tevent request to write a packet to given fd. The fd + * should be nonblocking. Freeing this request will free all the memory + * associated with the request. + * + * @param[in] mem_ctx Talloc memory context + * @param[in] ev Tevent context + * @param[in] fd The non-blocking file/socket descriptor to write to + * @param[in] buf The data + * @param[in] buflen The size of the data + * @return new tevent request or NULL on failure + */ +struct tevent_req *pkt_write_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + int fd, uint8_t *buf, size_t buflen); + +/** + * @brief Function to actually write data to the socket + * + * This function should be called, when tevent fd event is triggered + * for TEVENT_FD_WRITE event. This function has the syntax of + * tevent_fd_handler_t. The private_data for this function is the tevent + * request created by pkt_write_send function. + * + * @param[in] ev Tevent context + * @param[in] fde Tevent fd context + * @param[in] flags Tevent fd flags + * @param[in] req The active tevent request + */ +void pkt_write_handler(struct tevent_context *ev, struct tevent_fd *fde, + uint16_t flags, struct tevent_req *req); + +/** + * @brief Packet is sent + * + * This function returns the number of bytes written. + * + * @param[in] req Tevent request + * @param[out] perrno errno in case of failure + * @return the number of bytes written, or -1 on failure + */ +ssize_t pkt_write_recv(struct tevent_req *req, int *perrno); + +#endif /* __CTDB_PKT_WRITE_H__ */ diff --git a/ctdb/tests/cunit/pkt_write_001.sh b/ctdb/tests/cunit/pkt_write_001.sh new file mode 100755 index 0000000..131af05 --- /dev/null +++ b/ctdb/tests/cunit/pkt_write_001.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +. "${TEST_SCRIPTS_DIR}/unit.sh" + +ok_null + +unit_test pkt_write_test diff --git a/ctdb/tests/src/pkt_write_test.c b/ctdb/tests/src/pkt_write_test.c new file mode 100644 index 0000000..0a5c654 --- /dev/null +++ b/ctdb/tests/src/pkt_write_test.c @@ -0,0 +1,370 @@ +/* + packet write tests + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include "replace.h" +#include "system/filesys.h" + +#include + +#include "common/pkt_read.c" +#include "common/pkt_write.c" + +struct writer_state { + struct tevent_context *ev; + int fd; + uint8_t *buf; + size_t buflen; + int count; + struct tevent_req *subreq; +}; + +static void writer_next(struct tevent_req *subreq); + +static struct tevent_req *writer_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + int fd, uint8_t *buf, size_t buflen) +{ + struct tevent_req *req, *subreq; + struct writer_state *state; + + req = tevent_req_create(mem_ctx, &state, struct writer_state); + if (req == NULL) { + return NULL; + } + + state->ev = ev; + state->fd = fd; + state->buf = buf; + state->buflen = buflen; + state->count = 0; + + subreq = pkt_write_send(state, state->ev, state->fd, + state->buf, state->buflen); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + + state->subreq = subreq; + tevent_req_set_callback(subreq, writer_next, req); + return req; +} + +static void writer_next(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct writer_state *state = tevent_req_data( + req, struct writer_state); + ssize_t nwritten; + int err = 0; + + nwritten = pkt_write_recv(subreq, &err); + TALLOC_FREE(subreq); + state->subreq = NULL; + if (nwritten == -1) { + tevent_req_error(req, err); + return; + } + + if (nwritten != state->buflen) { + tevent_req_error(req, EIO); + return; + } + + state->count++; + if (state->count >= 1000) { + tevent_req_done(req); + return; + } + + subreq = pkt_write_send(state, state->ev, state->fd, + state->buf, state->buflen); + if (tevent_req_nomem(subreq, req)) { + return; + } + + state->subreq = subreq; + tevent_req_set_callback(subreq, writer_next, req); +} + +static void writer_recv(struct tevent_req *req, int *perr) +{ + struct writer_state *state = tevent_req_data( + req, struct writer_state); + int err = 0; + + if (state->subreq != NULL) { + *perr = -1; + return; + } + + if (tevent_req_is_unix_error(req, &err)) { + *perr = err; + return; + } + + *perr = 0; +} + +static void writer_handler(struct tevent_context *ev, struct tevent_fd *fde, + uint16_t flags, void *private_data) +{ + struct tevent_req *req = talloc_get_type_abort( + private_data, struct tevent_req); + struct writer_state *state = tevent_req_data( + req, struct writer_state); + + assert(state->subreq != NULL); + pkt_write_handler(ev, fde, flags, state->subreq); +} + +static void writer(int fd) +{ + TALLOC_CTX *mem_ctx; + struct tevent_context *ev; + struct tevent_fd *fde; + struct tevent_req *req; + uint8_t buf[1024*1024]; + size_t buflen; + size_t pkt_size[4] = { 100, 500, 1024, 1024*1024 }; + int i, err; + + mem_ctx = talloc_new(NULL); + assert(mem_ctx != NULL); + + ev = tevent_context_init(mem_ctx); + assert(ev != NULL); + + for (i=0; i<1024*1024; i++) { + buf[i] = i%256; + } + + for (i=0; i<4; i++) { + buflen = pkt_size[i]; + *(uint32_t *)buf = buflen; + + req = writer_send(mem_ctx, ev, fd, buf, buflen); + assert(req != NULL); + + fde = tevent_add_fd(ev, mem_ctx, fd, TEVENT_FD_WRITE, + writer_handler, req); + assert(fde != NULL); + + tevent_req_poll(req, ev); + + writer_recv(req, &err); + assert(err == 0); + + talloc_free(fde); + talloc_free(req); + } + + close(fd); + + talloc_free(mem_ctx); +} + +struct reader_state { + struct tevent_context *ev; + int fd; + uint8_t buf[1024]; + struct tevent_req *subreq; +}; + +static ssize_t reader_more(uint8_t *buf, size_t buflen, void *private_data); +static void reader_done(struct tevent_req *subreq); + +static struct tevent_req *reader_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + int fd) +{ + struct tevent_req *req, *subreq; + struct reader_state *state; + + req = tevent_req_create(mem_ctx, &state, struct reader_state); + if (req == NULL) { + return NULL; + } + + state->ev = ev; + state->fd = fd; + + subreq = pkt_read_send(state, state->ev, state->fd, 4, + state->buf, 1024, reader_more, NULL); + if (tevent_req_nomem(subreq, req)) { + tevent_req_post(req, ev); + } + + state->subreq = subreq; + tevent_req_set_callback(subreq, reader_done, req); + return req; +} + +static ssize_t reader_more(uint8_t *buf, size_t buflen, void *private_data) +{ + uint32_t pkt_len; + + if (buflen < sizeof(pkt_len)) { + return sizeof(pkt_len) - buflen; + } + + pkt_len = *(uint32_t *)buf; + return pkt_len - buflen; +} + +static void reader_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct reader_state *state = tevent_req_data( + req, struct reader_state); + ssize_t nread; + uint8_t *buf; + bool free_buf; + int err = 0; + + nread = pkt_read_recv(subreq, state, &buf, &free_buf, &err); + TALLOC_FREE(subreq); + state->subreq = NULL; + if (nread == -1) { + if (err == EPIPE) { + tevent_req_done(req); + } else { + tevent_req_error(req, err); + } + return; + } + + if (free_buf) { + talloc_free(buf); + } + + subreq = pkt_read_send(state, state->ev, state->fd, 4, + state->buf, 1024, reader_more, NULL); + if (tevent_req_nomem(subreq, req)) { + return; + } + + state->subreq = subreq; + tevent_req_set_callback(subreq, reader_done, req); +} + +static void reader_recv(struct tevent_req *req, int *perr) +{ + struct reader_state *state = tevent_req_data( + req, struct reader_state); + int err = 0; + + if (state->subreq != NULL) { + *perr = -1; + } + + if (tevent_req_is_unix_error(req, &err)) { + *perr = err; + return; + } + + *perr = 0; +} + +static void reader_handler(struct tevent_context *ev, struct tevent_fd *fde, + uint16_t flags, void *private_data) +{ + struct tevent_req *req = talloc_get_type_abort( + private_data, struct tevent_req); + struct reader_state *state = tevent_req_data( + req, struct reader_state); + + assert(state->subreq != NULL); + pkt_read_handler(ev, fde, flags, state->subreq); +} + +static void reader(int fd) +{ + TALLOC_CTX *mem_ctx; + struct tevent_context *ev; + struct tevent_fd *fde; + struct tevent_req *req; + int err; + + mem_ctx = talloc_new(NULL); + assert(mem_ctx != NULL); + + ev = tevent_context_init(mem_ctx); + assert(ev != NULL); + + req = reader_send(mem_ctx, ev, fd); + assert(req != NULL); + + fde = tevent_add_fd(ev, mem_ctx, fd, TEVENT_FD_READ, + reader_handler, req); + assert(fde != NULL); + + tevent_req_poll(req, ev); + + reader_recv(req, &err); + assert(err == 0); + + close(fd); + + talloc_free(mem_ctx); +} + +static bool set_nonblocking(int fd) +{ + int v; + + v = fcntl(fd, F_GETFL, 0); + if (v == -1) { + return false; + } + if (fcntl(fd, F_SETFL, v | O_NONBLOCK) == -1) { + return false; + } + return true; +} + +int main(void) +{ + int fd[2]; + int ret; + pid_t pid; + + ret = pipe(fd); + assert(ret == 0); + + pid = fork(); + assert(pid != -1); + + if (pid == 0) { + /* Child process */ + close(fd[0]); + writer(fd[1]); + exit(0); + } + + close(fd[1]); + if (!set_nonblocking(fd[0])) { + exit(1); + } + + reader(fd[0]); + + return 0; +} diff --git a/ctdb/wscript b/ctdb/wscript index a4523d8..454f03f 100755 --- a/ctdb/wscript +++ b/ctdb/wscript @@ -336,7 +336,7 @@ def build(bld): bld.SAMBA_SUBSYSTEM('ctdb-util', source=bld.SUBDIR('common', '''db_hash.c srvid.c reqid.c - pkt_read.c'''), + pkt_read.c pkt_write.c'''), deps='replace talloc tevent tdb tevent-unix-util') bld.SAMBA_SUBSYSTEM('ctdb-client', @@ -579,6 +579,7 @@ def build(bld): 'db_hash_test', 'srvid_test', 'pkt_read_test', + 'pkt_write_test', ] for target in ctdb_unit_tests: From 1543eedb8feaa85336216aa22df2145522425184 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Sat, 4 Apr 2015 20:23:44 +1100 Subject: [PATCH 059/136] ctdb-common: Add communication endpoint abstraction Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/common/comm.c | 404 ++++++++++++++++++++++++++++++++++++++ ctdb/common/comm.h | 101 ++++++++++ ctdb/tests/cunit/comm_test_001.sh | 7 + ctdb/tests/cunit/comm_test_002.sh | 24 +++ ctdb/tests/src/comm_client_test.c | 207 +++++++++++++++++++ ctdb/tests/src/comm_server_test.c | 363 ++++++++++++++++++++++++++++++++++ ctdb/tests/src/comm_test.c | 260 ++++++++++++++++++++++++ ctdb/wscript | 5 +- 8 files changed, 1370 insertions(+), 1 deletion(-) create mode 100644 ctdb/common/comm.c create mode 100644 ctdb/common/comm.h create mode 100755 ctdb/tests/cunit/comm_test_001.sh create mode 100755 ctdb/tests/cunit/comm_test_002.sh create mode 100644 ctdb/tests/src/comm_client_test.c create mode 100644 ctdb/tests/src/comm_server_test.c create mode 100644 ctdb/tests/src/comm_test.c diff --git a/ctdb/common/comm.c b/ctdb/common/comm.c new file mode 100644 index 0000000..1bbb460 --- /dev/null +++ b/ctdb/common/comm.c @@ -0,0 +1,404 @@ +/* + Communication endpoint implementation + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include "replace.h" +#include "system/network.h" +#include "system/filesys.h" + +#include +#include + +#include "lib/util/tevent_unix.h" + +#include "pkt_read.h" +#include "pkt_write.h" +#include "comm.h" + +static bool set_nonblocking(int fd) +{ + int v; + + v = fcntl(fd, F_GETFL, 0); + if (v == -1) { + return false; + } + if (fcntl(fd, F_SETFL, v | O_NONBLOCK) == -1) { + return false; + } + return true; +} + +/* + * Communication endpoint around a socket + */ + +#define SMALL_PKT_SIZE 1024 + +struct comm_context { + int fd; + comm_read_handler_fn read_handler; + void *read_private_data; + comm_dead_handler_fn dead_handler; + void *dead_private_data; + uint8_t small_pkt[SMALL_PKT_SIZE]; + struct tevent_req *read_req, *write_req; + struct tevent_fd *fde; + struct tevent_queue *queue; +}; + +static void comm_fd_handler(struct tevent_context *ev, + struct tevent_fd *fde, + uint16_t flags, void *private_data); +static struct tevent_req *comm_read_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct comm_context *comm, + uint8_t *buf, size_t buflen); +static void comm_read_failed(struct tevent_req *req); + + +int comm_setup(TALLOC_CTX *mem_ctx, struct tevent_context *ev, int fd, + comm_read_handler_fn read_handler, void *read_private_data, + comm_dead_handler_fn dead_handler, void *dead_private_data, + struct comm_context **result) +{ + struct comm_context *comm; + + if (fd < 0) { + return EINVAL; + } + + if (dead_handler == NULL) { + return EINVAL; + } + + /* Socket queue relies on non-blocking sockets. */ + if (!set_nonblocking(fd)) { + return EIO; + } + + comm = talloc_zero(mem_ctx, struct comm_context); + if (comm == NULL) { + return ENOMEM; + } + + comm->fd = fd; + comm->read_handler = read_handler; + comm->read_private_data = read_private_data; + comm->dead_handler = dead_handler; + comm->dead_private_data = dead_private_data; + + comm->queue = tevent_queue_create(comm, "comm write queue"); + if (comm->queue == NULL) { + goto fail; + } + + /* Set up to write packets */ + comm->fde = tevent_add_fd(ev, comm, fd, TEVENT_FD_READ, + comm_fd_handler, comm); + if (comm->fde == NULL) { + goto fail; + } + + /* Set up to read packets */ + if (read_handler != NULL) { + struct tevent_req *req; + + req = comm_read_send(comm, ev, comm, comm->small_pkt, + SMALL_PKT_SIZE); + if (req == NULL) { + goto fail; + } + + tevent_req_set_callback(req, comm_read_failed, comm); + comm->read_req = req; + } + + *result = comm; + return 0; + +fail: + talloc_free(comm); + return ENOMEM; +} + + +/* + * Read packets + */ + +struct comm_read_state { + struct tevent_context *ev; + struct comm_context *comm; + uint8_t *buf; + size_t buflen; + struct tevent_req *subreq; +}; + +static ssize_t comm_read_more(uint8_t *buf, size_t buflen, void *private_data); +static void comm_read_done(struct tevent_req *subreq); + +static struct tevent_req *comm_read_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct comm_context *comm, + uint8_t *buf, size_t buflen) +{ + struct tevent_req *req, *subreq; + struct comm_read_state *state; + + req = tevent_req_create(mem_ctx, &state, struct comm_read_state); + if (req == NULL) { + return NULL; + } + + state->ev = ev; + state->comm = comm; + state->buf = buf; + state->buflen = buflen; + + subreq = pkt_read_send(state, state->ev, comm->fd, sizeof(uint32_t), + state->buf, state->buflen, + comm_read_more, NULL); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + state->subreq = subreq; + + tevent_req_set_callback(subreq, comm_read_done, req); + return req; +} + +static ssize_t comm_read_more(uint8_t *buf, size_t buflen, void *private_data) +{ + uint32_t packet_len; + + if (buflen < sizeof(uint32_t)) { + return sizeof(uint32_t) - buflen; + } + + packet_len = *(uint32_t *)buf; + + return packet_len - buflen; +} + +static void comm_read_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct comm_read_state *state = tevent_req_data( + req, struct comm_read_state); + struct comm_context *comm = state->comm; + ssize_t nread; + uint8_t *buf; + bool free_buf; + int err = 0; + + nread = pkt_read_recv(subreq, state, &buf, &free_buf, &err); + TALLOC_FREE(subreq); + state->subreq = NULL; + if (nread == -1) { + tevent_req_error(req, err); + return; + } + + comm->read_handler(buf, nread, comm->read_private_data); + + if (free_buf) { + talloc_free(buf); + } + + subreq = pkt_read_send(state, state->ev, comm->fd, sizeof(uint32_t), + state->buf, state->buflen, + comm_read_more, NULL); + if (tevent_req_nomem(subreq, req)) { + return; + } + state->subreq = subreq; + + tevent_req_set_callback(subreq, comm_read_done, req); +} + +static void comm_read_recv(struct tevent_req *req, int *perr) +{ + int err; + + if (tevent_req_is_unix_error(req, &err)) { + if (perr != NULL) { + *perr = err; + } + } +} + +static void comm_read_failed(struct tevent_req *req) +{ + struct comm_context *comm = tevent_req_callback_data( + req, struct comm_context); + + comm_read_recv(req, NULL); + TALLOC_FREE(req); + comm->read_req = NULL; + if (comm->dead_handler != NULL) { + comm->dead_handler(comm->dead_private_data); + } +} + + +/* + * Write packets + */ + +struct comm_write_state { + struct tevent_context *ev; + struct comm_context *comm; + struct tevent_req *subreq; + uint8_t *buf; + size_t buflen, nwritten; +}; + +static void comm_write_trigger(struct tevent_req *req, void *private_data); +static void comm_write_done(struct tevent_req *subreq); + +struct tevent_req *comm_write_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct comm_context *comm, + uint8_t *buf, size_t buflen) +{ + struct tevent_req *req; + struct comm_write_state *state; + + req = tevent_req_create(mem_ctx, &state, struct comm_write_state); + if (req == NULL) { + return NULL; + } + + state->ev = ev; + state->comm = comm; + state->buf = buf; + state->buflen = buflen; + + if (!tevent_queue_add_entry(comm->queue, ev, req, + comm_write_trigger, NULL)) { + talloc_free(req); + return NULL; + } + + return req; +} + +static void comm_write_trigger(struct tevent_req *req, void *private_data) +{ + struct comm_write_state *state = tevent_req_data( + req, struct comm_write_state); + struct comm_context *comm = state->comm; + struct tevent_req *subreq; + + comm->write_req = req; + + subreq = pkt_write_send(state, state->ev, comm->fd, + state->buf, state->buflen); + if (tevent_req_nomem(subreq, req)) { + return; + } + + state->subreq = subreq; + tevent_req_set_callback(subreq, comm_write_done, req); + TEVENT_FD_WRITEABLE(comm->fde); +} + +static void comm_write_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct comm_write_state *state = tevent_req_data( + req, struct comm_write_state); + struct comm_context *comm = state->comm; + ssize_t nwritten; + int err = 0; + + TEVENT_FD_NOT_WRITEABLE(comm->fde); + nwritten = pkt_write_recv(subreq, &err); + TALLOC_FREE(subreq); + state->subreq = NULL; + comm->write_req = NULL; + if (nwritten == -1) { + if (err == EPIPE) { + comm->dead_handler(comm->dead_private_data); + } + tevent_req_error(req, err); + return; + } + + state->nwritten = nwritten; + tevent_req_done(req); +} + +bool comm_write_recv(struct tevent_req *req, int *perr) +{ + struct comm_write_state *state = tevent_req_data( + req, struct comm_write_state); + int err; + + if (tevent_req_is_unix_error(req, &err)) { + if (perr != NULL) { + *perr = err; + } + return false; + } + + if (state->nwritten != state->buflen) { + *perr = EIO; + return false; + } + + *perr = 0; + return true; +} + +static void comm_fd_handler(struct tevent_context *ev, + struct tevent_fd *fde, + uint16_t flags, void *private_data) +{ + struct comm_context *comm = talloc_get_type_abort( + private_data, struct comm_context); + + if (flags & TEVENT_FD_READ) { + struct comm_read_state *read_state; + + if (comm->read_req == NULL) { + /* This should never happen */ + abort(); + } + + read_state = tevent_req_data(comm->read_req, + struct comm_read_state); + pkt_read_handler(ev, fde, flags, read_state->subreq); + } + + if (flags & TEVENT_FD_WRITE) { + struct comm_write_state *write_state; + + if (comm->write_req == NULL) { + /* This should never happen */ + abort(); + } + + write_state = tevent_req_data(comm->write_req, + struct comm_write_state); + pkt_write_handler(ev, fde, flags, write_state->subreq); + } +} diff --git a/ctdb/common/comm.h b/ctdb/common/comm.h new file mode 100644 index 0000000..27021e9 --- /dev/null +++ b/ctdb/common/comm.h @@ -0,0 +1,101 @@ +/* + Communication endpoint API + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#ifndef __CTDB_COMM_H__ +#define __CTDB_COMM_H__ + +#include +#include + +/** + * @file comm.h + * + * @brief Communication over a socket or file descriptor + * + * This abstraction is a wrapper around a socket or file descriptor to + * send/receive complete packets. + */ + +/** + * @brief Packet handler function + * + * This function is registered while setting up communication endpoint. Any + * time packets are read, this function is called. + */ +typedef void (*comm_read_handler_fn)(uint8_t *buf, size_t buflen, + void *private_data); + +/** + * @brief Communication endpoint dead handler function + * + * This function is called when the communication endpoint is closed. + */ +typedef void (*comm_dead_handler_fn)(void *private_data); + +/** + * @brief Abstract struct to store communication endpoint details + */ +struct comm_context; + +/** + * @brief Initialize the communication endpoint + * + * This return a new communication context. Freeing this context will free all + * memory assoicated with it. + * + * @param[in] mem_ctx Talloc memory context + * @param[in] ev Tevent context + * @param[in] fd The socket or file descriptor + * @param[in] read_handler The packet handler function + * @param[in] read_private_data Private data for read handler function + * @param[in] dead_handler The communication dead handler function + * @param[in] dead_private_data Private data for dead handler function + * @param[out] result The new comm_context structure + * @return 0 on success, errno on failure + */ +int comm_setup(TALLOC_CTX *mem_ctx, struct tevent_context *ev, int fd, + comm_read_handler_fn read_handler, void *read_private_data, + comm_dead_handler_fn dead_handler, void *dead_private_data, + struct comm_context **result); + +/** + * @brief Async computation start to send a packet + * + * @param[in] mem_ctx Talloc memory context + * @param[in] ev Tevent context + * @param[in] comm Communication context + * @param[in] buf The packet data + * @param[in] buflen The size of the packet + * @return new tevent request, or NULL on failure + */ +struct tevent_req *comm_write_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct comm_context *comm, + uint8_t *buf, size_t buflen); + +/** + * @brief Async computation end to send a packet + * + * @param[in] req Tevent request + * @param[out] perr errno in case of failure + * @return true on success, false on failure + */ +bool comm_write_recv(struct tevent_req *req, int *perr); + +#endif /* __CTDB_COMM_H__ */ diff --git a/ctdb/tests/cunit/comm_test_001.sh b/ctdb/tests/cunit/comm_test_001.sh new file mode 100755 index 0000000..5d20db2 --- /dev/null +++ b/ctdb/tests/cunit/comm_test_001.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +. "${TEST_SCRIPTS_DIR}/unit.sh" + +ok "100 2048 500 4096 1024 8192 200 16384 300 32768 400 65536 1048576 " + +unit_test comm_test diff --git a/ctdb/tests/cunit/comm_test_002.sh b/ctdb/tests/cunit/comm_test_002.sh new file mode 100755 index 0000000..76ee62d --- /dev/null +++ b/ctdb/tests/cunit/comm_test_002.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +. "${TEST_SCRIPTS_DIR}/unit.sh" + +socket="${TEST_VAR_DIR}/test_sock.$$" +num_clients=10 + +remove_socket () +{ + rm -f "$socket" +} + +test_cleanup remove_socket + +ok_null + +unit_test comm_server_test "$socket" $num_clients & +pid=$! + +for i in $(seq 1 $num_clients) ; do + unit_test comm_client_test "$socket" +done + +wait $pid diff --git a/ctdb/tests/src/comm_client_test.c b/ctdb/tests/src/comm_client_test.c new file mode 100644 index 0000000..d3f5f9e --- /dev/null +++ b/ctdb/tests/src/comm_client_test.c @@ -0,0 +1,207 @@ +/* + comm tests + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include "replace.h" +#include "system/filesys.h" + +#include + +#include "common/pkt_read.c" +#include "common/pkt_write.c" +#include "common/comm.c" + + +struct writer_state { + struct tevent_context *ev; + struct comm_context *comm; + uint8_t *buf; + size_t *pkt_size; + int count, id; +}; + +static void writer_done(struct tevent_req *subreq); +static void read_handler(uint8_t *buf, size_t buflen, void *private_data); +static void dead_handler(void *private_data); + +static struct tevent_req *writer_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + int fd, size_t *pkt_size, + int count) +{ + struct tevent_req *req, *subreq; + struct writer_state *state; + size_t max_size = 0, buflen; + int i, ret; + + for (i=0; i max_size) { + max_size = pkt_size[i]; + } + } + + req = tevent_req_create(mem_ctx, &state, struct writer_state); + if (req == NULL) { + return NULL; + } + + state->ev = ev; + state->pkt_size = pkt_size; + state->count = count; + state->id = 0; + + ret = comm_setup(state, ev, fd, read_handler, req, + dead_handler, req, &state->comm); + if (ret != 0) { + tevent_req_error(req, ret); + return tevent_req_post(req, ev); + } + + state->buf = talloc_array(state, uint8_t, max_size); + if (state->buf == NULL) { + talloc_free(req); + return NULL; + } + for (i=0; ibuf[i] = i%256; + } + + buflen = state->pkt_size[state->id]; + *(uint32_t *)state->buf = buflen; + subreq = comm_write_send(state, state->ev, state->comm, + state->buf, buflen); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, writer_done, req); + + return req; +} + +static void writer_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + bool ret; + int err; + + ret = comm_write_recv(subreq, &err); + TALLOC_FREE(subreq); + if (!ret) { + tevent_req_error(req, err); + return; + } +} + +static void read_handler(uint8_t *buf, size_t buflen, void *private_data) +{ + struct tevent_req *req = talloc_get_type_abort( + private_data, struct tevent_req); + struct writer_state *state = tevent_req_data( + req, struct writer_state); + struct tevent_req *subreq; + + if (buflen != state->pkt_size[state->id]) { + tevent_req_error(req, EIO); + return; + } + + state->id++; + if (state->id >= state->count) { + tevent_req_done(req); + return; + } + + buflen = state->pkt_size[state->id]; + *(uint32_t *)state->buf = buflen; + subreq = comm_write_send(state, state->ev, state->comm, + state->buf, buflen); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, writer_done, req); +} + +static void dead_handler(void *private_data) +{ + struct tevent_req *req = talloc_get_type_abort( + private_data, struct tevent_req); + + tevent_req_error(req, EPIPE); +} + +static void writer_recv(struct tevent_req *req, int *perr) +{ + if (tevent_req_is_unix_error(req, perr)) { + return; + } + *perr = 0; +} + +static int socket_init(char *sockpath) +{ + struct sockaddr_un addr; + int fd, ret; + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strcpy(addr.sun_path, sockpath); + + fd = socket(AF_UNIX, SOCK_STREAM, 0); + assert(fd != -1); + + ret = connect(fd, (struct sockaddr *)&addr, sizeof(addr)); + assert(ret != -1); + + return fd; +} + +int main(int argc, char *argv[]) +{ + TALLOC_CTX *mem_ctx; + struct tevent_context *ev; + struct tevent_req *req; + int fd; + size_t pkt_size[13] = { 100, 2048, 500, 4096, 1024, 8192, + 200, 16384, 300, 32768, 400, 65536, + 1024*1024 }; + int err; + + if (argc != 2) { + printf("Usage: %s \n", argv[0]); + exit(1); + } + + mem_ctx = talloc_new(NULL); + assert(mem_ctx != NULL); + + ev = tevent_context_init(mem_ctx); + assert(ev != NULL); + + fd = socket_init(argv[1]); + + req = writer_send(mem_ctx, ev, fd, pkt_size, 13); + assert(req != NULL); + + tevent_req_poll(req, ev); + + writer_recv(req, &err); + assert(err == 0); + + exit(0); +} diff --git a/ctdb/tests/src/comm_server_test.c b/ctdb/tests/src/comm_server_test.c new file mode 100644 index 0000000..fe0fffd --- /dev/null +++ b/ctdb/tests/src/comm_server_test.c @@ -0,0 +1,363 @@ +/* + comm tests + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include "replace.h" +#include "system/filesys.h" + +#include + +#include "common/pkt_read.c" +#include "common/pkt_write.c" +#include "common/comm.c" + + +struct accept_state { + int listen_fd; + struct tevent_fd *fde; + int client_fd; +}; + +static void accept_handler(struct tevent_context *ev, struct tevent_fd *fde, + uint16_t flags, void *private_data); + +static struct tevent_req *accept_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + int listen_fd) +{ + struct tevent_req *req; + struct accept_state *state; + + req = tevent_req_create(mem_ctx, &state, struct accept_state); + if (req == NULL) { + return NULL; + } + + state->listen_fd = listen_fd; + + state->fde = tevent_add_fd(ev, state, listen_fd, TEVENT_FD_READ, + accept_handler, req); + if (tevent_req_nomem(state->fde, req)) { + return tevent_req_post(req, ev); + } + return req; +} + +static void accept_handler(struct tevent_context *ev, struct tevent_fd *fde, + uint16_t flags, void *private_data) +{ + struct tevent_req *req = talloc_get_type_abort( + private_data, struct tevent_req); + struct accept_state *state = tevent_req_data( + req, struct accept_state); + struct sockaddr addr; + socklen_t addrlen = sizeof(addr); + int ret; + + TALLOC_FREE(state->fde); + + if ((flags & TEVENT_FD_READ) == 0) { + tevent_req_error(req, EIO); + return; + } + + ret = accept(state->listen_fd, &addr, &addrlen); + if (ret == -1) { + tevent_req_error(req, errno); + return; + } + + state->client_fd = ret; + tevent_req_done(req); +} + +static int accept_recv(struct tevent_req *req, int *perr) +{ + struct accept_state *state = tevent_req_data( + req, struct accept_state); + int err; + + if (tevent_req_is_unix_error(req, &err)) { + if (perr != NULL) { + *perr = err; + } + return -1; + } + + return state->client_fd; +} + + +struct echo_state { + struct tevent_context *ev; + int fd; + struct comm_context *comm; + uint8_t *data; +}; + +static void read_handler(uint8_t *buf, size_t buflen, void *private_data); +static void read_failed(void *private_data); +static void write_done(struct tevent_req *subreq); + +static struct tevent_req *echo_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, int fd) +{ + struct tevent_req *req; + struct echo_state *state; + int ret; + + req = tevent_req_create(mem_ctx, &state, struct echo_state); + if (req == NULL) { + return NULL; + } + + state->ev = ev; + state->fd = fd; + + ret = comm_setup(state, ev, fd, read_handler, req, + read_failed, req, &state->comm); + if (ret != 0) { + tevent_req_error(req, ret); + return tevent_req_post(req, ev); + } + + return req; +} + +static void read_handler(uint8_t *buf, size_t buflen, void *private_data) +{ + struct tevent_req *req = talloc_get_type_abort( + private_data, struct tevent_req); + struct echo_state *state = tevent_req_data( + req, struct echo_state); + struct tevent_req *subreq; + + state->data = talloc_memdup(state, buf, buflen); + if (tevent_req_nomem(state->data, req)) { + return; + } + + subreq = comm_write_send(state, state->ev, state->comm, + state->data, buflen); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, write_done, req); +} + +static void read_failed(void *private_data) +{ + struct tevent_req *req = talloc_get_type_abort( + private_data, struct tevent_req); + + tevent_req_done(req); +} + +static void write_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct echo_state *state = tevent_req_data( + req, struct echo_state); + bool ret; + int err; + + TALLOC_FREE(state->data); + + ret = comm_write_recv(subreq, &err); + TALLOC_FREE(subreq); + if (!ret) { + tevent_req_error(req, err); + return; + } +} + +static bool echo_recv(struct tevent_req *req, int *perr) +{ + struct echo_state *state = tevent_req_data( + req, struct echo_state); + int err; + + if (tevent_req_is_unix_error(req, &err)) { + if (perr != NULL) { + *perr = err; + } + return false; + } + + close(state->fd); + return true; +} + + +struct socket_process_state { + struct tevent_context *ev; + int fd; + int max_clients; + int num_clients; +}; + +static void socket_process_client(struct tevent_req *subreq); +static void socket_process_client_done(struct tevent_req *subreq); + +static struct tevent_req *socket_process_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + int fd, int max_clients) +{ + struct tevent_req *req, *subreq; + struct socket_process_state *state; + + req = tevent_req_create(mem_ctx, &state, struct socket_process_state); + if (req == NULL) { + return NULL; + } + + state->ev = ev; + state->fd = fd; + state->max_clients = max_clients; + state->num_clients = 0; + + subreq = accept_send(state, ev, fd); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, socket_process_client, req); + + return req; +} + +static void socket_process_client(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct socket_process_state *state = tevent_req_data( + req, struct socket_process_state); + int client_fd, err; + + client_fd = accept_recv(subreq, &err); + TALLOC_FREE(subreq); + + state->num_clients++; + + if (client_fd == -1) { + tevent_req_error(req, err); + return; + } + + subreq = echo_send(state, state->ev, client_fd); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, socket_process_client_done, req); + + if (state->num_clients == state->max_clients) { + /* Stop accepting any more clients */ + return; + } + + subreq = accept_send(state, state->ev, state->fd); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, socket_process_client, req); +} + +static void socket_process_client_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct socket_process_state *state = tevent_req_data( + req, struct socket_process_state); + bool ret; + int err = 0; + + ret = echo_recv(subreq, &err); + TALLOC_FREE(subreq); + if (!ret) { + tevent_req_error(req, EIO); + return; + } + + if (state->num_clients == state->max_clients) { + tevent_req_done(req); + } +} + +static void socket_process_recv(struct tevent_req *req, int *perr) +{ + int err; + + if (tevent_req_is_unix_error(req, &err)) { + if (perr != NULL) { + *perr = err; + } + } +} + +static int socket_init(char *sockpath) +{ + struct sockaddr_un addr; + int fd, ret; + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strcpy(addr.sun_path, sockpath); + + fd = socket(AF_UNIX, SOCK_STREAM, 0); + assert(fd != -1); + + ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr)); + assert(ret != -1); + + ret = listen(fd, 10); + assert(ret != -1); + + return fd; +} + +int main(int argc, char *argv[]) +{ + TALLOC_CTX *mem_ctx; + struct tevent_context *ev; + struct tevent_req *req; + int fd, err = 0; + int num_clients; + + if (argc != 3) { + printf("Usage: %s \n", argv[0]); + exit(1); + } + + mem_ctx = talloc_new(NULL); + assert(mem_ctx != NULL); + + ev = tevent_context_init(mem_ctx); + assert(ev != NULL); + + fd = socket_init(argv[1]); + num_clients = atoi(argv[2]); + assert(num_clients > 0); + + req = socket_process_send(mem_ctx, ev, fd, num_clients); + assert(req != NULL); + + tevent_req_poll(req, ev); + + socket_process_recv(req, &err); + return err; +} diff --git a/ctdb/tests/src/comm_test.c b/ctdb/tests/src/comm_test.c new file mode 100644 index 0000000..2189435 --- /dev/null +++ b/ctdb/tests/src/comm_test.c @@ -0,0 +1,260 @@ +/* + comm tests + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include "replace.h" +#include "system/filesys.h" + +#include + +#include "common/pkt_read.c" +#include "common/pkt_write.c" +#include "common/comm.c" + +static void dead_handler(void *private_data) +{ + int dead_data = *(int *)private_data; + + assert(dead_data == 1 || dead_data == 2); + + if (dead_data == 1) { + /* reader */ + printf("writer closed pipe\n"); + } else { + /* writer */ + printf("reader closed pipe\n"); + } +} + +struct writer_state { + struct tevent_context *ev; + struct comm_context *comm; + uint8_t *buf; + size_t *pkt_size; + int count, id; +}; + +static void writer_next(struct tevent_req *subreq); + +static struct tevent_req *writer_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct comm_context *comm, + size_t *pkt_size, int count) +{ + struct tevent_req *req, *subreq; + struct writer_state *state; + size_t max_size = 0, buflen; + int i; + + for (i=0; i max_size) { + max_size = pkt_size[i]; + } + } + + req = tevent_req_create(mem_ctx, &state, struct writer_state); + if (req == NULL) { + return NULL; + } + + state->ev = ev; + state->comm = comm; + state->pkt_size = pkt_size; + state->count = count; + state->id = 0; + + state->buf = talloc_array(state, uint8_t, max_size); + if (state->buf == NULL) { + talloc_free(req); + return NULL; + } + for (i=0; ibuf[i] = i%256; + } + + buflen = state->pkt_size[state->id]; + *(uint32_t *)state->buf = buflen; + subreq = comm_write_send(state, state->ev, state->comm, + state->buf, buflen); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + + tevent_req_set_callback(subreq, writer_next, req); + return req; +} + +static void writer_next(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct writer_state *state = tevent_req_data( + req, struct writer_state); + bool ret; + int err; + size_t buflen; + + ret = comm_write_recv(subreq, &err); + TALLOC_FREE(subreq); + if (!ret) { + tevent_req_error(req, err); + return; + } + + state->id++; + if (state->id >= state->count) { + tevent_req_done(req); + return; + } + + buflen = state->pkt_size[state->id]; + *(uint32_t *)state->buf = buflen; + subreq = comm_write_send(state, state->ev, state->comm, + state->buf, buflen); + if (tevent_req_nomem(subreq, req)) { + return; + } + + tevent_req_set_callback(subreq, writer_next, req); +} + +static void writer_recv(struct tevent_req *req, int *perr) +{ + if (tevent_req_is_unix_error(req, perr)) { + return; + } + *perr = 0; +} + +static void writer(int fd, size_t *pkt_size, int count) +{ + TALLOC_CTX *mem_ctx; + struct tevent_context *ev; + struct comm_context *comm; + struct tevent_req *req; + int dead_data = 2; + int err; + + mem_ctx = talloc_new(NULL); + assert(mem_ctx != NULL); + + ev = tevent_context_init(mem_ctx); + assert(ev != NULL); + + err = comm_setup(mem_ctx, ev, fd, NULL, NULL, + dead_handler, &dead_data, &comm); + assert(err == 0); + assert(comm != NULL); + + req = writer_send(mem_ctx, ev, comm, pkt_size, count); + assert(req != NULL); + + tevent_req_poll(req, ev); + + writer_recv(req, &err); + assert(err == 0); + + talloc_free(mem_ctx); +} + +struct reader_state { + size_t *pkt_size; + int count, received; + bool done; +}; + +static void reader_handler(uint8_t *buf, size_t buflen, void *private_data) +{ + struct reader_state *state = talloc_get_type_abort( + private_data, struct reader_state); + + assert(buflen == state->pkt_size[state->received]); + printf("%zi ", buflen); + state->received++; + + if (state->received == state->count) { + printf("\n"); + state->done = true; + } +} + +static void reader(int fd, size_t *pkt_size, int count) +{ + TALLOC_CTX *mem_ctx; + struct tevent_context *ev; + struct comm_context *comm; + struct reader_state *state; + int dead_data = 1; + int err; + + mem_ctx = talloc_new(NULL); + assert(mem_ctx != NULL); + + ev = tevent_context_init(mem_ctx); + assert(ev != NULL); + + state = talloc_zero(mem_ctx, struct reader_state); + assert(state != NULL); + + state->pkt_size = pkt_size; + state->count = count; + state->received = 0; + state->done = false; + + err = comm_setup(mem_ctx, ev, fd, reader_handler, state, + dead_handler, &dead_data, &comm); + assert(err == 0); + assert(comm != NULL); + + while (!state->done) { + tevent_loop_once(ev); + } + + talloc_free(mem_ctx); +} + +int main(void) +{ + int fd[2]; + int ret; + pid_t pid; + size_t pkt_size[13] = { 100, 2048, 500, 4096, 1024, 8192, + 200, 16384, 300, 32768, 400, 65536, + 1024*1024 }; + + + ret = pipe(fd); + assert(ret == 0); + + pid = fork(); + assert(pid != -1); + + if (pid == 0) { + /* Child process */ + close(fd[0]); + writer(fd[1], pkt_size, 13); + close(fd[1]); + exit(0); + } + + close(fd[1]); + reader(fd[0], pkt_size, 13); + close(fd[0]); + + return 0; +} diff --git a/ctdb/wscript b/ctdb/wscript index 454f03f..a08d861 100755 --- a/ctdb/wscript +++ b/ctdb/wscript @@ -336,7 +336,7 @@ def build(bld): bld.SAMBA_SUBSYSTEM('ctdb-util', source=bld.SUBDIR('common', '''db_hash.c srvid.c reqid.c - pkt_read.c pkt_write.c'''), + pkt_read.c pkt_write.c comm.c'''), deps='replace talloc tevent tdb tevent-unix-util') bld.SAMBA_SUBSYSTEM('ctdb-client', @@ -580,6 +580,9 @@ def build(bld): 'srvid_test', 'pkt_read_test', 'pkt_write_test', + 'comm_test', + 'comm_server_test', + 'comm_client_test', ] for target in ctdb_unit_tests: From 54da5c6603059709529d50d4f5c5c39373ca4216 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Sat, 1 Aug 2015 22:36:04 +1000 Subject: [PATCH 060/136] ctdb-common: Add logging utilities Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/common/logging.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++ ctdb/common/logging.h | 39 +++++++++++++++++++++++++++ ctdb/wscript | 3 ++- 3 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 ctdb/common/logging.c create mode 100644 ctdb/common/logging.h diff --git a/ctdb/common/logging.c b/ctdb/common/logging.c new file mode 100644 index 0000000..82cf3d9 --- /dev/null +++ b/ctdb/common/logging.c @@ -0,0 +1,74 @@ +/* + Logging utilities + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include + +#include "common/logging.h" + +struct { + enum debug_level log_level; + const char *log_string; +} log_string_map[] = { + { DEBUG_ERR, "ERROR" }, + { DEBUG_WARNING, "WARNING" }, + { DEBUG_NOTICE, "NOTICE" }, + { DEBUG_INFO, "INFO" }, + { DEBUG_DEBUG, "DEBUG" }, +}; + +bool debug_level_parse(const char *log_string, enum debug_level *log_level) +{ + int i; + + for (i=0; ARRAY_SIZE(log_string_map); i++) { + if (strcasecmp(log_string_map[i].log_string, + log_string) == 0) { + *log_level = log_string_map[i].log_level; + return true; + } + } + + return false; +} + +const char *debug_level_to_string(enum debug_level log_level) +{ + int i; + + for (i=0; ARRAY_SIZE(log_string_map); i++) { + if (log_string_map[i].log_level == log_level) { + return log_string_map[i].log_string; + } + } + return "UNKNOWN"; +} + +enum debug_level debug_level_from_string(const char *log_string) +{ + bool found; + enum debug_level log_level; + + found = debug_level_parse(log_string, &log_level); + if (found) { + return log_level; + } + + /* Default debug level */ + return DEBUG_ERR; +} diff --git a/ctdb/common/logging.h b/ctdb/common/logging.h new file mode 100644 index 0000000..f427fbb --- /dev/null +++ b/ctdb/common/logging.h @@ -0,0 +1,39 @@ +/* + Logging utilities + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#ifndef __CTDB_LOGGING_H__ +#define __CTDB_LOGGING_H__ + +enum debug_level { + DEBUG_ERR = 0, + DEBUG_WARNING = 1, + DEBUG_NOTICE = 2, + DEBUG_INFO = 3, + DEBUG_DEBUG = 4, +}; + +/* These are used in many places, so define them here to avoid churn */ +#define DEBUG_ALERT DEBUG_ERR +#define DEBUG_CRIT DEBUG_ERR + +bool debug_level_parse(const char *log_string, enum debug_level *log_level); +const char *debug_level_to_string(enum debug_level log_level); +enum debug_level debug_level_from_string(const char *log_string); + +#endif /* __CTDB_LOGGING_H__ */ diff --git a/ctdb/wscript b/ctdb/wscript index a08d861..243ac9b 100755 --- a/ctdb/wscript +++ b/ctdb/wscript @@ -336,7 +336,8 @@ def build(bld): bld.SAMBA_SUBSYSTEM('ctdb-util', source=bld.SUBDIR('common', '''db_hash.c srvid.c reqid.c - pkt_read.c pkt_write.c comm.c'''), + pkt_read.c pkt_write.c comm.c + logging.c'''), deps='replace talloc tevent tdb tevent-unix-util') bld.SAMBA_SUBSYSTEM('ctdb-client', From 8b45badfdaa8d9b618d551fcbbe8a2f7d680c4f9 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Tue, 14 Apr 2015 11:42:45 +1000 Subject: [PATCH 061/136] ctdb-include: Remove unused structure definitions Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/include/ctdb_protocol.h | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/ctdb/include/ctdb_protocol.h b/ctdb/include/ctdb_protocol.h index d49a641..e195e57 100644 --- a/ctdb/include/ctdb_protocol.h +++ b/ctdb/include/ctdb_protocol.h @@ -487,17 +487,6 @@ struct ctdb_req_message { uint8_t data[1]; }; -struct ctdb_req_getdbpath { - struct ctdb_req_header hdr; - uint32_t db_id; -}; - -struct ctdb_reply_getdbpath { - struct ctdb_req_header hdr; - uint32_t datalen; - uint8_t data[1]; -}; - struct ctdb_req_control { struct ctdb_req_header hdr; uint32_t opcode; From 34a6c99776cd50dfa4f6c2e02a6439d6d59b045e Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Tue, 14 Apr 2015 17:20:05 +1000 Subject: [PATCH 062/136] ctdb-protocol: Add ctdb protocol serialization routines Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/protocol/protocol.h | 1002 +++++++++++++ ctdb/protocol/protocol_api.h | 643 +++++++++ ctdb/protocol/protocol_call.c | 446 ++++++ ctdb/protocol/protocol_client.c | 2370 +++++++++++++++++++++++++++++++ ctdb/protocol/protocol_control.c | 2007 ++++++++++++++++++++++++++ ctdb/protocol/protocol_header.c | 73 + ctdb/protocol/protocol_message.c | 383 +++++ ctdb/protocol/protocol_packet.c | 44 + ctdb/protocol/protocol_private.h | 274 ++++ ctdb/protocol/protocol_types.c | 2519 +++++++++++++++++++++++++++++++++ ctdb/protocol/protocol_util.c | 114 ++ ctdb/tests/cunit/protocol_test_001.sh | 9 + ctdb/tests/cunit/protocol_test_002.sh | 36 + ctdb/tests/src/protocol_client_test.c | 2311 ++++++++++++++++++++++++++++++ ctdb/tests/src/protocol_types_test.c | 1278 +++++++++++++++++ ctdb/wscript | 13 + 16 files changed, 13522 insertions(+) create mode 100644 ctdb/protocol/protocol.h create mode 100644 ctdb/protocol/protocol_api.h create mode 100644 ctdb/protocol/protocol_call.c create mode 100644 ctdb/protocol/protocol_client.c create mode 100644 ctdb/protocol/protocol_control.c create mode 100644 ctdb/protocol/protocol_header.c create mode 100644 ctdb/protocol/protocol_message.c create mode 100644 ctdb/protocol/protocol_packet.c create mode 100644 ctdb/protocol/protocol_private.h create mode 100644 ctdb/protocol/protocol_types.c create mode 100644 ctdb/protocol/protocol_util.c create mode 100755 ctdb/tests/cunit/protocol_test_001.sh create mode 100755 ctdb/tests/cunit/protocol_test_002.sh create mode 100644 ctdb/tests/src/protocol_client_test.c create mode 100644 ctdb/tests/src/protocol_types_test.c diff --git a/ctdb/protocol/protocol.h b/ctdb/protocol/protocol.h new file mode 100644 index 0000000..805fdd1 --- /dev/null +++ b/ctdb/protocol/protocol.h @@ -0,0 +1,1002 @@ +/* + CTDB protocol marshalling + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#ifndef __CTDB_PROTOCOL_H__ +#define __CTDB_PROTOCOL_H__ + +#define CTDB_MAGIC 0x43544442 /* CTDB */ +#define CTDB_PROTOCOL 1 + +enum ctdb_operation { + CTDB_REQ_CALL = 0, + CTDB_REPLY_CALL = 1, + CTDB_REQ_DMASTER = 2, + CTDB_REPLY_DMASTER = 3, + CTDB_REPLY_ERROR = 4, + CTDB_REQ_MESSAGE = 5, + /* #6 removed */ + CTDB_REQ_CONTROL = 7, + CTDB_REPLY_CONTROL = 8, + CTDB_REQ_KEEPALIVE = 9, +}; + +/* used on the domain socket, send a pdu to the local daemon */ +#define CTDB_CURRENT_NODE 0xF0000001 +/* send a broadcast to all nodes in the cluster, active or not */ +#define CTDB_BROADCAST_ALL 0xF0000002 +/* send a broadcast to all nodes in the current vnn map */ +#define CTDB_BROADCAST_VNNMAP 0xF0000003 +/* send a broadcast to all connected nodes */ +#define CTDB_BROADCAST_CONNECTED 0xF0000004 +/* send a broadcast to selected connected nodes */ +#define CTDB_MULTICAST 0xF0000005 + +#define CTDB_UNKNOWN_PNN 0xFFFFFFFF + +/* the key used to store persistent db sequence number */ +#define CTDB_DB_SEQNUM_KEY "__db_sequence_number__" + +struct ctdb_req_header { + uint32_t length; + uint32_t ctdb_magic; + uint32_t ctdb_version; + uint32_t generation; + uint32_t operation; + uint32_t destnode; + uint32_t srcnode; + uint32_t reqid; +}; + +struct ctdb_req_call { + uint32_t flags; + uint32_t db_id; + uint32_t callid; + uint32_t hopcount; + TDB_DATA key; + TDB_DATA calldata; +}; + +struct ctdb_reply_call { + int32_t status; + TDB_DATA data; +}; + +struct ctdb_reply_error { + int32_t status; + TDB_DATA msg; +}; + +struct ctdb_req_dmaster { + uint32_t db_id; + uint64_t rsn; + uint32_t dmaster; + TDB_DATA key; + TDB_DATA data; +}; + +struct ctdb_reply_dmaster { + uint32_t db_id; + uint64_t rsn; + TDB_DATA key; + TDB_DATA data; +}; + +#define CTDB_NULL_FUNC 0xFF000001 +#define CTDB_FETCH_FUNC 0xFF000002 +#define CTDB_FETCH_WITH_HEADER_FUNC 0xFF000003 + +struct ctdb_call { + int call_id; + TDB_DATA key; + TDB_DATA call_data; + TDB_DATA reply_data; + uint32_t status; +#define CTDB_IMMEDIATE_MIGRATION 0x00000001 +#define CTDB_CALL_FLAG_VACUUM_MIGRATION 0x00000002 +#define CTDB_WANT_READONLY 0x00000004 + uint32_t flags; +}; + +/* SRVID to catch all messages */ +#define CTDB_SRVID_ALL (~(uint64_t)0) + +/* SRVID prefix used by CTDB */ +#define CTDB_SRVID_PREFIX 0xF000000000000000LL + +/* SRVID to inform of election data */ +#define CTDB_SRVID_ELECTION 0xF100000000000000LL + +/* SRVID to inform clients that the cluster has been reconfigured */ +#define CTDB_SRVID_RECONFIGURE 0xF200000000000000LL + +/* SRVID to inform clients an IP address has been released */ +#define CTDB_SRVID_RELEASE_IP 0xF300000000000000LL + +/* SRVID to inform clients that an IP address has been taken over */ +#define CTDB_SRVID_TAKE_IP 0xF301000000000000LL + +/* SRVID to inform recovery daemon of the node flags */ +#define CTDB_SRVID_SET_NODE_FLAGS 0xF400000000000000LL + +/* SRVID to inform recovery daemon to update public ip assignment */ +#define CTDB_SRVID_RECD_UPDATE_IP 0xF500000000000000LL + +/* SRVID to inform recovery daemon to migrate a set of records */ +#define CTDB_SRVID_VACUUM_FETCH 0xF700000000000000LL + +/* SRVID to inform recovery daemon to detach a database */ +#define CTDB_SRVID_DETACH_DATABASE 0xF701000000000000LL + +/* SRVID to inform recovery daemon to dump talloc memdump to the log */ +#define CTDB_SRVID_MEM_DUMP 0xF800000000000000LL + +/* SRVID to inform recovery daemon to send logs */ +#define CTDB_SRVID_GETLOG 0xF801000000000000LL + +/* SRVID to inform recovery daemon to clear logs */ +#define CTDB_SRVID_CLEARLOG 0xF802000000000000LL + +/* SRVID to inform recovery daemon to push the node flags to other nodes */ +#define CTDB_SRVID_PUSH_NODE_FLAGS 0xF900000000000000LL + +/* SRVID to inform recovery daemon to reload the nodes file */ +#define CTDB_SRVID_RELOAD_NODES 0xFA00000000000000LL + +/* SRVID to inform recovery daemon to perform a takeover run */ +#define CTDB_SRVID_TAKEOVER_RUN 0xFB00000000000000LL + +/* SRVID to inform recovery daemon to rebalance ips for a node. */ +#define CTDB_SRVID_REBALANCE_NODE 0xFB01000000000000LL + +/* SRVID to inform recovery daemon to stop takeover runs from occurring */ +#define CTDB_SRVID_DISABLE_TAKEOVER_RUNS 0xFB03000000000000LL + +/* SRVID to inform recovery daemon to stop recoveries from occurring */ +#define CTDB_SRVID_DISABLE_RECOVERIES 0xFB04000000000000LL + +/* SRVID to inform recovery daemon to disable the public ip checks */ +#define CTDB_SRVID_DISABLE_IP_CHECK 0xFC00000000000000LL + +/* SRVID to inform recovery daemon of ipreallocate resposnes from ctdbd */ +#define CTDB_SRVID_TAKEOVER_RUN_RESPONSE 0xFD00000000000000LL + +/* A range of ports reserved for registering a PID (top 8 bits) + * All ports matching the 8 top bits are reserved for exclusive use by + * registering a SRVID that matches the process-id of the requesting process + */ +#define CTDB_SRVID_PID_RANGE 0x0000000000000000LL + +/* A range of ports reserved for samba (top 8 bits) + * All ports matching the 8 top bits are reserved for exclusive use by + * CIFS server + */ +#define CTDB_SRVID_SAMBA_NOTIFY 0xFE00000000000000LL +#define CTDB_SRVID_SAMBA_RANGE 0xFE00000000000000LL + +/* A range of ports reserved for a CTDB NFS server (top 8 bits) + * All ports matching the 8 top bits are reserved for exclusive use by + * NFS server + */ +#define CTDB_SRVID_NFSD_RANGE 0xEE00000000000000LL + +/* A range of ports reserved for a CTDB ISCSI server (top 8 bits) + * All ports matching the 8 top bits are reserved for exclusive use by + * ISCSI server + */ +#define CTDB_SRVID_ISCSID_RANGE 0xDE00000000000000LL + +/* A range of ports reserved for testing (top 8 bits) + * All ports matching the 8 top bits are reserved for exclusive use by + * test applications + */ +#define CTDB_SRVID_TEST_RANGE 0xCE00000000000000LL + +/* Range of ports reserved for traversals */ +#define CTDB_SRVID_TRAVERSE_RANGE 0xBE00000000000000LL + + +enum ctdb_controls {CTDB_CONTROL_PROCESS_EXISTS = 0, + CTDB_CONTROL_STATISTICS = 1, + /* #2 removed */ + CTDB_CONTROL_PING = 3, + CTDB_CONTROL_GETDBPATH = 4, + CTDB_CONTROL_GETVNNMAP = 5, + CTDB_CONTROL_SETVNNMAP = 6, + CTDB_CONTROL_GET_DEBUG = 7, + CTDB_CONTROL_SET_DEBUG = 8, + CTDB_CONTROL_GET_DBMAP = 9, + CTDB_CONTROL_GET_NODEMAPv4 = 10, /* obsolete */ + CTDB_CONTROL_SET_DMASTER = 11, /* obsolete */ + /* #12 removed */ + CTDB_CONTROL_PULL_DB = 13, + CTDB_CONTROL_PUSH_DB = 14, + CTDB_CONTROL_GET_RECMODE = 15, + CTDB_CONTROL_SET_RECMODE = 16, + CTDB_CONTROL_STATISTICS_RESET = 17, + CTDB_CONTROL_DB_ATTACH = 18, + CTDB_CONTROL_SET_CALL = 19, /* obsolete */ + CTDB_CONTROL_TRAVERSE_START = 20, + CTDB_CONTROL_TRAVERSE_ALL = 21, + CTDB_CONTROL_TRAVERSE_DATA = 22, + CTDB_CONTROL_REGISTER_SRVID = 23, + CTDB_CONTROL_DEREGISTER_SRVID = 24, + CTDB_CONTROL_GET_DBNAME = 25, + CTDB_CONTROL_ENABLE_SEQNUM = 26, + CTDB_CONTROL_UPDATE_SEQNUM = 27, + /* #28 removed */ + CTDB_CONTROL_DUMP_MEMORY = 29, + CTDB_CONTROL_GET_PID = 30, + CTDB_CONTROL_GET_RECMASTER = 31, + CTDB_CONTROL_SET_RECMASTER = 32, + CTDB_CONTROL_FREEZE = 33, + CTDB_CONTROL_THAW = 34, + CTDB_CONTROL_GET_PNN = 35, + CTDB_CONTROL_SHUTDOWN = 36, + CTDB_CONTROL_GET_MONMODE = 37, + /* #38 removed */ + /* #39 removed */ + /* #40 removed */ + /* #41 removed */ + CTDB_CONTROL_TAKEOVER_IPv4 = 42, /* obsolete */ + CTDB_CONTROL_RELEASE_IPv4 = 43, /* obsolete */ + CTDB_CONTROL_TCP_CLIENT = 44, + CTDB_CONTROL_TCP_ADD = 45, + CTDB_CONTROL_TCP_REMOVE = 46, + CTDB_CONTROL_STARTUP = 47, + CTDB_CONTROL_SET_TUNABLE = 48, + CTDB_CONTROL_GET_TUNABLE = 49, + CTDB_CONTROL_LIST_TUNABLES = 50, + CTDB_CONTROL_GET_PUBLIC_IPSv4 = 51, /* obsolete */ + CTDB_CONTROL_MODIFY_FLAGS = 52, + CTDB_CONTROL_GET_ALL_TUNABLES = 53, + CTDB_CONTROL_KILL_TCP = 54, + CTDB_CONTROL_GET_TCP_TICKLE_LIST = 55, + CTDB_CONTROL_SET_TCP_TICKLE_LIST = 56, + CTDB_CONTROL_REGISTER_SERVER_ID = 57, + CTDB_CONTROL_UNREGISTER_SERVER_ID = 58, + CTDB_CONTROL_CHECK_SERVER_ID = 59, + CTDB_CONTROL_GET_SERVER_ID_LIST = 60, + CTDB_CONTROL_DB_ATTACH_PERSISTENT = 61, + CTDB_CONTROL_PERSISTENT_STORE = 62, /* obsolete */ + CTDB_CONTROL_UPDATE_RECORD = 63, + CTDB_CONTROL_SEND_GRATUITOUS_ARP = 64, + CTDB_CONTROL_TRANSACTION_START = 65, + CTDB_CONTROL_TRANSACTION_COMMIT = 66, + CTDB_CONTROL_WIPE_DATABASE = 67, + /* #68 removed */ + CTDB_CONTROL_UPTIME = 69, + CTDB_CONTROL_START_RECOVERY = 70, + CTDB_CONTROL_END_RECOVERY = 71, + CTDB_CONTROL_RELOAD_NODES_FILE = 72, + /* #73 removed */ + CTDB_CONTROL_TRY_DELETE_RECORDS = 74, + CTDB_CONTROL_ENABLE_MONITOR = 75, + CTDB_CONTROL_DISABLE_MONITOR = 76, + CTDB_CONTROL_ADD_PUBLIC_IP = 77, + CTDB_CONTROL_DEL_PUBLIC_IP = 78, + CTDB_CONTROL_RUN_EVENTSCRIPTS = 79, + CTDB_CONTROL_GET_CAPABILITIES = 80, + CTDB_CONTROL_START_PERSISTENT_UPDATE = 81, /* obsolete */ + CTDB_CONTROL_CANCEL_PERSISTENT_UPDATE= 82, /* obsolete */ + CTDB_CONTROL_TRANS2_COMMIT = 83, /* obsolete */ + CTDB_CONTROL_TRANS2_FINISHED = 84, /* obsolete */ + CTDB_CONTROL_TRANS2_ERROR = 85, /* obsolete */ + CTDB_CONTROL_TRANS2_COMMIT_RETRY = 86, /* obsolete */ + CTDB_CONTROL_RECD_PING = 87, + CTDB_CONTROL_RELEASE_IP = 88, + CTDB_CONTROL_TAKEOVER_IP = 89, + CTDB_CONTROL_GET_PUBLIC_IPS = 90, + CTDB_CONTROL_GET_NODEMAP = 91, + /* missing */ + CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS = 96, + CTDB_CONTROL_TRAVERSE_KILL = 97, + CTDB_CONTROL_RECD_RECLOCK_LATENCY = 98, + CTDB_CONTROL_GET_RECLOCK_FILE = 99, + CTDB_CONTROL_SET_RECLOCK_FILE = 100, + CTDB_CONTROL_STOP_NODE = 101, + CTDB_CONTROL_CONTINUE_NODE = 102, + CTDB_CONTROL_SET_NATGWSTATE = 103, + CTDB_CONTROL_SET_LMASTERROLE = 104, + CTDB_CONTROL_SET_RECMASTERROLE = 105, + CTDB_CONTROL_ENABLE_SCRIPT = 107, + CTDB_CONTROL_DISABLE_SCRIPT = 108, + CTDB_CONTROL_SET_BAN_STATE = 109, + CTDB_CONTROL_GET_BAN_STATE = 110, + CTDB_CONTROL_SET_DB_PRIORITY = 111, + CTDB_CONTROL_GET_DB_PRIORITY = 112, + CTDB_CONTROL_TRANSACTION_CANCEL = 113, + CTDB_CONTROL_REGISTER_NOTIFY = 114, + CTDB_CONTROL_DEREGISTER_NOTIFY = 115, + CTDB_CONTROL_TRANS2_ACTIVE = 116, /* obsolete */ + CTDB_CONTROL_GET_LOG = 117, /* obsolete */ + CTDB_CONTROL_CLEAR_LOG = 118, /* obsolete */ + CTDB_CONTROL_TRANS3_COMMIT = 119, + CTDB_CONTROL_GET_DB_SEQNUM = 120, + CTDB_CONTROL_DB_SET_HEALTHY = 121, + CTDB_CONTROL_DB_GET_HEALTH = 122, + CTDB_CONTROL_GET_PUBLIC_IP_INFO = 123, + CTDB_CONTROL_GET_IFACES = 124, + CTDB_CONTROL_SET_IFACE_LINK_STATE = 125, + CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE = 126, + CTDB_CONTROL_GET_STAT_HISTORY = 127, + CTDB_CONTROL_SCHEDULE_FOR_DELETION = 128, + CTDB_CONTROL_SET_DB_READONLY = 129, + CTDB_CONTROL_CHECK_SRVIDS = 130, + CTDB_CONTROL_TRAVERSE_START_EXT = 131, + CTDB_CONTROL_GET_DB_STATISTICS = 132, + CTDB_CONTROL_SET_DB_STICKY = 133, + CTDB_CONTROL_RELOAD_PUBLIC_IPS = 134, + CTDB_CONTROL_TRAVERSE_ALL_EXT = 135, + CTDB_CONTROL_RECEIVE_RECORDS = 136, + CTDB_CONTROL_IPREALLOCATED = 137, + CTDB_CONTROL_GET_RUNSTATE = 138, + CTDB_CONTROL_DB_DETACH = 139, + CTDB_CONTROL_GET_NODES_FILE = 140, +}; + +#define CTDB_MONITORING_ACTIVE 0 +#define CTDB_MONITORING_DISABLED 1 + +#define MAX_COUNT_BUCKETS 16 +#define MAX_HOT_KEYS 10 + +struct ctdb_latency_counter { + int num; + double min; + double max; + double total; +}; + +struct ctdb_statistics { + uint32_t num_clients; + uint32_t frozen; + uint32_t recovering; + uint32_t client_packets_sent; + uint32_t client_packets_recv; + uint32_t node_packets_sent; + uint32_t node_packets_recv; + uint32_t keepalive_packets_sent; + uint32_t keepalive_packets_recv; + struct { + uint32_t req_call; + uint32_t reply_call; + uint32_t req_dmaster; + uint32_t reply_dmaster; + uint32_t reply_error; + uint32_t req_message; + uint32_t req_control; + uint32_t reply_control; + } node; + struct { + uint32_t req_call; + uint32_t req_message; + uint32_t req_control; + } client; + struct { + uint32_t call; + uint32_t control; + uint32_t traverse; + } timeouts; + struct { + struct ctdb_latency_counter ctdbd; + struct ctdb_latency_counter recd; + } reclock; + struct { + uint32_t num_calls; + uint32_t num_current; + uint32_t num_pending; + uint32_t num_failed; + struct ctdb_latency_counter latency; + uint32_t buckets[MAX_COUNT_BUCKETS]; + } locks; + uint32_t total_calls; + uint32_t pending_calls; + uint32_t childwrite_calls; + uint32_t pending_childwrite_calls; + uint32_t memory_used; + uint32_t __last_counter; /* hack */ + uint32_t max_hop_count; + uint32_t hop_count_bucket[MAX_COUNT_BUCKETS]; + struct ctdb_latency_counter call_latency; + struct ctdb_latency_counter childwrite_latency; + uint32_t num_recoveries; + struct timeval statistics_start_time; + struct timeval statistics_current_time; + uint32_t total_ro_delegations; + uint32_t total_ro_revokes; +}; + +#define INVALID_GENERATION 1 +/* table that contains the mapping between a hash value and lmaster + */ +struct ctdb_vnn_map { + uint32_t generation; + uint32_t size; + uint32_t *map; +}; + +struct ctdb_dbid { + uint32_t db_id; +#define CTDB_DB_FLAGS_PERSISTENT 0x01 +#define CTDB_DB_FLAGS_READONLY 0x02 +#define CTDB_DB_FLAGS_STICKY 0x04 + uint8_t flags; +}; + +struct ctdb_dbid_map { + uint32_t num; + struct ctdb_dbid *dbs; +}; + +struct ctdb_pulldb { + uint32_t db_id; +#define CTDB_LMASTER_ANY 0xffffffff + uint32_t lmaster; +}; + +#define CTDB_RECOVERY_NORMAL 0 +#define CTDB_RECOVERY_ACTIVE 1 + +#define CTDB_NUM_DB_PRIORITIES 3 + +/* + the extended header for records in the ltdb +*/ +struct ctdb_ltdb_header { + uint64_t rsn; + uint32_t dmaster; + uint32_t reserved1; +#define CTDB_REC_FLAG_DEFAULT 0x00000000 +#define CTDB_REC_FLAG_MIGRATED_WITH_DATA 0x00010000 +#define CTDB_REC_FLAG_VACUUM_MIGRATED 0x00020000 +#define CTDB_REC_FLAG_AUTOMATIC 0x00040000 +#define CTDB_REC_RO_HAVE_DELEGATIONS 0x01000000 +#define CTDB_REC_RO_HAVE_READONLY 0x02000000 +#define CTDB_REC_RO_REVOKING_READONLY 0x04000000 +#define CTDB_REC_RO_REVOKE_COMPLETE 0x08000000 +#define CTDB_REC_RO_FLAGS (CTDB_REC_RO_HAVE_DELEGATIONS|\ + CTDB_REC_RO_HAVE_READONLY|\ + CTDB_REC_RO_REVOKING_READONLY|\ + CTDB_REC_RO_REVOKE_COMPLETE) + uint32_t flags; +}; + +struct ctdb_rec_data { + uint32_t reqid; + struct ctdb_ltdb_header *header; + TDB_DATA key, data; +}; + +struct ctdb_rec_buffer { + uint32_t db_id; + uint32_t count; + uint8_t *buf; + size_t buflen; +}; + +typedef int (*ctdb_rec_parser_func_t)(uint32_t reqid, + struct ctdb_ltdb_header *header, + TDB_DATA key, TDB_DATA data, + void *private_data); + +struct ctdb_traverse_start { + uint32_t db_id; + uint32_t reqid; + uint64_t srvid; +}; + +struct ctdb_traverse_all { + uint32_t db_id; + uint32_t reqid; + uint32_t pnn; + uint32_t client_reqid; + uint64_t srvid; +}; + +struct ctdb_traverse_start_ext { + uint32_t db_id; + uint32_t reqid; + uint64_t srvid; + bool withemptyrecords; +}; + +struct ctdb_traverse_all_ext { + uint32_t db_id; + uint32_t reqid; + uint32_t pnn; + uint32_t client_reqid; + uint64_t srvid; + bool withemptyrecords; +}; + +typedef union { + struct sockaddr sa; + struct sockaddr_in ip; + struct sockaddr_in6 ip6; +} ctdb_sock_addr; + +struct ctdb_connection { + ctdb_sock_addr src; + ctdb_sock_addr dst; +}; + +struct ctdb_tunable { + const char *name; + uint32_t value; +}; + +struct ctdb_var_list { + int count; + const char **var; +}; + +struct ctdb_node_flag_change { + uint32_t pnn; + uint32_t new_flags; + uint32_t old_flags; +}; + +/* all tunable variables go in here */ +struct ctdb_tunable_list { + uint32_t max_redirect_count; + uint32_t seqnum_interval; /* unit is ms */ + uint32_t control_timeout; + uint32_t traverse_timeout; + uint32_t keepalive_interval; + uint32_t keepalive_limit; + uint32_t recover_timeout; + uint32_t recover_interval; + uint32_t election_timeout; + uint32_t takeover_timeout; + uint32_t monitor_interval; + uint32_t tickle_update_interval; + uint32_t script_timeout; + uint32_t script_timeout_count; /* allow dodgy scripts to hang this many times in a row before we mark the node unhealthy */ + uint32_t script_unhealthy_on_timeout; /* obsolete */ + uint32_t recovery_grace_period; + uint32_t recovery_ban_period; + uint32_t database_hash_size; + uint32_t database_max_dead; + uint32_t rerecovery_timeout; + uint32_t enable_bans; + uint32_t deterministic_public_ips; + uint32_t reclock_ping_period; + uint32_t no_ip_failback; + uint32_t disable_ip_failover; + uint32_t verbose_memory_names; + uint32_t recd_ping_timeout; + uint32_t recd_ping_failcount; + uint32_t log_latency_ms; + uint32_t reclock_latency_ms; + uint32_t recovery_drop_all_ips; + uint32_t verify_recovery_lock; + uint32_t vacuum_interval; + uint32_t vacuum_max_run_time; + uint32_t repack_limit; + uint32_t vacuum_limit; + uint32_t max_queue_depth_drop_msg; + uint32_t allow_unhealthy_db_read; + uint32_t stat_history_interval; + uint32_t deferred_attach_timeout; + uint32_t vacuum_fast_path_count; + uint32_t lcp2_public_ip_assignment; + uint32_t allow_client_db_attach; + uint32_t recover_pdb_by_seqnum; + uint32_t deferred_rebalance_on_node_add; + uint32_t fetch_collapse; + uint32_t hopcount_make_sticky; + uint32_t sticky_duration; + uint32_t sticky_pindown; + uint32_t no_ip_takeover; + uint32_t db_record_count_warn; + uint32_t db_record_size_warn; + uint32_t db_size_warn; + uint32_t pulldb_preallocation_size; + uint32_t no_ip_host_on_all_disabled; + uint32_t samba3_hack; + uint32_t mutex_enabled; + uint32_t lock_processes_per_db; +}; + +struct ctdb_tickle_list { + ctdb_sock_addr addr; + uint32_t num; + struct ctdb_connection *conn; +}; + +enum ctdb_client_type { + SERVER_TYPE_CTDB = 0, + SERVER_TYPE_SAMBA = 1, + SERVER_TYPE_NFSD = 2, + SERVER_TYPE_ISCSID = 3 +}; + +struct ctdb_client_id { + enum ctdb_client_type type; + uint32_t pnn; + uint32_t server_id; +}; + +struct ctdb_client_id_list { + uint32_t num; + struct ctdb_client_id *cid; +}; + +struct ctdb_client_id_map { + int count; + struct ctdb_client_id_list *list; +}; + +struct ctdb_addr_info { + ctdb_sock_addr addr; + uint32_t mask; + const char *iface; +}; + +struct ctdb_transdb { + uint32_t db_id; + uint32_t tid; +}; + +struct ctdb_uptime { + struct timeval current_time; + struct timeval ctdbd_start_time; + struct timeval last_recovery_started; + struct timeval last_recovery_finished; +}; + +struct ctdb_public_ip { + uint32_t pnn; + ctdb_sock_addr addr; +}; + +struct ctdb_public_ip_list { + uint32_t num; + struct ctdb_public_ip *ip; +}; + +/* + * Node flags + */ +#define NODE_FLAGS_DISCONNECTED 0x00000001 /* node isn't connected */ +#define NODE_FLAGS_UNHEALTHY 0x00000002 /* monitoring says node is unhealthy */ +#define NODE_FLAGS_PERMANENTLY_DISABLED 0x00000004 /* administrator has disabled node */ +#define NODE_FLAGS_BANNED 0x00000008 /* recovery daemon has banned the node */ +#define NODE_FLAGS_DELETED 0x00000010 /* this node has been deleted */ +#define NODE_FLAGS_STOPPED 0x00000020 /* this node has been stopped */ +#define NODE_FLAGS_DISABLED (NODE_FLAGS_UNHEALTHY|NODE_FLAGS_PERMANENTLY_DISABLED) +#define NODE_FLAGS_INACTIVE (NODE_FLAGS_DELETED|NODE_FLAGS_DISCONNECTED|NODE_FLAGS_BANNED|NODE_FLAGS_STOPPED) + +/* + * Node capabilities + */ +#define CTDB_CAP_RECMASTER 0x00000001 +#define CTDB_CAP_LMASTER 0x00000002 +/* This capability is set if CTDB_LVS_PUBLIC_IP is set */ +#define CTDB_CAP_LVS 0x00000004 +/* This capability is set if NATGW is enabled */ +#define CTDB_CAP_NATGW 0x00000008 + +struct ctdb_node_and_flags { + uint32_t pnn; + uint32_t flags; + ctdb_sock_addr addr; +}; + +struct ctdb_node_map { + uint32_t num; + struct ctdb_node_and_flags *node; +}; + +enum ctdb_event { + CTDB_EVENT_INIT, /* CTDB starting up: no args */ + CTDB_EVENT_SETUP, /* CTDB starting up after transport is readdy: no args. */ + CTDB_EVENT_STARTUP, /* CTDB starting up after initial recovery: no args. */ + CTDB_EVENT_START_RECOVERY, /* CTDB recovery starting: no args. */ + CTDB_EVENT_RECOVERED, /* CTDB recovery finished: no args. */ + CTDB_EVENT_TAKE_IP, /* IP taken: interface, IP address, netmask bits. */ + CTDB_EVENT_RELEASE_IP, /* IP released: interface, IP address, netmask bits. */ + CTDB_EVENT_STOPPED, /* Deprecated, do not use. */ + CTDB_EVENT_MONITOR, /* Please check if service is healthy: no args. */ + CTDB_EVENT_STATUS, /* Deprecated, do not use. */ + CTDB_EVENT_SHUTDOWN, /* CTDB shutting down: no args. */ + CTDB_EVENT_RELOAD, /* Deprecated, do not use */ + CTDB_EVENT_UPDATE_IP, /* IP updating: old interface, new interface, IP address, netmask bits. */ + CTDB_EVENT_IPREALLOCATED, /* when a takeover_run() completes */ + CTDB_EVENT_MAX +}; + +#define MAX_SCRIPT_NAME 31 +#define MAX_SCRIPT_OUTPUT 511 + +struct ctdb_script { + char name[MAX_SCRIPT_NAME+1]; + struct timeval start; + struct timeval finished; + int32_t status; + char output[MAX_SCRIPT_OUTPUT+1]; +}; + +struct ctdb_script_list { + uint32_t num_scripts; + struct ctdb_script *script; +}; + +struct ctdb_ban_state { + uint32_t pnn; + uint32_t time; +}; + +struct ctdb_db_priority { + uint32_t db_id; + uint32_t priority; +}; + +struct ctdb_notify_data { + uint64_t srvid; + TDB_DATA data; +}; + +#ifdef IFNAMSIZ +#define CTDB_IFACE_SIZE IFNAMSIZ +#else +#define CTDB_IFACE_SIZE 16 +#endif + +struct ctdb_iface { + char name[CTDB_IFACE_SIZE+2]; + uint16_t link_state; + uint32_t references; +}; + +struct ctdb_iface_list { + uint32_t num; + struct ctdb_iface *iface; +}; + +struct ctdb_public_ip_info { + struct ctdb_public_ip ip; + uint32_t active_idx; + struct ctdb_iface_list *ifaces; +}; + +struct ctdb_statistics_list { + int num; + struct ctdb_statistics *stats; +}; + +struct ctdb_key_data { + uint32_t db_id; + struct ctdb_ltdb_header header; + TDB_DATA key; +}; + +struct ctdb_uint8_array { + int num; + uint8_t *val; +}; + +struct ctdb_uint64_array { + int num; + uint64_t *val; +}; + +struct ctdb_db_statistics { + struct { + uint32_t num_calls; + uint32_t num_current; + uint32_t num_pending; + uint32_t num_failed; + struct ctdb_latency_counter latency; + uint32_t buckets[MAX_COUNT_BUCKETS]; + } locks; + struct { + struct ctdb_latency_counter latency; + } vacuum; + uint32_t db_ro_delegations; + uint32_t db_ro_revokes; + uint32_t hop_count_bucket[MAX_COUNT_BUCKETS]; + uint32_t num_hot_keys; + struct { + uint32_t count; + TDB_DATA key; + } hot_keys[MAX_HOT_KEYS]; +}; + +enum ctdb_runstate { + CTDB_RUNSTATE_UNKNOWN, + CTDB_RUNSTATE_INIT, + CTDB_RUNSTATE_SETUP, + CTDB_RUNSTATE_FIRST_RECOVERY, + CTDB_RUNSTATE_STARTUP, + CTDB_RUNSTATE_RUNNING, + CTDB_RUNSTATE_SHUTDOWN, +}; + +struct ctdb_req_control_data { + uint32_t opcode; + union { + pid_t pid; + uint32_t db_id; + struct ctdb_vnn_map *vnnmap; + uint32_t loglevel; + struct ctdb_pulldb *pulldb; + struct ctdb_rec_buffer *recbuf; + uint32_t recmode; + const char *db_name; + struct ctdb_traverse_start *traverse_start; + struct ctdb_traverse_all *traverse_all; + struct ctdb_rec_data *rec_data; + uint32_t recmaster; + struct ctdb_connection *conn; + struct ctdb_tunable *tunable; + const char *tun_var; + struct ctdb_node_flag_change *flag_change; + ctdb_sock_addr *addr; + struct ctdb_tickle_list *tickles; + struct ctdb_client_id *cid; + struct ctdb_addr_info *addr_info; + uint32_t tid; + struct ctdb_transdb *transdb; + const char *event_str; + struct ctdb_public_ip *pubip; + enum ctdb_event event; + double reclock_latency; + const char *reclock_file; + uint32_t role; + const char *script; + struct ctdb_ban_state *ban_state; + struct ctdb_db_priority *db_prio; + struct ctdb_notify_data *notify; + uint64_t srvid; + struct ctdb_iface *iface; + struct ctdb_key_data *key; + struct ctdb_uint64_array *u64_array; + struct ctdb_traverse_start_ext *traverse_start_ext; + struct ctdb_traverse_all_ext *traverse_all_ext; + } data; +}; + +struct ctdb_reply_control_data { + uint32_t opcode; + union { + struct ctdb_statistics *stats; + const char *db_path; + struct ctdb_vnn_map *vnnmap; + uint32_t loglevel; + struct ctdb_dbid_map *dbmap; + struct ctdb_rec_buffer *recbuf; + uint32_t db_id; + const char *db_name; + const char *mem_str; + uint32_t tun_value; + struct ctdb_var_list *tun_var_list; + struct ctdb_tunable_list *tun_list; + struct ctdb_tickle_list *tickles; + struct ctdb_client_id_map *cid_map; + struct ctdb_uptime *uptime; + uint32_t caps; + struct ctdb_public_ip_list *pubip_list; + struct ctdb_node_map *nodemap; + struct ctdb_script_list *script_list; + const char *reclock_file; + struct ctdb_ban_state *ban_state; + uint64_t seqnum; + const char *reason; + struct ctdb_public_ip_info *ipinfo; + struct ctdb_iface_list *iface_list; + struct ctdb_statistics_list *stats_list; + struct ctdb_uint8_array *u8_array; + struct ctdb_db_statistics *dbstats; + enum ctdb_runstate runstate; + } data; +}; + +struct ctdb_req_control { + uint32_t opcode; + uint32_t pad; + uint64_t srvid; + uint32_t client_id; +#define CTDB_CTRL_FLAG_NOREPLY 1 +#define CTDB_CTRL_FLAG_OPCODE_SPECIFIC 0xFFFF0000 + uint32_t flags; + struct ctdb_req_control_data rdata; +}; + +struct ctdb_reply_control { + int32_t status; + const char *errmsg; + struct ctdb_reply_control_data rdata; +}; + +struct ctdb_election_message { + uint32_t num_connected; + struct timeval priority_time; + uint32_t pnn; + uint32_t node_flags; +}; + +struct ctdb_srvid_message { + uint32_t pnn; + uint64_t srvid; +}; + +struct ctdb_disable_message { + uint32_t pnn; + uint64_t srvid; + uint32_t timeout; +}; + +union ctdb_message_data { + /* SRVID_ELECTION */ + struct ctdb_election_message *election; + /* SRVID_RELEASE_IP, SRVID_TAKE_IP */ + const char *ipaddr; + /* SRVID_SET_NODE_FLAGS, SERVID_PUSH_NODE_FLAGS */ + struct ctdb_node_flag_change *flag_change; + /* SRVID_RECD_UPDATE_IP */ + struct ctdb_public_ip *pubip; + /* SRVID_VACUUM_FETCH */ + struct ctdb_rec_buffer *recbuf; + /* SRVID_DETACH_DATABASE */ + uint32_t db_id; + /* SRVID_MEM_DUMP, SRVID_TAKEOVER_RUN */ + struct ctdb_srvid_message *msg; + /* SRVID_REBALANCE_NODE */ + uint32_t pnn; + /* SRVID_DISABLE_TAKEOVER_RUNS, SRVID_DISABLE_RECOVERIES */ + struct ctdb_disable_message *disable; + /* SRVID_DISABLE_IP_CHECK */ + uint32_t timeout; +}; + +struct ctdb_req_message { + uint64_t srvid; + union ctdb_message_data data; +}; + +struct ctdb_req_message_data { + uint64_t srvid; + TDB_DATA data; +}; + +/* This is equivalent to server_id */ +struct ctdb_server_id { + uint64_t pid; + uint32_t task_id; + uint32_t vnn; + uint64_t unique_id; +}; + +enum ctdb_g_lock_type { + G_LOCK_READ = 0, + G_LOCK_WRITE = 1, +}; + +struct ctdb_g_lock { + enum ctdb_g_lock_type type; + struct ctdb_server_id sid; +}; + +struct ctdb_g_lock_list { + unsigned int num; + struct ctdb_g_lock *lock; +}; + +#endif /* __CTDB_PROTOCOL_H__ */ diff --git a/ctdb/protocol/protocol_api.h b/ctdb/protocol/protocol_api.h new file mode 100644 index 0000000..3628c3e --- /dev/null +++ b/ctdb/protocol/protocol_api.h @@ -0,0 +1,643 @@ +/* + CTDB protocol marshalling + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#ifndef __CTDB_PROTOCOL_API_H__ +#define __CTDB_PROTOCOL_API_H__ + +#include "protocol/protocol.h" + +/* From protocol/protocol_types.c */ + +size_t ctdb_ltdb_header_len(struct ctdb_ltdb_header *header); +void ctdb_ltdb_header_push(struct ctdb_ltdb_header *header, uint8_t *buf); +int ctdb_ltdb_header_pull(uint8_t *buf, size_t buflen, + struct ctdb_ltdb_header *header); + +size_t ctdb_rec_data_len(struct ctdb_rec_data *rec); +void ctdb_rec_data_push(struct ctdb_rec_data *rec, uint8_t *buf); +int ctdb_rec_data_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_rec_data **out); + +size_t ctdb_rec_buffer_len(struct ctdb_rec_buffer *recbuf); +void ctdb_rec_buffer_push(struct ctdb_rec_buffer *recbuf, uint8_t *buf); +int ctdb_rec_buffer_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_rec_buffer **out); + +struct ctdb_rec_buffer *ctdb_rec_buffer_init(TALLOC_CTX *mem_ctx, + uint32_t db_id); +int ctdb_rec_buffer_add(TALLOC_CTX *mem_ctx, struct ctdb_rec_buffer *recbuf, + uint32_t reqid, struct ctdb_ltdb_header *header, + TDB_DATA key, TDB_DATA data); +int ctdb_rec_buffer_traverse(struct ctdb_rec_buffer *recbuf, + ctdb_rec_parser_func_t func, + void *private_data); + +size_t ctdb_server_id_len(struct ctdb_server_id *sid); +void ctdb_server_id_push(struct ctdb_server_id *sid, uint8_t *buf); +int ctdb_server_id_pull(uint8_t *buf, size_t buflen, + struct ctdb_server_id *sid); + +size_t ctdb_g_lock_len(struct ctdb_g_lock *lock); +void ctdb_g_lock_push(struct ctdb_g_lock *lock, uint8_t *buf); +int ctdb_g_lock_pull(uint8_t *buf, size_t buflen, struct ctdb_g_lock *lock); + +size_t ctdb_g_lock_list_len(struct ctdb_g_lock_list *lock_list); +void ctdb_g_lock_list_push(struct ctdb_g_lock_list *lock_list, uint8_t *buf); +int ctdb_g_lock_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_g_lock_list **out); + +/* From protocol/protocol_header.c */ + +void ctdb_req_header_fill(struct ctdb_req_header *h, uint32_t generation, + uint32_t operation, uint32_t destnode, + uint32_t srcnode, uint32_t reqid); + +int ctdb_req_header_pull(uint8_t *pkt, size_t pkt_len, + struct ctdb_req_header *h); + +int ctdb_req_header_verify(struct ctdb_req_header *h, uint32_t operation); + +/* From protocol/protocol_call.c */ + +int ctdb_req_call_push(struct ctdb_req_header *h, + struct ctdb_req_call *c, + TALLOC_CTX *mem_ctx, + uint8_t **pkt, size_t *pkt_len); + +int ctdb_req_call_pull(uint8_t *pkt, size_t pkt_len, + struct ctdb_req_header *h, + TALLOC_CTX *mem_ctx, + struct ctdb_req_call *c); + +int ctdb_reply_call_push(struct ctdb_req_header *h, + struct ctdb_reply_call *c, + TALLOC_CTX *mem_ctx, + uint8_t **pkt, size_t *pkt_len); + +int ctdb_reply_call_pull(uint8_t *pkt, size_t pkt_len, + struct ctdb_req_header *h, + TALLOC_CTX *mem_ctx, + struct ctdb_reply_call *c); + +int ctdb_reply_error_push(struct ctdb_req_header *h, + struct ctdb_reply_error *c, + TALLOC_CTX *mem_ctx, + uint8_t **pkt, size_t *pkt_len); + +int ctdb_reply_error_pull(uint8_t *pkt, size_t pkt_len, + struct ctdb_req_header *h, + TALLOC_CTX *mem_ctx, + struct ctdb_reply_error *c); + +int ctdb_req_dmaster_push(struct ctdb_req_header *h, + struct ctdb_req_dmaster *c, + TALLOC_CTX *mem_ctx, + uint8_t **pkt, size_t *pkt_len); + +int ctdb_req_dmaster_pull(uint8_t *pkt, size_t pkt_len, + struct ctdb_req_header *h, + TALLOC_CTX *mem_ctx, + struct ctdb_req_dmaster *c); + +int ctdb_reply_dmaster_push(struct ctdb_req_header *h, + struct ctdb_reply_dmaster *c, + TALLOC_CTX *mem_ctx, + uint8_t **pkt, size_t *pkt_len); + +int ctdb_reply_dmaster_pull(uint8_t *pkt, size_t pkt_len, + struct ctdb_req_header *h, + TALLOC_CTX *mem_ctx, + struct ctdb_reply_dmaster *c); + +/* From protocol/protocol_control.c */ + +int ctdb_req_control_push(struct ctdb_req_header *h, + struct ctdb_req_control *c, + TALLOC_CTX *mem_ctx, + uint8_t **pkt, size_t *pkt_len); + +int ctdb_req_control_pull(uint8_t *pkt, size_t pkt_len, + struct ctdb_req_header *h, + TALLOC_CTX *mem_ctx, + struct ctdb_req_control *c); + +int ctdb_reply_control_push(struct ctdb_req_header *h, + struct ctdb_reply_control *c, + TALLOC_CTX *mem_ctx, + uint8_t **pkt, size_t *pkt_len); + +int ctdb_reply_control_pull(uint8_t *pkt, size_t pkt_len, uint32_t opcode, + struct ctdb_req_header *h, + TALLOC_CTX *mem_ctx, + struct ctdb_reply_control *c); + +/* From protocol/protocol_client.c */ + +void ctdb_req_control_process_exists(struct ctdb_req_control *request, + pid_t pid); +int ctdb_reply_control_process_exists(struct ctdb_reply_control *reply, + int *status); + +void ctdb_req_control_statistics(struct ctdb_req_control *request); + +int ctdb_reply_control_statistics(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + struct ctdb_statistics **stats); + +void ctdb_req_control_ping(struct ctdb_req_control *request); +int ctdb_reply_control_ping(struct ctdb_reply_control *reply, + int *num_clients); + +void ctdb_req_control_getdbpath(struct ctdb_req_control *request, + uint32_t db_id); +int ctdb_reply_control_getdbpath(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, const char **db_path); + +void ctdb_req_control_getvnnmap(struct ctdb_req_control *request); +int ctdb_reply_control_getvnnmap(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + struct ctdb_vnn_map **vnnmap); + +void ctdb_req_control_setvnnmap(struct ctdb_req_control *request, + struct ctdb_vnn_map *vnnmap); +int ctdb_reply_control_setvnnmap(struct ctdb_reply_control *reply); + +void ctdb_req_control_get_debug(struct ctdb_req_control *request); +int ctdb_reply_control_get_debug(struct ctdb_reply_control *reply, + uint32_t *debug_level); + +void ctdb_req_control_set_debug(struct ctdb_req_control *request, + uint32_t debug_level); +int ctdb_reply_control_set_debug(struct ctdb_reply_control *reply); + +void ctdb_req_control_get_dbmap(struct ctdb_req_control *request); +int ctdb_reply_control_get_dbmap(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + struct ctdb_dbid_map **dbmap); + +void ctdb_req_control_pull_db(struct ctdb_req_control *request, + struct ctdb_pulldb *pulldb); +int ctdb_reply_control_pull_db(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + struct ctdb_rec_buffer **recbuf); + +void ctdb_req_control_push_db(struct ctdb_req_control *request, + struct ctdb_rec_buffer *recbuf); +int ctdb_reply_control_push_db(struct ctdb_reply_control *reply); + +void ctdb_req_control_get_recmode(struct ctdb_req_control *request); +int ctdb_reply_control_get_recmode(struct ctdb_reply_control *reply, + int *recmode); + +void ctdb_req_control_set_recmode(struct ctdb_req_control *request, + int recmode); +int ctdb_reply_control_set_recmode(struct ctdb_reply_control *reply); + +void ctdb_req_control_statistics_reset(struct ctdb_req_control *request); +int ctdb_reply_control_statistics_reset(struct ctdb_reply_control *reply); + +void ctdb_req_control_db_attach(struct ctdb_req_control *request, + const char *db_name, uint32_t tdb_flags); +int ctdb_reply_control_db_attach(struct ctdb_reply_control *reply, + uint32_t *db_id); + +void ctdb_req_control_traverse_start(struct ctdb_req_control *request, + struct ctdb_traverse_start *traverse); +int ctdb_reply_control_traverse_start(struct ctdb_reply_control *reply); + +void ctdb_req_control_register_srvid(struct ctdb_req_control *request, + uint64_t srvid); +int ctdb_reply_control_register_srvid(struct ctdb_reply_control *reply); + +void ctdb_req_control_deregister_srvid(struct ctdb_req_control *request, + uint64_t srvid); +int ctdb_reply_control_deregister_srvid(struct ctdb_reply_control *reply); + +void ctdb_req_control_get_dbname(struct ctdb_req_control *request, + uint32_t db_id); +int ctdb_reply_control_get_dbname(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, const char **db_name); + +void ctdb_req_control_enable_seqnum(struct ctdb_req_control *request, + uint32_t db_id); +int ctdb_reply_control_enable_seqnum(struct ctdb_reply_control *reply); + +void ctdb_req_control_update_seqnum(struct ctdb_req_control *request, + uint32_t db_id); +int ctdb_reply_control_update_seqnum(struct ctdb_reply_control *reply); + +void ctdb_req_control_dump_memory(struct ctdb_req_control *request); +int ctdb_reply_control_dump_memory(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, const char **mem_str); + +void ctdb_req_control_get_pid(struct ctdb_req_control *request); +int ctdb_reply_control_get_pid(struct ctdb_reply_control *reply, + pid_t *pid); + +void ctdb_req_control_get_recmaster(struct ctdb_req_control *request); +int ctdb_reply_control_get_recmaster(struct ctdb_reply_control *reply, + uint32_t *recmaster); + +void ctdb_req_control_set_recmaster(struct ctdb_req_control *request, + int recmaster); +int ctdb_reply_control_set_recmaster(struct ctdb_reply_control *reply); + +void ctdb_req_control_freeze(struct ctdb_req_control *request, + uint32_t priority); +int ctdb_reply_control_freeze(struct ctdb_reply_control *reply); + +void ctdb_req_control_thaw(struct ctdb_req_control *request, + uint32_t priority); +int ctdb_reply_control_thaw(struct ctdb_reply_control *reply); + +void ctdb_req_control_get_pnn(struct ctdb_req_control *request); +int ctdb_reply_control_get_pnn(struct ctdb_reply_control *reply, + uint32_t *pnn); + +void ctdb_req_control_shutdown(struct ctdb_req_control *request); +int ctdb_reply_control_shutdown(struct ctdb_reply_control *reply); + +void ctdb_req_control_get_monmode(struct ctdb_req_control *request); +int ctdb_reply_control_get_monmode(struct ctdb_reply_control *reply, + int *mon_mode); + +void ctdb_req_control_tcp_client(struct ctdb_req_control *request, + struct ctdb_connection *conn); +int ctdb_reply_control_tcp_client(struct ctdb_reply_control *reply); + +void ctdb_req_control_tcp_add(struct ctdb_req_control *request, + struct ctdb_connection *conn); +int ctdb_reply_control_tcp_add(struct ctdb_reply_control *reply); + +void ctdb_req_control_tcp_remove(struct ctdb_req_control *request, + struct ctdb_connection *conn); +int ctdb_reply_control_tcp_remove(struct ctdb_reply_control *reply); + +void ctdb_req_control_startup(struct ctdb_req_control *request); +int ctdb_reply_control_startup(struct ctdb_reply_control *reply); + +void ctdb_req_control_set_tunable(struct ctdb_req_control *request, + struct ctdb_tunable *tunable); +int ctdb_reply_control_set_tunable(struct ctdb_reply_control *reply); + +void ctdb_req_control_get_tunable(struct ctdb_req_control *request, + const char *name); +int ctdb_reply_control_get_tunable(struct ctdb_reply_control *reply, + uint32_t *value); + +void ctdb_req_control_list_tunables(struct ctdb_req_control *request); +int ctdb_reply_control_list_tunables(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + struct ctdb_var_list **tun_var_list); + +void ctdb_req_control_modify_flags(struct ctdb_req_control *request, + struct ctdb_node_flag_change *flag_change); +int ctdb_reply_control_modify_flags(struct ctdb_reply_control *reply); + +void ctdb_req_control_get_all_tunables(struct ctdb_req_control *request); +int ctdb_reply_control_get_all_tunables(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + struct ctdb_tunable_list **tun_list); + +void ctdb_req_control_kill_tcp(struct ctdb_req_control *request, + struct ctdb_connection *conn); +int ctdb_reply_control_kill_tcp(struct ctdb_reply_control *reply); + +void ctdb_req_control_get_tcp_tickle_list(struct ctdb_req_control *request, + ctdb_sock_addr *addr); +int ctdb_reply_control_get_tcp_tickle_list(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + struct ctdb_tickle_list **tickles); + +void ctdb_req_control_set_tcp_tickle_list(struct ctdb_req_control *request, + struct ctdb_tickle_list *tickles); +int ctdb_reply_control_set_tcp_tickle_list(struct ctdb_reply_control *reply); + +void ctdb_req_control_register_server_id(struct ctdb_req_control *request, + struct ctdb_client_id *sid); +int ctdb_reply_control_register_server_id(struct ctdb_reply_control *reply); + +void ctdb_req_control_unregister_server_id(struct ctdb_req_control *request, + struct ctdb_client_id *sid); +int ctdb_reply_control_unregister_server_id(struct ctdb_reply_control *reply); + +void ctdb_req_control_check_server_id(struct ctdb_req_control *request, + struct ctdb_client_id *sid); +int ctdb_reply_control_check_server_id(struct ctdb_reply_control *reply); + +void ctdb_req_control_get_server_id_list(struct ctdb_req_control *request); +int ctdb_reply_control_get_server_id_list(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + struct ctdb_client_id_map **cid_map); + +void ctdb_req_control_db_attach_persistent(struct ctdb_req_control *request, + const char *name, + uint32_t tdb_flags); +int ctdb_reply_control_db_attach_persistent(struct ctdb_reply_control *reply, + uint32_t *db_id); + +void ctdb_req_control_update_record(struct ctdb_req_control *request, + struct ctdb_rec_buffer *recbuf); +int ctdb_reply_control_update_record(struct ctdb_reply_control *reply); + +void ctdb_req_control_send_gratuitous_arp(struct ctdb_req_control *request, + struct ctdb_addr_info *addr_info); +int ctdb_reply_control_send_gratuitous_arp(struct ctdb_reply_control *reply); + +void ctdb_req_control_transaction_start(struct ctdb_req_control *request, + uint32_t tid); +int ctdb_reply_control_transaction_start(struct ctdb_reply_control *reply); + +void ctdb_req_control_transaction_commit(struct ctdb_req_control *request, + uint32_t tid); +int ctdb_reply_control_transaction_commit(struct ctdb_reply_control *reply); + +void ctdb_req_control_wipe_database(struct ctdb_req_control *request, + struct ctdb_transdb *transdb); +int ctdb_reply_control_wipe_database(struct ctdb_reply_control *reply); + +void ctdb_req_control_uptime(struct ctdb_req_control *request); +int ctdb_reply_control_uptime(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + struct ctdb_uptime **uptime); + +void ctdb_req_control_start_recovery(struct ctdb_req_control *request); +int ctdb_reply_control_start_recovery(struct ctdb_reply_control *reply); + +void ctdb_req_control_end_recovery(struct ctdb_req_control *request); +int ctdb_reply_control_end_recovery(struct ctdb_reply_control *reply); + +void ctdb_req_control_reload_nodes_file(struct ctdb_req_control *request); +int ctdb_reply_control_reload_nodes_file(struct ctdb_reply_control *reply); + +void ctdb_req_control_try_delete_records(struct ctdb_req_control *request, + struct ctdb_rec_buffer *recbuf); +int ctdb_reply_control_try_delete_records(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + struct ctdb_rec_buffer **recbuf); + +void ctdb_req_control_enable_monitor(struct ctdb_req_control *request); +int ctdb_reply_control_enable_monitor(struct ctdb_reply_control *reply); + +void ctdb_req_control_disable_monitor(struct ctdb_req_control *request); +int ctdb_reply_control_disable_monitor(struct ctdb_reply_control *reply); + +void ctdb_req_control_add_public_ip(struct ctdb_req_control *request, + struct ctdb_addr_info *addr_info); +int ctdb_reply_control_add_public_ip(struct ctdb_reply_control *reply); + +void ctdb_req_control_del_public_ip(struct ctdb_req_control *request, + struct ctdb_addr_info *addr_info); +int ctdb_reply_control_del_public_ip(struct ctdb_reply_control *reply); + +void ctdb_req_control_run_eventscripts(struct ctdb_req_control *request, + const char *event_str); +int ctdb_reply_control_run_eventscripts(struct ctdb_reply_control *reply); + +void ctdb_req_control_get_capabilities(struct ctdb_req_control *request); +int ctdb_reply_control_get_capabilities(struct ctdb_reply_control *reply, + uint32_t *caps); + +void ctdb_req_control_recd_ping(struct ctdb_req_control *request); +int ctdb_reply_control_recd_ping(struct ctdb_reply_control *reply); + +void ctdb_req_control_release_ip(struct ctdb_req_control *request, + struct ctdb_public_ip *pubip); +int ctdb_reply_control_release_ip(struct ctdb_reply_control *reply); + +void ctdb_req_control_takeover_ip(struct ctdb_req_control *request, + struct ctdb_public_ip *pubip); +int ctdb_reply_control_takeover_ip(struct ctdb_reply_control *reply); + +void ctdb_req_control_get_public_ips(struct ctdb_req_control *request); +int ctdb_reply_control_get_public_ips(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + struct ctdb_public_ip_list **pubip_list); + +void ctdb_req_control_get_nodemap(struct ctdb_req_control *request); +int ctdb_reply_control_get_nodemap(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + struct ctdb_node_map **nodemap); + +void ctdb_req_control_get_event_script_status(struct ctdb_req_control *request, + uint32_t event); +int ctdb_reply_control_get_event_script_status(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + struct ctdb_script_list **script_list); + +void ctdb_req_control_traverse_kill(struct ctdb_req_control *request, + struct ctdb_traverse_start *traverse); +int ctdb_reply_control_traverse_kill(struct ctdb_reply_control *reply); + +void ctdb_req_control_recd_reclock_latency(struct ctdb_req_control *request, + double reclock_latency); +int ctdb_reply_control_recd_reclock_latency(struct ctdb_reply_control *reply); + +void ctdb_req_control_get_reclock_file(struct ctdb_req_control *request); +int ctdb_reply_control_get_reclock_file(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + const char **reclock_file); + +void ctdb_req_control_set_reclock_file(struct ctdb_req_control *request, + const char *reclock_file); +int ctdb_reply_control_set_reclock_file(struct ctdb_reply_control *reply); + +void ctdb_req_control_stop_node(struct ctdb_req_control *request); +int ctdb_reply_control_stop_node(struct ctdb_reply_control *reply); + +void ctdb_req_control_continue_node(struct ctdb_req_control *request); +int ctdb_reply_control_continue_node(struct ctdb_reply_control *reply); + +void ctdb_req_control_set_natgwstate(struct ctdb_req_control *request, + uint32_t natgw_role); +int ctdb_reply_control_set_natgwstate(struct ctdb_reply_control *reply); + +void ctdb_req_control_set_lmasterrole(struct ctdb_req_control *request, + uint32_t lmaster_role); +int ctdb_reply_control_set_lmasterrole(struct ctdb_reply_control *reply); + +void ctdb_req_control_set_recmasterrole(struct ctdb_req_control *request, + uint32_t recmaster_role); +int ctdb_reply_control_set_recmasterrole(struct ctdb_reply_control *reply); + +void ctdb_req_control_enable_script(struct ctdb_req_control *request, + const char *script); +int ctdb_reply_control_enable_script(struct ctdb_reply_control *reply); + +void ctdb_req_control_disable_script(struct ctdb_req_control *request, + const char *script); +int ctdb_reply_control_disable_script(struct ctdb_reply_control *reply); + +void ctdb_req_control_set_ban_state(struct ctdb_req_control *request, + struct ctdb_ban_state *ban_state); +int ctdb_reply_control_set_ban_state(struct ctdb_reply_control *reply); + +void ctdb_req_control_get_ban_state(struct ctdb_req_control *request); +int ctdb_reply_control_get_ban_state(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + struct ctdb_ban_state **ban_state); + +void ctdb_req_control_set_db_priority(struct ctdb_req_control *request, + struct ctdb_db_priority *db_prio); +int ctdb_reply_control_set_db_priority(struct ctdb_reply_control *reply); + +void ctdb_req_control_get_db_priority(struct ctdb_req_control *request, + uint32_t db_id); +int ctdb_reply_control_get_db_priority(struct ctdb_reply_control *reply, + uint32_t *priority); + +void ctdb_req_control_transaction_cancel(struct ctdb_req_control *request, + uint32_t tid); +int ctdb_reply_control_transaction_cancel(struct ctdb_reply_control *reply); + +void ctdb_req_control_register_notify(struct ctdb_req_control *request, + struct ctdb_notify_data *notify); +int ctdb_reply_control_register_notify(struct ctdb_reply_control *reply); + +void ctdb_req_control_deregister_notify(struct ctdb_req_control *request, + uint64_t srvid); +int ctdb_reply_control_deregister_notify(struct ctdb_reply_control *reply); + +void ctdb_req_control_trans3_commit(struct ctdb_req_control *request, + struct ctdb_rec_buffer *recbuf); +int ctdb_reply_control_trans3_commit(struct ctdb_reply_control *reply); + +void ctdb_req_control_get_db_seqnum(struct ctdb_req_control *request, + uint32_t db_id); +int ctdb_reply_control_get_db_seqnum(struct ctdb_reply_control *reply, + uint64_t *seqnum); + +void ctdb_req_control_db_set_healthy(struct ctdb_req_control *request, + uint32_t db_id); +int ctdb_reply_control_db_set_healthy(struct ctdb_reply_control *reply); + +void ctdb_req_control_db_get_health(struct ctdb_req_control *request, + uint32_t db_id); +int ctdb_reply_control_db_get_health(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + const char **reason); + +void ctdb_req_control_get_public_ip_info(struct ctdb_req_control *request, + ctdb_sock_addr *addr); +int ctdb_reply_control_get_public_ip_info(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + struct ctdb_public_ip_info **ipinfo); + +void ctdb_req_control_get_ifaces(struct ctdb_req_control *request); +int ctdb_reply_control_get_ifaces(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + struct ctdb_iface_list **iface_list); + +void ctdb_req_control_set_iface_link_state(struct ctdb_req_control *request, + struct ctdb_iface *iface); +int ctdb_reply_control_set_iface_link_state(struct ctdb_reply_control *reply); + +void ctdb_req_control_tcp_add_delayed_update(struct ctdb_req_control *request, + struct ctdb_connection *conn); +int ctdb_reply_control_tcp_add_delayed_update(struct ctdb_reply_control *reply); + +void ctdb_req_control_get_stat_history(struct ctdb_req_control *request); +int ctdb_reply_control_get_stat_history(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + struct ctdb_statistics_list **stats_list); + +void ctdb_req_control_schedule_for_deletion(struct ctdb_req_control *request, + struct ctdb_key_data *key); +int ctdb_reply_control_schedule_for_deletion(struct ctdb_reply_control *reply); + +void ctdb_req_control_set_db_readonly(struct ctdb_req_control *request, + uint32_t db_id); +int ctdb_reply_control_set_db_readonly(struct ctdb_reply_control *reply); + +void ctdb_req_control_check_srvids(struct ctdb_req_control *request, + struct ctdb_uint64_array *u64_array); +int ctdb_reply_control_check_srvids(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + struct ctdb_uint8_array **u8_array); + +void ctdb_req_control_traverse_start_ext(struct ctdb_req_control *request, + struct ctdb_traverse_start_ext *traverse); +int ctdb_reply_control_traverse_start_ext(struct ctdb_reply_control *reply); + +void ctdb_req_control_get_db_statistics(struct ctdb_req_control *request, + uint32_t db_id); +int ctdb_reply_control_get_db_statistics(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + struct ctdb_db_statistics **dbstats); + +void ctdb_req_control_set_db_sticky(struct ctdb_req_control *request, + uint32_t db_id); +int ctdb_reply_control_set_db_sticky(struct ctdb_reply_control *reply); + +void ctdb_req_control_reload_public_ips(struct ctdb_req_control *request); +int ctdb_reply_control_reload_public_ips(struct ctdb_reply_control *reply); + +void ctdb_req_control_receive_records(struct ctdb_req_control *request, + struct ctdb_rec_buffer *recbuf); +int ctdb_reply_control_receive_records(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + struct ctdb_rec_buffer **recbuf); + +void ctdb_req_control_ipreallocated(struct ctdb_req_control *request); +int ctdb_reply_control_ipreallocated(struct ctdb_reply_control *reply); + +void ctdb_req_control_get_runstate(struct ctdb_req_control *request); +int ctdb_reply_control_get_runstate(struct ctdb_reply_control *reply, + enum ctdb_runstate *runstate); + +void ctdb_req_control_db_detach(struct ctdb_req_control *request, + uint32_t db_id); +int ctdb_reply_control_db_detach(struct ctdb_reply_control *reply); + +void ctdb_req_control_get_nodes_file(struct ctdb_req_control *request); +int ctdb_reply_control_get_nodes_file(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + struct ctdb_node_map **nodemap); + +/* From protocol/protocol_message.c */ + +int ctdb_req_message_push(struct ctdb_req_header *h, + struct ctdb_req_message *c, + TALLOC_CTX *mem_ctx, + uint8_t **pkt, size_t *pkt_len); + +int ctdb_req_message_pull(uint8_t *pkt, size_t pkt_len, + struct ctdb_req_header *h, + TALLOC_CTX *mem_ctx, + struct ctdb_req_message *c); + +int ctdb_req_message_data_push(struct ctdb_req_header *h, + struct ctdb_req_message_data *message, + TALLOC_CTX *mem_ctx, + uint8_t **pkt, size_t *pkt_len); + +int ctdb_req_message_data_pull(uint8_t *pkt, size_t pkt_len, + struct ctdb_req_header *h, + TALLOC_CTX *mem_ctx, + struct ctdb_req_message_data *message); + +/* From protocol/protocol_util.c */ + +const char *ctdb_runstate_to_string(enum ctdb_runstate runstate); +enum ctdb_runstate ctdb_runstate_from_string(const char *runstate_str); + +const char *ctdb_event_to_string(enum ctdb_event event); +enum ctdb_event ctdb_event_from_string(const char *event_str); + +#endif /* __CTDB_PROTOCOL_API_H__ */ diff --git a/ctdb/protocol/protocol_call.c b/ctdb/protocol/protocol_call.c new file mode 100644 index 0000000..e0f38d9 --- /dev/null +++ b/ctdb/protocol/protocol_call.c @@ -0,0 +1,446 @@ +/* + CTDB protocol marshalling + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include "replace.h" +#include "system/network.h" + +#include +#include + +#include "protocol.h" +#include "protocol_api.h" +#include "protocol_private.h" + +struct ctdb_req_call_wire { + struct ctdb_req_header hdr; + uint32_t flags; + uint32_t db_id; + uint32_t callid; + uint32_t hopcount; + uint32_t keylen; + uint32_t calldatalen; + uint8_t data[1]; /* key[] followed by calldata[] */ +}; + +struct ctdb_reply_call_wire { + struct ctdb_req_header hdr; + uint32_t status; + uint32_t datalen; + uint8_t data[1]; +}; + +struct ctdb_reply_error_wire { + struct ctdb_req_header hdr; + uint32_t status; + uint32_t msglen; + uint8_t msg[1]; +}; + +struct ctdb_req_dmaster_wire { + struct ctdb_req_header hdr; + uint32_t db_id; + uint64_t rsn; + uint32_t dmaster; + uint32_t keylen; + uint32_t datalen; + uint8_t data[1]; +}; + +struct ctdb_reply_dmaster_wire { + struct ctdb_req_header hdr; + uint32_t db_id; + uint64_t rsn; + uint32_t keylen; + uint32_t datalen; + uint8_t data[1]; +}; + +int ctdb_req_call_push(struct ctdb_req_header *h, struct ctdb_req_call *c, + TALLOC_CTX *mem_ctx, uint8_t **pkt, size_t *pkt_len) +{ + struct ctdb_req_call_wire *wire; + uint8_t *buf; + size_t length, buflen; + int ret; + + if (c->key.dsize == 0) { + return EINVAL; + } + + length = offsetof(struct ctdb_req_call_wire, data) + + c->key.dsize + c->calldata.dsize; + + ret = allocate_pkt(mem_ctx, length, &buf, &buflen); + if (ret != 0) { + return ret; + } + + wire = (struct ctdb_req_call_wire *)buf; + + h->length = buflen; + memcpy(&wire->hdr, h, sizeof(struct ctdb_req_header)); + + wire->flags = c->flags; + wire->db_id = c->db_id; + wire->callid = c->callid; + wire->hopcount = c->hopcount; + wire->keylen = c->key.dsize; + wire->calldatalen = c->calldata.dsize; + memcpy(wire->data, c->key.dptr, c->key.dsize); + if (c->calldata.dsize > 0) { + memcpy(wire->data + c->key.dsize, c->calldata.dptr, + c->calldata.dsize); + } + + *pkt = buf; + *pkt_len = buflen; + return 0; +} + +int ctdb_req_call_pull(uint8_t *pkt, size_t pkt_len, + struct ctdb_req_header *h, + TALLOC_CTX *mem_ctx, + struct ctdb_req_call *c) +{ + struct ctdb_req_call_wire *wire; + size_t length; + + length = offsetof(struct ctdb_req_call_wire, data); + if (pkt_len < length) { + return EMSGSIZE; + } + + wire = (struct ctdb_req_call_wire *)pkt; + + if (pkt_len < length + wire->keylen + wire->calldatalen) { + return EMSGSIZE; + } + + memcpy(h, &wire->hdr, sizeof(struct ctdb_req_header)); + + c->flags = wire->flags; + c->db_id = wire->db_id; + c->callid = wire->callid; + c->hopcount = wire->hopcount; + c->key.dsize = wire->keylen; + c->key.dptr = talloc_memdup(mem_ctx, wire->data, wire->keylen); + if (c->key.dptr == NULL) { + return ENOMEM; + } + c->calldata.dsize = wire->calldatalen; + if (wire->calldatalen > 0) { + c->calldata.dptr = talloc_memdup(mem_ctx, + wire->data + wire->keylen, + wire->calldatalen); + if (c->calldata.dptr == NULL) { + talloc_free(c->key.dptr); + return ENOMEM; + } + } + + return 0; +} + +int ctdb_reply_call_push(struct ctdb_req_header *h, struct ctdb_reply_call *c, + TALLOC_CTX *mem_ctx, uint8_t **pkt, size_t *pkt_len) +{ + struct ctdb_reply_call_wire *wire; + uint8_t *buf; + size_t length, buflen; + int ret; + + length = offsetof(struct ctdb_reply_call_wire, data) + c->data.dsize; + + ret = allocate_pkt(mem_ctx, length, &buf, &buflen); + if (ret != 0) { + return ret; + } + + wire = (struct ctdb_reply_call_wire *)buf; + + h->length = buflen; + memcpy(&wire->hdr, h, sizeof(struct ctdb_req_header)); + + wire->status = c->status; + wire->datalen = c->data.dsize; + if (c->data.dsize > 0) { + memcpy(wire->data, c->data.dptr, c->data.dsize); + } + + *pkt = buf; + *pkt_len = buflen; + return 0; +} + +int ctdb_reply_call_pull(uint8_t *pkt, size_t pkt_len, + struct ctdb_req_header *h, + TALLOC_CTX *mem_ctx, + struct ctdb_reply_call *c) +{ + struct ctdb_reply_call_wire *wire; + size_t length; + + length = offsetof(struct ctdb_reply_call_wire, data); + if (pkt_len < length) { + return EMSGSIZE; + } + + wire = (struct ctdb_reply_call_wire *)pkt; + + if (pkt_len < length + wire->datalen) { + return EMSGSIZE; + } + + memcpy(h, &wire->hdr, sizeof(struct ctdb_req_header)); + + c->status = wire->status; + c->data.dsize = wire->datalen; + if (wire->datalen > 0) { + c->data.dptr = talloc_memdup(mem_ctx, wire->data, + wire->datalen); + if (c->data.dptr == NULL) { + return ENOMEM; + } + } + + return 0; +} + +int ctdb_reply_error_push(struct ctdb_req_header *h, struct ctdb_reply_error *c, + TALLOC_CTX *mem_ctx, uint8_t **pkt, size_t *pkt_len) +{ + struct ctdb_reply_error_wire *wire; + uint8_t *buf; + size_t length, buflen; + int ret; + + length = offsetof(struct ctdb_reply_error_wire, msg) + c->msg.dsize; + + ret = allocate_pkt(mem_ctx, length, &buf, &buflen); + if (ret != 0) { + return ret; + } + + wire = (struct ctdb_reply_error_wire *)buf; + + h->length = buflen; + memcpy(&wire->hdr, h, sizeof(struct ctdb_req_header)); + + wire->status = c->status; + wire->msglen = c->msg.dsize; + if (c->msg.dsize > 0) { + memcpy(wire->msg, c->msg.dptr, c->msg.dsize); + } + + *pkt = buf; + *pkt_len = buflen; + return 0; +} + +int ctdb_reply_error_pull(uint8_t *pkt, size_t pkt_len, + struct ctdb_req_header *h, + TALLOC_CTX *mem_ctx, + struct ctdb_reply_error *c) +{ + struct ctdb_reply_error_wire *wire; + size_t length; + + length = offsetof(struct ctdb_reply_error_wire, msg); + if (pkt_len < length) { + return EMSGSIZE; + } + + wire = (struct ctdb_reply_error_wire *)pkt; + + if (pkt_len < length + wire->msglen) { + return EMSGSIZE; + } + + memcpy(h, &wire->hdr, sizeof(struct ctdb_req_header)); + + c->status = wire->status; + c->msg.dsize = wire->msglen; + if (wire->msglen > 0) { + c->msg.dptr = talloc_memdup(mem_ctx, wire->msg, wire->msglen); + if (c->msg.dptr == NULL) { + return ENOMEM; + } + } + + return 0; +} + +int ctdb_req_dmaster_push(struct ctdb_req_header *h, struct ctdb_req_dmaster *c, + TALLOC_CTX *mem_ctx, uint8_t **pkt, size_t *pkt_len) +{ + struct ctdb_req_dmaster_wire *wire; + uint8_t *buf; + size_t length, buflen; + int ret; + + length = offsetof(struct ctdb_req_dmaster_wire, data) + + c->key.dsize + c->data.dsize; + + ret = allocate_pkt(mem_ctx, length, &buf, &buflen); + if (ret != 0) { + return ret; + } + + wire = (struct ctdb_req_dmaster_wire *)buf; + + h->length = buflen; + memcpy(&wire->hdr, h, sizeof(struct ctdb_req_header)); + + wire->db_id = c->db_id; + wire->rsn = c->rsn; + wire->dmaster = c->dmaster; + wire->keylen = c->key.dsize; + if (c->key.dsize > 0) { + memcpy(wire->data, c->key.dptr, c->key.dsize); + } + wire->datalen = c->data.dsize; + if (c->data.dsize > 0) { + memcpy(wire->data + c->key.dsize, c->data.dptr, c->data.dsize); + } + + *pkt = buf; + *pkt_len = buflen; + return 0; +} + +int ctdb_req_dmaster_pull(uint8_t *pkt, size_t pkt_len, + struct ctdb_req_header *h, + TALLOC_CTX *mem_ctx, + struct ctdb_req_dmaster *c) +{ + struct ctdb_req_dmaster_wire *wire; + size_t length; + + length = offsetof(struct ctdb_req_dmaster_wire, data); + if (pkt_len < length) { + return EMSGSIZE; + } + + wire = (struct ctdb_req_dmaster_wire *)pkt; + + if (pkt_len < length + wire->keylen + wire->datalen) { + return EMSGSIZE; + } + + memcpy(h, &wire->hdr, sizeof(struct ctdb_req_header)); + + c->db_id = wire->db_id; + c->rsn = wire->rsn; + c->dmaster = wire->dmaster; + c->key.dsize = wire->keylen; + c->key.dptr = talloc_memdup(mem_ctx, wire->data, wire->keylen); + if (c->key.dptr == NULL) { + return ENOMEM; + } + c->data.dsize = wire->datalen; + if (wire->datalen > 0) { + c->data.dptr = talloc_memdup(mem_ctx, wire->data + wire->keylen, + wire->datalen); + if (c->data.dptr == NULL) { + talloc_free(c->key.dptr); + return ENOMEM; + } + } + + return 0; +} + +int ctdb_reply_dmaster_push(struct ctdb_req_header *h, + struct ctdb_reply_dmaster *c, + TALLOC_CTX *mem_ctx, uint8_t **pkt, size_t *pkt_len) +{ + struct ctdb_reply_dmaster_wire *wire; + uint8_t *buf; + size_t length, buflen; + int ret; + + length = offsetof(struct ctdb_reply_dmaster_wire, data) + + c->key.dsize + c->data.dsize; + + ret = allocate_pkt(mem_ctx, length, &buf, &buflen); + if (ret != 0) { + return ret; + } + + wire = (struct ctdb_reply_dmaster_wire *)buf; + + h->length = buflen; + memcpy(&wire->hdr, h, sizeof(struct ctdb_req_header)); + + wire->db_id = c->db_id; + wire->rsn = c->rsn; + wire->keylen = c->key.dsize; + if (c->key.dsize > 0) { + memcpy(wire->data, c->key.dptr, c->key.dsize); + } + wire->datalen = c->data.dsize; + if (c->data.dsize > 0) { + memcpy(wire->data + c->key.dsize, c->data.dptr, c->data.dsize); + } + + *pkt = buf; + *pkt_len = buflen; + return 0; +} + +int ctdb_reply_dmaster_pull(uint8_t *pkt, size_t pkt_len, + struct ctdb_req_header *h, + TALLOC_CTX *mem_ctx, + struct ctdb_reply_dmaster *c) +{ + struct ctdb_reply_dmaster_wire *wire; + size_t length; + + length = offsetof(struct ctdb_reply_dmaster_wire, data); + if (pkt_len < length) { + return EMSGSIZE; + } + + wire = (struct ctdb_reply_dmaster_wire *)pkt; + + if (pkt_len < length + wire->keylen + wire->datalen) { + return EMSGSIZE; + } + + memcpy(h, &wire->hdr, sizeof(struct ctdb_req_header)); + + c->db_id = wire->db_id; + c->rsn = wire->rsn; + c->key.dsize = wire->keylen; + c->key.dptr = talloc_memdup(mem_ctx, wire->data, wire->keylen); + if (c->key.dptr == NULL) { + return ENOMEM; + } + c->data.dsize = wire->datalen; + if (wire->datalen > 0) { + c->data.dptr = talloc_memdup(mem_ctx, wire->data + wire->keylen, + wire->datalen); + if (c->data.dptr == NULL) { + talloc_free(c->key.dptr); + return ENOMEM; + } + } + + return 0; +} diff --git a/ctdb/protocol/protocol_client.c b/ctdb/protocol/protocol_client.c new file mode 100644 index 0000000..f4bfe19 --- /dev/null +++ b/ctdb/protocol/protocol_client.c @@ -0,0 +1,2370 @@ +/* + CTDB protocol marshalling + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include "replace.h" +#include "system/network.h" + +#include +#include + +#include "protocol.h" +#include "protocol_api.h" +#include "protocol_private.h" + +/* +void ctdb_req_call_fill(struct ctdb_req_call *c, + uint32_t db_id, uint32_t flags, + uint32_t call_id, TDB_DATA key) +{ + request->flags = flags; + c->db_id = db_id; + c->call_id = call_id; + c->key = key; + c->calldata = tdb_null; +} +*/ + +static int ctdb_reply_control_generic(struct ctdb_reply_control *reply) +{ + return reply->status; +} + +/* CTDB_CONTROL_PROCESS_EXISTS */ + +void ctdb_req_control_process_exists(struct ctdb_req_control *request, + pid_t pid) +{ + request->opcode = CTDB_CONTROL_PROCESS_EXISTS; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_PROCESS_EXISTS; + request->rdata.data.pid = pid; + +} + +int ctdb_reply_control_process_exists(struct ctdb_reply_control *reply, + int *status) +{ + if (reply->rdata.opcode == CTDB_CONTROL_PROCESS_EXISTS) { + *status = reply->status; + reply->status = 0; + + } + return reply->status; +} + +/* CTDB_CONTROL_STATISTICS */ + +void ctdb_req_control_statistics(struct ctdb_req_control *request) +{ + request->opcode = CTDB_CONTROL_STATISTICS; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_STATISTICS; +} + +int ctdb_reply_control_statistics(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + struct ctdb_statistics **stats) +{ + if (reply->status == 0 && + reply->rdata.opcode == CTDB_CONTROL_STATISTICS) { + *stats = talloc_steal(mem_ctx, reply->rdata.data.stats); + } + return reply->status; +} + +/* CTDB_CONTROL_PING */ + +void ctdb_req_control_ping(struct ctdb_req_control *request) +{ + request->opcode = CTDB_CONTROL_PING; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_PING; +} + +int ctdb_reply_control_ping(struct ctdb_reply_control *reply, + int *num_clients) +{ + if (reply->status >= 0) { + *num_clients = reply->status; + reply->status = 0; + } + return reply->status; +} + +/* CTDB_CONTROL_GETDBPATH */ + +void ctdb_req_control_getdbpath(struct ctdb_req_control *request, + uint32_t db_id) +{ + request->opcode = CTDB_CONTROL_GETDBPATH; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_GETDBPATH; + request->rdata.data.db_id = db_id; +} + +int ctdb_reply_control_getdbpath(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, const char **db_path) +{ + if (reply->status == 0 && + reply->rdata.opcode == CTDB_CONTROL_GETDBPATH) { + *db_path = talloc_steal(mem_ctx, reply->rdata.data.db_path); + } + return reply->status; +} + +/* CTDB_CONTROL_GETVNNMAP */ + +void ctdb_req_control_getvnnmap(struct ctdb_req_control *request) +{ + request->opcode = CTDB_CONTROL_GETVNNMAP; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_GETVNNMAP; +} + +int ctdb_reply_control_getvnnmap(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + struct ctdb_vnn_map **vnnmap) +{ + if (reply->status == 0 && + reply->rdata.opcode == CTDB_CONTROL_GETVNNMAP) { + *vnnmap = talloc_steal(mem_ctx, reply->rdata.data.vnnmap); + } + return reply->status; +} + +/* CTDB_CONTROL_SETVNNMAP */ + +void ctdb_req_control_setvnnmap(struct ctdb_req_control *request, + struct ctdb_vnn_map *vnnmap) +{ + request->opcode = CTDB_CONTROL_SETVNNMAP; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_SETVNNMAP; + request->rdata.data.vnnmap = vnnmap; +} + +int ctdb_reply_control_setvnnmap(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_GET_DEBUG */ + +void ctdb_req_control_get_debug(struct ctdb_req_control *request) +{ + request->opcode = CTDB_CONTROL_GET_DEBUG; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_GET_DEBUG; +} + +int ctdb_reply_control_get_debug(struct ctdb_reply_control *reply, + uint32_t *loglevel) +{ + if (reply->status == 0 && + reply->rdata.opcode == CTDB_CONTROL_GET_DEBUG) { + *loglevel = reply->rdata.data.loglevel; + } + return reply->status; +} + +/* CTDB_CONTROL_SET_DEBUG */ + +void ctdb_req_control_set_debug(struct ctdb_req_control *request, + uint32_t loglevel) +{ + request->opcode = CTDB_CONTROL_SET_DEBUG; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_SET_DEBUG; + request->rdata.data.loglevel = loglevel; +} + +int ctdb_reply_control_set_debug(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_GET_DBMAP */ + +void ctdb_req_control_get_dbmap(struct ctdb_req_control *request) +{ + request->opcode = CTDB_CONTROL_GET_DBMAP; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_GET_DBMAP; +} + +int ctdb_reply_control_get_dbmap(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + struct ctdb_dbid_map **dbmap) +{ + if (reply->status == 0 && + reply->rdata.opcode == CTDB_CONTROL_GET_DBMAP) { + *dbmap = talloc_steal(mem_ctx, reply->rdata.data.dbmap); + } + return reply->status; +} + +/* CTDB_CONTROL_PULL_DB */ + +void ctdb_req_control_pull_db(struct ctdb_req_control *request, + struct ctdb_pulldb *pulldb) +{ + request->opcode = CTDB_CONTROL_PULL_DB; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_PULL_DB; + request->rdata.data.pulldb = pulldb; +} + +int ctdb_reply_control_pull_db(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + struct ctdb_rec_buffer **recbuf) +{ + if (reply->status == 0 && + reply->rdata.opcode == CTDB_CONTROL_PULL_DB) { + *recbuf = talloc_steal(mem_ctx, reply->rdata.data.recbuf); + } + return reply->status; +} + +/* CTDB_CONTROL_PUSH_DB */ + +void ctdb_req_control_push_db(struct ctdb_req_control *request, + struct ctdb_rec_buffer *recbuf) +{ + request->opcode = CTDB_CONTROL_PUSH_DB; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_PUSH_DB; + request->rdata.data.recbuf = recbuf; +} + +int ctdb_reply_control_push_db(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_GET_RECMODE */ + +void ctdb_req_control_get_recmode(struct ctdb_req_control *request) +{ + request->opcode = CTDB_CONTROL_GET_RECMODE; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_GET_RECMODE; +} + +int ctdb_reply_control_get_recmode(struct ctdb_reply_control *reply, + int *recmode) +{ + if (reply->status >= 0) { + *recmode = reply->status; + reply->status = 0; + } + return reply->status; +} + +/* CTDB_CONTROL_SET_RECMODE */ + +void ctdb_req_control_set_recmode(struct ctdb_req_control *request, + int recmode) +{ + request->opcode = CTDB_CONTROL_SET_RECMODE; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_SET_RECMODE; + request->rdata.data.recmode = recmode; +} + +int ctdb_reply_control_set_recmode(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_STATISTICS_RESET */ + +void ctdb_req_control_statistics_reset(struct ctdb_req_control *request) +{ + request->opcode = CTDB_CONTROL_STATISTICS_RESET; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_STATISTICS_RESET; +} + +int ctdb_reply_control_statistics_reset(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_DB_ATTACH */ + +void ctdb_req_control_db_attach(struct ctdb_req_control *request, + const char *db_name, uint32_t tdb_flags) +{ + request->opcode = CTDB_CONTROL_DB_ATTACH; + request->pad = 0; + request->srvid = tdb_flags; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_DB_ATTACH; + request->rdata.data.db_name = db_name; +} + +int ctdb_reply_control_db_attach(struct ctdb_reply_control *reply, + uint32_t *db_id) +{ + if (reply->status == 0 && + reply->rdata.opcode == CTDB_CONTROL_DB_ATTACH) { + *db_id = reply->rdata.data.db_id; + } + return reply->status; +} + +/* CTDB_CONTROL_SET_CALL */ + +/* CTDB_CONTROL_TRAVERSE_START */ + +void ctdb_req_control_traverse_start(struct ctdb_req_control *request, + struct ctdb_traverse_start *traverse) +{ + request->opcode = CTDB_CONTROL_TRAVERSE_START; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_TRAVERSE_START; + request->rdata.data.traverse_start = traverse; +} + +int ctdb_reply_control_traverse_start(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_TRAVERSE_ALL */ +/* CTDB_CONTROL_TRAVERSE_DATA */ + +/* CTDB_CONTROL_REGISTER_SRVID */ + +void ctdb_req_control_register_srvid(struct ctdb_req_control *request, + uint64_t srvid) +{ + request->opcode = CTDB_CONTROL_REGISTER_SRVID; + request->pad = 0; + request->srvid = srvid; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_REGISTER_SRVID; +} + +int ctdb_reply_control_register_srvid(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_DEREGISTER_SRVID */ + +void ctdb_req_control_deregister_srvid(struct ctdb_req_control *request, + uint64_t srvid) +{ + request->opcode = CTDB_CONTROL_DEREGISTER_SRVID; + request->pad = 0; + request->srvid = srvid; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_DEREGISTER_SRVID; +} + +int ctdb_reply_control_deregister_srvid(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_GET_DBNAME */ + +void ctdb_req_control_get_dbname(struct ctdb_req_control *request, + uint32_t db_id) +{ + request->opcode = CTDB_CONTROL_GET_DBNAME; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_GET_DBNAME; + request->rdata.data.db_id = db_id; +} + +int ctdb_reply_control_get_dbname(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, const char **db_name) +{ + if (reply->status == 0 && + reply->rdata.opcode == CTDB_CONTROL_GET_DBNAME) { + *db_name = talloc_steal(mem_ctx, reply->rdata.data.db_name); + } + return reply->status; +} + +/* CTDB_CONTROL_ENABLE_SEQNUM */ + +void ctdb_req_control_enable_seqnum(struct ctdb_req_control *request, + uint32_t db_id) +{ + request->opcode = CTDB_CONTROL_ENABLE_SEQNUM; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_ENABLE_SEQNUM; + request->rdata.data.db_id = db_id; +} + +int ctdb_reply_control_enable_seqnum(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_UPDATE_SEQNUM */ + +void ctdb_req_control_update_seqnum(struct ctdb_req_control *request, + uint32_t db_id) +{ + request->opcode = CTDB_CONTROL_UPDATE_SEQNUM; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_UPDATE_SEQNUM; + request->rdata.data.db_id = db_id; +} + +int ctdb_reply_control_update_seqnum(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_DUMP_MEMORY */ + +void ctdb_req_control_dump_memory(struct ctdb_req_control *request) +{ + request->opcode = CTDB_CONTROL_DUMP_MEMORY; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_DUMP_MEMORY; +} + +int ctdb_reply_control_dump_memory(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, const char **mem_str) +{ + if (reply->status == 0 && + reply->rdata.opcode == CTDB_CONTROL_DUMP_MEMORY) { + *mem_str = talloc_steal(mem_ctx, reply->rdata.data.mem_str); + } + return reply->status; +} + +/* CTDB_CONTROL_GET_PID */ + +void ctdb_req_control_get_pid(struct ctdb_req_control *request) +{ + request->opcode = CTDB_CONTROL_GET_PID; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_GET_PID; +} + +int ctdb_reply_control_get_pid(struct ctdb_reply_control *reply, + pid_t *pid) +{ + if (reply->rdata.opcode == CTDB_CONTROL_GET_PID) { + *pid = reply->status; + reply->status = 0; + } + return reply->status; +} + +/* CTDB_CONTROL_GET_RECMASTER */ + +void ctdb_req_control_get_recmaster(struct ctdb_req_control *request) +{ + request->opcode = CTDB_CONTROL_GET_RECMASTER; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_GET_RECMASTER; +} + +int ctdb_reply_control_get_recmaster(struct ctdb_reply_control *reply, + uint32_t *recmaster) +{ + if (reply->rdata.opcode == CTDB_CONTROL_GET_RECMASTER) { + *recmaster = reply->status; + reply->status = 0; + } + return reply->status; +} + +/* CTDB_CONTROL_SET_RECMASTER */ + +void ctdb_req_control_set_recmaster(struct ctdb_req_control *request, + int recmaster) +{ + request->opcode = CTDB_CONTROL_SET_RECMASTER; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_SET_RECMASTER; + request->rdata.data.recmaster = recmaster; +} + +int ctdb_reply_control_set_recmaster(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_FREEZE */ + +void ctdb_req_control_freeze(struct ctdb_req_control *request, + uint32_t priority) +{ + request->opcode = CTDB_CONTROL_FREEZE; + request->pad = 0; + request->srvid = priority; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_FREEZE; +} + +int ctdb_reply_control_freeze(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_THAW */ + +void ctdb_req_control_thaw(struct ctdb_req_control *request, + uint32_t priority) +{ + request->opcode = CTDB_CONTROL_THAW; + request->pad = 0; + request->srvid = priority; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_THAW; +} + +int ctdb_reply_control_thaw(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_GET_PNN */ + +void ctdb_req_control_get_pnn(struct ctdb_req_control *request) +{ + request->opcode = CTDB_CONTROL_GET_PNN; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_GET_PNN; +} + +int ctdb_reply_control_get_pnn(struct ctdb_reply_control *reply, + uint32_t *pnn) +{ + if (reply->status >= 0) { + *pnn = reply->status; + reply->status = 0; + } + return reply->status; +} + +/* CTDB_CONTROL_SHUTDOWN */ + +void ctdb_req_control_shutdown(struct ctdb_req_control *request) +{ + request->opcode = CTDB_CONTROL_SHUTDOWN; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_SHUTDOWN; +} + +int ctdb_reply_control_shutdown(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_GET_MONMODE */ + +void ctdb_req_control_get_monmode(struct ctdb_req_control *request) +{ + request->opcode = CTDB_CONTROL_GET_MONMODE; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_GET_MONMODE; +} + +int ctdb_reply_control_get_monmode(struct ctdb_reply_control *reply, + int *mon_mode) +{ + if (reply->status >= 0) { + *mon_mode = reply->status; + reply->status = 0; + } + return reply->status; +} + +/* CTDB_CONTROL_TCP_CLIENT */ + +void ctdb_req_control_tcp_client(struct ctdb_req_control *request, + struct ctdb_connection *conn) +{ + request->opcode = CTDB_CONTROL_TCP_CLIENT; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_TCP_CLIENT; + request->rdata.data.conn = conn; +} + +int ctdb_reply_control_tcp_client(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_TCP_ADD */ + +void ctdb_req_control_tcp_add(struct ctdb_req_control *request, + struct ctdb_connection *conn) +{ + request->opcode = CTDB_CONTROL_TCP_ADD; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_TCP_ADD; + request->rdata.data.conn = conn; +} + +int ctdb_reply_control_tcp_add(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_TCP_REMOVE */ + +void ctdb_req_control_tcp_remove(struct ctdb_req_control *request, + struct ctdb_connection *conn) +{ + request->opcode = CTDB_CONTROL_TCP_REMOVE; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_TCP_REMOVE; + request->rdata.data.conn = conn; +} + +int ctdb_reply_control_tcp_remove(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_STARTUP */ + +void ctdb_req_control_startup(struct ctdb_req_control *request) +{ + request->opcode = CTDB_CONTROL_STARTUP; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_STARTUP; +} + +int ctdb_reply_control_startup(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_SET_TUNABLE */ + +void ctdb_req_control_set_tunable(struct ctdb_req_control *request, + struct ctdb_tunable *tunable) +{ + request->opcode = CTDB_CONTROL_SET_TUNABLE; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_SET_TUNABLE; + request->rdata.data.tunable = tunable; +} + +int ctdb_reply_control_set_tunable(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_GET_TUNABLE */ + +void ctdb_req_control_get_tunable(struct ctdb_req_control *request, + const char *name) +{ + request->opcode = CTDB_CONTROL_GET_TUNABLE; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_GET_TUNABLE; + request->rdata.data.tun_var = discard_const(name); +} + +int ctdb_reply_control_get_tunable(struct ctdb_reply_control *reply, + uint32_t *value) +{ + if (reply->status == 0 && + reply->rdata.opcode == CTDB_CONTROL_GET_TUNABLE) { + *value = reply->rdata.data.tun_value; + } + return reply->status; +} + +/* CTDB_CONTROL_LIST_TUNABLES */ + +void ctdb_req_control_list_tunables(struct ctdb_req_control *request) +{ + request->opcode = CTDB_CONTROL_LIST_TUNABLES; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_LIST_TUNABLES; +} + +int ctdb_reply_control_list_tunables(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + struct ctdb_var_list **tun_var_list) +{ + if (reply->status == 0 && + reply->rdata.opcode == CTDB_CONTROL_LIST_TUNABLES) { + *tun_var_list = talloc_steal(mem_ctx, + reply->rdata.data.tun_var_list); + } + return reply->status; +} + +/* CTDB_CONTROL_MODIFY_FLAGS */ + +void ctdb_req_control_modify_flags(struct ctdb_req_control *request, + struct ctdb_node_flag_change *flag_change) +{ + request->opcode = CTDB_CONTROL_MODIFY_FLAGS; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_MODIFY_FLAGS; + request->rdata.data.flag_change = flag_change; +} + +int ctdb_reply_control_modify_flags(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_GET_ALL_TUNABLES */ + +void ctdb_req_control_get_all_tunables(struct ctdb_req_control *request) +{ + request->opcode = CTDB_CONTROL_GET_ALL_TUNABLES; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_GET_ALL_TUNABLES; +} + +int ctdb_reply_control_get_all_tunables(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + struct ctdb_tunable_list **tun_list) +{ + if (reply->status == 0 && + reply->rdata.opcode == CTDB_CONTROL_GET_ALL_TUNABLES) { + *tun_list = talloc_steal(mem_ctx, reply->rdata.data.tun_list); + } + return reply->status; +} + +/* CTDB_CONTROL_KILL_TCP */ + +void ctdb_req_control_kill_tcp(struct ctdb_req_control *request, + struct ctdb_connection *conn) +{ + request->opcode = CTDB_CONTROL_KILL_TCP; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_KILL_TCP; + request->rdata.data.conn = conn; +} + +int ctdb_reply_control_kill_tcp(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_GET_TCP_TICKLE_LIST */ + +void ctdb_req_control_get_tcp_tickle_list(struct ctdb_req_control *request, + ctdb_sock_addr *addr) +{ + request->opcode = CTDB_CONTROL_GET_TCP_TICKLE_LIST; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_GET_TCP_TICKLE_LIST; + request->rdata.data.addr = addr; +} + +int ctdb_reply_control_get_tcp_tickle_list(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + struct ctdb_tickle_list **tickles) +{ + if (reply->status == 0 && + reply->rdata.opcode == CTDB_CONTROL_GET_TCP_TICKLE_LIST) { + *tickles = talloc_steal(mem_ctx, reply->rdata.data.tickles); + } + return reply->status; +} + +/* CTDB_CONTROL_SET_TCP_TICKLE_LIST */ + +void ctdb_req_control_set_tcp_tickle_list(struct ctdb_req_control *request, + struct ctdb_tickle_list *tickles) +{ + request->opcode = CTDB_CONTROL_SET_TCP_TICKLE_LIST; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_SET_TCP_TICKLE_LIST; + request->rdata.data.tickles = tickles; +} + +int ctdb_reply_control_set_tcp_tickle_list(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_REGISTER_SERVER_ID */ + +void ctdb_req_control_register_server_id(struct ctdb_req_control *request, + struct ctdb_client_id *cid) +{ + request->opcode = CTDB_CONTROL_REGISTER_SERVER_ID; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_REGISTER_SERVER_ID; + request->rdata.data.cid = cid; +} + +int ctdb_reply_control_register_server_id(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_UNREGISTER_SERVER_ID */ + +void ctdb_req_control_unregister_server_id(struct ctdb_req_control *request, + struct ctdb_client_id *cid) +{ + request->opcode = CTDB_CONTROL_UNREGISTER_SERVER_ID; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_UNREGISTER_SERVER_ID; + request->rdata.data.cid = cid; +} + +int ctdb_reply_control_unregister_server_id(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_CHECK_SERVER_ID */ + +void ctdb_req_control_check_server_id(struct ctdb_req_control *request, + struct ctdb_client_id *cid) +{ + request->opcode = CTDB_CONTROL_CHECK_SERVER_ID; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_CHECK_SERVER_ID; + request->rdata.data.cid = cid; +} + +int ctdb_reply_control_check_server_id(struct ctdb_reply_control *reply) +{ + return reply->status; +} + +/* CTDB_CONTROL_GET_SERVER_ID_LIST */ + +void ctdb_req_control_get_server_id_list(struct ctdb_req_control *request) +{ + request->opcode = CTDB_CONTROL_GET_SERVER_ID_LIST; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_GET_SERVER_ID_LIST; +} + +int ctdb_reply_control_get_server_id_list(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + struct ctdb_client_id_map **cid_map) +{ + if (reply->status == 0 && + reply->rdata.opcode == CTDB_CONTROL_GET_SERVER_ID_LIST) { + *cid_map = talloc_steal(mem_ctx, reply->rdata.data.cid_map); + } + return reply->status; +} + +/* CTDB_CONTROL_DB_ATTACH_PERSISTENT */ + +void ctdb_req_control_db_attach_persistent(struct ctdb_req_control *request, + const char *db_name, + uint32_t tdb_flags) +{ + request->opcode = CTDB_CONTROL_DB_ATTACH_PERSISTENT; + request->pad = 0; + request->srvid = tdb_flags; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_DB_ATTACH_PERSISTENT; + request->rdata.data.db_name = db_name; +} + +int ctdb_reply_control_db_attach_persistent(struct ctdb_reply_control *reply, + uint32_t *db_id) +{ + if (reply->status == 0 && + reply->rdata.opcode == CTDB_CONTROL_DB_ATTACH_PERSISTENT) { + *db_id = reply->rdata.data.db_id; + } + return reply->status; +} + +/* CTDB_CONTROL_UPDATE_RECORD */ + +void ctdb_req_control_update_record(struct ctdb_req_control *request, + struct ctdb_rec_buffer *recbuf) +{ + request->opcode = CTDB_CONTROL_UPDATE_RECORD; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_UPDATE_RECORD; + request->rdata.data.recbuf = recbuf; +} + +int ctdb_reply_control_update_record(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_SEND_GRATUITOUS_ARP */ + +void ctdb_req_control_send_gratuitous_arp(struct ctdb_req_control *request, + struct ctdb_addr_info *addr_info) +{ + request->opcode = CTDB_CONTROL_SEND_GRATUITOUS_ARP; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_SEND_GRATUITOUS_ARP; + request->rdata.data.addr_info = addr_info; +} + +int ctdb_reply_control_send_gratuitous_arp(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_TRANSACTION_START */ + +void ctdb_req_control_transaction_start(struct ctdb_req_control *request, + uint32_t tid) +{ + request->opcode = CTDB_CONTROL_TRANSACTION_START; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_TRANSACTION_START; + request->rdata.data.tid = tid; +} + +int ctdb_reply_control_transaction_start(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_TRANSACTION_COMMIT */ + +void ctdb_req_control_transaction_commit(struct ctdb_req_control *request, + uint32_t tid) +{ + request->opcode = CTDB_CONTROL_TRANSACTION_COMMIT; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_TRANSACTION_COMMIT; + request->rdata.data.tid = tid; +} + +int ctdb_reply_control_transaction_commit(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_WIPE_DATABASE */ + +void ctdb_req_control_wipe_database(struct ctdb_req_control *request, + struct ctdb_transdb *transdb) +{ + request->opcode = CTDB_CONTROL_WIPE_DATABASE; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_WIPE_DATABASE; + request->rdata.data.transdb = transdb; +} + +int ctdb_reply_control_wipe_database(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_UPTIME */ + +void ctdb_req_control_uptime(struct ctdb_req_control *request) +{ + request->opcode = CTDB_CONTROL_UPTIME; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_UPTIME; +} + +int ctdb_reply_control_uptime(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, struct ctdb_uptime **uptime) +{ + if (reply->status == 0 && + reply->rdata.opcode == CTDB_CONTROL_UPTIME) { + *uptime = talloc_steal(mem_ctx, reply->rdata.data.uptime); + } + return reply->status; +} + +/* CTDB_CONTROL_START_RECOVERY */ + +void ctdb_req_control_start_recovery(struct ctdb_req_control *request) +{ + request->opcode = CTDB_CONTROL_START_RECOVERY; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_START_RECOVERY; +} + +int ctdb_reply_control_start_recovery(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_END_RECOVERY */ + +void ctdb_req_control_end_recovery(struct ctdb_req_control *request) +{ + request->opcode = CTDB_CONTROL_END_RECOVERY; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_END_RECOVERY; +} + +int ctdb_reply_control_end_recovery(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_RELOAD_NODES_FILE */ + +void ctdb_req_control_reload_nodes_file(struct ctdb_req_control *request) +{ + request->opcode = CTDB_CONTROL_RELOAD_NODES_FILE; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_RELOAD_NODES_FILE; +} + +int ctdb_reply_control_reload_nodes_file(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_TRY_DELETE_RECORDS */ + +void ctdb_req_control_try_delete_records(struct ctdb_req_control *request, + struct ctdb_rec_buffer *recbuf) +{ + request->opcode = CTDB_CONTROL_TRY_DELETE_RECORDS; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_TRY_DELETE_RECORDS; + request->rdata.data.recbuf = recbuf; +} + +int ctdb_reply_control_try_delete_records(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + struct ctdb_rec_buffer **recbuf) +{ + if (reply->status == 0 && + reply->rdata.opcode == CTDB_CONTROL_TRY_DELETE_RECORDS) { + *recbuf = talloc_steal(mem_ctx, reply->rdata.data.recbuf); + } + return reply->status; +} + +/* CTDB_CONTROL_ENABLE_MONITOR */ + +void ctdb_req_control_enable_monitor(struct ctdb_req_control *request) +{ + request->opcode = CTDB_CONTROL_ENABLE_MONITOR; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_ENABLE_MONITOR; +} + +int ctdb_reply_control_enable_monitor(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_DISABLE_MONITOR */ + +void ctdb_req_control_disable_monitor(struct ctdb_req_control *request) +{ + request->opcode = CTDB_CONTROL_DISABLE_MONITOR; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_DISABLE_MONITOR; +} + +int ctdb_reply_control_disable_monitor(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_ADD_PUBLIC_IP */ + +void ctdb_req_control_add_public_ip(struct ctdb_req_control *request, + struct ctdb_addr_info *addr_info) +{ + request->opcode = CTDB_CONTROL_ADD_PUBLIC_IP; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_ADD_PUBLIC_IP; + request->rdata.data.addr_info = addr_info; +} + +int ctdb_reply_control_add_public_ip(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_DEL_PUBLIC_IP */ + +void ctdb_req_control_del_public_ip(struct ctdb_req_control *request, + struct ctdb_addr_info *addr_info) +{ + request->opcode = CTDB_CONTROL_DEL_PUBLIC_IP; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_DEL_PUBLIC_IP; + request->rdata.data.addr_info = addr_info; +} + +int ctdb_reply_control_del_public_ip(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_RUN_EVENTSCRIPTS */ + +void ctdb_req_control_run_eventscripts(struct ctdb_req_control *request, + const char *event_str) +{ + request->opcode = CTDB_CONTROL_RUN_EVENTSCRIPTS; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_RUN_EVENTSCRIPTS; + request->rdata.data.event_str = event_str; +} + +int ctdb_reply_control_run_eventscripts(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_GET_CAPABILITIES */ + +void ctdb_req_control_get_capabilities(struct ctdb_req_control *request) +{ + request->opcode = CTDB_CONTROL_GET_CAPABILITIES; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_GET_CAPABILITIES; +} + +int ctdb_reply_control_get_capabilities(struct ctdb_reply_control *reply, + uint32_t *caps) +{ + if (reply->status == 0 && + reply->rdata.opcode == CTDB_CONTROL_GET_CAPABILITIES) { + *caps = reply->rdata.data.caps; + } + return reply->status; +} + +/* CTDB_CONTROL_RECD_PING */ + +void ctdb_req_control_recd_ping(struct ctdb_req_control *request) +{ + request->opcode = CTDB_CONTROL_RECD_PING; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_RECD_PING; +} + +int ctdb_reply_control_recd_ping(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_RELEASE_IP */ + +void ctdb_req_control_release_ip(struct ctdb_req_control *request, + struct ctdb_public_ip *pubip) +{ + request->opcode = CTDB_CONTROL_RELEASE_IP; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_RELEASE_IP; + request->rdata.data.pubip = pubip; +} + +int ctdb_reply_control_release_ip(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_TAKEOVER_IP */ + +void ctdb_req_control_takeover_ip(struct ctdb_req_control *request, + struct ctdb_public_ip *pubip) +{ + request->opcode = CTDB_CONTROL_TAKEOVER_IP; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_TAKEOVER_IP; + request->rdata.data.pubip = pubip; +} + +int ctdb_reply_control_takeover_ip(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_GET_PUBLIC_IPS */ + +void ctdb_req_control_get_public_ips(struct ctdb_req_control *request) +{ + request->opcode = CTDB_CONTROL_GET_PUBLIC_IPS; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_GET_PUBLIC_IPS; +} + +int ctdb_reply_control_get_public_ips(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + struct ctdb_public_ip_list **pubip_list) +{ + if (reply->status == 0 && + reply->rdata.opcode == CTDB_CONTROL_GET_PUBLIC_IPS) { + *pubip_list = talloc_steal(mem_ctx, reply->rdata.data.pubip_list); + } + return reply->status; +} + +/* CTDB_CONTROL_GET_NODEMAP */ + +void ctdb_req_control_get_nodemap(struct ctdb_req_control *request) +{ + request->opcode = CTDB_CONTROL_GET_NODEMAP; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_GET_NODEMAP; +} + +int ctdb_reply_control_get_nodemap(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + struct ctdb_node_map **nodemap) +{ + if (reply->status == 0 && + reply->rdata.opcode == CTDB_CONTROL_GET_NODEMAP) { + *nodemap = talloc_steal(mem_ctx, reply->rdata.data.nodemap); + } + return reply->status; +} + +/* CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS */ + +void ctdb_req_control_get_event_script_status(struct ctdb_req_control *request, + uint32_t event) +{ + request->opcode = CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS; + request->rdata.data.event = event; +} + +int ctdb_reply_control_get_event_script_status(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + struct ctdb_script_list **slist) +{ + if (reply->status == 0 && + reply->rdata.opcode == CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS) { + *slist = talloc_steal(mem_ctx, reply->rdata.data.script_list); + } + return reply->status; +} + +/* CTDB_CONTROL_TRAVERSE_KILL */ + +void ctdb_req_control_traverse_kill(struct ctdb_req_control *request, + struct ctdb_traverse_start *traverse) +{ + request->opcode = CTDB_CONTROL_TRAVERSE_KILL; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_TRAVERSE_KILL; + request->rdata.data.traverse_start = traverse; +} + +int ctdb_reply_control_traverse_kill(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_RECD_RECLOCK_LATENCY */ + +void ctdb_req_control_recd_reclock_latency(struct ctdb_req_control *request, + double reclock_latency) +{ + request->opcode = CTDB_CONTROL_RECD_RECLOCK_LATENCY; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_RECD_RECLOCK_LATENCY; + request->rdata.data.reclock_latency = reclock_latency; +} + +int ctdb_reply_control_recd_reclock_latency(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_GET_RECLOCK_FILE */ + +void ctdb_req_control_get_reclock_file(struct ctdb_req_control *request) +{ + request->opcode = CTDB_CONTROL_GET_RECLOCK_FILE; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_GET_RECLOCK_FILE; +} + +int ctdb_reply_control_get_reclock_file(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + const char **reclock_file) +{ + if (reply->status == 0 && + reply->rdata.opcode == CTDB_CONTROL_GET_RECLOCK_FILE) { + *reclock_file = talloc_steal(mem_ctx, + reply->rdata.data.reclock_file); + } + return reply->status; +} + +/* CTDB_CONTROL_SET_RECLOCK_FILE */ + +void ctdb_req_control_set_reclock_file(struct ctdb_req_control *request, + const char *reclock_file) +{ + request->opcode = CTDB_CONTROL_SET_RECLOCK_FILE; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_SET_RECLOCK_FILE; + request->rdata.data.reclock_file = reclock_file; +} + +int ctdb_reply_control_set_reclock_file(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + + +/* CTDB_CONTROL_STOP_NODE */ + +void ctdb_req_control_stop_node(struct ctdb_req_control *request) +{ + request->opcode = CTDB_CONTROL_STOP_NODE; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_STOP_NODE; +} + +int ctdb_reply_control_stop_node(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_CONTINUE_NODE */ + +void ctdb_req_control_continue_node(struct ctdb_req_control *request) +{ + request->opcode = CTDB_CONTROL_CONTINUE_NODE; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_CONTINUE_NODE; +} + +int ctdb_reply_control_continue_node(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_SET_NATGWSTATE */ + +void ctdb_req_control_set_natgwstate(struct ctdb_req_control *request, + uint32_t natgw_role) +{ + request->opcode = CTDB_CONTROL_SET_NATGWSTATE; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_SET_NATGWSTATE; + request->rdata.data.role = natgw_role; +} + +int ctdb_reply_control_set_natgwstate(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_SET_LMASTERROLE */ + +void ctdb_req_control_set_lmasterrole(struct ctdb_req_control *request, + uint32_t lmaster_role) +{ + request->opcode = CTDB_CONTROL_SET_LMASTERROLE; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_SET_LMASTERROLE; + request->rdata.data.role = lmaster_role; +} + +int ctdb_reply_control_set_lmasterrole(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_SET_RECMASTERROLE */ + +void ctdb_req_control_set_recmasterrole(struct ctdb_req_control *request, + uint32_t recmaster_role) +{ + request->opcode = CTDB_CONTROL_SET_RECMASTERROLE; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_SET_RECMASTERROLE; + request->rdata.data.role = recmaster_role; +} + +int ctdb_reply_control_set_recmasterrole(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_ENABLE_SCRIPT */ + +void ctdb_req_control_enable_script(struct ctdb_req_control *request, + const char *script) +{ + request->opcode = CTDB_CONTROL_ENABLE_SCRIPT; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_ENABLE_SCRIPT; + request->rdata.data.script = script; +} + +int ctdb_reply_control_enable_script(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_DISABLE_SCRIPT */ + +void ctdb_req_control_disable_script(struct ctdb_req_control *request, + const char *script) +{ + request->opcode = CTDB_CONTROL_DISABLE_SCRIPT; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_DISABLE_SCRIPT; + request->rdata.data.script = script; +} + +int ctdb_reply_control_disable_script(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_SET_BAN_STATE */ + +void ctdb_req_control_set_ban_state(struct ctdb_req_control *request, + struct ctdb_ban_state *ban_state) +{ + request->opcode = CTDB_CONTROL_SET_BAN_STATE; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_SET_BAN_STATE; + request->rdata.data.ban_state = ban_state; +} + +int ctdb_reply_control_set_ban_state(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_GET_BAN_STATE */ + +void ctdb_req_control_get_ban_state(struct ctdb_req_control *request) +{ + request->opcode = CTDB_CONTROL_GET_BAN_STATE; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_GET_BAN_STATE; +} + +int ctdb_reply_control_get_ban_state(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + struct ctdb_ban_state **ban_state) +{ + if (reply->status == 0 && + reply->rdata.opcode == CTDB_CONTROL_GET_BAN_STATE) { + *ban_state = talloc_steal(mem_ctx, + reply->rdata.data.ban_state); + } + return reply->status; +} + +/* CTDB_CONTROL_SET_DB_PRIORITY */ + +void ctdb_req_control_set_db_priority(struct ctdb_req_control *request, + struct ctdb_db_priority *db_prio) +{ + request->opcode = CTDB_CONTROL_SET_DB_PRIORITY; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_SET_DB_PRIORITY; + request->rdata.data.db_prio = db_prio; +} + +int ctdb_reply_control_set_db_priority(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_GET_DB_PRIORITY */ + +void ctdb_req_control_get_db_priority(struct ctdb_req_control *request, + uint32_t db_id) +{ + request->opcode = CTDB_CONTROL_GET_DB_PRIORITY; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_GET_DB_PRIORITY; + request->rdata.data.db_id = db_id; +} + +int ctdb_reply_control_get_db_priority(struct ctdb_reply_control *reply, + uint32_t *priority) +{ + if (reply->rdata.opcode == CTDB_CONTROL_GET_DB_PRIORITY) { + *priority = reply->status; + reply->status = 0; + } + return reply->status; +} + +/* CTDB_CONTROL_TRANSACTION_CANCEL */ + +void ctdb_req_control_transaction_cancel(struct ctdb_req_control *request, + uint32_t tid) +{ + request->opcode = CTDB_CONTROL_TRANSACTION_CANCEL; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_TRANSACTION_CANCEL; + request->rdata.data.tid = tid; +} + +int ctdb_reply_control_transaction_cancel(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_REGISTER_NOTIFY */ + +void ctdb_req_control_register_notify(struct ctdb_req_control *request, + struct ctdb_notify_data *notify) +{ + request->opcode = CTDB_CONTROL_REGISTER_NOTIFY; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_REGISTER_NOTIFY; + request->rdata.data.notify = notify; +} + +int ctdb_reply_control_register_notify(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_DEREGISTER_NOTIFY */ + +void ctdb_req_control_deregister_notify(struct ctdb_req_control *request, + uint64_t srvid) +{ + request->opcode = CTDB_CONTROL_DEREGISTER_NOTIFY; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_DEREGISTER_NOTIFY; + request->rdata.data.srvid = srvid; +} + +int ctdb_reply_control_deregister_notify(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_TRANS3_COMMIT */ + +void ctdb_req_control_trans3_commit(struct ctdb_req_control *request, + struct ctdb_rec_buffer *recbuf) +{ + request->opcode = CTDB_CONTROL_TRANS3_COMMIT; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_TRANS3_COMMIT; + request->rdata.data.recbuf = recbuf; +} + +int ctdb_reply_control_trans3_commit(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_GET_DB_SEQNUM */ + +void ctdb_req_control_get_db_seqnum(struct ctdb_req_control *request, + uint32_t db_id) +{ + request->opcode = CTDB_CONTROL_GET_DB_SEQNUM; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_GET_DB_SEQNUM; + request->rdata.data.db_id = db_id; +} + +int ctdb_reply_control_get_db_seqnum(struct ctdb_reply_control *reply, + uint64_t *seqnum) +{ + if (reply->status == 0 && + reply->rdata.opcode == CTDB_CONTROL_GET_DB_SEQNUM) { + *seqnum = reply->rdata.data.seqnum; + } + return reply->status; +} + +/* CTDB_CONTROL_DB_SET_HEALTHY */ + +void ctdb_req_control_db_set_healthy(struct ctdb_req_control *request, + uint32_t db_id) +{ + request->opcode = CTDB_CONTROL_DB_SET_HEALTHY; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_DB_SET_HEALTHY; + request->rdata.data.db_id = db_id; +} + +int ctdb_reply_control_db_set_healthy(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_DB_GET_HEALTH */ + +void ctdb_req_control_db_get_health(struct ctdb_req_control *request, + uint32_t db_id) +{ + request->opcode = CTDB_CONTROL_DB_GET_HEALTH; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_DB_GET_HEALTH; + request->rdata.data.db_id = db_id; +} + +int ctdb_reply_control_db_get_health(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, const char **reason) +{ + if (reply->status == 0 && + reply->rdata.opcode == CTDB_CONTROL_DB_GET_HEALTH) { + *reason = talloc_steal(mem_ctx, reply->rdata.data.reason); + } + return reply->status; +} + +/* CTDB_CONTROL_GET_PUBLIC_IP_INFO */ + +void ctdb_req_control_get_public_ip_info(struct ctdb_req_control *request, + ctdb_sock_addr *addr) +{ + request->opcode = CTDB_CONTROL_GET_PUBLIC_IP_INFO; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_GET_PUBLIC_IP_INFO; + request->rdata.data.addr = addr; +} + +int ctdb_reply_control_get_public_ip_info(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + struct ctdb_public_ip_info **ipinfo) +{ + if (reply->status == 0 && + reply->rdata.opcode == CTDB_CONTROL_GET_PUBLIC_IP_INFO) { + *ipinfo = talloc_steal(mem_ctx, reply->rdata.data.ipinfo); + } + return reply->status; +} + +/* CTDB_CONTROL_GET_IFACES */ + +void ctdb_req_control_get_ifaces(struct ctdb_req_control *request) +{ + request->opcode = CTDB_CONTROL_GET_IFACES; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_GET_IFACES; +} + +int ctdb_reply_control_get_ifaces(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + struct ctdb_iface_list **iface_list) +{ + if (reply->status == 0 && + reply->rdata.opcode == CTDB_CONTROL_GET_IFACES) { + *iface_list = talloc_steal(mem_ctx, + reply->rdata.data.iface_list); + } + return reply->status; +} + +/* CTDB_CONTROL_SET_IFACE_LINK_STATE */ + +void ctdb_req_control_set_iface_link_state(struct ctdb_req_control *request, + struct ctdb_iface *iface) +{ + request->opcode = CTDB_CONTROL_SET_IFACE_LINK_STATE; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_SET_IFACE_LINK_STATE; + request->rdata.data.iface = iface; +} + +int ctdb_reply_control_set_iface_link_state(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE */ + +void ctdb_req_control_tcp_add_delayed_update(struct ctdb_req_control *request, + struct ctdb_connection *conn) +{ + request->opcode = CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE; + request->rdata.data.conn = conn; +} + +int ctdb_reply_control_tcp_add_delayed_update(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_GET_STAT_HISTORY */ + +void ctdb_req_control_get_stat_history(struct ctdb_req_control *request) +{ + request->opcode = CTDB_CONTROL_GET_STAT_HISTORY; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_GET_STAT_HISTORY; +} + +int ctdb_reply_control_get_stat_history(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + struct ctdb_statistics_list **stats_list) +{ + if (reply->status == 0 && + reply->rdata.opcode == CTDB_CONTROL_GET_STAT_HISTORY) { + *stats_list = talloc_steal(mem_ctx, + reply->rdata.data.stats_list); + } + return reply->status; +} + +/* CTDB_CONTROL_SCHEDULE_FOR_DELETION */ + +void ctdb_req_control_schedule_for_deletion(struct ctdb_req_control *request, + struct ctdb_key_data *key) +{ + request->opcode = CTDB_CONTROL_SCHEDULE_FOR_DELETION; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_SCHEDULE_FOR_DELETION; + request->rdata.data.key = key; +} + +int ctdb_reply_control_schedule_for_deletion(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_SET_DB_READONLY */ + +void ctdb_req_control_set_db_readonly(struct ctdb_req_control *request, + uint32_t db_id) +{ + request->opcode = CTDB_CONTROL_SET_DB_READONLY; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_SET_DB_READONLY; + request->rdata.data.db_id = db_id; +} + +int ctdb_reply_control_set_db_readonly(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_CHECK_SRVIDS */ + +void ctdb_req_control_check_srvids(struct ctdb_req_control *request, + struct ctdb_uint64_array *u64_array) +{ + request->opcode = CTDB_CONTROL_CHECK_SRVIDS; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_CHECK_SRVIDS; + request->rdata.data.u64_array = u64_array; +} + +int ctdb_reply_control_check_srvids(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + struct ctdb_uint8_array **u8_array) +{ + if (reply->status == 0 && + reply->rdata.opcode == CTDB_CONTROL_CHECK_SRVIDS) { + *u8_array = talloc_steal(mem_ctx, reply->rdata.data.u8_array); + } + return reply->status; +} + +/* CTDB_CONTROL_TRAVERSE_START_EXT */ + +void ctdb_req_control_traverse_start_ext(struct ctdb_req_control *request, + struct ctdb_traverse_start_ext *traverse) +{ + request->opcode = CTDB_CONTROL_TRAVERSE_START_EXT; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_TRAVERSE_START_EXT; + request->rdata.data.traverse_start_ext = traverse; +} + +int ctdb_reply_control_traverse_start_ext(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_GET_DB_STATISTICS */ + +void ctdb_req_control_get_db_statistics(struct ctdb_req_control *request, + uint32_t db_id) +{ + request->opcode = CTDB_CONTROL_GET_DB_STATISTICS; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_GET_DB_STATISTICS; + request->rdata.data.db_id = db_id; +} + +int ctdb_reply_control_get_db_statistics(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + struct ctdb_db_statistics **dbstats) +{ + if (reply->status == 0 && + reply->rdata.opcode == CTDB_CONTROL_GET_DB_STATISTICS) { + *dbstats = talloc_steal(mem_ctx, reply->rdata.data.dbstats); + } + return reply->status; +} + +/* CTDB_CONTROL_SET_DB_STICKY */ + +void ctdb_req_control_set_db_sticky(struct ctdb_req_control *request, + uint32_t db_id) +{ + request->opcode = CTDB_CONTROL_SET_DB_STICKY; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_SET_DB_STICKY; + request->rdata.data.db_id = db_id; +} + +int ctdb_reply_control_set_db_sticky(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_RELOAD_PUBLIC_IPS */ + +void ctdb_req_control_reload_public_ips(struct ctdb_req_control *request) +{ + request->opcode = CTDB_CONTROL_RELOAD_PUBLIC_IPS; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_RELOAD_PUBLIC_IPS; +} + +int ctdb_reply_control_reload_public_ips(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_TRAVERSE_ALL_EXT */ + +/* CTDB_CONTROL_RECEIVE_RECORDS */ + +void ctdb_req_control_receive_records(struct ctdb_req_control *request, + struct ctdb_rec_buffer *recbuf) +{ + request->opcode = CTDB_CONTROL_RECEIVE_RECORDS; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_RECEIVE_RECORDS; + request->rdata.data.recbuf = recbuf; +} + +int ctdb_reply_control_receive_records(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + struct ctdb_rec_buffer **recbuf) +{ + if (reply->status == 0 && + reply->rdata.opcode == CTDB_CONTROL_RECEIVE_RECORDS) { + *recbuf = talloc_steal(mem_ctx, reply->rdata.data.recbuf); + } + return reply->status; +} + +/* CTDB_CONTROL_IPREALLOCATED */ + +void ctdb_req_control_ipreallocated(struct ctdb_req_control *request) +{ + request->opcode = CTDB_CONTROL_IPREALLOCATED; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_IPREALLOCATED; +} + +int ctdb_reply_control_ipreallocated(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_GET_RUNSTATE */ + +void ctdb_req_control_get_runstate(struct ctdb_req_control *request) +{ + request->opcode = CTDB_CONTROL_GET_RUNSTATE; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_GET_RUNSTATE; +} + +int ctdb_reply_control_get_runstate(struct ctdb_reply_control *reply, + enum ctdb_runstate *runstate) +{ + if (reply->status == 0 && + reply->rdata.opcode == CTDB_CONTROL_GET_RUNSTATE) { + *runstate = reply->rdata.data.runstate; + } + return reply->status; +} + +/* CTDB_CONTROL_DB_DETACH */ + +void ctdb_req_control_db_detach(struct ctdb_req_control *request, + uint32_t db_id) +{ + request->opcode = CTDB_CONTROL_DB_DETACH; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_DB_DETACH; + request->rdata.data.db_id = db_id; +} + +int ctdb_reply_control_db_detach(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_GET_NODES_FILE */ + +void ctdb_req_control_get_nodes_file(struct ctdb_req_control *request) +{ + request->opcode = CTDB_CONTROL_GET_NODES_FILE; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_GET_NODES_FILE; +} + +int ctdb_reply_control_get_nodes_file(struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + struct ctdb_node_map **nodemap) +{ + if (reply->status == 0 && + reply->rdata.opcode == CTDB_CONTROL_GET_NODES_FILE) { + *nodemap = talloc_steal(mem_ctx, reply->rdata.data.nodemap); + } + return reply->status; +} diff --git a/ctdb/protocol/protocol_control.c b/ctdb/protocol/protocol_control.c new file mode 100644 index 0000000..da87351 --- /dev/null +++ b/ctdb/protocol/protocol_control.c @@ -0,0 +1,2007 @@ +/* + CTDB protocol marshalling + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include "replace.h" +#include "system/network.h" + +#include +#include + +#include "protocol.h" +#include "protocol_api.h" +#include "protocol_private.h" + +struct ctdb_req_control_wire { + struct ctdb_req_header hdr; + uint32_t opcode; + uint32_t pad; + uint64_t srvid; + uint32_t client_id; + uint32_t flags; + uint32_t datalen; + uint8_t data[1]; +}; + +struct ctdb_reply_control_wire { + struct ctdb_req_header hdr; + int32_t status; + uint32_t datalen; + uint32_t errorlen; + uint8_t data[1]; +}; + +static size_t ctdb_req_control_data_len(struct ctdb_req_control_data *cd) +{ + size_t len = 0; + uint64_t u64; + + if (cd == NULL) { + return 0; + } + + switch (cd->opcode) { + case CTDB_CONTROL_PROCESS_EXISTS: + len = ctdb_pid_len(cd->data.pid); + break; + + case CTDB_CONTROL_STATISTICS: + break; + + case CTDB_CONTROL_PING: + break; + + case CTDB_CONTROL_GETDBPATH: + len = ctdb_uint32_len(cd->data.db_id); + break; + + case CTDB_CONTROL_GETVNNMAP: + break; + + case CTDB_CONTROL_SETVNNMAP: + len = ctdb_vnn_map_len(cd->data.vnnmap); + break; + + case CTDB_CONTROL_GET_DEBUG: + break; + + case CTDB_CONTROL_SET_DEBUG: + len = ctdb_uint32_len(cd->data.loglevel); + break; + + case CTDB_CONTROL_GET_DBMAP: + break; + + case CTDB_CONTROL_PULL_DB: + len = ctdb_pulldb_len(cd->data.pulldb); + break; + + case CTDB_CONTROL_PUSH_DB: + len = ctdb_rec_buffer_len(cd->data.recbuf); + break; + + case CTDB_CONTROL_GET_RECMODE: + break; + + case CTDB_CONTROL_SET_RECMODE: + len = ctdb_uint32_len(cd->data.recmode); + break; + + case CTDB_CONTROL_STATISTICS_RESET: + break; + + case CTDB_CONTROL_DB_ATTACH: + len = ctdb_string_len(cd->data.db_name); + break; + + case CTDB_CONTROL_SET_CALL: + break; + + case CTDB_CONTROL_TRAVERSE_START: + len = ctdb_traverse_start_len(cd->data.traverse_start); + break; + + case CTDB_CONTROL_TRAVERSE_ALL: + len = ctdb_traverse_all_len(cd->data.traverse_all); + break; + + case CTDB_CONTROL_TRAVERSE_DATA: + len = ctdb_rec_data_len(cd->data.rec_data); + break; + + case CTDB_CONTROL_REGISTER_SRVID: + break; + + case CTDB_CONTROL_DEREGISTER_SRVID: + break; + + case CTDB_CONTROL_GET_DBNAME: + len = ctdb_uint32_len(cd->data.db_id); + break; + + case CTDB_CONTROL_ENABLE_SEQNUM: + len = ctdb_uint32_len(cd->data.db_id); + break; + + case CTDB_CONTROL_UPDATE_SEQNUM: + len = ctdb_uint32_len(cd->data.db_id); + break; + + case CTDB_CONTROL_DUMP_MEMORY: + break; + + case CTDB_CONTROL_GET_PID: + break; + + case CTDB_CONTROL_GET_RECMASTER: + break; + + case CTDB_CONTROL_SET_RECMASTER: + len = ctdb_uint32_len(cd->data.recmaster); + break; + + case CTDB_CONTROL_FREEZE: + break; + + case CTDB_CONTROL_THAW: + break; + + case CTDB_CONTROL_GET_PNN: + break; + + case CTDB_CONTROL_SHUTDOWN: + break; + + case CTDB_CONTROL_GET_MONMODE: + break; + + case CTDB_CONTROL_TCP_CLIENT: + len = ctdb_connection_len(cd->data.conn); + break; + + case CTDB_CONTROL_TCP_ADD: + len = ctdb_connection_len(cd->data.conn); + break; + + case CTDB_CONTROL_TCP_REMOVE: + len = ctdb_connection_len(cd->data.conn); + break; + + case CTDB_CONTROL_STARTUP: + break; + + case CTDB_CONTROL_SET_TUNABLE: + len = ctdb_tunable_len(cd->data.tunable); + break; + + case CTDB_CONTROL_GET_TUNABLE: + len = ctdb_stringn_len(cd->data.tun_var); + break; + + case CTDB_CONTROL_LIST_TUNABLES: + break; + + case CTDB_CONTROL_MODIFY_FLAGS: + len = ctdb_node_flag_change_len(cd->data.flag_change); + break; + + case CTDB_CONTROL_GET_ALL_TUNABLES: + break; + + case CTDB_CONTROL_KILL_TCP: + len = ctdb_connection_len(cd->data.conn); + break; + + case CTDB_CONTROL_GET_TCP_TICKLE_LIST: + len = ctdb_sock_addr_len(cd->data.addr); + break; + + case CTDB_CONTROL_SET_TCP_TICKLE_LIST: + len = ctdb_tickle_list_len(cd->data.tickles); + break; + + case CTDB_CONTROL_REGISTER_SERVER_ID: + len = ctdb_client_id_len(cd->data.cid); + break; + + case CTDB_CONTROL_UNREGISTER_SERVER_ID: + len = ctdb_client_id_len(cd->data.cid); + break; + + case CTDB_CONTROL_CHECK_SERVER_ID: + len = ctdb_client_id_len(cd->data.cid); + break; + + case CTDB_CONTROL_GET_SERVER_ID_LIST: + break; + + case CTDB_CONTROL_DB_ATTACH_PERSISTENT: + len = ctdb_string_len(cd->data.db_name); + break; + + case CTDB_CONTROL_UPDATE_RECORD: + len = ctdb_rec_buffer_len(cd->data.recbuf); + break; + + case CTDB_CONTROL_SEND_GRATUITOUS_ARP: + len = ctdb_addr_info_len(cd->data.addr_info); + break; + + case CTDB_CONTROL_TRANSACTION_START: + len = ctdb_uint32_len(cd->data.tid); + break; + + case CTDB_CONTROL_TRANSACTION_COMMIT: + len = ctdb_uint32_len(cd->data.tid); + break; + + case CTDB_CONTROL_WIPE_DATABASE: + len = ctdb_transdb_len(cd->data.transdb); + break; + + case CTDB_CONTROL_UPTIME: + break; + + case CTDB_CONTROL_START_RECOVERY: + break; + + case CTDB_CONTROL_END_RECOVERY: + break; + + case CTDB_CONTROL_RELOAD_NODES_FILE: + break; + + case CTDB_CONTROL_TRY_DELETE_RECORDS: + len = ctdb_rec_buffer_len(cd->data.recbuf); + break; + + case CTDB_CONTROL_ENABLE_MONITOR: + break; + + case CTDB_CONTROL_DISABLE_MONITOR: + break; + + case CTDB_CONTROL_ADD_PUBLIC_IP: + len = ctdb_addr_info_len(cd->data.addr_info); + break; + + case CTDB_CONTROL_DEL_PUBLIC_IP: + len = ctdb_addr_info_len(cd->data.addr_info); + break; + + case CTDB_CONTROL_RUN_EVENTSCRIPTS: + len = ctdb_string_len(cd->data.event_str); + break; + + case CTDB_CONTROL_GET_CAPABILITIES: + break; + + case CTDB_CONTROL_RECD_PING: + break; + + case CTDB_CONTROL_RELEASE_IP: + len = ctdb_public_ip_len(cd->data.pubip); + break; + + case CTDB_CONTROL_TAKEOVER_IP: + len = ctdb_public_ip_len(cd->data.pubip); + break; + + case CTDB_CONTROL_GET_PUBLIC_IPS: + break; + + case CTDB_CONTROL_GET_NODEMAP: + break; + + case CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS: + len = ctdb_uint32_len(cd->data.event); + break; + + case CTDB_CONTROL_TRAVERSE_KILL: + len = ctdb_traverse_start_len(cd->data.traverse_start); + break; + + case CTDB_CONTROL_RECD_RECLOCK_LATENCY: + len = ctdb_double_len(cd->data.reclock_latency); + break; + + case CTDB_CONTROL_GET_RECLOCK_FILE: + break; + + case CTDB_CONTROL_SET_RECLOCK_FILE: + len = ctdb_string_len(cd->data.reclock_file); + break; + + case CTDB_CONTROL_STOP_NODE: + break; + + case CTDB_CONTROL_CONTINUE_NODE: + break; + + case CTDB_CONTROL_SET_NATGWSTATE: + len = ctdb_uint32_len(cd->data.role); + break; + + case CTDB_CONTROL_SET_LMASTERROLE: + len = ctdb_uint32_len(cd->data.role); + break; + + case CTDB_CONTROL_SET_RECMASTERROLE: + len = ctdb_uint32_len(cd->data.role); + break; + + case CTDB_CONTROL_ENABLE_SCRIPT: + len = ctdb_string_len(cd->data.script); + break; + + case CTDB_CONTROL_DISABLE_SCRIPT: + len = ctdb_string_len(cd->data.script); + break; + + case CTDB_CONTROL_SET_BAN_STATE: + len = ctdb_ban_state_len(cd->data.ban_state); + break; + + case CTDB_CONTROL_GET_BAN_STATE: + break; + + case CTDB_CONTROL_SET_DB_PRIORITY: + len = ctdb_db_priority_len(cd->data.db_prio); + break; + + case CTDB_CONTROL_GET_DB_PRIORITY: + len = ctdb_uint32_len(cd->data.db_id); + break; + + case CTDB_CONTROL_TRANSACTION_CANCEL: + break; + + case CTDB_CONTROL_REGISTER_NOTIFY: + len = ctdb_notify_data_len(cd->data.notify); + break; + + case CTDB_CONTROL_DEREGISTER_NOTIFY: + len = ctdb_uint64_len(cd->data.srvid); + break; + + case CTDB_CONTROL_TRANS3_COMMIT: + len = ctdb_rec_buffer_len(cd->data.recbuf); + break; + + case CTDB_CONTROL_GET_DB_SEQNUM: + u64 = cd->data.db_id; + len = ctdb_uint64_len(u64); + break; + + case CTDB_CONTROL_DB_SET_HEALTHY: + len = ctdb_uint32_len(cd->data.db_id); + break; + + case CTDB_CONTROL_DB_GET_HEALTH: + len = ctdb_uint32_len(cd->data.db_id); + break; + + case CTDB_CONTROL_GET_PUBLIC_IP_INFO: + len = ctdb_sock_addr_len(cd->data.addr); + break; + + case CTDB_CONTROL_GET_IFACES: + break; + + case CTDB_CONTROL_SET_IFACE_LINK_STATE: + len = ctdb_iface_len(cd->data.iface); + break; + + case CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE: + len = ctdb_connection_len(cd->data.conn); + break; + + case CTDB_CONTROL_GET_STAT_HISTORY: + break; + + case CTDB_CONTROL_SCHEDULE_FOR_DELETION: + len = ctdb_key_data_len(cd->data.key); + break; + + case CTDB_CONTROL_SET_DB_READONLY: + len = ctdb_uint32_len(cd->data.db_id); + break; + + case CTDB_CONTROL_CHECK_SRVIDS: + len = ctdb_uint64_array_len(cd->data.u64_array); + break; + + case CTDB_CONTROL_TRAVERSE_START_EXT: + len = ctdb_traverse_start_ext_len(cd->data.traverse_start_ext); + break; + + case CTDB_CONTROL_GET_DB_STATISTICS: + len = ctdb_uint32_len(cd->data.db_id); + break; + + case CTDB_CONTROL_SET_DB_STICKY: + len = ctdb_uint32_len(cd->data.db_id); + break; + + case CTDB_CONTROL_RELOAD_PUBLIC_IPS: + break; + + case CTDB_CONTROL_TRAVERSE_ALL_EXT: + len = ctdb_traverse_all_ext_len(cd->data.traverse_all_ext); + break; + + case CTDB_CONTROL_RECEIVE_RECORDS: + len = ctdb_rec_buffer_len(cd->data.recbuf); + break; + + case CTDB_CONTROL_IPREALLOCATED: + break; + + case CTDB_CONTROL_GET_RUNSTATE: + break; + + case CTDB_CONTROL_DB_DETACH: + len = ctdb_uint32_len(cd->data.db_id); + break; + + case CTDB_CONTROL_GET_NODES_FILE: + break; + } + + return len; +} + +static void ctdb_req_control_data_push(struct ctdb_req_control_data *cd, + uint8_t *buf) +{ + uint64_t u64; + + switch (cd->opcode) { + case CTDB_CONTROL_PROCESS_EXISTS: + ctdb_pid_push(cd->data.pid, buf); + break; + + case CTDB_CONTROL_GETDBPATH: + ctdb_uint32_push(cd->data.db_id, buf); + break; + + case CTDB_CONTROL_SETVNNMAP: + ctdb_vnn_map_push(cd->data.vnnmap, buf); + break; + + case CTDB_CONTROL_SET_DEBUG: + ctdb_uint32_push(cd->data.loglevel, buf); + break; + + case CTDB_CONTROL_PULL_DB: + ctdb_pulldb_push(cd->data.pulldb, buf); + break; + + case CTDB_CONTROL_PUSH_DB: + ctdb_rec_buffer_push(cd->data.recbuf, buf); + break; + + case CTDB_CONTROL_SET_RECMODE: + ctdb_uint32_push(cd->data.recmode, buf); + break; + + case CTDB_CONTROL_DB_ATTACH: + ctdb_string_push(cd->data.db_name, buf); + break; + + case CTDB_CONTROL_SET_CALL: + break; + + case CTDB_CONTROL_TRAVERSE_START: + ctdb_traverse_start_push(cd->data.traverse_start, buf); + break; + + case CTDB_CONTROL_TRAVERSE_ALL: + ctdb_traverse_all_push(cd->data.traverse_all, buf); + break; + + case CTDB_CONTROL_TRAVERSE_DATA: + ctdb_rec_data_push(cd->data.rec_data, buf); + break; + + case CTDB_CONTROL_GET_DBNAME: + ctdb_uint32_push(cd->data.db_id, buf); + break; + + case CTDB_CONTROL_ENABLE_SEQNUM: + ctdb_uint32_push(cd->data.db_id, buf); + break; + + case CTDB_CONTROL_UPDATE_SEQNUM: + ctdb_uint32_push(cd->data.db_id, buf); + break; + + case CTDB_CONTROL_SET_RECMASTER: + ctdb_uint32_push(cd->data.recmaster, buf); + break; + + case CTDB_CONTROL_TCP_CLIENT: + ctdb_connection_push(cd->data.conn, buf); + break; + + case CTDB_CONTROL_TCP_ADD: + ctdb_connection_push(cd->data.conn, buf); + break; + + case CTDB_CONTROL_TCP_REMOVE: + ctdb_connection_push(cd->data.conn, buf); + break; + + case CTDB_CONTROL_SET_TUNABLE: + ctdb_tunable_push(cd->data.tunable, buf); + break; + + case CTDB_CONTROL_GET_TUNABLE: + ctdb_stringn_push(cd->data.tun_var, buf); + break; + + case CTDB_CONTROL_MODIFY_FLAGS: + ctdb_node_flag_change_push(cd->data.flag_change, buf); + break; + + case CTDB_CONTROL_KILL_TCP: + ctdb_connection_push(cd->data.conn, buf); + break; + + case CTDB_CONTROL_GET_TCP_TICKLE_LIST: + ctdb_sock_addr_push(cd->data.addr, buf); + break; + + case CTDB_CONTROL_SET_TCP_TICKLE_LIST: + ctdb_tickle_list_push(cd->data.tickles, buf); + break; + + case CTDB_CONTROL_REGISTER_SERVER_ID: + ctdb_client_id_push(cd->data.cid, buf); + break; + + case CTDB_CONTROL_UNREGISTER_SERVER_ID: + ctdb_client_id_push(cd->data.cid, buf); + break; + + case CTDB_CONTROL_CHECK_SERVER_ID: + ctdb_client_id_push(cd->data.cid, buf); + break; + + case CTDB_CONTROL_DB_ATTACH_PERSISTENT: + ctdb_string_push(cd->data.db_name, buf); + break; + + case CTDB_CONTROL_UPDATE_RECORD: + ctdb_rec_buffer_push(cd->data.recbuf, buf); + break; + + case CTDB_CONTROL_SEND_GRATUITOUS_ARP: + ctdb_addr_info_push(cd->data.addr_info, buf); + break; + + case CTDB_CONTROL_TRANSACTION_START: + ctdb_uint32_push(cd->data.tid, buf); + break; + + case CTDB_CONTROL_TRANSACTION_COMMIT: + ctdb_uint32_push(cd->data.tid, buf); + break; + + case CTDB_CONTROL_WIPE_DATABASE: + ctdb_transdb_push(cd->data.transdb, buf); + break; + + case CTDB_CONTROL_TRY_DELETE_RECORDS: + ctdb_rec_buffer_push(cd->data.recbuf, buf); + break; + + case CTDB_CONTROL_ADD_PUBLIC_IP: + ctdb_addr_info_push(cd->data.addr_info, buf); + break; + + case CTDB_CONTROL_DEL_PUBLIC_IP: + ctdb_addr_info_push(cd->data.addr_info, buf); + break; + + case CTDB_CONTROL_RUN_EVENTSCRIPTS: + ctdb_string_push(cd->data.event_str, buf); + break; + + case CTDB_CONTROL_RELEASE_IP: + ctdb_public_ip_push(cd->data.pubip, buf); + break; + + case CTDB_CONTROL_TAKEOVER_IP: + ctdb_public_ip_push(cd->data.pubip, buf); + break; + + case CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS: + ctdb_uint32_push(cd->data.event, buf); + break; + + case CTDB_CONTROL_TRAVERSE_KILL: + ctdb_traverse_start_push(cd->data.traverse_start, buf); + break; + + case CTDB_CONTROL_RECD_RECLOCK_LATENCY: + ctdb_double_push(cd->data.reclock_latency, buf); + break; + + case CTDB_CONTROL_SET_RECLOCK_FILE: + ctdb_string_push(cd->data.reclock_file, buf); + break; + + case CTDB_CONTROL_SET_NATGWSTATE: + ctdb_uint32_push(cd->data.role, buf); + break; + + case CTDB_CONTROL_SET_LMASTERROLE: + ctdb_uint32_push(cd->data.role, buf); + break; + + case CTDB_CONTROL_SET_RECMASTERROLE: + ctdb_uint32_push(cd->data.role, buf); + break; + + case CTDB_CONTROL_ENABLE_SCRIPT: + ctdb_string_push(cd->data.script, buf); + break; + + case CTDB_CONTROL_DISABLE_SCRIPT: + ctdb_string_push(cd->data.script, buf); + break; + + case CTDB_CONTROL_SET_BAN_STATE: + ctdb_ban_state_push(cd->data.ban_state, buf); + break; + + case CTDB_CONTROL_SET_DB_PRIORITY: + ctdb_db_priority_push(cd->data.db_prio, buf); + break; + + case CTDB_CONTROL_GET_DB_PRIORITY: + ctdb_uint32_push(cd->data.db_id, buf); + break; + + case CTDB_CONTROL_REGISTER_NOTIFY: + ctdb_notify_data_push(cd->data.notify, buf); + break; + + case CTDB_CONTROL_DEREGISTER_NOTIFY: + ctdb_uint64_push(cd->data.srvid, buf); + break; + + case CTDB_CONTROL_TRANS3_COMMIT: + ctdb_rec_buffer_push(cd->data.recbuf, buf); + break; + + case CTDB_CONTROL_GET_DB_SEQNUM: + u64 = cd->data.db_id; + ctdb_uint32_push(u64, buf); + break; + + case CTDB_CONTROL_DB_SET_HEALTHY: + ctdb_uint32_push(cd->data.db_id, buf); + break; + + case CTDB_CONTROL_DB_GET_HEALTH: + ctdb_uint32_push(cd->data.db_id, buf); + break; + + case CTDB_CONTROL_GET_PUBLIC_IP_INFO: + ctdb_sock_addr_push(cd->data.addr, buf); + break; + + case CTDB_CONTROL_SET_IFACE_LINK_STATE: + ctdb_iface_push(cd->data.iface, buf); + break; + + case CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE: + ctdb_connection_push(cd->data.conn, buf); + break; + + case CTDB_CONTROL_SCHEDULE_FOR_DELETION: + ctdb_key_data_push(cd->data.key, buf); + break; + + case CTDB_CONTROL_SET_DB_READONLY: + ctdb_uint32_push(cd->data.db_id, buf); + break; + + case CTDB_CONTROL_CHECK_SRVIDS: + ctdb_uint64_array_push(cd->data.u64_array, buf); + break; + + case CTDB_CONTROL_TRAVERSE_START_EXT: + ctdb_traverse_start_ext_push(cd->data.traverse_start_ext, buf); + break; + + case CTDB_CONTROL_GET_DB_STATISTICS: + ctdb_uint32_push(cd->data.db_id, buf); + break; + + case CTDB_CONTROL_SET_DB_STICKY: + ctdb_uint32_push(cd->data.db_id, buf); + break; + + case CTDB_CONTROL_TRAVERSE_ALL_EXT: + ctdb_traverse_all_ext_push(cd->data.traverse_all_ext, buf); + break; + + case CTDB_CONTROL_RECEIVE_RECORDS: + ctdb_rec_buffer_push(cd->data.recbuf, buf); + break; + + case CTDB_CONTROL_DB_DETACH: + ctdb_uint32_push(cd->data.db_id, buf); + break; + } +} + +static int ctdb_req_control_data_pull(uint8_t *buf, size_t buflen, + uint32_t opcode, + TALLOC_CTX *mem_ctx, + struct ctdb_req_control_data *cd) +{ + int ret = 0; + uint64_t u64; + + cd->opcode = opcode; + + switch (opcode) { + case CTDB_CONTROL_PROCESS_EXISTS: + ret = ctdb_pid_pull(buf, buflen, mem_ctx, + &cd->data.pid); + break; + + case CTDB_CONTROL_GETDBPATH: + ret = ctdb_uint32_pull(buf, buflen, mem_ctx, + &cd->data.db_id); + break; + + case CTDB_CONTROL_SETVNNMAP: + ret = ctdb_vnn_map_pull(buf, buflen, mem_ctx, + &cd->data.vnnmap); + break; + + case CTDB_CONTROL_SET_DEBUG: + ret = ctdb_uint32_pull(buf, buflen, mem_ctx, + &cd->data.loglevel); + break; + + case CTDB_CONTROL_PULL_DB: + ret = ctdb_pulldb_pull(buf, buflen, mem_ctx, + &cd->data.pulldb); + break; + + case CTDB_CONTROL_PUSH_DB: + ret = ctdb_rec_buffer_pull(buf, buflen, mem_ctx, + &cd->data.recbuf); + break; + + case CTDB_CONTROL_SET_RECMODE: + ret = ctdb_uint32_pull(buf, buflen, mem_ctx, + &cd->data.recmode); + break; + + case CTDB_CONTROL_DB_ATTACH: + ret = ctdb_string_pull(buf, buflen, mem_ctx, + &cd->data.db_name); + break; + + case CTDB_CONTROL_SET_CALL: + break; + + case CTDB_CONTROL_TRAVERSE_START: + ret = ctdb_traverse_start_pull(buf, buflen, mem_ctx, + &cd->data.traverse_start); + break; + + case CTDB_CONTROL_TRAVERSE_ALL: + ret = ctdb_traverse_all_pull(buf, buflen, mem_ctx, + &cd->data.traverse_all); + break; + + case CTDB_CONTROL_TRAVERSE_DATA: + ret = ctdb_rec_data_pull(buf, buflen, mem_ctx, + &cd->data.rec_data); + break; + + case CTDB_CONTROL_GET_DBNAME: + ret = ctdb_uint32_pull(buf, buflen, mem_ctx, + &cd->data.db_id); + break; + + case CTDB_CONTROL_ENABLE_SEQNUM: + ret = ctdb_uint32_pull(buf, buflen, mem_ctx, + &cd->data.db_id); + break; + + case CTDB_CONTROL_UPDATE_SEQNUM: + ret = ctdb_uint32_pull(buf, buflen, mem_ctx, + &cd->data.db_id); + break; + + case CTDB_CONTROL_SET_RECMASTER: + ret = ctdb_uint32_pull(buf, buflen, mem_ctx, + &cd->data.recmaster); + break; + + case CTDB_CONTROL_TCP_CLIENT: + ret = ctdb_connection_pull(buf, buflen, mem_ctx, + &cd->data.conn); + break; + + case CTDB_CONTROL_TCP_ADD: + ret = ctdb_connection_pull(buf, buflen, mem_ctx, + &cd->data.conn); + break; + + case CTDB_CONTROL_TCP_REMOVE: + ret = ctdb_connection_pull(buf, buflen, mem_ctx, + &cd->data.conn); + break; + + case CTDB_CONTROL_SET_TUNABLE: + ret = ctdb_tunable_pull(buf, buflen, mem_ctx, + &cd->data.tunable); + break; + + case CTDB_CONTROL_GET_TUNABLE: + ret = ctdb_stringn_pull(buf, buflen, mem_ctx, + &cd->data.tun_var); + break; + + case CTDB_CONTROL_MODIFY_FLAGS: + ret = ctdb_node_flag_change_pull(buf, buflen, mem_ctx, + &cd->data.flag_change); + break; + + case CTDB_CONTROL_KILL_TCP: + ret = ctdb_connection_pull(buf, buflen, mem_ctx, + &cd->data.conn); + break; + + case CTDB_CONTROL_GET_TCP_TICKLE_LIST: + ret = ctdb_sock_addr_pull(buf, buflen, mem_ctx, + &cd->data.addr); + break; + + case CTDB_CONTROL_SET_TCP_TICKLE_LIST: + ret = ctdb_tickle_list_pull(buf, buflen, mem_ctx, + &cd->data.tickles); + break; + + case CTDB_CONTROL_REGISTER_SERVER_ID: + ret = ctdb_client_id_pull(buf, buflen, mem_ctx, + &cd->data.cid); + break; + + case CTDB_CONTROL_UNREGISTER_SERVER_ID: + ret = ctdb_client_id_pull(buf, buflen, mem_ctx, + &cd->data.cid); + break; + + case CTDB_CONTROL_CHECK_SERVER_ID: + ret = ctdb_client_id_pull(buf, buflen, mem_ctx, + &cd->data.cid); + break; + + case CTDB_CONTROL_DB_ATTACH_PERSISTENT: + ret = ctdb_string_pull(buf, buflen, mem_ctx, + &cd->data.db_name); + break; + + case CTDB_CONTROL_UPDATE_RECORD: + ret = ctdb_rec_buffer_pull(buf, buflen, mem_ctx, + &cd->data.recbuf); + break; + + case CTDB_CONTROL_SEND_GRATUITOUS_ARP: + ret = ctdb_addr_info_pull(buf, buflen, mem_ctx, + &cd->data.addr_info); + break; + + case CTDB_CONTROL_TRANSACTION_START: + ret = ctdb_uint32_pull(buf, buflen, mem_ctx, + &cd->data.tid); + break; + + case CTDB_CONTROL_TRANSACTION_COMMIT: + ret = ctdb_uint32_pull(buf, buflen, mem_ctx, + &cd->data.tid); + break; + + case CTDB_CONTROL_WIPE_DATABASE: + ret = ctdb_transdb_pull(buf, buflen, mem_ctx, + &cd->data.transdb); + break; + + case CTDB_CONTROL_TRY_DELETE_RECORDS: + ret = ctdb_rec_buffer_pull(buf, buflen, mem_ctx, + &cd->data.recbuf); + break; + + case CTDB_CONTROL_ADD_PUBLIC_IP: + ret = ctdb_addr_info_pull(buf, buflen, mem_ctx, + &cd->data.addr_info); + break; + + case CTDB_CONTROL_DEL_PUBLIC_IP: + ret = ctdb_addr_info_pull(buf, buflen, mem_ctx, + &cd->data.addr_info); + break; + + case CTDB_CONTROL_RUN_EVENTSCRIPTS: + ret = ctdb_string_pull(buf, buflen, mem_ctx, + &cd->data.event_str); + break; + + case CTDB_CONTROL_RELEASE_IP: + ret = ctdb_public_ip_pull(buf, buflen, mem_ctx, + &cd->data.pubip); + break; + + case CTDB_CONTROL_TAKEOVER_IP: + ret = ctdb_public_ip_pull(buf, buflen, mem_ctx, + &cd->data.pubip); + break; + + case CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS: + ret = ctdb_uint32_pull(buf, buflen, mem_ctx, + &cd->data.event); + break; + + case CTDB_CONTROL_TRAVERSE_KILL: + ret = ctdb_traverse_start_pull(buf, buflen, mem_ctx, + &cd->data.traverse_start); + break; + + case CTDB_CONTROL_RECD_RECLOCK_LATENCY: + ret = ctdb_double_pull(buf, buflen, mem_ctx, + &cd->data.reclock_latency); + break; + + case CTDB_CONTROL_SET_RECLOCK_FILE: + ret = ctdb_string_pull(buf, buflen, mem_ctx, + &cd->data.reclock_file); + break; + + case CTDB_CONTROL_SET_NATGWSTATE: + ret = ctdb_uint32_pull(buf, buflen, mem_ctx, + &cd->data.role); + break; + + case CTDB_CONTROL_SET_LMASTERROLE: + ret = ctdb_uint32_pull(buf, buflen, mem_ctx, + &cd->data.role); + break; + + case CTDB_CONTROL_SET_RECMASTERROLE: + ret = ctdb_uint32_pull(buf, buflen, mem_ctx, + &cd->data.role); + break; + + case CTDB_CONTROL_ENABLE_SCRIPT: + ret = ctdb_string_pull(buf, buflen, mem_ctx, + &cd->data.script); + break; + + case CTDB_CONTROL_DISABLE_SCRIPT: + ret = ctdb_string_pull(buf, buflen, mem_ctx, + &cd->data.script); + break; + + case CTDB_CONTROL_SET_BAN_STATE: + ret = ctdb_ban_state_pull(buf, buflen, mem_ctx, + &cd->data.ban_state); + break; + + case CTDB_CONTROL_SET_DB_PRIORITY: + ret = ctdb_db_priority_pull(buf, buflen, mem_ctx, + &cd->data.db_prio); + break; + + case CTDB_CONTROL_GET_DB_PRIORITY: + ret = ctdb_uint32_pull(buf, buflen, mem_ctx, + &cd->data.db_id); + break; + + case CTDB_CONTROL_REGISTER_NOTIFY: + ret = ctdb_notify_data_pull(buf, buflen, mem_ctx, + &cd->data.notify); + break; + + case CTDB_CONTROL_DEREGISTER_NOTIFY: + ctdb_uint64_pull(buf, buflen, mem_ctx, + &cd->data.srvid); + break; + + case CTDB_CONTROL_TRANS3_COMMIT: + ret = ctdb_rec_buffer_pull(buf, buflen, mem_ctx, + &cd->data.recbuf); + break; + + case CTDB_CONTROL_GET_DB_SEQNUM: + ret = ctdb_uint64_pull(buf, buflen, mem_ctx, &u64); + cd->data.db_id = (uint32_t)u64; + break; + + case CTDB_CONTROL_DB_SET_HEALTHY: + ret = ctdb_uint32_pull(buf, buflen, mem_ctx, + &cd->data.db_id); + break; + + case CTDB_CONTROL_DB_GET_HEALTH: + ret = ctdb_uint32_pull(buf, buflen, mem_ctx, + &cd->data.db_id); + break; + + case CTDB_CONTROL_GET_PUBLIC_IP_INFO: + ret = ctdb_sock_addr_pull(buf, buflen, mem_ctx, + &cd->data.addr); + break; + + case CTDB_CONTROL_SET_IFACE_LINK_STATE: + ret = ctdb_iface_pull(buf, buflen, mem_ctx, + &cd->data.iface); + break; + + case CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE: + ret = ctdb_connection_pull(buf, buflen, mem_ctx, + &cd->data.conn); + break; + + case CTDB_CONTROL_SCHEDULE_FOR_DELETION: + ret = ctdb_key_data_pull(buf, buflen, mem_ctx, + &cd->data.key); + break; + + case CTDB_CONTROL_SET_DB_READONLY: + ret = ctdb_uint32_pull(buf, buflen, mem_ctx, + &cd->data.db_id); + break; + + case CTDB_CONTROL_CHECK_SRVIDS: + ret = ctdb_uint64_array_pull(buf, buflen, mem_ctx, + &cd->data.u64_array); + break; + + case CTDB_CONTROL_TRAVERSE_START_EXT: + ret = ctdb_traverse_start_ext_pull(buf, buflen, mem_ctx, + &cd->data.traverse_start_ext); + break; + + case CTDB_CONTROL_GET_DB_STATISTICS: + ret = ctdb_uint32_pull(buf, buflen, mem_ctx, + &cd->data.db_id); + break; + + case CTDB_CONTROL_SET_DB_STICKY: + ret = ctdb_uint32_pull(buf, buflen, mem_ctx, + &cd->data.db_id); + break; + + case CTDB_CONTROL_TRAVERSE_ALL_EXT: + ret = ctdb_traverse_all_ext_pull(buf, buflen, mem_ctx, + &cd->data.traverse_all_ext); + break; + + case CTDB_CONTROL_RECEIVE_RECORDS: + ret = ctdb_rec_buffer_pull(buf, buflen, mem_ctx, + &cd->data.recbuf); + break; + + case CTDB_CONTROL_DB_DETACH: + ret = ctdb_uint32_pull(buf, buflen, mem_ctx, + &cd->data.db_id); + break; + } + + return ret; +} + +static size_t ctdb_reply_control_data_len(struct ctdb_reply_control_data *cd) +{ + size_t len = 0; + + if (cd == NULL) { + return 0; + } + + switch (cd->opcode) { + case CTDB_CONTROL_PROCESS_EXISTS: + break; + + case CTDB_CONTROL_STATISTICS: + len = ctdb_statistics_len(cd->data.stats); + break; + + case CTDB_CONTROL_PING: + break; + + case CTDB_CONTROL_GETDBPATH: + len = ctdb_string_len(cd->data.db_path); + break; + + case CTDB_CONTROL_GETVNNMAP: + len = ctdb_vnn_map_len(cd->data.vnnmap); + break; + + case CTDB_CONTROL_SETVNNMAP: + break; + + case CTDB_CONTROL_GET_DEBUG: + len = ctdb_uint32_len(cd->data.loglevel); + break; + + case CTDB_CONTROL_SET_DEBUG: + break; + + case CTDB_CONTROL_GET_DBMAP: + len = ctdb_dbid_map_len(cd->data.dbmap); + break; + + case CTDB_CONTROL_PULL_DB: + len = ctdb_rec_buffer_len(cd->data.recbuf); + break; + + case CTDB_CONTROL_PUSH_DB: + break; + + case CTDB_CONTROL_GET_RECMODE: + break; + + case CTDB_CONTROL_SET_RECMODE: + break; + + case CTDB_CONTROL_STATISTICS_RESET: + break; + + case CTDB_CONTROL_DB_ATTACH: + len = ctdb_uint32_len(cd->data.db_id); + break; + + case CTDB_CONTROL_SET_CALL: + break; + + case CTDB_CONTROL_TRAVERSE_START: + break; + + case CTDB_CONTROL_TRAVERSE_ALL: + break; + + case CTDB_CONTROL_TRAVERSE_DATA: + break; + + case CTDB_CONTROL_REGISTER_SRVID: + break; + + case CTDB_CONTROL_DEREGISTER_SRVID: + break; + + case CTDB_CONTROL_GET_DBNAME: + len = ctdb_string_len(cd->data.db_name); + break; + + case CTDB_CONTROL_ENABLE_SEQNUM: + break; + + case CTDB_CONTROL_UPDATE_SEQNUM: + break; + + case CTDB_CONTROL_DUMP_MEMORY: + len = ctdb_string_len(cd->data.mem_str); + break; + + case CTDB_CONTROL_GET_PID: + break; + + case CTDB_CONTROL_GET_RECMASTER: + break; + + case CTDB_CONTROL_SET_RECMASTER: + break; + + case CTDB_CONTROL_FREEZE: + break; + + case CTDB_CONTROL_THAW: + break; + + case CTDB_CONTROL_GET_PNN: + break; + + case CTDB_CONTROL_SHUTDOWN: + break; + + case CTDB_CONTROL_GET_MONMODE: + break; + + case CTDB_CONTROL_TCP_CLIENT: + break; + + case CTDB_CONTROL_TCP_ADD: + break; + + case CTDB_CONTROL_TCP_REMOVE: + break; + + case CTDB_CONTROL_STARTUP: + break; + + case CTDB_CONTROL_SET_TUNABLE: + break; + + case CTDB_CONTROL_GET_TUNABLE: + len = ctdb_uint32_len(cd->data.tun_value); + break; + + case CTDB_CONTROL_LIST_TUNABLES: + len = ctdb_var_list_len(cd->data.tun_var_list); + break; + + case CTDB_CONTROL_MODIFY_FLAGS: + break; + + case CTDB_CONTROL_GET_ALL_TUNABLES: + len = ctdb_tunable_list_len(cd->data.tun_list); + break; + + case CTDB_CONTROL_KILL_TCP: + break; + + case CTDB_CONTROL_GET_TCP_TICKLE_LIST: + len = ctdb_tickle_list_len(cd->data.tickles); + break; + + case CTDB_CONTROL_SET_TCP_TICKLE_LIST: + break; + + case CTDB_CONTROL_REGISTER_SERVER_ID: + break; + + case CTDB_CONTROL_UNREGISTER_SERVER_ID: + break; + + case CTDB_CONTROL_CHECK_SERVER_ID: + break; + + case CTDB_CONTROL_GET_SERVER_ID_LIST: + len = ctdb_client_id_map_len(cd->data.cid_map); + break; + + case CTDB_CONTROL_DB_ATTACH_PERSISTENT: + len = ctdb_uint32_len(cd->data.db_id); + break; + + case CTDB_CONTROL_UPDATE_RECORD: + break; + + case CTDB_CONTROL_SEND_GRATUITOUS_ARP: + break; + + case CTDB_CONTROL_TRANSACTION_START: + break; + + case CTDB_CONTROL_TRANSACTION_COMMIT: + break; + + case CTDB_CONTROL_WIPE_DATABASE: + break; + + case CTDB_CONTROL_UPTIME: + len = ctdb_uptime_len(cd->data.uptime); + break; + + case CTDB_CONTROL_START_RECOVERY: + break; + + case CTDB_CONTROL_END_RECOVERY: + break; + + case CTDB_CONTROL_RELOAD_NODES_FILE: + break; + + case CTDB_CONTROL_TRY_DELETE_RECORDS: + len = ctdb_rec_buffer_len(cd->data.recbuf); + break; + + case CTDB_CONTROL_ENABLE_MONITOR: + break; + + case CTDB_CONTROL_DISABLE_MONITOR: + break; + + case CTDB_CONTROL_ADD_PUBLIC_IP: + break; + + case CTDB_CONTROL_DEL_PUBLIC_IP: + break; + + case CTDB_CONTROL_RUN_EVENTSCRIPTS: + break; + + case CTDB_CONTROL_GET_CAPABILITIES: + len = ctdb_uint32_len(cd->data.caps); + break; + + case CTDB_CONTROL_RECD_PING: + break; + + case CTDB_CONTROL_RELEASE_IP: + break; + + case CTDB_CONTROL_TAKEOVER_IP: + break; + + case CTDB_CONTROL_GET_PUBLIC_IPS: + len = ctdb_public_ip_list_len(cd->data.pubip_list); + break; + + case CTDB_CONTROL_GET_NODEMAP: + len = ctdb_node_map_len(cd->data.nodemap); + break; + + case CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS: + len = ctdb_script_list_len(cd->data.script_list); + break; + + case CTDB_CONTROL_TRAVERSE_KILL: + break; + + case CTDB_CONTROL_RECD_RECLOCK_LATENCY: + break; + + case CTDB_CONTROL_GET_RECLOCK_FILE: + len = ctdb_string_len(cd->data.reclock_file); + break; + + case CTDB_CONTROL_SET_RECLOCK_FILE: + break; + + case CTDB_CONTROL_STOP_NODE: + break; + + case CTDB_CONTROL_CONTINUE_NODE: + break; + + case CTDB_CONTROL_SET_NATGWSTATE: + break; + + case CTDB_CONTROL_SET_LMASTERROLE: + break; + + case CTDB_CONTROL_SET_RECMASTERROLE: + break; + + case CTDB_CONTROL_ENABLE_SCRIPT: + break; + + case CTDB_CONTROL_DISABLE_SCRIPT: + break; + + case CTDB_CONTROL_SET_BAN_STATE: + break; + + case CTDB_CONTROL_GET_BAN_STATE: + len = ctdb_ban_state_len(cd->data.ban_state); + break; + + case CTDB_CONTROL_SET_DB_PRIORITY: + break; + + case CTDB_CONTROL_GET_DB_PRIORITY: + break; + + case CTDB_CONTROL_TRANSACTION_CANCEL: + break; + + case CTDB_CONTROL_REGISTER_NOTIFY: + break; + + case CTDB_CONTROL_DEREGISTER_NOTIFY: + break; + + case CTDB_CONTROL_TRANS3_COMMIT: + break; + + case CTDB_CONTROL_GET_DB_SEQNUM: + len = ctdb_uint64_len(cd->data.seqnum); + break; + + case CTDB_CONTROL_DB_SET_HEALTHY: + break; + + case CTDB_CONTROL_DB_GET_HEALTH: + len = ctdb_string_len(cd->data.reason); + break; + + case CTDB_CONTROL_GET_PUBLIC_IP_INFO: + len = ctdb_public_ip_info_len(cd->data.ipinfo); + break; + + case CTDB_CONTROL_GET_IFACES: + len = ctdb_iface_list_len(cd->data.iface_list); + break; + + case CTDB_CONTROL_SET_IFACE_LINK_STATE: + break; + + case CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE: + break; + + case CTDB_CONTROL_GET_STAT_HISTORY: + len = ctdb_statistics_list_len(cd->data.stats_list); + break; + + case CTDB_CONTROL_SCHEDULE_FOR_DELETION: + break; + + case CTDB_CONTROL_SET_DB_READONLY: + break; + + case CTDB_CONTROL_CHECK_SRVIDS: + len = ctdb_uint8_array_len(cd->data.u8_array); + break; + + case CTDB_CONTROL_TRAVERSE_START_EXT: + break; + + case CTDB_CONTROL_GET_DB_STATISTICS: + len = ctdb_db_statistics_len(cd->data.dbstats); + break; + + case CTDB_CONTROL_SET_DB_STICKY: + break; + + case CTDB_CONTROL_RELOAD_PUBLIC_IPS: + break; + + case CTDB_CONTROL_TRAVERSE_ALL_EXT: + break; + + case CTDB_CONTROL_RECEIVE_RECORDS: + len = ctdb_rec_buffer_len(cd->data.recbuf); + break; + + case CTDB_CONTROL_IPREALLOCATED: + break; + + case CTDB_CONTROL_GET_RUNSTATE: + len = ctdb_uint32_len(cd->data.runstate); + break; + + case CTDB_CONTROL_DB_DETACH: + break; + + case CTDB_CONTROL_GET_NODES_FILE: + len = ctdb_node_map_len(cd->data.nodemap); + break; + } + + return len; +} + +static void ctdb_reply_control_data_push(struct ctdb_reply_control_data *cd, + uint8_t *buf) +{ + switch (cd->opcode) { + case CTDB_CONTROL_STATISTICS: + ctdb_statistics_push(cd->data.stats, buf); + break; + + case CTDB_CONTROL_GETDBPATH: + ctdb_string_push(cd->data.db_path, buf); + break; + + case CTDB_CONTROL_GETVNNMAP: + ctdb_vnn_map_push(cd->data.vnnmap, buf); + break; + + case CTDB_CONTROL_GET_DEBUG: + ctdb_uint32_push(cd->data.loglevel, buf); + break; + + case CTDB_CONTROL_GET_DBMAP: + ctdb_dbid_map_push(cd->data.dbmap, buf); + break; + + case CTDB_CONTROL_PULL_DB: + ctdb_rec_buffer_push(cd->data.recbuf, buf); + break; + + case CTDB_CONTROL_PUSH_DB: + break; + + case CTDB_CONTROL_DB_ATTACH: + ctdb_uint32_push(cd->data.db_id, buf); + break; + + case CTDB_CONTROL_GET_DBNAME: + ctdb_string_push(cd->data.db_name, buf); + break; + + case CTDB_CONTROL_DUMP_MEMORY: + ctdb_string_push(cd->data.mem_str, buf); + break; + + case CTDB_CONTROL_GET_PID: + break; + + case CTDB_CONTROL_GET_RECMASTER: + break; + + case CTDB_CONTROL_GET_TUNABLE: + ctdb_uint32_push(cd->data.tun_value, buf); + break; + + case CTDB_CONTROL_LIST_TUNABLES: + ctdb_var_list_push(cd->data.tun_var_list, buf); + break; + + case CTDB_CONTROL_GET_ALL_TUNABLES: + ctdb_tunable_list_push(cd->data.tun_list, buf); + break; + + case CTDB_CONTROL_GET_TCP_TICKLE_LIST: + ctdb_tickle_list_push(cd->data.tickles, buf); + break; + + case CTDB_CONTROL_GET_SERVER_ID_LIST: + ctdb_client_id_map_push(cd->data.cid_map, buf); + break; + + case CTDB_CONTROL_DB_ATTACH_PERSISTENT: + ctdb_uint32_push(cd->data.db_id, buf); + break; + + case CTDB_CONTROL_UPTIME: + ctdb_uptime_push(cd->data.uptime, buf); + break; + + case CTDB_CONTROL_TRY_DELETE_RECORDS: + ctdb_rec_buffer_push(cd->data.recbuf, buf); + break; + + case CTDB_CONTROL_GET_CAPABILITIES: + ctdb_uint32_push(cd->data.caps, buf); + break; + + case CTDB_CONTROL_GET_PUBLIC_IPS: + ctdb_public_ip_list_push(cd->data.pubip_list, buf); + break; + + case CTDB_CONTROL_GET_NODEMAP: + ctdb_node_map_push(cd->data.nodemap, buf); + break; + + case CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS: + ctdb_script_list_push(cd->data.script_list, buf); + break; + + case CTDB_CONTROL_GET_RECLOCK_FILE: + ctdb_string_push(cd->data.reclock_file, buf); + break; + + case CTDB_CONTROL_GET_BAN_STATE: + ctdb_ban_state_push(cd->data.ban_state, buf); + break; + + case CTDB_CONTROL_GET_DB_PRIORITY: + break; + + case CTDB_CONTROL_GET_DB_SEQNUM: + ctdb_uint64_push(cd->data.seqnum, buf); + break; + + case CTDB_CONTROL_DB_GET_HEALTH: + ctdb_string_push(cd->data.reason, buf); + break; + + case CTDB_CONTROL_GET_PUBLIC_IP_INFO: + ctdb_public_ip_info_push(cd->data.ipinfo, buf); + break; + + case CTDB_CONTROL_GET_IFACES: + ctdb_iface_list_push(cd->data.iface_list, buf); + break; + + case CTDB_CONTROL_GET_STAT_HISTORY: + ctdb_statistics_list_push(cd->data.stats_list, buf); + break; + + case CTDB_CONTROL_CHECK_SRVIDS: + ctdb_uint8_array_push(cd->data.u8_array, buf); + break; + + case CTDB_CONTROL_GET_DB_STATISTICS: + ctdb_db_statistics_push(cd->data.dbstats, buf); + break; + + case CTDB_CONTROL_RECEIVE_RECORDS: + ctdb_rec_buffer_push(cd->data.recbuf, buf); + break; + + case CTDB_CONTROL_GET_RUNSTATE: + ctdb_uint32_push(cd->data.runstate, buf); + break; + + case CTDB_CONTROL_GET_NODES_FILE: + ctdb_node_map_push(cd->data.nodemap, buf); + break; + } +} + +static int ctdb_reply_control_data_pull(uint8_t *buf, size_t buflen, + uint32_t opcode, TALLOC_CTX *mem_ctx, + struct ctdb_reply_control_data *cd) +{ + int ret = 0; + cd->opcode = opcode; + + switch (opcode) { + case CTDB_CONTROL_STATISTICS: + ret = ctdb_statistics_pull(buf, buflen, mem_ctx, + &cd->data.stats); + break; + + case CTDB_CONTROL_GETDBPATH: + ret = ctdb_string_pull(buf, buflen, mem_ctx, + &cd->data.db_path); + break; + + case CTDB_CONTROL_GETVNNMAP: + ret = ctdb_vnn_map_pull(buf, buflen, mem_ctx, + &cd->data.vnnmap); + break; + + case CTDB_CONTROL_GET_DEBUG: + ret = ctdb_uint32_pull(buf, buflen, mem_ctx, + &cd->data.loglevel); + break; + + case CTDB_CONTROL_GET_DBMAP: + ret = ctdb_dbid_map_pull(buf, buflen, mem_ctx, + &cd->data.dbmap); + break; + + case CTDB_CONTROL_PULL_DB: + ret = ctdb_rec_buffer_pull(buf, buflen, mem_ctx, + &cd->data.recbuf); + break; + + case CTDB_CONTROL_PUSH_DB: + break; + + case CTDB_CONTROL_DB_ATTACH: + ret = ctdb_uint32_pull(buf, buflen, mem_ctx, + &cd->data.db_id); + break; + + case CTDB_CONTROL_GET_DBNAME: + ret = ctdb_string_pull(buf, buflen, mem_ctx, + &cd->data.db_name); + break; + + case CTDB_CONTROL_DUMP_MEMORY: + ret = ctdb_string_pull(buf, buflen, mem_ctx, + &cd->data.mem_str); + break; + + case CTDB_CONTROL_GET_PID: + break; + + case CTDB_CONTROL_GET_RECMASTER: + break; + + case CTDB_CONTROL_GET_TUNABLE: + ret = ctdb_uint32_pull(buf, buflen, mem_ctx, + &cd->data.tun_value); + break; + + case CTDB_CONTROL_LIST_TUNABLES: + ret = ctdb_var_list_pull(buf, buflen, mem_ctx, + &cd->data.tun_var_list); + break; + + case CTDB_CONTROL_GET_ALL_TUNABLES: + ret = ctdb_tunable_list_pull(buf, buflen, mem_ctx, + &cd->data.tun_list); + break; + + case CTDB_CONTROL_GET_TCP_TICKLE_LIST: + ret = ctdb_tickle_list_pull(buf, buflen, mem_ctx, + &cd->data.tickles); + break; + + case CTDB_CONTROL_GET_SERVER_ID_LIST: + ret = ctdb_client_id_map_pull(buf, buflen, mem_ctx, + &cd->data.cid_map); + break; + + case CTDB_CONTROL_DB_ATTACH_PERSISTENT: + ret = ctdb_uint32_pull(buf, buflen, mem_ctx, + &cd->data.db_id); + break; + + case CTDB_CONTROL_UPTIME: + ret = ctdb_uptime_pull(buf, buflen, mem_ctx, + &cd->data.uptime); + break; + + case CTDB_CONTROL_TRY_DELETE_RECORDS: + ctdb_rec_buffer_pull(buf, buflen, mem_ctx, + &cd->data.recbuf); + break; + + case CTDB_CONTROL_GET_CAPABILITIES: + ret = ctdb_uint32_pull(buf, buflen, mem_ctx, + &cd->data.caps); + break; + + case CTDB_CONTROL_GET_PUBLIC_IPS: + ret = ctdb_public_ip_list_pull(buf, buflen, mem_ctx, + &cd->data.pubip_list); + break; + + case CTDB_CONTROL_GET_NODEMAP: + ret = ctdb_node_map_pull(buf, buflen, mem_ctx, + &cd->data.nodemap); + break; + + case CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS: + ret = ctdb_script_list_pull(buf, buflen, mem_ctx, + &cd->data.script_list); + break; + + case CTDB_CONTROL_GET_RECLOCK_FILE: + ret = ctdb_string_pull(buf, buflen, mem_ctx, + &cd->data.reclock_file); + break; + + case CTDB_CONTROL_GET_BAN_STATE: + ret = ctdb_ban_state_pull(buf, buflen, mem_ctx, + &cd->data.ban_state); + break; + + case CTDB_CONTROL_GET_DB_PRIORITY: + break; + + case CTDB_CONTROL_GET_DB_SEQNUM: + ret = ctdb_uint64_pull(buf, buflen, mem_ctx, + &cd->data.seqnum); + break; + + case CTDB_CONTROL_DB_GET_HEALTH: + ret = ctdb_string_pull(buf, buflen, mem_ctx, + &cd->data.reason); + break; + + case CTDB_CONTROL_GET_PUBLIC_IP_INFO: + ret = ctdb_public_ip_info_pull(buf, buflen, mem_ctx, + &cd->data.ipinfo); + break; + + case CTDB_CONTROL_GET_IFACES: + ret = ctdb_iface_list_pull(buf, buflen, mem_ctx, + &cd->data.iface_list); + break; + + case CTDB_CONTROL_GET_STAT_HISTORY: + ret = ctdb_statistics_list_pull(buf, buflen, mem_ctx, + &cd->data.stats_list); + break; + + case CTDB_CONTROL_CHECK_SRVIDS: + ret = ctdb_uint8_array_pull(buf, buflen, mem_ctx, + &cd->data.u8_array); + break; + + case CTDB_CONTROL_GET_DB_STATISTICS: + ret = ctdb_db_statistics_pull(buf, buflen, mem_ctx, + &cd->data.dbstats); + break; + + case CTDB_CONTROL_RECEIVE_RECORDS: + ret = ctdb_rec_buffer_pull(buf, buflen, mem_ctx, + &cd->data.recbuf); + break; + + case CTDB_CONTROL_GET_RUNSTATE: + ret = ctdb_uint32_pull(buf, buflen, mem_ctx, + &cd->data.runstate); + break; + + case CTDB_CONTROL_GET_NODES_FILE: + ret = ctdb_node_map_pull(buf, buflen, mem_ctx, + &cd->data.nodemap); + break; + } + + return ret; +} + +int ctdb_req_control_push(struct ctdb_req_header *h, + struct ctdb_req_control *request, + TALLOC_CTX *mem_ctx, + uint8_t **pkt, size_t *pkt_len) +{ + struct ctdb_req_control_wire *wire; + uint8_t *buf; + size_t length, buflen, datalen; + int ret; + + datalen = ctdb_req_control_data_len(&request->rdata); + length = offsetof(struct ctdb_req_control_wire, data) + datalen; + + ret = allocate_pkt(mem_ctx, length, &buf, &buflen); + if (ret != 0) { + return ret; + } + + wire = (struct ctdb_req_control_wire *)buf; + + h->length = buflen; + memcpy(&wire->hdr, h, sizeof(struct ctdb_req_header)); + + wire->opcode = request->opcode; + wire->pad = request->pad; + wire->srvid = request->srvid; + wire->client_id = request->client_id; + wire->flags = request->flags; + + wire->datalen = datalen; + ctdb_req_control_data_push(&request->rdata, wire->data); + + *pkt = buf; + *pkt_len = buflen; + return 0; +} + +int ctdb_req_control_pull(uint8_t *pkt, size_t pkt_len, + struct ctdb_req_header *h, + TALLOC_CTX *mem_ctx, + struct ctdb_req_control *request) +{ + struct ctdb_req_control_wire *wire = + (struct ctdb_req_control_wire *)pkt; + size_t length; + int ret; + + length = offsetof(struct ctdb_req_control_wire, data); + if (pkt_len < length) { + return EMSGSIZE; + } + if (pkt_len < length + wire->datalen) { + return EMSGSIZE; + } + + memcpy(h, &wire->hdr, sizeof(struct ctdb_req_header)); + + request->opcode = wire->opcode; + request->pad = wire->pad; + request->srvid = wire->srvid; + request->client_id = wire->client_id; + request->flags = wire->flags; + + ret = ctdb_req_control_data_pull(wire->data, wire->datalen, + request->opcode, mem_ctx, + &request->rdata); + if (ret != 0) { + return ret; + } + + return 0; +} + +int ctdb_reply_control_push(struct ctdb_req_header *h, + struct ctdb_reply_control *reply, + TALLOC_CTX *mem_ctx, + uint8_t **pkt, size_t *pkt_len) +{ + struct ctdb_reply_control_wire *wire; + uint8_t *buf; + size_t length, buflen, datalen, errlen; + int ret; + + if (reply->status == 0) { + datalen = ctdb_reply_control_data_len(&reply->rdata); + } else { + datalen = 0; + } + + if (reply->errmsg == NULL) { + errlen = 0; + } else { + errlen = strlen(reply->errmsg) + 1; + } + + length = offsetof(struct ctdb_reply_control_wire, data) + + datalen + errlen; + + ret = allocate_pkt(mem_ctx, length, &buf, &buflen); + if (ret != 0) { + return ret; + } + + wire = (struct ctdb_reply_control_wire *)buf; + + h->length = buflen; + memcpy(&wire->hdr, h, sizeof(struct ctdb_req_header)); + + wire->status = reply->status; + + wire->datalen = datalen; + if (reply->status == 0) { + ctdb_reply_control_data_push(&reply->rdata, wire->data); + } + + wire->errorlen = errlen; + if (errlen > 0) { + memcpy(wire->data + datalen, reply->errmsg, wire->errorlen); + } + + *pkt = buf; + *pkt_len = buflen; + return 0; +} + +int ctdb_reply_control_pull(uint8_t *pkt, size_t pkt_len, uint32_t opcode, + struct ctdb_req_header *h, + TALLOC_CTX *mem_ctx, + struct ctdb_reply_control *reply) +{ + struct ctdb_reply_control_wire *wire = + (struct ctdb_reply_control_wire *)pkt; + size_t length; + int ret; + + length = offsetof(struct ctdb_reply_control_wire, data); + + if (pkt_len < length) { + return EMSGSIZE; + } + if (pkt_len < length + wire->datalen + wire->errorlen) { + return EMSGSIZE; + } + + memcpy(h, &wire->hdr, sizeof(struct ctdb_req_header)); + + reply->status = wire->status; + + if (reply->status != -1) { + ret = ctdb_reply_control_data_pull(wire->data, wire->datalen, + opcode, mem_ctx, + &reply->rdata); + if (ret != 0) { + return ret; + } + } + + if (wire->errorlen > 0) { + reply->errmsg = talloc_memdup(mem_ctx, + wire->data + wire->datalen, + wire->errorlen); + } else { + reply->errmsg = NULL; + } + + return 0; +} diff --git a/ctdb/protocol/protocol_header.c b/ctdb/protocol/protocol_header.c new file mode 100644 index 0000000..b802d08 --- /dev/null +++ b/ctdb/protocol/protocol_header.c @@ -0,0 +1,73 @@ +/* + CTDB protocol marshalling + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include "replace.h" +#include "system/network.h" + +#include +#include + +#include "protocol.h" +#include "protocol_api.h" + +int ctdb_req_header_verify(struct ctdb_req_header *h, uint32_t operation) +{ + if (h->length < sizeof(struct ctdb_req_header)) { + return EMSGSIZE; + } + + if (h->ctdb_magic != CTDB_MAGIC) { + return EPROTO; + } + + if (h->ctdb_version != CTDB_PROTOCOL) { + return EPROTO; + } + + if (operation != 0 && h->operation != operation) { + return EPROTO; + } + + return 0; +} + +void ctdb_req_header_fill(struct ctdb_req_header *h, uint32_t generation, + uint32_t operation, uint32_t destnode, + uint32_t srcnode, uint32_t reqid) +{ + h->length = sizeof(struct ctdb_req_header); + h->ctdb_magic = CTDB_MAGIC; + h->ctdb_version = CTDB_PROTOCOL; + h->generation = generation; + h->operation = operation; + h->destnode = destnode; + h->srcnode = srcnode; + h->reqid = reqid; +} + +int ctdb_req_header_pull(uint8_t *pkt, size_t pkt_len, + struct ctdb_req_header *h) +{ + if (pkt_len < sizeof(struct ctdb_req_header)) { + return EMSGSIZE; + } + + memcpy(h, pkt, sizeof(struct ctdb_req_header)); + return 0; +} diff --git a/ctdb/protocol/protocol_message.c b/ctdb/protocol/protocol_message.c new file mode 100644 index 0000000..07d2dbb --- /dev/null +++ b/ctdb/protocol/protocol_message.c @@ -0,0 +1,383 @@ +/* + CTDB protocol marshalling + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include "replace.h" +#include "system/network.h" + +#include +#include + +#include "protocol.h" +#include "protocol_api.h" +#include "protocol_private.h" + +struct ctdb_req_message_wire { + struct ctdb_req_header hdr; + uint64_t srvid; + uint32_t datalen; + uint8_t data[1]; +}; + +static size_t ctdb_message_data_len(union ctdb_message_data *mdata, + uint64_t srvid) +{ + size_t len = 0; + + switch (srvid) { + case CTDB_SRVID_ELECTION: + len = ctdb_election_message_len(mdata->election); + break; + + case CTDB_SRVID_RECONFIGURE: + break; + + case CTDB_SRVID_RELEASE_IP: + len = ctdb_string_len(mdata->ipaddr); + break; + + case CTDB_SRVID_TAKE_IP: + len = ctdb_string_len(mdata->ipaddr); + break; + + case CTDB_SRVID_SET_NODE_FLAGS: + len = ctdb_node_flag_change_len(mdata->flag_change); + break; + + case CTDB_SRVID_RECD_UPDATE_IP: + len = ctdb_public_ip_len(mdata->pubip); + break; + + case CTDB_SRVID_VACUUM_FETCH: + len = ctdb_rec_buffer_len(mdata->recbuf); + break; + + case CTDB_SRVID_DETACH_DATABASE: + len = ctdb_uint32_len(mdata->db_id); + break; + + case CTDB_SRVID_MEM_DUMP: + len = ctdb_srvid_message_len(mdata->msg); + break; + + case CTDB_SRVID_PUSH_NODE_FLAGS: + len = ctdb_node_flag_change_len(mdata->flag_change); + break; + + case CTDB_SRVID_RELOAD_NODES: + break; + + case CTDB_SRVID_TAKEOVER_RUN: + len = ctdb_srvid_message_len(mdata->msg); + break; + + case CTDB_SRVID_REBALANCE_NODE: + len = ctdb_uint32_len(mdata->pnn); + break; + + case CTDB_SRVID_DISABLE_TAKEOVER_RUNS: + len = ctdb_disable_message_len(mdata->disable); + break; + + case CTDB_SRVID_DISABLE_RECOVERIES: + len = ctdb_disable_message_len(mdata->disable); + break; + + case CTDB_SRVID_DISABLE_IP_CHECK: + len = ctdb_uint32_len(mdata->timeout); + break; + } + + return len; +} + +static void ctdb_message_data_push(union ctdb_message_data *mdata, + uint64_t srvid, uint8_t *buf) +{ + switch (srvid) { + case CTDB_SRVID_ELECTION: + ctdb_election_message_push(mdata->election, buf); + break; + + case CTDB_SRVID_RECONFIGURE: + break; + + case CTDB_SRVID_RELEASE_IP: + ctdb_string_push(mdata->ipaddr, buf); + break; + + case CTDB_SRVID_TAKE_IP: + ctdb_string_push(mdata->ipaddr, buf); + break; + + case CTDB_SRVID_SET_NODE_FLAGS: + ctdb_node_flag_change_push(mdata->flag_change, buf); + break; + + case CTDB_SRVID_RECD_UPDATE_IP: + ctdb_public_ip_push(mdata->pubip, buf); + break; + + case CTDB_SRVID_VACUUM_FETCH: + ctdb_rec_buffer_push(mdata->recbuf, buf); + break; + + case CTDB_SRVID_DETACH_DATABASE: + ctdb_uint32_push(mdata->db_id, buf); + break; + + case CTDB_SRVID_MEM_DUMP: + ctdb_srvid_message_push(mdata->msg, buf); + break; + + case CTDB_SRVID_PUSH_NODE_FLAGS: + ctdb_node_flag_change_push(mdata->flag_change, buf); + break; + + case CTDB_SRVID_RELOAD_NODES: + break; + + case CTDB_SRVID_TAKEOVER_RUN: + ctdb_srvid_message_push(mdata->msg, buf); + break; + + case CTDB_SRVID_REBALANCE_NODE: + ctdb_uint32_push(mdata->pnn, buf); + break; + + case CTDB_SRVID_DISABLE_TAKEOVER_RUNS: + ctdb_disable_message_push(mdata->disable, buf); + break; + + case CTDB_SRVID_DISABLE_RECOVERIES: + ctdb_disable_message_push(mdata->disable, buf); + break; + + case CTDB_SRVID_DISABLE_IP_CHECK: + ctdb_uint32_push(mdata->timeout, buf); + break; + } +} + +static int ctdb_message_data_pull(uint8_t *buf, size_t buflen, + uint64_t srvid, TALLOC_CTX *mem_ctx, + union ctdb_message_data *mdata) +{ + int ret = 0; + + switch (srvid) { + case CTDB_SRVID_ELECTION: + ret = ctdb_election_message_pull(buf, buflen, mem_ctx, + &mdata->election); + break; + + case CTDB_SRVID_RECONFIGURE: + break; + + case CTDB_SRVID_RELEASE_IP: + ret = ctdb_string_pull(buf, buflen, mem_ctx, &mdata->ipaddr); + break; + + case CTDB_SRVID_TAKE_IP: + ret = ctdb_string_pull(buf, buflen, mem_ctx, &mdata->ipaddr); + break; + + case CTDB_SRVID_SET_NODE_FLAGS: + ret = ctdb_node_flag_change_pull(buf, buflen, mem_ctx, + &mdata->flag_change); + break; + + case CTDB_SRVID_RECD_UPDATE_IP: + ret = ctdb_public_ip_pull(buf, buflen, mem_ctx, + &mdata->pubip); + break; + + case CTDB_SRVID_VACUUM_FETCH: + ret = ctdb_rec_buffer_pull(buf, buflen, mem_ctx, + &mdata->recbuf); + break; + + case CTDB_SRVID_DETACH_DATABASE: + ret = ctdb_uint32_pull(buf, buflen, mem_ctx, &mdata->db_id); + break; + + case CTDB_SRVID_MEM_DUMP: + ret = ctdb_srvid_message_pull(buf, buflen, mem_ctx, + &mdata->msg); + break; + + case CTDB_SRVID_PUSH_NODE_FLAGS: + ret = ctdb_node_flag_change_pull(buf, buflen, mem_ctx, + &mdata->flag_change); + break; + + case CTDB_SRVID_RELOAD_NODES: + break; + + case CTDB_SRVID_TAKEOVER_RUN: + ret = ctdb_srvid_message_pull(buf, buflen, mem_ctx, + &mdata->msg); + break; + + case CTDB_SRVID_REBALANCE_NODE: + ret = ctdb_uint32_pull(buf, buflen, mem_ctx, &mdata->pnn); + break; + + case CTDB_SRVID_DISABLE_TAKEOVER_RUNS: + ret = ctdb_disable_message_pull(buf, buflen, mem_ctx, + &mdata->disable); + break; + + case CTDB_SRVID_DISABLE_RECOVERIES: + ret = ctdb_disable_message_pull(buf, buflen, mem_ctx, + &mdata->disable); + break; + + case CTDB_SRVID_DISABLE_IP_CHECK: + ret = ctdb_uint32_pull(buf, buflen, mem_ctx, &mdata->timeout); + break; + } + + return ret; +} + +int ctdb_req_message_push(struct ctdb_req_header *h, + struct ctdb_req_message *message, + TALLOC_CTX *mem_ctx, + uint8_t **pkt, size_t *pkt_len) +{ + struct ctdb_req_message_wire *wire; + uint8_t *buf; + size_t length, buflen, datalen; + int ret; + + datalen = ctdb_message_data_len(&message->data, message->srvid); + length = offsetof(struct ctdb_req_message_wire, data) + datalen; + + ret = allocate_pkt(mem_ctx, length, &buf, &buflen); + if (ret != 0) { + return ret; + } + + wire = (struct ctdb_req_message_wire *)buf; + + h->length = buflen; + memcpy(&wire->hdr, h, sizeof(struct ctdb_req_header)); + + wire->srvid = message->srvid; + wire->datalen = datalen; + ctdb_message_data_push(&message->data, message->srvid, wire->data); + + *pkt = buf; + *pkt_len = buflen; + return 0; +} + +int ctdb_req_message_pull(uint8_t *pkt, size_t pkt_len, + struct ctdb_req_header *h, + TALLOC_CTX *mem_ctx, + struct ctdb_req_message *message) +{ + struct ctdb_req_message_wire *wire = + (struct ctdb_req_message_wire *)pkt; + size_t length; + int ret; + + length = offsetof(struct ctdb_req_message_wire, data); + + if (pkt_len < length) { + return EMSGSIZE; + } + if (pkt_len < length + wire->datalen) { + return EMSGSIZE; + } + + memcpy(h, &wire->hdr, sizeof(struct ctdb_req_header)); + + message->srvid = wire->srvid; + ret = ctdb_message_data_pull(wire->data, wire->datalen, wire->srvid, + mem_ctx, &message->data); + return ret; +} + +int ctdb_req_message_data_push(struct ctdb_req_header *h, + struct ctdb_req_message_data *message, + TALLOC_CTX *mem_ctx, + uint8_t **pkt, size_t *pkt_len) +{ + struct ctdb_req_message_wire *wire; + uint8_t *buf; + size_t length, buflen; + int ret; + + length = offsetof(struct ctdb_req_message_wire, data) + + message->data.dsize; + + ret = allocate_pkt(mem_ctx, length, &buf, &buflen); + if (ret != 0) { + return ret; + } + + wire = (struct ctdb_req_message_wire *)buf; + + h->length = buflen; + memcpy(&wire->hdr, h, sizeof(struct ctdb_req_header)); + + wire->srvid = message->srvid; + wire->datalen = message->data.dsize; + if (message->data.dsize > 0) { + memcpy(wire->data, message->data.dptr, message->data.dsize); + } + + *pkt = buf; + *pkt_len = buflen; + return 0; +} + +int ctdb_req_message_data_pull(uint8_t *pkt, size_t pkt_len, + struct ctdb_req_header *h, + TALLOC_CTX *mem_ctx, + struct ctdb_req_message_data *message) +{ + struct ctdb_req_message_wire *wire = + (struct ctdb_req_message_wire *)pkt; + size_t length; + + length = offsetof(struct ctdb_req_message_wire, data); + + if (pkt_len < length) { + return EMSGSIZE; + } + if (pkt_len < length + wire->datalen) { + return EMSGSIZE; + } + + memcpy(h, &wire->hdr, sizeof(struct ctdb_req_header)); + + message->srvid = wire->srvid; + message->data.dsize = wire->datalen; + if (wire->datalen > 0) { + message->data.dptr = talloc_memdup(mem_ctx, wire->data, + wire->datalen); + if (message->data.dptr == NULL) { + return ENOMEM; + } + } + + return 0; +} diff --git a/ctdb/protocol/protocol_packet.c b/ctdb/protocol/protocol_packet.c new file mode 100644 index 0000000..0e1a61c --- /dev/null +++ b/ctdb/protocol/protocol_packet.c @@ -0,0 +1,44 @@ +/* + CTDB protocol marshalling + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include "replace.h" +#include "system/network.h" + +#include +#include + +#include "protocol_private.h" + +#define CTDB_DS_ALIGNMENT 8 + +int allocate_pkt(TALLOC_CTX *mem_ctx, size_t length, + uint8_t **buf, size_t *buflen) +{ + size_t new_length; + + new_length = (length + CTDB_DS_ALIGNMENT-1) & ~(CTDB_DS_ALIGNMENT-1); + + *buflen = new_length; + *buf = talloc_zero_size(mem_ctx, new_length); + if (*buf == NULL) { + return ENOMEM; + } + + return 0; +} diff --git a/ctdb/protocol/protocol_private.h b/ctdb/protocol/protocol_private.h new file mode 100644 index 0000000..ffe3fb2 --- /dev/null +++ b/ctdb/protocol/protocol_private.h @@ -0,0 +1,274 @@ +/* + CTDB protocol marshalling + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#ifndef __PROTOCOL_PRIVATE_H__ +#define __PROTOCOL_PRIVATE_H__ + +#include "protocol.h" + +int allocate_pkt(TALLOC_CTX *mem_ctx, size_t length, + uint8_t **buf, size_t *buflen); + +size_t ctdb_uint32_len(uint32_t val); +void ctdb_uint32_push(uint32_t val, uint8_t *buf); +int ctdb_uint32_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + uint32_t *out); + +size_t ctdb_uint64_len(uint64_t val); +void ctdb_uint64_push(uint64_t val, uint8_t *buf); +int ctdb_uint64_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + uint64_t *out); + +size_t ctdb_double_len(double val); +void ctdb_double_push(double val, uint8_t *buf); +int ctdb_double_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + double *out); + +size_t ctdb_uint8_array_len(struct ctdb_uint8_array *array); +void ctdb_uint8_array_push(struct ctdb_uint8_array *array, uint8_t *buf); +int ctdb_uint8_array_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_uint8_array **out); + +size_t ctdb_uint64_array_len(struct ctdb_uint64_array *array); +void ctdb_uint64_array_push(struct ctdb_uint64_array *array, uint8_t *buf); +int ctdb_uint64_array_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_uint64_array **out); + +size_t ctdb_pid_len(pid_t pid); +void ctdb_pid_push(pid_t pid, uint8_t *buf); +int ctdb_pid_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + pid_t *out); + +size_t ctdb_string_len(const char *str); +void ctdb_string_push(const char *str, uint8_t *buf); +int ctdb_string_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + const char **out); + +size_t ctdb_stringn_len(const char *str); +void ctdb_stringn_push(const char *str, uint8_t *buf); +int ctdb_stringn_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + const char **out); + +size_t ctdb_statistics_len(struct ctdb_statistics *stats); +void ctdb_statistics_push(struct ctdb_statistics *stats, uint8_t *buf); +int ctdb_statistics_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_statistics **out); + +size_t ctdb_statistics_list_len(struct ctdb_statistics_list *stats_list); +void ctdb_statistics_list_push(struct ctdb_statistics_list *stats_list, + uint8_t *buf); +int ctdb_statistics_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_statistics_list **out); + +size_t ctdb_vnn_map_len(struct ctdb_vnn_map *vnnmap); +void ctdb_vnn_map_push(struct ctdb_vnn_map *vnnmap, uint8_t *buf); +int ctdb_vnn_map_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_vnn_map **out); + +size_t ctdb_dbid_map_len(struct ctdb_dbid_map *dbmap); +void ctdb_dbid_map_push(struct ctdb_dbid_map *dbmap, uint8_t *buf); +int ctdb_dbid_map_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_dbid_map **out); + +size_t ctdb_pulldb_len(struct ctdb_pulldb *pulldb); +void ctdb_pulldb_push(struct ctdb_pulldb *pulldb, uint8_t *buf); +int ctdb_pulldb_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_pulldb **out); + +size_t ctdb_traverse_start_len(struct ctdb_traverse_start *traverse); +void ctdb_traverse_start_push(struct ctdb_traverse_start *traverse, + uint8_t *buf); +int ctdb_traverse_start_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_traverse_start **out); + +size_t ctdb_traverse_all_len(struct ctdb_traverse_all *traverse); +void ctdb_traverse_all_push(struct ctdb_traverse_all *traverse, uint8_t *buf); +int ctdb_traverse_all_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_traverse_all **out); + +size_t ctdb_traverse_start_ext_len(struct ctdb_traverse_start_ext *traverse); +void ctdb_traverse_start_ext_push(struct ctdb_traverse_start_ext *traverse, + uint8_t *buf); +int ctdb_traverse_start_ext_pull(uint8_t *buf, size_t buflen, + TALLOC_CTX *mem_ctx, + struct ctdb_traverse_start_ext **out); + +size_t ctdb_traverse_all_ext_len(struct ctdb_traverse_all_ext *traverse); +void ctdb_traverse_all_ext_push(struct ctdb_traverse_all_ext *traverse, + uint8_t *buf); +int ctdb_traverse_all_ext_pull(uint8_t *buf, size_t buflen, + TALLOC_CTX *mem_ctx, + struct ctdb_traverse_all_ext **out); + +size_t ctdb_sock_addr_len(ctdb_sock_addr *addr); +void ctdb_sock_addr_push(ctdb_sock_addr *addr, uint8_t *buf); +int ctdb_sock_addr_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + ctdb_sock_addr **out); + +size_t ctdb_connection_len(struct ctdb_connection *conn); +void ctdb_connection_push(struct ctdb_connection *conn, uint8_t *buf); +int ctdb_connection_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_connection **out); + +size_t ctdb_tunable_len(struct ctdb_tunable *tunable); +void ctdb_tunable_push(struct ctdb_tunable *tunable, uint8_t *buf); +int ctdb_tunable_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_tunable **out); + +size_t ctdb_node_flag_change_len(struct ctdb_node_flag_change *flag_change); +void ctdb_node_flag_change_push(struct ctdb_node_flag_change *flag_change, + uint8_t *buf); +int ctdb_node_flag_change_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_node_flag_change **out); + +size_t ctdb_var_list_len(struct ctdb_var_list *var_list); +void ctdb_var_list_push(struct ctdb_var_list *var_list, uint8_t *buf); +int ctdb_var_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_var_list **out); + +size_t ctdb_tunable_list_len(struct ctdb_tunable_list *tun_list); +void ctdb_tunable_list_push(struct ctdb_tunable_list *tun_list, uint8_t *buf); +int ctdb_tunable_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_tunable_list **out); + +size_t ctdb_tickle_list_len(struct ctdb_tickle_list *tickles); +void ctdb_tickle_list_push(struct ctdb_tickle_list *tickles, uint8_t *buf); +int ctdb_tickle_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_tickle_list **out); + +size_t ctdb_client_id_len(struct ctdb_client_id *cid); +void ctdb_client_id_push(struct ctdb_client_id *cid, uint8_t *buf); +int ctdb_client_id_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_client_id **out); + +size_t ctdb_client_id_list_len(struct ctdb_client_id_list *cid_list); +void ctdb_client_id_list_push(struct ctdb_client_id_list *cid_list, + uint8_t *buf); +int ctdb_client_id_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_client_id_list **out); + +size_t ctdb_client_id_map_len(struct ctdb_client_id_map *cid_map); +void ctdb_client_id_map_push(struct ctdb_client_id_map *cid_map, uint8_t *buf); +int ctdb_client_id_map_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_client_id_map **out); + +size_t ctdb_addr_info_len(struct ctdb_addr_info *addr_info); +void ctdb_addr_info_push(struct ctdb_addr_info *addr_info, uint8_t *buf); +int ctdb_addr_info_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_addr_info **out); + +size_t ctdb_transdb_len(struct ctdb_transdb *transdb); +void ctdb_transdb_push(struct ctdb_transdb *transdb, uint8_t *buf); +int ctdb_transdb_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_transdb **out); + +size_t ctdb_uptime_len(struct ctdb_uptime *uptime); +void ctdb_uptime_push(struct ctdb_uptime *uptime, uint8_t *buf); +int ctdb_uptime_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_uptime **out); + +size_t ctdb_public_ip_len(struct ctdb_public_ip *public_ip); +void ctdb_public_ip_push(struct ctdb_public_ip *public_ip, uint8_t *buf); +int ctdb_public_ip_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_public_ip **out); + +size_t ctdb_public_ip_list_len(struct ctdb_public_ip_list *pubip_list); +void ctdb_public_ip_list_push(struct ctdb_public_ip_list *pubip_list, + uint8_t *buf); +int ctdb_public_ip_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_public_ip_list **out); + +size_t ctdb_node_and_flags_len(struct ctdb_node_and_flags *node); +void ctdb_node_and_flags_push(struct ctdb_node_and_flags *node, uint8_t *buf); +int ctdb_node_and_flags_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_node_and_flags **out); + +size_t ctdb_node_map_len(struct ctdb_node_map *nodemap); +void ctdb_node_map_push(struct ctdb_node_map *nodemap, uint8_t *buf); +int ctdb_node_map_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_node_map **out); + +size_t ctdb_script_len(struct ctdb_script *script); +void ctdb_script_push(struct ctdb_script *script, uint8_t *buf); +int ctdb_script_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_script **out); + +size_t ctdb_script_list_len(struct ctdb_script_list *script_list); +void ctdb_script_list_push(struct ctdb_script_list *script_list, uint8_t *buf); +int ctdb_script_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_script_list **out); + +size_t ctdb_ban_state_len(struct ctdb_ban_state *ban_state); +void ctdb_ban_state_push(struct ctdb_ban_state *ban_state, uint8_t *buf); +int ctdb_ban_state_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_ban_state **out); + +size_t ctdb_db_priority_len(struct ctdb_db_priority *db_prio); +void ctdb_db_priority_push(struct ctdb_db_priority *db_prio, uint8_t *buf); +int ctdb_db_priority_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_db_priority **out); + +size_t ctdb_notify_data_len(struct ctdb_notify_data *notify); +void ctdb_notify_data_push(struct ctdb_notify_data *notify, uint8_t *buf); +int ctdb_notify_data_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_notify_data **out); + +size_t ctdb_iface_len(struct ctdb_iface *iface); +void ctdb_iface_push(struct ctdb_iface *iface, uint8_t *buf); +int ctdb_iface_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_iface **out); + +size_t ctdb_iface_list_len(struct ctdb_iface_list *iface_list); +void ctdb_iface_list_push(struct ctdb_iface_list *iface_list, uint8_t *buf); +int ctdb_iface_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_iface_list **out); + +size_t ctdb_public_ip_info_len(struct ctdb_public_ip_info *ipinfo); +void ctdb_public_ip_info_push(struct ctdb_public_ip_info *ipinfo, uint8_t *buf); +int ctdb_public_ip_info_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_public_ip_info **out); + +size_t ctdb_key_data_len(struct ctdb_key_data *key); +void ctdb_key_data_push(struct ctdb_key_data *key, uint8_t *buf); +int ctdb_key_data_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_key_data **out); + +size_t ctdb_db_statistics_len(struct ctdb_db_statistics *dbstats); +void ctdb_db_statistics_push(struct ctdb_db_statistics *dbstats, void *buf); +int ctdb_db_statistics_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_db_statistics **out); + +size_t ctdb_election_message_len(struct ctdb_election_message *election); +void ctdb_election_message_push(struct ctdb_election_message *election, + uint8_t *buf); +int ctdb_election_message_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_election_message **out); + +size_t ctdb_srvid_message_len(struct ctdb_srvid_message *msg); +void ctdb_srvid_message_push(struct ctdb_srvid_message *msg, uint8_t *buf); +int ctdb_srvid_message_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_srvid_message **out); + +size_t ctdb_disable_message_len(struct ctdb_disable_message *disable); +void ctdb_disable_message_push(struct ctdb_disable_message *disable, + uint8_t *buf); +int ctdb_disable_message_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_disable_message **out); + +#endif /* __PROTOCOL_PRIVATE_H__ */ diff --git a/ctdb/protocol/protocol_types.c b/ctdb/protocol/protocol_types.c new file mode 100644 index 0000000..f868d76 --- /dev/null +++ b/ctdb/protocol/protocol_types.c @@ -0,0 +1,2519 @@ +/* + CTDB protocol marshalling + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include "replace.h" +#include "system/network.h" + +#include +#include + +#include "protocol.h" +#include "protocol_private.h" +#include "protocol_api.h" + +size_t ctdb_uint32_len(uint32_t val) +{ + return sizeof(uint32_t); +} + +void ctdb_uint32_push(uint32_t val, uint8_t *buf) +{ + memcpy(buf, &val, sizeof(uint32_t)); +} + +int ctdb_uint32_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + uint32_t *out) +{ + if (buflen < sizeof(uint32_t)) { + return EMSGSIZE; + } + + *out = *(uint32_t *)buf; + return 0; +} + +size_t ctdb_uint64_len(uint64_t val) +{ + return sizeof(uint64_t); +} + +void ctdb_uint64_push(uint64_t val, uint8_t *buf) +{ + memcpy(buf, &val, sizeof(uint64_t)); +} + +int ctdb_uint64_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + uint64_t *out) +{ + if (buflen < sizeof(uint64_t)) { + return EMSGSIZE; + } + + *out = *(uint64_t *)buf; + return 0; +} + +size_t ctdb_double_len(double val) +{ + return sizeof(double); +} + +void ctdb_double_push(double val, uint8_t *buf) +{ + memcpy(buf, &val, sizeof(double)); +} + +int ctdb_double_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + double *out) +{ + if (buflen < sizeof(double)) { + return EMSGSIZE; + } + + *out = *(double *)buf; + return 0; +} + +size_t ctdb_uint8_array_len(struct ctdb_uint8_array *array) +{ + return array->num * sizeof(uint8_t); +} + +void ctdb_uint8_array_push(struct ctdb_uint8_array *array, uint8_t *buf) +{ + memcpy(buf, array->val, array->num * sizeof(uint8_t)); +} + +int ctdb_uint8_array_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_uint8_array **out) +{ + struct ctdb_uint8_array *array; + + array = talloc(mem_ctx, struct ctdb_uint8_array); + if (array == NULL) { + return ENOMEM; + } + + array->num = buflen / sizeof(uint8_t); + + array->val = talloc_array(array, uint8_t, array->num); + if (array->val == NULL) { + talloc_free(array); + return ENOMEM; + } + memcpy(array->val, buf, buflen); + + *out = array; + return 0; +} + +size_t ctdb_uint64_array_len(struct ctdb_uint64_array *array) +{ + return array->num * sizeof(uint64_t); +} + +void ctdb_uint64_array_push(struct ctdb_uint64_array *array, uint8_t *buf) +{ + memcpy(buf, array->val, array->num * sizeof(uint64_t)); +} + +int ctdb_uint64_array_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_uint64_array **out) +{ + struct ctdb_uint64_array *array; + + array = talloc(mem_ctx, struct ctdb_uint64_array); + if (array == NULL) { + return ENOMEM; + } + + array->num = buflen / sizeof(uint64_t); + + array->val = talloc_array(array, uint64_t, array->num); + if (array->val == NULL) { + talloc_free(array); + return ENOMEM; + } + memcpy(array->val, buf, buflen); + + *out = array; + return 0; +} + +size_t ctdb_pid_len(pid_t pid) +{ + return sizeof(pid_t); +} + +void ctdb_pid_push(pid_t pid, uint8_t *buf) +{ + memcpy(buf, &pid, sizeof(pid_t)); +} + +int ctdb_pid_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + pid_t *out) +{ + if (buflen < sizeof(pid_t)) { + return EMSGSIZE; + } + + *out = *(pid_t *)buf; + return 0; +} + +size_t ctdb_string_len(const char *str) +{ + if (str == NULL) { + return 0; + } + return strlen(str) + 1; +} + +void ctdb_string_push(const char *str, uint8_t *buf) +{ + if (str == NULL) { + return; + } + memcpy(buf, str, strlen(str)+1); +} + +int ctdb_string_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + const char **out) +{ + char *str; + + if (buflen == 0) { + return 0; + } + + str = talloc_strndup(mem_ctx, (char *)buf, buflen); + if (str == NULL) { + return ENOMEM; + } + + *out = str; + return 0; +} + +struct stringn_wire { + uint32_t length; + uint8_t str[1]; +}; + +size_t ctdb_stringn_len(const char *str) +{ + return sizeof(uint32_t) + strlen(str) + 1; +} + +void ctdb_stringn_push(const char *str, uint8_t *buf) +{ + struct stringn_wire *wire = (struct stringn_wire *)buf; + + if (str == NULL) { + wire->length = 0; + } else { + wire->length = strlen(str) + 1; + memcpy(wire->str, str, wire->length); + } +} + +int ctdb_stringn_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + const char **out) +{ + char *str; + struct stringn_wire *wire = (struct stringn_wire *)buf; + + if (buflen < sizeof(uint32_t)) { + return EMSGSIZE; + } + + if (buflen < sizeof(uint32_t) + wire->length) { + return EMSGSIZE; + } + + str = talloc_strndup(mem_ctx, (char *)wire->str, wire->length); + if (str == NULL) { + return ENOMEM; + } + + *out = str; + return 0; +} + +size_t ctdb_statistics_len(struct ctdb_statistics *stats) +{ + return sizeof(struct ctdb_statistics); +} + +void ctdb_statistics_push(struct ctdb_statistics *stats, uint8_t *buf) +{ + memcpy(buf, stats, sizeof(struct ctdb_statistics)); +} + +int ctdb_statistics_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_statistics **out) +{ + struct ctdb_statistics *stats; + struct ctdb_statistics *wire = (struct ctdb_statistics *)buf; + + if (buflen < sizeof(struct ctdb_statistics)) { + return EMSGSIZE; + } + + stats = talloc(mem_ctx, struct ctdb_statistics); + if (stats == NULL) { + return ENOMEM; + } + memcpy(stats, wire, sizeof(struct ctdb_statistics)); + + *out = stats; + return 0; +} + +struct ctdb_statistics_list_wire { + uint32_t num; + struct ctdb_statistics stats[1]; +}; + +size_t ctdb_statistics_list_len(struct ctdb_statistics_list *stats_list) +{ + return offsetof(struct ctdb_statistics_list_wire, stats) + + stats_list->num * sizeof(struct ctdb_statistics); +} + +void ctdb_statistics_list_push(struct ctdb_statistics_list *stats_list, + uint8_t *buf) +{ + struct ctdb_statistics_list_wire *wire = + (struct ctdb_statistics_list_wire *)buf; + + wire->num = stats_list->num; + memcpy(wire->stats, stats_list->stats, + stats_list->num * sizeof(struct ctdb_statistics)); +} + +int ctdb_statistics_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_statistics_list **out) +{ + struct ctdb_statistics_list *stats_list; + struct ctdb_statistics_list_wire *wire = + (struct ctdb_statistics_list_wire *)buf; + + if (buflen < offsetof(struct ctdb_statistics_list_wire, stats)) { + return EMSGSIZE; + } + if (buflen < offsetof(struct ctdb_statistics_list_wire, stats) + + wire->num * sizeof(struct ctdb_statistics)) { + return EMSGSIZE; + } + + stats_list = talloc(mem_ctx, struct ctdb_statistics_list); + if (stats_list == NULL) { + return ENOMEM; + } + + stats_list->num = wire->num; + + stats_list->stats = talloc_array(stats_list, struct ctdb_statistics, + wire->num); + if (stats_list->stats == NULL) { + talloc_free(stats_list); + return ENOMEM; + } + + memcpy(stats_list->stats, wire->stats, + wire->num * sizeof(struct ctdb_statistics)); + + *out = stats_list; + return 0; +} + +struct ctdb_vnn_map_wire { + uint32_t generation; + uint32_t size; + uint32_t map[1]; +}; + +size_t ctdb_vnn_map_len(struct ctdb_vnn_map *vnnmap) +{ + return offsetof(struct ctdb_vnn_map, map) + + vnnmap->size * sizeof(uint32_t); +} + +void ctdb_vnn_map_push(struct ctdb_vnn_map *vnnmap, uint8_t *buf) +{ + struct ctdb_vnn_map_wire *wire = (struct ctdb_vnn_map_wire *)buf; + + memcpy(wire, vnnmap, offsetof(struct ctdb_vnn_map, map)); + memcpy(wire->map, vnnmap->map, vnnmap->size * sizeof(uint32_t)); +} + +int ctdb_vnn_map_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_vnn_map **out) +{ + struct ctdb_vnn_map *vnnmap; + struct ctdb_vnn_map_wire *wire = (struct ctdb_vnn_map_wire *)buf; + + if (buflen < offsetof(struct ctdb_vnn_map_wire, map)) { + return EMSGSIZE; + } + if (buflen < offsetof(struct ctdb_vnn_map_wire, map) + + wire->size * sizeof(uint32_t)) { + return EMSGSIZE; + } + + vnnmap = talloc(mem_ctx, struct ctdb_vnn_map); + if (vnnmap == NULL) { + return ENOMEM; + } + + memcpy(vnnmap, wire, offsetof(struct ctdb_vnn_map, map)); + + vnnmap->map = talloc_memdup(vnnmap, wire->map, + wire->size * sizeof(uint32_t)); + if (vnnmap->map == NULL) { + talloc_free(vnnmap); + return ENOMEM; + } + + *out = vnnmap; + return 0; +} + +struct ctdb_dbid_map_wire { + uint32_t num; + struct ctdb_dbid dbs[1]; +}; + +size_t ctdb_dbid_map_len(struct ctdb_dbid_map *dbmap) +{ + return sizeof(uint32_t) + dbmap->num * sizeof(struct ctdb_dbid); +} + +void ctdb_dbid_map_push(struct ctdb_dbid_map *dbmap, uint8_t *buf) +{ + struct ctdb_dbid_map_wire *wire = (struct ctdb_dbid_map_wire *)buf; + + wire->num = dbmap->num; + memcpy(wire->dbs, dbmap->dbs, dbmap->num * sizeof(struct ctdb_dbid)); +} + +int ctdb_dbid_map_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_dbid_map **out) +{ + struct ctdb_dbid_map *dbmap; + struct ctdb_dbid_map_wire *wire = (struct ctdb_dbid_map_wire *)buf; + + if (buflen < sizeof(uint32_t)) { + return EMSGSIZE; + } + if (buflen < sizeof(uint32_t) + wire->num * sizeof(struct ctdb_dbid)) { + return EMSGSIZE; + } + + dbmap = talloc(mem_ctx, struct ctdb_dbid_map); + if (dbmap == NULL) { + return ENOMEM; + } + + dbmap->num = wire->num; + + dbmap->dbs = talloc_memdup(dbmap, wire->dbs, + wire->num * sizeof(struct ctdb_dbid)); + if (dbmap->dbs == NULL) { + talloc_free(dbmap); + return ENOMEM; + } + + *out = dbmap; + return 0; +} + +size_t ctdb_pulldb_len(struct ctdb_pulldb *pulldb) +{ + return sizeof(struct ctdb_pulldb); +} + +void ctdb_pulldb_push(struct ctdb_pulldb *pulldb, uint8_t *buf) +{ + memcpy(buf, pulldb, sizeof(struct ctdb_pulldb)); +} + +int ctdb_pulldb_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_pulldb **out) +{ + struct ctdb_pulldb *pulldb; + + if (buflen < sizeof(struct ctdb_pulldb)) { + return EMSGSIZE; + } + + pulldb = talloc_memdup(mem_ctx, buf, sizeof(struct ctdb_pulldb)); + if (pulldb == NULL) { + return ENOMEM; + } + + *out = pulldb; + return 0; +} + +size_t ctdb_ltdb_header_len(struct ctdb_ltdb_header *header) +{ + return sizeof(struct ctdb_ltdb_header); +} + +void ctdb_ltdb_header_push(struct ctdb_ltdb_header *header, uint8_t *buf) +{ + memcpy(buf, header, sizeof(struct ctdb_ltdb_header)); +} + +int ctdb_ltdb_header_pull(uint8_t *buf, size_t buflen, + struct ctdb_ltdb_header *header) +{ + if (buflen < sizeof(struct ctdb_ltdb_header)) { + return EMSGSIZE; + } + + memcpy(header, buf, sizeof(struct ctdb_ltdb_header)); + return 0; +} + +struct ctdb_rec_data_wire { + uint32_t length; + uint32_t reqid; + uint32_t keylen; + uint32_t datalen; + uint8_t data[1]; +}; + +size_t ctdb_rec_data_len(struct ctdb_rec_data *rec) +{ + return offsetof(struct ctdb_rec_data_wire, data) + + rec->key.dsize + rec->data.dsize + + (rec->header == NULL ? 0 : sizeof(struct ctdb_ltdb_header)); +} + +void ctdb_rec_data_push(struct ctdb_rec_data *rec, uint8_t *buf) +{ + struct ctdb_rec_data_wire *wire = (struct ctdb_rec_data_wire *)buf; + size_t offset; + + wire->length = ctdb_rec_data_len(rec); + wire->reqid = rec->reqid; + wire->keylen = rec->key.dsize; + wire->datalen = rec->data.dsize; + + memcpy(wire->data, rec->key.dptr, rec->key.dsize); + offset = rec->key.dsize; + if (rec->header != NULL) { + memcpy(&wire->data[offset], rec->header, + sizeof(struct ctdb_ltdb_header)); + offset += sizeof(struct ctdb_ltdb_header); + } + if (rec->data.dsize > 0) { + memcpy(&wire->data[offset], rec->data.dptr, rec->data.dsize); + } +} + +static int ctdb_rec_data_pull_data(uint8_t *buf, size_t buflen, + uint32_t *reqid, + struct ctdb_ltdb_header **header, + TDB_DATA *key, TDB_DATA *data, + size_t *reclen) +{ + struct ctdb_rec_data_wire *wire = (struct ctdb_rec_data_wire *)buf; + size_t offset, n; + + if (buflen < offsetof(struct ctdb_rec_data_wire, data)) { + return EMSGSIZE; + } + n = offsetof(struct ctdb_rec_data_wire, data) + + wire->keylen + wire->datalen; + if (buflen < n) { + return EMSGSIZE; + } + + *reqid = wire->reqid; + + key->dsize = wire->keylen; + key->dptr = wire->data; + offset = wire->keylen; + + if (wire->length - n == sizeof(struct ctdb_ltdb_header)) { + *header = (struct ctdb_ltdb_header *)&wire->data[offset]; + offset += sizeof(struct ctdb_ltdb_header); + } else { + *header = NULL; + } + + data->dsize = wire->datalen; + data->dptr = &wire->data[offset]; + + *reclen = n; + + return 0; +} + +static int ctdb_rec_data_pull_elems(uint8_t *buf, size_t buflen, + TALLOC_CTX *mem_ctx, + struct ctdb_rec_data *out) +{ + uint32_t reqid; + struct ctdb_ltdb_header *header; + TDB_DATA key, data; + size_t reclen; + int ret; + + ret = ctdb_rec_data_pull_data(buf, buflen, &reqid, &header, + &key, &data, &reclen); + if (ret != 0) { + return ret; + } + + out->reqid = reqid; + + if (header != NULL) { + out->header = talloc_memdup(mem_ctx, header, + sizeof(struct ctdb_ltdb_header)); + if (out->header == NULL) { + return ENOMEM; + } + } else { + out->header = NULL; + } + + out->key.dsize = key.dsize; + if (key.dsize > 0) { + out->key.dptr = talloc_memdup(mem_ctx, key.dptr, key.dsize); + if (out->key.dptr == NULL) { + return ENOMEM; + } + } + + out->data.dsize = data.dsize; + if (data.dsize > 0) { + out->data.dptr = talloc_memdup(mem_ctx, data.dptr, data.dsize); + if (out->data.dptr == NULL) { + return ENOMEM; + } + } + + return 0; +} + +int ctdb_rec_data_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_rec_data **out) +{ + struct ctdb_rec_data *rec; + int ret; + + rec = talloc(mem_ctx, struct ctdb_rec_data); + if (rec == NULL) { + return ENOMEM; + } + + ret = ctdb_rec_data_pull_elems(buf, buflen, rec, rec); + if (ret != 0) { + TALLOC_FREE(rec); + } + + *out = rec; + return ret; +} + +struct ctdb_rec_buffer_wire { + uint32_t db_id; + uint32_t count; + uint8_t data[1]; +}; + +size_t ctdb_rec_buffer_len(struct ctdb_rec_buffer *recbuf) +{ + return offsetof(struct ctdb_rec_buffer_wire, data) + recbuf->buflen; +} + +void ctdb_rec_buffer_push(struct ctdb_rec_buffer *recbuf, uint8_t *buf) +{ + struct ctdb_rec_buffer_wire *wire = (struct ctdb_rec_buffer_wire *)buf; + + wire->db_id = recbuf->db_id; + wire->count = recbuf->count; + if (recbuf->buflen > 0) { + memcpy(wire->data, recbuf->buf, recbuf->buflen); + } +} + +int ctdb_rec_buffer_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_rec_buffer **out) +{ + struct ctdb_rec_buffer *recbuf; + struct ctdb_rec_buffer_wire *wire = (struct ctdb_rec_buffer_wire *)buf; + size_t offset; + + if (buflen < offsetof(struct ctdb_rec_buffer_wire, data)) { + return EMSGSIZE; + } + + recbuf = talloc(mem_ctx, struct ctdb_rec_buffer); + if (recbuf == NULL) { + return ENOMEM; + } + + recbuf->db_id = wire->db_id; + recbuf->count = wire->count; + + offset = offsetof(struct ctdb_rec_buffer_wire, data); + recbuf->buflen = buflen - offset; + recbuf->buf = talloc_memdup(recbuf, wire->data, recbuf->buflen); + if (recbuf->buf == NULL) { + talloc_free(recbuf); + return ENOMEM; + } + + *out = recbuf; + return 0; +} + +struct ctdb_rec_buffer *ctdb_rec_buffer_init(TALLOC_CTX *mem_ctx, + uint32_t db_id) +{ + struct ctdb_rec_buffer *recbuf; + + recbuf = talloc_zero(mem_ctx, struct ctdb_rec_buffer); + if (recbuf == NULL) { + return recbuf; + } + + recbuf->db_id = db_id; + + return recbuf; +} + +int ctdb_rec_buffer_add(TALLOC_CTX *mem_ctx, struct ctdb_rec_buffer *recbuf, + uint32_t reqid, struct ctdb_ltdb_header *header, + TDB_DATA key, TDB_DATA data) +{ + struct ctdb_rec_data recdata; + size_t len; + uint8_t *ptr; + + recdata.reqid = reqid; + recdata.header = header; + recdata.key = key; + recdata.data = data; + + len = ctdb_rec_data_len(&recdata); + + ptr = talloc_realloc(mem_ctx, recbuf->buf, uint8_t, + recbuf->buflen + len); + if (ptr == NULL) { + return ENOMEM; + } + + ctdb_rec_data_push(&recdata, &ptr[recbuf->buflen]); + + recbuf->count++; + recbuf->buf = ptr; + recbuf->buflen += len; + return 0; +} + +int ctdb_rec_buffer_traverse(struct ctdb_rec_buffer *recbuf, + ctdb_rec_parser_func_t func, + void *private_data) +{ + struct ctdb_ltdb_header *header; + TDB_DATA key, data; + uint32_t reqid; + size_t offset, reclen; + int ret = 0, i; + + offset = 0; + for (i=0; icount; i++) { + ret = ctdb_rec_data_pull_data(&recbuf->buf[offset], + recbuf->buflen - offset, + &reqid, &header, + &key, &data, &reclen); + if (ret != 0) { + return ret; + } + + ret = func(reqid, header, key, data, private_data); + if (ret != 0) { + break; + } + + offset += reclen; + } + + return ret; +} + +size_t ctdb_traverse_start_len(struct ctdb_traverse_start *traverse) +{ + return sizeof(struct ctdb_traverse_start); +} + +void ctdb_traverse_start_push(struct ctdb_traverse_start *traverse, + uint8_t *buf) +{ + memcpy(buf, traverse, sizeof(struct ctdb_traverse_start)); +} + +int ctdb_traverse_start_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_traverse_start **out) +{ + struct ctdb_traverse_start *traverse; + + if (buflen < sizeof(struct ctdb_traverse_start)) { + return EMSGSIZE; + } + + traverse = talloc_memdup(mem_ctx, buf, + sizeof(struct ctdb_traverse_start)); + if (traverse == NULL) { + return ENOMEM; + } + + *out = traverse; + return 0; +} + +size_t ctdb_traverse_all_len(struct ctdb_traverse_all *traverse) +{ + return sizeof(struct ctdb_traverse_all); +} + +void ctdb_traverse_all_push(struct ctdb_traverse_all *traverse, uint8_t *buf) +{ + memcpy(buf, traverse, sizeof(struct ctdb_traverse_all)); +} + +int ctdb_traverse_all_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_traverse_all **out) +{ + struct ctdb_traverse_all *traverse; + + if (buflen < sizeof(struct ctdb_traverse_all)) { + return EMSGSIZE; + } + + traverse = talloc_memdup(mem_ctx, buf, + sizeof(struct ctdb_traverse_all)); + if (traverse == NULL) { + return ENOMEM; + } + + *out = traverse; + return 0; +} + +size_t ctdb_traverse_start_ext_len(struct ctdb_traverse_start_ext *traverse) +{ + return sizeof(struct ctdb_traverse_start_ext); +} + +void ctdb_traverse_start_ext_push(struct ctdb_traverse_start_ext *traverse, + uint8_t *buf) +{ + memcpy(buf, traverse, sizeof(struct ctdb_traverse_start_ext)); +} + +int ctdb_traverse_start_ext_pull(uint8_t *buf, size_t buflen, + TALLOC_CTX *mem_ctx, + struct ctdb_traverse_start_ext **out) +{ + struct ctdb_traverse_start_ext *traverse; + + if (buflen < sizeof(struct ctdb_traverse_start_ext)) { + return EMSGSIZE; + } + + traverse = talloc_memdup(mem_ctx, buf, + sizeof(struct ctdb_traverse_start_ext)); + if (traverse == NULL) { + return ENOMEM; + } + + *out = traverse; + return 0; +} + +size_t ctdb_traverse_all_ext_len(struct ctdb_traverse_all_ext *traverse) +{ + return sizeof(struct ctdb_traverse_all_ext); +} + +void ctdb_traverse_all_ext_push(struct ctdb_traverse_all_ext *traverse, + uint8_t *buf) +{ + memcpy(buf, traverse, sizeof(struct ctdb_traverse_all_ext)); +} + +int ctdb_traverse_all_ext_pull(uint8_t *buf, size_t buflen, + TALLOC_CTX *mem_ctx, + struct ctdb_traverse_all_ext **out) +{ + struct ctdb_traverse_all_ext *traverse; + + if (buflen < sizeof(struct ctdb_traverse_all_ext)) { + return EMSGSIZE; + } + + traverse = talloc_memdup(mem_ctx, buf, + sizeof(struct ctdb_traverse_all_ext)); + if (traverse == NULL) { + return ENOMEM; + } + + *out = traverse; + return 0; +} + +size_t ctdb_sock_addr_len(ctdb_sock_addr *addr) +{ + return sizeof(ctdb_sock_addr); +} + +void ctdb_sock_addr_push(ctdb_sock_addr *addr, uint8_t *buf) +{ + memcpy(buf, addr, sizeof(ctdb_sock_addr)); +} + +static int ctdb_sock_addr_pull_elems(uint8_t *buf, size_t buflen, + TALLOC_CTX *mem_ctx, ctdb_sock_addr *out) +{ + if (buflen < sizeof(ctdb_sock_addr)) { + return EMSGSIZE; + } + + memcpy(out, buf, sizeof(ctdb_sock_addr)); + + return 0; +} + +int ctdb_sock_addr_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + ctdb_sock_addr **out) +{ + ctdb_sock_addr *addr; + int ret; + + addr = talloc(mem_ctx, ctdb_sock_addr); + if (addr == NULL) { + return false; + } + + ret = ctdb_sock_addr_pull_elems(buf, buflen, addr, addr); + if (ret != 0) { + TALLOC_FREE(addr); + } + + *out = addr; + return ret; +} + +size_t ctdb_connection_len(struct ctdb_connection *conn) +{ + return sizeof(struct ctdb_connection); +} + +void ctdb_connection_push(struct ctdb_connection *conn, uint8_t *buf) +{ + memcpy(buf, conn, sizeof(struct ctdb_connection)); +} + +static int ctdb_connection_pull_elems(uint8_t *buf, size_t buflen, + TALLOC_CTX *mem_ctx, + struct ctdb_connection *out) +{ + if (buflen < sizeof(struct ctdb_connection)) { + return EMSGSIZE; + } + + memcpy(out, buf, sizeof(struct ctdb_connection)); + + return 0; +} + +int ctdb_connection_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_connection **out) +{ + struct ctdb_connection *conn; + int ret; + + conn = talloc(mem_ctx, struct ctdb_connection); + if (conn == NULL) { + return ENOMEM; + } + + ret = ctdb_connection_pull_elems(buf, buflen, conn, conn); + if (ret != 0) { + TALLOC_FREE(conn); + } + + *out = conn; + return ret; +} + +struct ctdb_tunable_wire { + uint32_t value; + uint32_t length; + uint8_t name[1]; +}; + +size_t ctdb_tunable_len(struct ctdb_tunable *tunable) +{ + return offsetof(struct ctdb_tunable_wire, name) + + strlen(tunable->name) + 1; +} + +void ctdb_tunable_push(struct ctdb_tunable *tunable, uint8_t *buf) +{ + struct ctdb_tunable_wire *wire = (struct ctdb_tunable_wire *)buf; + + wire->value = tunable->value; + wire->length = strlen(tunable->name) + 1; + memcpy(wire->name, tunable->name, wire->length); +} + +int ctdb_tunable_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_tunable **out) +{ + struct ctdb_tunable *tunable; + struct ctdb_tunable_wire *wire = (struct ctdb_tunable_wire *)buf; + + if (buflen < offsetof(struct ctdb_tunable_wire, name)) { + return EMSGSIZE; + } + if (buflen < offsetof(struct ctdb_tunable_wire, name) + wire->length) { + return EMSGSIZE; + } + + tunable = talloc(mem_ctx, struct ctdb_tunable); + if (tunable == NULL) { + return ENOMEM; + } + + tunable->value = wire->value; + tunable->name = talloc_memdup(tunable, wire->name, wire->length); + if (tunable->name == NULL) { + talloc_free(tunable); + return ENOMEM; + } + + *out = tunable; + return 0; +} + +size_t ctdb_node_flag_change_len(struct ctdb_node_flag_change *flag_change) +{ + return sizeof(struct ctdb_node_flag_change); +} + +void ctdb_node_flag_change_push(struct ctdb_node_flag_change *flag_change, + uint8_t *buf) +{ + memcpy(buf, flag_change, sizeof(struct ctdb_node_flag_change)); +} + +int ctdb_node_flag_change_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_node_flag_change **out) +{ + struct ctdb_node_flag_change *flag_change; + + if (buflen < sizeof(struct ctdb_node_flag_change)) { + return EMSGSIZE; + } + + flag_change = talloc_memdup(mem_ctx, buf, + sizeof(struct ctdb_node_flag_change)); + if (flag_change == NULL) { + return ENOMEM; + } + + *out = flag_change; + return 0; +} + +struct ctdb_var_list_wire { + uint32_t length; + char list_str[1]; +}; + +size_t ctdb_var_list_len(struct ctdb_var_list *var_list) +{ + int i; + size_t len = sizeof(uint32_t); + + for (i=0; icount; i++) { + len += strlen(var_list->var[i]) + 1; + } + return len; +} + +void ctdb_var_list_push(struct ctdb_var_list *var_list, uint8_t *buf) +{ + struct ctdb_var_list_wire *wire = (struct ctdb_var_list_wire *)buf; + int i, n; + size_t offset = 0; + + if (var_list->count > 0) { + n = sprintf(wire->list_str, "%s", var_list->var[0]); + offset += n; + } + for (i=1; icount; i++) { + n = sprintf(&wire->list_str[offset], ":%s", var_list->var[i]); + offset += n; + } + wire->length = offset + 1; +} + +int ctdb_var_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_var_list **out) +{ + struct ctdb_var_list *var_list = NULL; + struct ctdb_var_list_wire *wire = (struct ctdb_var_list_wire *)buf; + char *str, *s, *tok, *ptr; + const char **list; + + if (buflen < sizeof(uint32_t)) { + return EMSGSIZE; + } + if (buflen < sizeof(uint32_t) + wire->length) { + return EMSGSIZE; + } + + str = talloc_strndup(mem_ctx, (char *)wire->list_str, wire->length); + if (str == NULL) { + return ENOMEM; + } + + var_list = talloc_zero(mem_ctx, struct ctdb_var_list); + if (var_list == NULL) { + goto fail; + } + + s = str; + while ((tok = strtok_r(s, ":", &ptr)) != NULL) { + s = NULL; + list = talloc_realloc(var_list, var_list->var, const char *, + var_list->count+1); + if (list == NULL) { + goto fail; + } + + var_list->var = list; + var_list->var[var_list->count] = talloc_strdup(var_list, tok); + if (var_list->var[var_list->count] == NULL) { + goto fail; + } + var_list->count++; + } + + talloc_free(str); + *out = var_list; + return 0; + +fail: + talloc_free(str); + talloc_free(var_list); + return ENOMEM; +} + +size_t ctdb_tunable_list_len(struct ctdb_tunable_list *tun_list) +{ + return sizeof(struct ctdb_tunable_list); +} + +void ctdb_tunable_list_push(struct ctdb_tunable_list *tun_list, uint8_t *buf) +{ + memcpy(buf, tun_list, sizeof(struct ctdb_tunable_list)); +} + +int ctdb_tunable_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_tunable_list **out) +{ + struct ctdb_tunable_list *tun_list; + + if (buflen < sizeof(struct ctdb_tunable_list)) { + return EMSGSIZE; + } + + tun_list = talloc_memdup(mem_ctx, buf, sizeof(struct ctdb_tunable_list)); + if (tun_list == NULL) { + return ENOMEM; + } + + *out = tun_list; + return 0; +} + +struct ctdb_tickle_list_wire { + ctdb_sock_addr addr; + uint32_t num; + struct ctdb_connection conn[1]; +}; + +size_t ctdb_tickle_list_len(struct ctdb_tickle_list *tickles) +{ + return offsetof(struct ctdb_tickle_list, conn) + + tickles->num * sizeof(struct ctdb_connection); +} + +void ctdb_tickle_list_push(struct ctdb_tickle_list *tickles, uint8_t *buf) +{ + struct ctdb_tickle_list_wire *wire = + (struct ctdb_tickle_list_wire *)buf; + size_t offset; + int i; + + memcpy(&wire->addr, &tickles->addr, sizeof(ctdb_sock_addr)); + wire->num = tickles->num; + + offset = offsetof(struct ctdb_tickle_list_wire, conn); + for (i=0; inum; i++) { + ctdb_connection_push(&tickles->conn[i], &buf[offset]); + offset += ctdb_connection_len(&tickles->conn[i]); + } +} + +int ctdb_tickle_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_tickle_list **out) +{ + struct ctdb_tickle_list *tickles; + struct ctdb_tickle_list_wire *wire = + (struct ctdb_tickle_list_wire *)buf; + size_t offset; + int i, ret; + + if (buflen < offsetof(struct ctdb_tickle_list_wire, conn)) { + return EMSGSIZE; + } + if (buflen < offsetof(struct ctdb_tickle_list_wire, conn) + + wire->num * sizeof(struct ctdb_connection)) { + return EMSGSIZE; + } + + tickles = talloc(mem_ctx, struct ctdb_tickle_list); + if (tickles == NULL) { + return ENOMEM; + } + + offset = offsetof(struct ctdb_tickle_list, conn); + memcpy(tickles, wire, offset); + + tickles->conn = talloc_array(tickles, struct ctdb_connection, + wire->num); + if (tickles->conn == NULL) { + talloc_free(tickles); + return ENOMEM; + } + + for (i=0; inum; i++) { + ret = ctdb_connection_pull_elems(&buf[offset], buflen-offset, + tickles->conn, + &tickles->conn[i]); + if (ret != 0) { + talloc_free(tickles); + return ret; + } + offset += ctdb_connection_len(&tickles->conn[i]); + } + + *out = tickles; + return 0; +} + +size_t ctdb_client_id_len(struct ctdb_client_id *cid) +{ + return sizeof(struct ctdb_client_id); +} + +void ctdb_client_id_push(struct ctdb_client_id *cid, uint8_t *buf) +{ + memcpy(buf, cid, sizeof(struct ctdb_client_id)); +} + +static int ctdb_client_id_pull_elems(uint8_t *buf, size_t buflen, + TALLOC_CTX *mem_ctx, + struct ctdb_client_id *out) +{ + if (buflen < sizeof(struct ctdb_client_id)) { + return EMSGSIZE; + } + + memcpy(out, buf, sizeof(struct ctdb_client_id)); + + return 0; +} + +int ctdb_client_id_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_client_id **out) +{ + struct ctdb_client_id *cid; + int ret; + + cid = talloc(mem_ctx, struct ctdb_client_id); + if (cid == NULL) { + return ENOMEM; + } + + ret = ctdb_client_id_pull_elems(buf, buflen, cid, cid); + if (ret != 0) { + TALLOC_FREE(cid); + } + + *out = cid; + return ret; +} + +struct ctdb_client_id_list_wire { + uint32_t num; + struct ctdb_client_id cid[1]; +}; + +size_t ctdb_client_id_list_len(struct ctdb_client_id_list *cid_list) +{ + return sizeof(uint32_t) + + cid_list->num * sizeof(struct ctdb_client_id); +} + +void ctdb_client_id_list_push(struct ctdb_client_id_list *cid_list, + uint8_t *buf) +{ + struct ctdb_client_id_list_wire *wire = + (struct ctdb_client_id_list_wire *)buf; + size_t offset; + int i; + + wire->num = cid_list->num; + + offset = offsetof(struct ctdb_client_id_list_wire, cid); + for (i=0; inum; i++) { + ctdb_client_id_push(&cid_list->cid[i], &buf[offset]); + offset += ctdb_client_id_len(&cid_list->cid[i]); + } +} + +static int ctdb_client_id_list_pull_elems(uint8_t *buf, size_t buflen, + TALLOC_CTX *mem_ctx, + struct ctdb_client_id_list *out) +{ + struct ctdb_client_id_list_wire *wire = + (struct ctdb_client_id_list_wire *)buf; + size_t offset; + int i; + + if (buflen < sizeof(uint32_t)) { + return EMSGSIZE; + } + if (buflen < sizeof(uint32_t) + + wire->num * sizeof(struct ctdb_client_id)) { + return EMSGSIZE; + } + + out->num = wire->num; + out->cid = talloc_array(mem_ctx, struct ctdb_client_id, + wire->num); + if (out->cid == NULL) { + return ENOMEM; + } + + offset = offsetof(struct ctdb_client_id_list_wire, cid); + for (i=0; inum; i++) { + bool ret; + ret = ctdb_client_id_pull_elems(&buf[offset], buflen-offset, + out->cid, &out->cid[i]); + if (ret != 0) { + return ret; + } + offset += ctdb_client_id_len(&out->cid[i]); + } + + return 0; +} + +int ctdb_client_id_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_client_id_list **out) +{ + struct ctdb_client_id_list *cid_list; + int ret; + + cid_list = talloc(mem_ctx, struct ctdb_client_id_list); + if (cid_list == NULL) { + return ENOMEM; + } + + ret = ctdb_client_id_list_pull_elems(buf, buflen, cid_list, cid_list); + if (ret != 0) { + TALLOC_FREE(cid_list); + } + + *out = cid_list; + return ret; +} + +struct ctdb_client_id_map_wire { + int count; + struct ctdb_client_id_list list[1]; +}; + +size_t ctdb_client_id_map_len(struct ctdb_client_id_map *cid_map) +{ + int i; + size_t len; + + len = sizeof(int); + for (i=0; icount; i++) { + len += ctdb_client_id_list_len(&cid_map->list[i]); + } + return len; +} + +void ctdb_client_id_map_push(struct ctdb_client_id_map *cid_map, uint8_t *buf) +{ + struct ctdb_client_id_map_wire *wire = + (struct ctdb_client_id_map_wire *)buf; + size_t offset; + int i; + + wire->count = cid_map->count; + + offset = sizeof(int); + for (i=0; icount; i++) { + ctdb_client_id_list_push(&cid_map->list[i], &buf[offset]); + offset += ctdb_client_id_list_len(&cid_map->list[i]); + } +} + +int ctdb_client_id_map_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_client_id_map **out) +{ + struct ctdb_client_id_map *cid_map; + struct ctdb_client_id_map_wire *wire = + (struct ctdb_client_id_map_wire *)buf; + size_t offset; + int i; + bool ret; + + if (buflen < sizeof(int)) { + return EMSGSIZE; + } + if (buflen < sizeof(int) + + wire->count * sizeof(struct ctdb_client_id_list)) { + return EMSGSIZE; + } + + cid_map = talloc(mem_ctx, struct ctdb_client_id_map); + if (cid_map == NULL) { + return ENOMEM; + } + + cid_map->count = wire->count; + cid_map->list = talloc_array(cid_map, struct ctdb_client_id_list, + wire->count); + if (cid_map->list == NULL) { + return ENOMEM; + } + + offset = sizeof(int); + for (i=0; icount; i++) { + ret = ctdb_client_id_list_pull_elems(&buf[offset], + buflen-offset, + cid_map->list, + &cid_map->list[i]); + if (ret != 0) { + talloc_free(cid_map); + return ret; + } + offset += ctdb_client_id_list_len(&cid_map->list[i]); + } + + *out = cid_map; + return 0; +} + +struct ctdb_addr_info_wire { + ctdb_sock_addr addr; + uint32_t mask; + uint32_t len; + char iface[1]; +}; + +size_t ctdb_addr_info_len(struct ctdb_addr_info *arp) +{ + return offsetof(struct ctdb_addr_info_wire, iface) + + strlen(arp->iface)+1; +} + +void ctdb_addr_info_push(struct ctdb_addr_info *addr_info, uint8_t *buf) +{ + struct ctdb_addr_info_wire *wire = (struct ctdb_addr_info_wire *)buf; + + wire->addr = addr_info->addr; + wire->mask = addr_info->mask; + wire->len = strlen(addr_info->iface)+1; + memcpy(wire->iface, addr_info->iface, wire->len); +} + +int ctdb_addr_info_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_addr_info **out) +{ + struct ctdb_addr_info *addr_info; + struct ctdb_addr_info_wire *wire = (struct ctdb_addr_info_wire *)buf; + + if (buflen < offsetof(struct ctdb_addr_info_wire, iface)) { + return EMSGSIZE; + } + if (buflen < offsetof(struct ctdb_addr_info_wire, iface) + wire->len) { + return EMSGSIZE; + } + + addr_info = talloc(mem_ctx, struct ctdb_addr_info); + if (addr_info == NULL) { + return ENOMEM; + } + + addr_info->addr = wire->addr; + addr_info->mask = wire->mask; + + addr_info->iface = talloc_strndup(addr_info, wire->iface, wire->len); + if (addr_info->iface == NULL) { + talloc_free(addr_info); + return ENOMEM; + } + + *out = addr_info; + return 0; +} + +size_t ctdb_transdb_len(struct ctdb_transdb *transdb) +{ + return sizeof(struct ctdb_transdb); +} + +void ctdb_transdb_push(struct ctdb_transdb *transdb, uint8_t *buf) +{ + memcpy(buf, transdb, sizeof(struct ctdb_transdb)); +} + +int ctdb_transdb_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_transdb **out) +{ + struct ctdb_transdb *transdb; + + if (buflen < sizeof(struct ctdb_transdb)) { + return EMSGSIZE; + } + + transdb = talloc_memdup(mem_ctx, buf, sizeof(struct ctdb_transdb)); + if (transdb == NULL) { + return ENOMEM; + } + + *out = transdb; + return 0; +} + +size_t ctdb_uptime_len(struct ctdb_uptime *uptime) +{ + return sizeof(struct ctdb_uptime); +} + +void ctdb_uptime_push(struct ctdb_uptime *uptime, uint8_t *buf) +{ + memcpy(buf, uptime, sizeof(struct ctdb_uptime)); +} + +int ctdb_uptime_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_uptime **out) +{ + struct ctdb_uptime *uptime; + + if (buflen < sizeof(struct ctdb_uptime)) { + return EMSGSIZE; + } + + uptime = talloc_memdup(mem_ctx, buf, sizeof(struct ctdb_uptime)); + if (uptime == NULL) { + return ENOMEM; + } + + *out = uptime; + return 0; +} + +size_t ctdb_public_ip_len(struct ctdb_public_ip *pubip) +{ + return sizeof(struct ctdb_public_ip); +} + +void ctdb_public_ip_push(struct ctdb_public_ip *pubip, uint8_t *buf) +{ + memcpy(buf, pubip, sizeof(struct ctdb_public_ip)); +} + +static int ctdb_public_ip_pull_elems(uint8_t *buf, size_t buflen, + TALLOC_CTX *mem_ctx, + struct ctdb_public_ip *out) +{ + if (buflen < sizeof(struct ctdb_public_ip)) { + return EMSGSIZE; + } + + memcpy(out, buf, sizeof(struct ctdb_public_ip)); + + return 0; +} + +int ctdb_public_ip_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_public_ip **out) +{ + struct ctdb_public_ip *pubip; + int ret; + + pubip = talloc(mem_ctx, struct ctdb_public_ip); + if (pubip == NULL) { + return ENOMEM; + } + + ret = ctdb_public_ip_pull_elems(buf, buflen, pubip, pubip); + if (ret != 0) { + TALLOC_FREE(pubip); + } + + *out = pubip; + return ret; +} + +struct ctdb_public_ip_list_wire { + uint32_t num; + struct ctdb_public_ip ip[1]; +}; + +size_t ctdb_public_ip_list_len(struct ctdb_public_ip_list *pubip_list) +{ + int i; + size_t len; + + len = sizeof(uint32_t); + for (i=0; inum; i++) { + len += ctdb_public_ip_len(&pubip_list->ip[i]); + } + return len; +} + +void ctdb_public_ip_list_push(struct ctdb_public_ip_list *pubip_list, + uint8_t *buf) +{ + struct ctdb_public_ip_list_wire *wire = + (struct ctdb_public_ip_list_wire *)buf; + size_t offset; + int i; + + wire->num = pubip_list->num; + + offset = offsetof(struct ctdb_public_ip_list_wire, ip); + for (i=0; inum; i++) { + ctdb_public_ip_push(&pubip_list->ip[i], &buf[offset]); + offset += ctdb_public_ip_len(&pubip_list->ip[i]); + } +} + +int ctdb_public_ip_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_public_ip_list **out) +{ + struct ctdb_public_ip_list *pubip_list; + struct ctdb_public_ip_list_wire *wire = + (struct ctdb_public_ip_list_wire *)buf; + size_t offset; + int i; + bool ret; + + if (buflen < sizeof(uint32_t)) { + return EMSGSIZE; + } + if (buflen < sizeof(uint32_t) + + wire->num * sizeof(struct ctdb_public_ip)) { + return EMSGSIZE; + } + + pubip_list = talloc(mem_ctx, struct ctdb_public_ip_list); + if (pubip_list == NULL) { + return ENOMEM; + } + + pubip_list->num = wire->num; + pubip_list->ip = talloc_array(pubip_list, struct ctdb_public_ip, + wire->num); + if (pubip_list->ip == NULL) { + talloc_free(pubip_list); + return ENOMEM; + } + + offset = offsetof(struct ctdb_public_ip_list_wire, ip); + for (i=0; inum; i++) { + ret = ctdb_public_ip_pull_elems(&buf[offset], buflen-offset, + pubip_list->ip, + &pubip_list->ip[i]); + if (ret != 0) { + talloc_free(pubip_list); + return ret; + } + offset += ctdb_public_ip_len(&pubip_list->ip[i]); + } + + *out = pubip_list; + return 0; +} + +size_t ctdb_node_and_flags_len(struct ctdb_node_and_flags *node) +{ + return sizeof(struct ctdb_node_and_flags); +} + +void ctdb_node_and_flags_push(struct ctdb_node_and_flags *node, uint8_t *buf) +{ + memcpy(buf, node, sizeof(struct ctdb_node_and_flags)); +} + +static int ctdb_node_and_flags_pull_elems(TALLOC_CTX *mem_ctx, + uint8_t *buf, size_t buflen, + struct ctdb_node_and_flags *out) +{ + if (buflen < sizeof(struct ctdb_node_and_flags)) { + return EMSGSIZE; + } + + memcpy(out, buf, sizeof(struct ctdb_node_and_flags)); + + return 0; +} + +int ctdb_node_and_flags_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_node_and_flags **out) +{ + struct ctdb_node_and_flags *node; + int ret; + + node = talloc(mem_ctx, struct ctdb_node_and_flags); + if (node == NULL) { + return ENOMEM; + } + + ret = ctdb_node_and_flags_pull_elems(node, buf, buflen, node); + if (ret != 0) { + TALLOC_FREE(node); + } + + *out = node; + return ret; +} + +struct ctdb_node_map_wire { + uint32_t num; + struct ctdb_node_and_flags node[1]; +}; + +size_t ctdb_node_map_len(struct ctdb_node_map *nodemap) +{ + return sizeof(uint32_t) + + nodemap->num * sizeof(struct ctdb_node_and_flags); +} + +void ctdb_node_map_push(struct ctdb_node_map *nodemap, uint8_t *buf) +{ + struct ctdb_node_map_wire *wire = (struct ctdb_node_map_wire *)buf; + size_t offset; + int i; + + wire->num = nodemap->num; + + offset = offsetof(struct ctdb_node_map_wire, node); + for (i=0; inum; i++) { + ctdb_node_and_flags_push(&nodemap->node[i], &buf[offset]); + offset += ctdb_node_and_flags_len(&nodemap->node[i]); + } +} + +int ctdb_node_map_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_node_map **out) +{ + struct ctdb_node_map *nodemap; + struct ctdb_node_map_wire *wire = (struct ctdb_node_map_wire *)buf; + size_t offset; + int i; + bool ret; + + nodemap = talloc(mem_ctx, struct ctdb_node_map); + if (nodemap == NULL) { + return ENOMEM; + } + + nodemap->num = wire->num; + nodemap->node = talloc_array(nodemap, struct ctdb_node_and_flags, + wire->num); + if (nodemap->node == NULL) { + talloc_free(nodemap); + return ENOMEM; + } + + offset = offsetof(struct ctdb_node_map_wire, node); + for (i=0; inum; i++) { + ret = ctdb_node_and_flags_pull_elems(nodemap->node, + &buf[offset], + buflen-offset, + &nodemap->node[i]); + if (ret != 0) { + talloc_free(nodemap); + return ret; + } + offset += ctdb_node_and_flags_len(&nodemap->node[i]); + } + + *out = nodemap; + return 0; +} + +size_t ctdb_script_len(struct ctdb_script *script) +{ + return sizeof(struct ctdb_script); +} + +void ctdb_script_push(struct ctdb_script *script, uint8_t *buf) +{ + memcpy(buf, script, sizeof(struct ctdb_script)); +} + +static int ctdb_script_pull_elems(uint8_t *buf, size_t buflen, + TALLOC_CTX *mem_ctx, + struct ctdb_script *out) +{ + if (buflen < sizeof(struct ctdb_script)) { + return EMSGSIZE; + } + + memcpy(out, buf, sizeof(struct ctdb_script)); + + return 0; +} + +int ctdb_script_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_script **out) +{ + struct ctdb_script *script; + int ret; + + script = talloc(mem_ctx, struct ctdb_script); + if (script == NULL) { + return ENOMEM; + } + + ret = ctdb_script_pull_elems(buf, buflen, script, script); + if (ret != 0) { + TALLOC_FREE(script); + } + + *out = script; + return ret; +} + +struct ctdb_script_list_wire { + uint32_t num_scripts; + struct ctdb_script script[1]; +}; + +size_t ctdb_script_list_len(struct ctdb_script_list *script_list) +{ + int i; + size_t len; + + if (script_list == NULL) { + return 0; + } + + len = offsetof(struct ctdb_script_list_wire, script); + for (i=0; inum_scripts; i++) { + len += ctdb_script_len(&script_list->script[i]); + } + return len; +} + +void ctdb_script_list_push(struct ctdb_script_list *script_list, uint8_t *buf) +{ + struct ctdb_script_list_wire *wire = + (struct ctdb_script_list_wire *)buf; + size_t offset; + int i; + + if (script_list == NULL) { + return; + } + + wire->num_scripts = script_list->num_scripts; + + offset = offsetof(struct ctdb_script_list_wire, script); + for (i=0; inum_scripts; i++) { + ctdb_script_push(&script_list->script[i], &buf[offset]); + offset += ctdb_script_len(&script_list->script[i]); + } +} + +int ctdb_script_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_script_list **out) +{ + struct ctdb_script_list *script_list; + struct ctdb_script_list_wire *wire = + (struct ctdb_script_list_wire *)buf; + size_t offset; + int i; + bool ret; + + /* If event scripts have never been run, the result will be NULL */ + if (buflen == 0) { + *out = NULL; + return 0; + } + + offset = offsetof(struct ctdb_script_list_wire, script); + + if (buflen < offset) { + return EMSGSIZE; + } + if (buflen < offset + wire->num_scripts * sizeof(struct ctdb_script)) { + return EMSGSIZE; + } + + script_list = talloc(mem_ctx, struct ctdb_script_list); + if (script_list == NULL) { + return ENOMEM; + + } + + script_list->num_scripts = wire->num_scripts; + script_list->script = talloc_array(script_list, struct ctdb_script, + wire->num_scripts); + if (script_list->script == NULL) { + talloc_free(script_list); + return ENOMEM; + } + + for (i=0; inum_scripts; i++) { + ret = ctdb_script_pull_elems(&buf[offset], buflen-offset, + script_list->script, + &script_list->script[i]); + if (ret != 0) { + talloc_free(script_list); + return ret; + } + offset += ctdb_script_len(&script_list->script[i]); + } + + *out = script_list; + return 0; +} + +size_t ctdb_ban_state_len(struct ctdb_ban_state *ban_state) +{ + return sizeof(struct ctdb_ban_state); +} + +void ctdb_ban_state_push(struct ctdb_ban_state *ban_state, uint8_t *buf) +{ + memcpy(buf, ban_state, sizeof(struct ctdb_ban_state)); +} + +int ctdb_ban_state_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_ban_state **out) +{ + struct ctdb_ban_state *ban_state; + + if (buflen < sizeof(struct ctdb_ban_state)) { + return EMSGSIZE; + } + + ban_state = talloc_memdup(mem_ctx, buf, sizeof(struct ctdb_ban_state)); + if (ban_state == NULL) { + return ENOMEM; + } + + *out = ban_state; + return 0; +} + +size_t ctdb_db_priority_len(struct ctdb_db_priority *db_prio) +{ + return sizeof(struct ctdb_db_priority); +} + +void ctdb_db_priority_push(struct ctdb_db_priority *db_prio, uint8_t *buf) +{ + memcpy(buf, db_prio, sizeof(struct ctdb_db_priority)); +} + +int ctdb_db_priority_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_db_priority **out) +{ + struct ctdb_db_priority *db_prio; + + if (buflen < sizeof(struct ctdb_db_priority)) { + return EMSGSIZE; + } + + db_prio = talloc_memdup(mem_ctx, buf, sizeof(struct ctdb_db_priority)); + if (db_prio == NULL) { + return ENOMEM; + } + + *out = db_prio; + return 0; +} + +struct ctdb_notify_data_wire { + uint64_t srvid; + uint32_t len; + uint8_t data[1]; +}; + +size_t ctdb_notify_data_len(struct ctdb_notify_data *notify) +{ + return offsetof(struct ctdb_notify_data_wire, data) + + notify->data.dsize; +} + +void ctdb_notify_data_push(struct ctdb_notify_data *notify, uint8_t *buf) +{ + struct ctdb_notify_data_wire *wire = + (struct ctdb_notify_data_wire *)buf; + + wire->srvid = notify->srvid; + wire->len = notify->data.dsize; + memcpy(wire->data, notify->data.dptr, notify->data.dsize); +} + +int ctdb_notify_data_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_notify_data **out) +{ + struct ctdb_notify_data *notify; + struct ctdb_notify_data_wire *wire = + (struct ctdb_notify_data_wire *)buf; + + if (buflen < offsetof(struct ctdb_notify_data_wire, data)) { + return EMSGSIZE; + } + if (buflen < offsetof(struct ctdb_notify_data_wire, data) + wire->len) { + return EMSGSIZE; + } + + notify = talloc(mem_ctx, struct ctdb_notify_data); + if (notify == NULL) { + return ENOMEM; + } + + notify->srvid = wire->srvid; + notify->data.dsize = wire->len; + notify->data.dptr = talloc_memdup(notify, wire->data, wire->len); + if (notify->data.dptr == NULL) { + talloc_free(notify); + return ENOMEM; + } + + *out = notify; + return 0; +} + +size_t ctdb_iface_len(struct ctdb_iface *iface) +{ + return sizeof(struct ctdb_iface); +} + +void ctdb_iface_push(struct ctdb_iface *iface, uint8_t *buf) +{ + memcpy(buf, iface, sizeof(struct ctdb_iface)); +} + +static int ctdb_iface_pull_elems(uint8_t *buf, size_t buflen, + TALLOC_CTX *mem_ctx, + struct ctdb_iface *out) +{ + if (buflen < sizeof(struct ctdb_iface)) { + return EMSGSIZE; + } + + memcpy(out, buf, sizeof(struct ctdb_iface)); + + return 0; +} + +int ctdb_iface_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_iface **out) +{ + struct ctdb_iface *iface; + int ret; + + iface = talloc(mem_ctx, struct ctdb_iface); + if (iface == NULL) { + return ENOMEM; + } + + ret = ctdb_iface_pull_elems(buf, buflen, iface, iface); + if (ret != 0) { + TALLOC_FREE(iface); + } + + *out = iface; + return ret; +} + +struct ctdb_iface_list_wire { + uint32_t num; + struct ctdb_iface iface[1]; +}; + +size_t ctdb_iface_list_len(struct ctdb_iface_list *iface_list) +{ + return sizeof(uint32_t) + + iface_list->num * sizeof(struct ctdb_iface); +} + +void ctdb_iface_list_push(struct ctdb_iface_list *iface_list, uint8_t *buf) +{ + struct ctdb_iface_list_wire *wire = + (struct ctdb_iface_list_wire *)buf; + + wire->num = iface_list->num; + memcpy(wire->iface, iface_list->iface, + iface_list->num * sizeof(struct ctdb_iface)); +} + +int ctdb_iface_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_iface_list **out) +{ + struct ctdb_iface_list *iface_list; + struct ctdb_iface_list_wire *wire = + (struct ctdb_iface_list_wire *)buf; + + if (buflen < sizeof(uint32_t)) { + return EMSGSIZE; + } + if (buflen < sizeof(uint32_t) + wire->num * sizeof(struct ctdb_iface)) { + return EMSGSIZE; + } + + iface_list = talloc(mem_ctx, struct ctdb_iface_list); + if (iface_list == NULL) { + return ENOMEM; + } + + iface_list->num = wire->num; + iface_list->iface = talloc_array(iface_list, struct ctdb_iface, + wire->num); + if (iface_list->iface == NULL) { + talloc_free(iface_list); + return ENOMEM; + } + + memcpy(iface_list->iface, wire->iface, + wire->num * sizeof(struct ctdb_iface)); + + *out = iface_list; + return 0; +} + +struct ctdb_public_ip_info_wire { + struct ctdb_public_ip ip; + uint32_t active_idx; + uint32_t num; + struct ctdb_iface ifaces[1]; +}; + +size_t ctdb_public_ip_info_len(struct ctdb_public_ip_info *ipinfo) +{ + return offsetof(struct ctdb_public_ip_info_wire, num) + + ctdb_iface_list_len(ipinfo->ifaces); +} + +void ctdb_public_ip_info_push(struct ctdb_public_ip_info *ipinfo, uint8_t *buf) +{ + struct ctdb_public_ip_info_wire *wire = + (struct ctdb_public_ip_info_wire *)buf; + size_t offset; + + offset = offsetof(struct ctdb_public_ip_info_wire, num); + memcpy(wire, ipinfo, offset); + wire->num = ipinfo->ifaces->num; + memcpy(wire->ifaces, ipinfo->ifaces->iface, + ipinfo->ifaces->num * sizeof(struct ctdb_iface)); +} + +int ctdb_public_ip_info_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_public_ip_info **out) +{ + struct ctdb_public_ip_info *ipinfo; + struct ctdb_public_ip_info_wire *wire = + (struct ctdb_public_ip_info_wire *)buf; + + if (buflen < offsetof(struct ctdb_public_ip_info_wire, ifaces)) { + return EMSGSIZE; + } + + ipinfo = talloc(mem_ctx, struct ctdb_public_ip_info); + if (ipinfo == NULL) { + return ENOMEM; + } + + memcpy(ipinfo, wire, offsetof(struct ctdb_public_ip_info_wire, num)); + + ipinfo->ifaces = talloc(ipinfo, struct ctdb_iface_list); + if (ipinfo->ifaces == NULL) { + talloc_free(ipinfo); + return ENOMEM; + } + + ipinfo->ifaces->num = wire->num; + ipinfo->ifaces->iface = talloc_array(ipinfo->ifaces, struct ctdb_iface, + wire->num); + if (ipinfo->ifaces->iface == NULL) { + talloc_free(ipinfo); + return ENOMEM; + } + + memcpy(ipinfo->ifaces->iface, wire->ifaces, + wire->num * sizeof(struct ctdb_iface)); + + *out = ipinfo; + return 0; +} + +struct ctdb_key_data_wire { + uint32_t db_id; + struct ctdb_ltdb_header header; + uint32_t keylen; + uint8_t key[1]; +}; + +size_t ctdb_key_data_len(struct ctdb_key_data *key) +{ + return offsetof(struct ctdb_key_data_wire, key) + key->key.dsize; +} + +void ctdb_key_data_push(struct ctdb_key_data *key, uint8_t *buf) +{ + struct ctdb_key_data_wire *wire = (struct ctdb_key_data_wire *)buf; + + memcpy(wire, key, offsetof(struct ctdb_key_data, key)); + wire->keylen = key->key.dsize; + memcpy(wire->key, key->key.dptr, key->key.dsize); +} + +int ctdb_key_data_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_key_data **out) +{ + struct ctdb_key_data *key_data; + struct ctdb_key_data_wire *wire = (struct ctdb_key_data_wire *)buf; + + if (buflen < offsetof(struct ctdb_key_data_wire, key)) { + return EMSGSIZE; + } + if (buflen < offsetof(struct ctdb_key_data_wire, key) + wire->keylen) { + return EMSGSIZE; + } + + key_data = talloc(mem_ctx, struct ctdb_key_data); + if (key_data == NULL) { + return ENOMEM; + } + + memcpy(key_data, wire, offsetof(struct ctdb_key_data, key)); + + key_data->key.dsize = wire->keylen; + key_data->key.dptr = talloc_memdup(key_data, wire->key, wire->keylen); + if (key_data->key.dptr == NULL) { + talloc_free(key_data); + return ENOMEM; + } + + *out = key_data; + return 0; +} + +struct ctdb_db_statistics_wire { + struct ctdb_db_statistics dbstats; + char hot_keys_wire[1]; +}; + +size_t ctdb_db_statistics_len(struct ctdb_db_statistics *dbstats) +{ + size_t len; + int i; + + len = sizeof(struct ctdb_db_statistics); + for (i=0; ihot_keys[i].key.dsize; + } + return len; +} + +void ctdb_db_statistics_push(struct ctdb_db_statistics *dbstats, void *buf) +{ + struct ctdb_db_statistics_wire *wire = + (struct ctdb_db_statistics_wire *)buf; + size_t offset; + int i; + + dbstats->num_hot_keys = MAX_HOT_KEYS; + memcpy(wire, dbstats, sizeof(struct ctdb_db_statistics)); + + offset = 0; + for (i=0; ihot_keys_wire[offset], + dbstats->hot_keys[i].key.dptr, + dbstats->hot_keys[i].key.dsize); + offset += dbstats->hot_keys[i].key.dsize; + } +} + +int ctdb_db_statistics_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_db_statistics **out) +{ + struct ctdb_db_statistics *dbstats; + struct ctdb_db_statistics_wire *wire = + (struct ctdb_db_statistics_wire *)buf; + size_t offset; + int i; + + if (buflen < sizeof(struct ctdb_db_statistics)) { + return EMSGSIZE; + } + offset = 0; + for (i=0; idbstats.num_hot_keys; i++) { + offset += wire->dbstats.hot_keys[i].key.dsize; + } + if (buflen < sizeof(struct ctdb_db_statistics) + offset) { + return EMSGSIZE; + } + + dbstats = talloc(mem_ctx, struct ctdb_db_statistics); + if (dbstats == NULL) { + return ENOMEM; + } + + memcpy(dbstats, wire, sizeof(struct ctdb_db_statistics)); + + offset = 0; + for (i=0; idbstats.num_hot_keys; i++) { + uint8_t *ptr; + size_t key_size; + + key_size = dbstats->hot_keys[i].key.dsize; + ptr = talloc_memdup(mem_ctx, &wire->hot_keys_wire[offset], + key_size); + if (ptr == NULL) { + talloc_free(dbstats); + return ENOMEM; + } + dbstats->hot_keys[i].key.dptr = ptr; + offset += key_size; + } + + *out = dbstats; + return 0; +} + +size_t ctdb_election_message_len(struct ctdb_election_message *election) +{ + return sizeof(struct ctdb_election_message); +} + +void ctdb_election_message_push(struct ctdb_election_message *election, + uint8_t *buf) +{ + memcpy(buf, election, sizeof(struct ctdb_election_message)); +} + +int ctdb_election_message_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_election_message **out) +{ + struct ctdb_election_message *election; + + if (buflen < sizeof(struct ctdb_election_message)) { + return EMSGSIZE; + } + + election = talloc_memdup(mem_ctx, buf, + sizeof(struct ctdb_election_message)); + if (election == NULL) { + return ENOMEM; + } + + *out = election; + return 0; +} + +size_t ctdb_srvid_message_len(struct ctdb_srvid_message *msg) +{ + return sizeof(struct ctdb_srvid_message); +} + +void ctdb_srvid_message_push(struct ctdb_srvid_message *msg, uint8_t *buf) +{ + memcpy(buf, msg, sizeof(struct ctdb_srvid_message)); +} + +int ctdb_srvid_message_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_srvid_message **out) +{ + struct ctdb_srvid_message *msg; + + if (buflen < sizeof(struct ctdb_srvid_message)) { + return EMSGSIZE; + } + + msg = talloc_memdup(mem_ctx, buf, sizeof(struct ctdb_srvid_message)); + if (msg == NULL) { + return ENOMEM; + } + + *out = msg; + return 0; +} + +size_t ctdb_disable_message_len(struct ctdb_disable_message *disable) +{ + return sizeof(struct ctdb_disable_message); +} + +void ctdb_disable_message_push(struct ctdb_disable_message *disable, + uint8_t *buf) +{ + memcpy(buf, disable, sizeof(struct ctdb_disable_message)); +} + +int ctdb_disable_message_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_disable_message **out) +{ + struct ctdb_disable_message *disable; + + if (buflen < sizeof(struct ctdb_disable_message)) { + return EMSGSIZE; + } + + disable = talloc_memdup(mem_ctx, buf, + sizeof(struct ctdb_disable_message)); + if (disable == NULL) { + return ENOMEM; + } + + *out = disable; + return 0; +} + +size_t ctdb_server_id_len(struct ctdb_server_id *sid) +{ + return sizeof(struct ctdb_server_id); +} + +void ctdb_server_id_push(struct ctdb_server_id *sid, uint8_t *buf) +{ + memcpy(buf, sid, sizeof(struct ctdb_server_id)); +} + +int ctdb_server_id_pull(uint8_t *buf, size_t buflen, + struct ctdb_server_id *sid) +{ + if (buflen < sizeof(struct ctdb_server_id)) { + return EMSGSIZE; + } + + memcpy(sid, buf, sizeof(struct ctdb_server_id)); + return 0; +} + +size_t ctdb_g_lock_len(struct ctdb_g_lock *lock) +{ + return sizeof(struct ctdb_g_lock); +} + +void ctdb_g_lock_push(struct ctdb_g_lock *lock, uint8_t *buf) +{ + memcpy(buf, lock, sizeof(struct ctdb_g_lock)); +} + +int ctdb_g_lock_pull(uint8_t *buf, size_t buflen, struct ctdb_g_lock *lock) +{ + if (buflen < sizeof(struct ctdb_g_lock)) { + return EMSGSIZE; + } + + memcpy(lock, buf, sizeof(struct ctdb_g_lock)); + return 0; +} + +size_t ctdb_g_lock_list_len(struct ctdb_g_lock_list *lock_list) +{ + return lock_list->num * sizeof(struct ctdb_g_lock); +} + +void ctdb_g_lock_list_push(struct ctdb_g_lock_list *lock_list, uint8_t *buf) +{ + size_t offset = 0; + int i; + + for (i=0; inum; i++) { + ctdb_g_lock_push(&lock_list->lock[i], &buf[offset]); + offset += sizeof(struct ctdb_g_lock); + } +} + +int ctdb_g_lock_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, + struct ctdb_g_lock_list **out) +{ + struct ctdb_g_lock_list *lock_list; + unsigned count; + size_t offset; + int ret, i; + + lock_list = talloc_zero(mem_ctx, struct ctdb_g_lock_list); + if (lock_list == NULL) { + return ENOMEM; + } + + count = buflen / sizeof(struct ctdb_g_lock); + lock_list->lock = talloc_array(lock_list, struct ctdb_g_lock, count); + if (lock_list->lock == NULL) { + talloc_free(lock_list); + return ENOMEM; + } + + offset = 0; + for (i=0; ilock[i]); + if (ret != 0) { + talloc_free(lock_list); + return ret; + } + offset += sizeof(struct ctdb_g_lock); + } + + lock_list->num = count; + + *out = lock_list; + return 0; +} diff --git a/ctdb/protocol/protocol_util.c b/ctdb/protocol/protocol_util.c new file mode 100644 index 0000000..1082b0b --- /dev/null +++ b/ctdb/protocol/protocol_util.c @@ -0,0 +1,114 @@ +/* + CTDB protocol marshalling + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include "replace.h" +#include "system/network.h" + +#include +#include + +#include "protocol.h" +#include "protocol_private.h" +#include "protocol_api.h" + +static struct { + enum ctdb_runstate runstate; + const char * label; +} runstate_map[] = { + { CTDB_RUNSTATE_UNKNOWN, "UNKNOWN" }, + { CTDB_RUNSTATE_INIT, "INIT" }, + { CTDB_RUNSTATE_SETUP, "SETUP" }, + { CTDB_RUNSTATE_FIRST_RECOVERY, "FIRST_RECOVERY" }, + { CTDB_RUNSTATE_STARTUP, "STARTUP" }, + { CTDB_RUNSTATE_RUNNING, "RUNNING" }, + { CTDB_RUNSTATE_SHUTDOWN, "SHUTDOWN" }, + { -1, NULL }, +}; + +const char *ctdb_runstate_to_string(enum ctdb_runstate runstate) +{ + int i; + + for (i=0; runstate_map[i].label != NULL; i++) { + if (runstate_map[i].runstate == runstate) { + return runstate_map[i].label; + } + } + + return runstate_map[0].label; +} + +enum ctdb_runstate ctdb_runstate_from_string(const char *runstate_str) +{ + int i; + + for (i=0; runstate_map[i].label != NULL; i++) { + if (strcasecmp(runstate_map[i].label, + runstate_str) == 0) { + return runstate_map[i].runstate; + } + } + + return CTDB_RUNSTATE_UNKNOWN; +} + +static struct { + enum ctdb_event event; + const char *label; +} event_map[] = { + { CTDB_EVENT_INIT, "init" }, + { CTDB_EVENT_SETUP, "setup" }, + { CTDB_EVENT_STARTUP, "startup" }, + { CTDB_EVENT_START_RECOVERY, "startrecovery" }, + { CTDB_EVENT_RECOVERED, "recovered" }, + { CTDB_EVENT_TAKE_IP, "takeip" }, + { CTDB_EVENT_RELEASE_IP, "releaseip" }, + { CTDB_EVENT_MONITOR, "monitor" }, + { CTDB_EVENT_SHUTDOWN, "shutdown" }, + { CTDB_EVENT_UPDATE_IP, "updateip" }, + { CTDB_EVENT_IPREALLOCATED, "ipreallocated" }, + { CTDB_EVENT_MAX, "all" }, + { -1, NULL }, +}; + +const char *ctdb_event_to_string(enum ctdb_event event) +{ + int i; + + for (i=0; event_map[i].label != NULL; i++) { + if (event_map[i].event == event) { + return event_map[i].label; + } + } + + return "unknown"; +} + +enum ctdb_event ctdb_event_from_string(const char *event_str) +{ + int i; + + for (i=0; event_map[i].label != NULL; i++) { + if (strcmp(event_map[i].label, event_str) == 0) { + return event_map[i].event; + } + } + + return CTDB_EVENT_MAX; +} diff --git a/ctdb/tests/cunit/protocol_test_001.sh b/ctdb/tests/cunit/protocol_test_001.sh new file mode 100755 index 0000000..41afda5 --- /dev/null +++ b/ctdb/tests/cunit/protocol_test_001.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +. "${TEST_SCRIPTS_DIR}/unit.sh" + +ok_null + +for i in $(seq 1 1000) ; do + unit_test protocol_types_test $i +done diff --git a/ctdb/tests/cunit/protocol_test_002.sh b/ctdb/tests/cunit/protocol_test_002.sh new file mode 100755 index 0000000..47410be --- /dev/null +++ b/ctdb/tests/cunit/protocol_test_002.sh @@ -0,0 +1,36 @@ +#!/bin/sh + +. "${TEST_SCRIPTS_DIR}/unit.sh" + +last_control=140 + +control_output=$( + for i in $(seq 0 $last_control) ; do + echo -n "$i.. " + done + echo +) + +output=$( + echo "ctdb_req_header" + echo "ctdb_req_call" + echo "ctdb_reply_call" + echo "ctdb_reply_error" + echo "ctdb_req_dmaster" + echo "ctdb_reply_dmaster" + echo "ctdb_req_control_data" + echo "$control_output" + echo "ctdb_reply_control_data" + echo "$control_output" + echo "ctdb_req_control" + echo "$control_output" + echo "ctdb_reply_control" + echo "$control_output" + echo "ctdb_req_message" +) + +ok "$output" + +for i in $(seq 1 100) ; do + unit_test protocol_client_test $i +done diff --git a/ctdb/tests/src/protocol_client_test.c b/ctdb/tests/src/protocol_client_test.c new file mode 100644 index 0000000..a17fac0 --- /dev/null +++ b/ctdb/tests/src/protocol_client_test.c @@ -0,0 +1,2311 @@ +/* + protocol tests + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include "replace.h" +#include "system/network.h" + +#include + +#define PROTOCOL_TEST + +#include "protocol_types_test.c" + + +#define GENERATION 0xabcdef12 +#define OPERATION CTDB_REQ_KEEPALIVE +#define REQID 0x34567890 +#define SRCNODE 7 +#define DESTNODE 13 + +/* + * Functions to fill and verify protocol structures + */ + +static void verify_ctdb_req_header(struct ctdb_req_header *h, + struct ctdb_req_header *h2) +{ + verify_buffer(h, h2, sizeof(struct ctdb_req_header)); +} + +static void fill_ctdb_req_call(TALLOC_CTX *mem_ctx, + struct ctdb_req_call *c) +{ + c->flags = rand32(); + c->db_id = rand32(); + c->callid = rand32(); + c->hopcount = rand32(); + fill_tdb_data(mem_ctx, &c->key); + fill_tdb_data(mem_ctx, &c->calldata); +} + +static void verify_ctdb_req_call(struct ctdb_req_call *c, + struct ctdb_req_call *c2) +{ + assert(c->flags == c2->flags); + assert(c->db_id == c2->db_id); + assert(c->callid == c2->callid); + assert(c->hopcount == c2->hopcount); + verify_tdb_data(&c->key, &c2->key); + verify_tdb_data(&c->calldata, &c2->calldata); +} + +static void fill_ctdb_reply_call(TALLOC_CTX *mem_ctx, + struct ctdb_reply_call *c) +{ + c->status = rand32(); + fill_tdb_data(mem_ctx, &c->data); +} + +static void verify_ctdb_reply_call(struct ctdb_reply_call *c, + struct ctdb_reply_call *c2) +{ + assert(c->status == c2->status); + verify_tdb_data(&c->data, &c2->data); +} + +static void fill_ctdb_reply_error(TALLOC_CTX *mem_ctx, + struct ctdb_reply_error *c) +{ + c->status = rand32(); + fill_tdb_data(mem_ctx, &c->msg); +} + +static void verify_ctdb_reply_error(struct ctdb_reply_error *c, + struct ctdb_reply_error *c2) +{ + assert(c->status == c2->status); + verify_tdb_data(&c->msg, &c2->msg); +} + +static void fill_ctdb_req_dmaster(TALLOC_CTX *mem_ctx, + struct ctdb_req_dmaster *c) +{ + c->db_id = rand32(); + c->rsn = rand64(); + c->dmaster = rand32(); + fill_tdb_data(mem_ctx, &c->key); + fill_tdb_data(mem_ctx, &c->data); +} + +static void verify_ctdb_req_dmaster(struct ctdb_req_dmaster *c, + struct ctdb_req_dmaster *c2) +{ + assert(c->db_id == c2->db_id); + assert(c->rsn == c2->rsn); + assert(c->dmaster == c2->dmaster); + verify_tdb_data(&c->key, &c2->key); + verify_tdb_data(&c->data, &c2->data); +} + +static void fill_ctdb_reply_dmaster(TALLOC_CTX *mem_ctx, + struct ctdb_reply_dmaster *c) +{ + c->db_id = rand32(); + c->rsn = rand64(); + fill_tdb_data(mem_ctx, &c->key); + fill_tdb_data(mem_ctx, &c->data); +} + +static void verify_ctdb_reply_dmaster(struct ctdb_reply_dmaster *c, + struct ctdb_reply_dmaster *c2) +{ + assert(c->db_id == c2->db_id); + assert(c->rsn == c2->rsn); + verify_tdb_data(&c->key, &c2->key); + verify_tdb_data(&c->data, &c2->data); +} + +static void fill_ctdb_req_control_data(TALLOC_CTX *mem_ctx, + struct ctdb_req_control_data *cd, + uint32_t opcode) +{ + cd->opcode = opcode; + switch (opcode) { + case CTDB_CONTROL_PROCESS_EXISTS: + cd->data.pid = rand32(); + break; + + case CTDB_CONTROL_STATISTICS: + break; + + case CTDB_CONTROL_PING: + break; + + case CTDB_CONTROL_GETDBPATH: + cd->data.db_id = rand32(); + break; + + case CTDB_CONTROL_GETVNNMAP: + break; + + case CTDB_CONTROL_SETVNNMAP: + cd->data.vnnmap = talloc(mem_ctx, struct ctdb_vnn_map); + assert(cd->data.vnnmap != NULL); + fill_ctdb_vnn_map(mem_ctx, cd->data.vnnmap); + break; + + case CTDB_CONTROL_GET_DEBUG: + break; + + case CTDB_CONTROL_SET_DEBUG: + cd->data.loglevel = rand_int(5); + break; + + case CTDB_CONTROL_GET_DBMAP: + break; + + case CTDB_CONTROL_PULL_DB: + cd->data.pulldb = talloc(mem_ctx, struct ctdb_pulldb); + assert(cd->data.pulldb != NULL); + fill_ctdb_pulldb(mem_ctx, cd->data.pulldb); + break; + + case CTDB_CONTROL_PUSH_DB: + cd->data.recbuf = talloc(mem_ctx, struct ctdb_rec_buffer); + assert(cd->data.recbuf != NULL); + fill_ctdb_rec_buffer(mem_ctx, cd->data.recbuf); + break; + + case CTDB_CONTROL_GET_RECMODE: + break; + + case CTDB_CONTROL_SET_RECMODE: + cd->data.recmode = rand_int(2); + break; + + case CTDB_CONTROL_STATISTICS_RESET: + break; + + case CTDB_CONTROL_DB_ATTACH: + fill_ctdb_string(mem_ctx, &cd->data.db_name); + assert(cd->data.db_name != NULL); + break; + + case CTDB_CONTROL_SET_CALL: + break; + + case CTDB_CONTROL_TRAVERSE_START: + cd->data.traverse_start = talloc(mem_ctx, struct ctdb_traverse_start); + assert(cd->data.traverse_start != NULL); + fill_ctdb_traverse_start(mem_ctx, cd->data.traverse_start); + break; + + case CTDB_CONTROL_TRAVERSE_ALL: + cd->data.traverse_all = talloc(mem_ctx, struct ctdb_traverse_all); + assert(cd->data.traverse_all != NULL); + fill_ctdb_traverse_all(mem_ctx, cd->data.traverse_all); + break; + + case CTDB_CONTROL_TRAVERSE_DATA: + cd->data.rec_data = talloc(mem_ctx, struct ctdb_rec_data); + assert(cd->data.rec_data != NULL); + fill_ctdb_rec_data(mem_ctx, cd->data.rec_data); + break; + + case CTDB_CONTROL_REGISTER_SRVID: + break; + + case CTDB_CONTROL_DEREGISTER_SRVID: + break; + + case CTDB_CONTROL_GET_DBNAME: + cd->data.db_id = rand32(); + break; + + case CTDB_CONTROL_ENABLE_SEQNUM: + cd->data.db_id = rand32(); + break; + + case CTDB_CONTROL_UPDATE_SEQNUM: + cd->data.db_id = rand32(); + break; + + case CTDB_CONTROL_DUMP_MEMORY: + break; + + case CTDB_CONTROL_GET_PID: + break; + + case CTDB_CONTROL_GET_RECMASTER: + break; + + case CTDB_CONTROL_SET_RECMASTER: + cd->data.recmaster = rand_int(32); + break; + + case CTDB_CONTROL_FREEZE: + break; + + case CTDB_CONTROL_THAW: + break; + + case CTDB_CONTROL_GET_PNN: + break; + + case CTDB_CONTROL_SHUTDOWN: + break; + + case CTDB_CONTROL_GET_MONMODE: + break; + + case CTDB_CONTROL_TCP_CLIENT: + cd->data.conn = talloc(mem_ctx, struct ctdb_connection); + assert(cd->data.conn != NULL); + fill_ctdb_connection(mem_ctx, cd->data.conn); + break; + + case CTDB_CONTROL_TCP_ADD: + cd->data.conn = talloc(mem_ctx, struct ctdb_connection); + assert(cd->data.conn != NULL); + fill_ctdb_connection(mem_ctx, cd->data.conn); + break; + + case CTDB_CONTROL_TCP_REMOVE: + cd->data.conn = talloc(mem_ctx, struct ctdb_connection); + assert(cd->data.conn != NULL); + fill_ctdb_connection(mem_ctx, cd->data.conn); + break; + + case CTDB_CONTROL_STARTUP: + break; + + case CTDB_CONTROL_SET_TUNABLE: + cd->data.tunable = talloc(mem_ctx, struct ctdb_tunable); + assert(cd->data.tunable != NULL); + fill_ctdb_tunable(mem_ctx, cd->data.tunable); + break; + + case CTDB_CONTROL_GET_TUNABLE: + fill_ctdb_string(mem_ctx, &cd->data.tun_var); + assert(cd->data.tun_var != NULL); + break; + + case CTDB_CONTROL_LIST_TUNABLES: + break; + + case CTDB_CONTROL_MODIFY_FLAGS: + cd->data.flag_change = talloc(mem_ctx, struct ctdb_node_flag_change); + assert(cd->data.flag_change != NULL); + fill_ctdb_node_flag_change(mem_ctx, cd->data.flag_change); + break; + + case CTDB_CONTROL_GET_ALL_TUNABLES: + break; + + case CTDB_CONTROL_KILL_TCP: + cd->data.conn = talloc(mem_ctx, struct ctdb_connection); + assert(cd->data.conn != NULL); + fill_ctdb_connection(mem_ctx, cd->data.conn); + break; + + case CTDB_CONTROL_GET_TCP_TICKLE_LIST: + cd->data.addr = talloc(mem_ctx, ctdb_sock_addr); + assert(cd->data.addr != NULL); + fill_ctdb_sock_addr(mem_ctx, cd->data.addr); + break; + + case CTDB_CONTROL_SET_TCP_TICKLE_LIST: + cd->data.tickles = talloc(mem_ctx, struct ctdb_tickle_list); + assert(cd->data.tickles != NULL); + fill_ctdb_tickle_list(mem_ctx, cd->data.tickles); + break; + + case CTDB_CONTROL_REGISTER_SERVER_ID: + cd->data.cid = talloc(mem_ctx, struct ctdb_client_id); + assert(cd->data.cid != NULL); + fill_ctdb_client_id(mem_ctx, cd->data.cid); + break; + + case CTDB_CONTROL_UNREGISTER_SERVER_ID: + cd->data.cid = talloc(mem_ctx, struct ctdb_client_id); + assert(cd->data.cid != NULL); + fill_ctdb_client_id(mem_ctx, cd->data.cid); + break; + + case CTDB_CONTROL_CHECK_SERVER_ID: + cd->data.cid = talloc(mem_ctx, struct ctdb_client_id); + assert(cd->data.cid != NULL); + fill_ctdb_client_id(mem_ctx, cd->data.cid); + break; + + case CTDB_CONTROL_GET_SERVER_ID_LIST: + break; + + case CTDB_CONTROL_DB_ATTACH_PERSISTENT: + fill_ctdb_string(mem_ctx, &cd->data.db_name); + assert(cd->data.db_name != NULL); + break; + + case CTDB_CONTROL_UPDATE_RECORD: + cd->data.recbuf = talloc(mem_ctx, struct ctdb_rec_buffer); + assert(cd->data.recbuf != NULL); + fill_ctdb_rec_buffer(mem_ctx, cd->data.recbuf); + break; + + case CTDB_CONTROL_SEND_GRATUITOUS_ARP: + cd->data.addr_info = talloc(mem_ctx, struct ctdb_addr_info); + assert(cd->data.addr_info != NULL); + fill_ctdb_addr_info(mem_ctx, cd->data.addr_info); + break; + + case CTDB_CONTROL_TRANSACTION_START: + cd->data.tid = rand32(); + break; + + case CTDB_CONTROL_TRANSACTION_COMMIT: + cd->data.tid = rand32(); + break; + + case CTDB_CONTROL_WIPE_DATABASE: + cd->data.transdb = talloc(mem_ctx, struct ctdb_transdb); + assert(cd->data.transdb != NULL); + fill_ctdb_transdb(mem_ctx, cd->data.transdb); + break; + + case CTDB_CONTROL_UPTIME: + break; + + case CTDB_CONTROL_START_RECOVERY: + break; + + case CTDB_CONTROL_END_RECOVERY: + break; + + case CTDB_CONTROL_RELOAD_NODES_FILE: + break; + + case CTDB_CONTROL_TRY_DELETE_RECORDS: + cd->data.recbuf = talloc(mem_ctx, struct ctdb_rec_buffer); + assert(cd->data.recbuf != NULL); + fill_ctdb_rec_buffer(mem_ctx, cd->data.recbuf); + break; + + case CTDB_CONTROL_ENABLE_MONITOR: + break; + + case CTDB_CONTROL_DISABLE_MONITOR: + break; + + case CTDB_CONTROL_ADD_PUBLIC_IP: + cd->data.addr_info = talloc(mem_ctx, struct ctdb_addr_info); + assert(cd->data.addr_info != NULL); + fill_ctdb_addr_info(mem_ctx, cd->data.addr_info); + break; + + case CTDB_CONTROL_DEL_PUBLIC_IP: + cd->data.addr_info = talloc(mem_ctx, struct ctdb_addr_info); + assert(cd->data.addr_info != NULL); + fill_ctdb_addr_info(mem_ctx, cd->data.addr_info); + break; + + case CTDB_CONTROL_RUN_EVENTSCRIPTS: + fill_ctdb_string(mem_ctx, &cd->data.event_str); + assert(cd->data.event_str != NULL); + break; + + case CTDB_CONTROL_GET_CAPABILITIES: + break; + + case CTDB_CONTROL_START_PERSISTENT_UPDATE: + break; + + case CTDB_CONTROL_CANCEL_PERSISTENT_UPDATE: + break; + + case CTDB_CONTROL_RECD_PING: + break; + + case CTDB_CONTROL_RELEASE_IP: + cd->data.pubip = talloc(mem_ctx, struct ctdb_public_ip); + assert(cd->data.pubip != NULL); + fill_ctdb_public_ip(mem_ctx, cd->data.pubip); + break; + + case CTDB_CONTROL_TAKEOVER_IP: + cd->data.pubip = talloc(mem_ctx, struct ctdb_public_ip); + assert(cd->data.pubip != NULL); + fill_ctdb_public_ip(mem_ctx, cd->data.pubip); + break; + + case CTDB_CONTROL_GET_PUBLIC_IPS: + break; + + case CTDB_CONTROL_GET_NODEMAP: + break; + + case CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS: + cd->data.event = rand_int(CTDB_EVENT_MAX); + break; + + case CTDB_CONTROL_TRAVERSE_KILL: + cd->data.traverse_start = talloc(mem_ctx, struct ctdb_traverse_start); + assert(cd->data.traverse_start != NULL); + fill_ctdb_traverse_start(mem_ctx, cd->data.traverse_start); + break; + + case CTDB_CONTROL_RECD_RECLOCK_LATENCY: + cd->data.reclock_latency = rand_double(); + break; + + case CTDB_CONTROL_GET_RECLOCK_FILE: + break; + + case CTDB_CONTROL_SET_RECLOCK_FILE: + fill_ctdb_string(mem_ctx, &cd->data.reclock_file); + assert(cd->data.reclock_file != NULL); + break; + + case CTDB_CONTROL_STOP_NODE: + break; + + case CTDB_CONTROL_CONTINUE_NODE: + break; + + case CTDB_CONTROL_SET_NATGWSTATE: + cd->data.role = rand_int(2); + break; + + case CTDB_CONTROL_SET_LMASTERROLE: + cd->data.role = rand_int(2); + break; + + case CTDB_CONTROL_SET_RECMASTERROLE: + cd->data.role = rand_int(2); + break; + + case CTDB_CONTROL_ENABLE_SCRIPT: + fill_ctdb_string(mem_ctx, &cd->data.script); + assert(cd->data.script != NULL); + break; + + case CTDB_CONTROL_DISABLE_SCRIPT: + fill_ctdb_string(mem_ctx, &cd->data.script); + assert(cd->data.script != NULL); + break; + + case CTDB_CONTROL_SET_BAN_STATE: + cd->data.ban_state = talloc(mem_ctx, struct ctdb_ban_state); + assert(cd->data.ban_state != NULL); + fill_ctdb_ban_state(mem_ctx, cd->data.ban_state); + break; + + case CTDB_CONTROL_GET_BAN_STATE: + break; + + case CTDB_CONTROL_SET_DB_PRIORITY: + cd->data.db_prio = talloc(mem_ctx, struct ctdb_db_priority); + assert(cd->data.db_prio != NULL); + fill_ctdb_db_priority(mem_ctx, cd->data.db_prio); + break; + + case CTDB_CONTROL_GET_DB_PRIORITY: + cd->data.db_prio = talloc(mem_ctx, struct ctdb_db_priority); + assert(cd->data.db_prio != NULL); + fill_ctdb_db_priority(mem_ctx, cd->data.db_prio); + break; + + case CTDB_CONTROL_TRANSACTION_CANCEL: + break; + + case CTDB_CONTROL_REGISTER_NOTIFY: + cd->data.notify = talloc(mem_ctx, struct ctdb_notify_data); + assert(cd->data.notify != NULL); + fill_ctdb_notify_data(mem_ctx, cd->data.notify); + break; + + case CTDB_CONTROL_DEREGISTER_NOTIFY: + cd->data.srvid = rand64(); + break; + + case CTDB_CONTROL_TRANS3_COMMIT: + cd->data.recbuf = talloc(mem_ctx, struct ctdb_rec_buffer); + assert(cd->data.recbuf != NULL); + fill_ctdb_rec_buffer(mem_ctx, cd->data.recbuf); + break; + + case CTDB_CONTROL_GET_DB_SEQNUM: + cd->data.db_id = rand32(); + break; + + case CTDB_CONTROL_DB_SET_HEALTHY: + cd->data.db_id = rand32(); + break; + + case CTDB_CONTROL_DB_GET_HEALTH: + cd->data.db_id = rand32(); + break; + + case CTDB_CONTROL_GET_PUBLIC_IP_INFO: + cd->data.addr = talloc(mem_ctx, ctdb_sock_addr); + assert(cd->data.addr != NULL); + fill_ctdb_sock_addr(mem_ctx, cd->data.addr); + break; + + case CTDB_CONTROL_GET_IFACES: + break; + + case CTDB_CONTROL_SET_IFACE_LINK_STATE: + cd->data.iface = talloc(mem_ctx, struct ctdb_iface); + assert(cd->data.iface != NULL); + fill_ctdb_iface(mem_ctx, cd->data.iface); + break; + + case CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE: + cd->data.conn = talloc(mem_ctx, struct ctdb_connection); + assert(cd->data.conn != NULL); + fill_ctdb_connection(mem_ctx, cd->data.conn); + break; + + case CTDB_CONTROL_GET_STAT_HISTORY: + break; + + case CTDB_CONTROL_SCHEDULE_FOR_DELETION: + cd->data.key = talloc(mem_ctx, struct ctdb_key_data); + assert(cd->data.key != NULL); + fill_ctdb_key_data(mem_ctx, cd->data.key); + break; + + case CTDB_CONTROL_SET_DB_READONLY: + cd->data.db_id = rand32(); + break; + + case CTDB_CONTROL_CHECK_SRVIDS: + cd->data.u64_array = talloc(mem_ctx, struct ctdb_uint64_array); + assert(cd->data.u64_array != NULL); + fill_ctdb_uint64_array(mem_ctx, cd->data.u64_array); + break; + + case CTDB_CONTROL_TRAVERSE_START_EXT: + cd->data.traverse_start_ext = talloc(mem_ctx, struct ctdb_traverse_start_ext); + assert(cd->data.traverse_start_ext != NULL); + fill_ctdb_traverse_start_ext(mem_ctx, cd->data.traverse_start_ext); + break; + + case CTDB_CONTROL_GET_DB_STATISTICS: + cd->data.db_id = rand32(); + break; + + case CTDB_CONTROL_SET_DB_STICKY: + cd->data.db_id = rand32(); + break; + + case CTDB_CONTROL_RELOAD_PUBLIC_IPS: + break; + + case CTDB_CONTROL_TRAVERSE_ALL_EXT: + cd->data.traverse_all_ext = talloc(mem_ctx, struct ctdb_traverse_all_ext); + assert(cd->data.traverse_all_ext != NULL); + fill_ctdb_traverse_all_ext(mem_ctx, cd->data.traverse_all_ext); + break; + + case CTDB_CONTROL_RECEIVE_RECORDS: + cd->data.recbuf = talloc(mem_ctx, struct ctdb_rec_buffer); + assert(cd->data.recbuf != NULL); + fill_ctdb_rec_buffer(mem_ctx, cd->data.recbuf); + break; + + case CTDB_CONTROL_IPREALLOCATED: + break; + + case CTDB_CONTROL_GET_RUNSTATE: + break; + + case CTDB_CONTROL_DB_DETACH: + cd->data.db_id = rand32(); + break; + + case CTDB_CONTROL_GET_NODES_FILE: + break; + + } +} + +static void verify_ctdb_req_control_data(struct ctdb_req_control_data *cd, + struct ctdb_req_control_data *cd2) +{ + assert(cd->opcode == cd2->opcode); + + switch (cd->opcode) { + case CTDB_CONTROL_PROCESS_EXISTS: + assert(cd->data.pid == cd2->data.pid); + break; + + case CTDB_CONTROL_STATISTICS: + break; + + case CTDB_CONTROL_PING: + break; + + case CTDB_CONTROL_GETDBPATH: + assert(cd->data.db_id == cd2->data.db_id); + break; + + case CTDB_CONTROL_GETVNNMAP: + break; + + case CTDB_CONTROL_SETVNNMAP: + verify_ctdb_vnn_map(cd->data.vnnmap, cd2->data.vnnmap); + break; + + case CTDB_CONTROL_GET_DEBUG: + break; + + case CTDB_CONTROL_SET_DEBUG: + assert(cd->data.loglevel == cd2->data.loglevel); + break; + + case CTDB_CONTROL_GET_DBMAP: + break; + + case CTDB_CONTROL_PULL_DB: + verify_ctdb_pulldb(cd->data.pulldb, cd2->data.pulldb); + break; + + case CTDB_CONTROL_PUSH_DB: + verify_ctdb_rec_buffer(cd->data.recbuf, cd2->data.recbuf); + break; + + case CTDB_CONTROL_GET_RECMODE: + break; + + case CTDB_CONTROL_SET_RECMODE: + assert(cd->data.recmode == cd2->data.recmode); + break; + + case CTDB_CONTROL_STATISTICS_RESET: + break; + + case CTDB_CONTROL_DB_ATTACH: + verify_ctdb_string(cd->data.db_name, cd2->data.db_name); + break; + + case CTDB_CONTROL_SET_CALL: + break; + + case CTDB_CONTROL_TRAVERSE_START: + verify_ctdb_traverse_start(cd->data.traverse_start, + cd2->data.traverse_start); + break; + + case CTDB_CONTROL_TRAVERSE_ALL: + verify_ctdb_traverse_all(cd->data.traverse_all, + cd2->data.traverse_all); + break; + + case CTDB_CONTROL_TRAVERSE_DATA: + verify_ctdb_rec_data(cd->data.rec_data, cd2->data.rec_data); + break; + + case CTDB_CONTROL_REGISTER_SRVID: + break; + + case CTDB_CONTROL_DEREGISTER_SRVID: + break; + + case CTDB_CONTROL_GET_DBNAME: + assert(cd->data.db_id == cd2->data.db_id); + break; + + case CTDB_CONTROL_ENABLE_SEQNUM: + assert(cd->data.db_id == cd2->data.db_id); + break; + + case CTDB_CONTROL_UPDATE_SEQNUM: + assert(cd->data.db_id == cd2->data.db_id); + break; + + case CTDB_CONTROL_DUMP_MEMORY: + break; + + case CTDB_CONTROL_GET_PID: + break; + + case CTDB_CONTROL_GET_RECMASTER: + break; + + case CTDB_CONTROL_SET_RECMASTER: + assert(cd->data.recmaster == cd2->data.recmaster); + break; + + case CTDB_CONTROL_FREEZE: + break; + + case CTDB_CONTROL_THAW: + break; + + case CTDB_CONTROL_GET_PNN: + break; + + case CTDB_CONTROL_SHUTDOWN: + break; + + case CTDB_CONTROL_GET_MONMODE: + break; + + case CTDB_CONTROL_TCP_CLIENT: + verify_ctdb_connection(cd->data.conn, cd2->data.conn); + break; + + case CTDB_CONTROL_TCP_ADD: + verify_ctdb_connection(cd->data.conn, cd2->data.conn); + break; + + case CTDB_CONTROL_TCP_REMOVE: + verify_ctdb_connection(cd->data.conn, cd2->data.conn); + break; + + case CTDB_CONTROL_STARTUP: + break; + + case CTDB_CONTROL_SET_TUNABLE: + verify_ctdb_tunable(cd->data.tunable, cd2->data.tunable); + break; + + case CTDB_CONTROL_GET_TUNABLE: + verify_ctdb_string(cd->data.tun_var, cd2->data.tun_var); + break; + + case CTDB_CONTROL_LIST_TUNABLES: + break; + + case CTDB_CONTROL_MODIFY_FLAGS: + verify_ctdb_node_flag_change(cd->data.flag_change, + cd2->data.flag_change); + break; + + case CTDB_CONTROL_GET_ALL_TUNABLES: + break; + + case CTDB_CONTROL_KILL_TCP: + verify_ctdb_connection(cd->data.conn, cd2->data.conn); + break; + + case CTDB_CONTROL_GET_TCP_TICKLE_LIST: + verify_ctdb_sock_addr(cd->data.addr, cd2->data.addr); + break; + + case CTDB_CONTROL_SET_TCP_TICKLE_LIST: + verify_ctdb_tickle_list(cd->data.tickles, cd2->data.tickles); + break; + + case CTDB_CONTROL_REGISTER_SERVER_ID: + verify_ctdb_client_id(cd->data.cid, cd2->data.cid); + break; + + case CTDB_CONTROL_UNREGISTER_SERVER_ID: + verify_ctdb_client_id(cd->data.cid, cd2->data.cid); + break; + + case CTDB_CONTROL_CHECK_SERVER_ID: + verify_ctdb_client_id(cd->data.cid, cd2->data.cid); + break; + + case CTDB_CONTROL_GET_SERVER_ID_LIST: + break; + + case CTDB_CONTROL_DB_ATTACH_PERSISTENT: + verify_ctdb_string(cd->data.db_name, cd2->data.db_name); + break; + + case CTDB_CONTROL_UPDATE_RECORD: + verify_ctdb_rec_buffer(cd->data.recbuf, cd2->data.recbuf); + break; + + case CTDB_CONTROL_SEND_GRATUITOUS_ARP: + verify_ctdb_addr_info(cd->data.addr_info, cd2->data.addr_info); + break; + + case CTDB_CONTROL_TRANSACTION_START: + assert(cd->data.tid == cd2->data.tid); + break; + + case CTDB_CONTROL_TRANSACTION_COMMIT: + assert(cd->data.tid == cd2->data.tid); + break; + + case CTDB_CONTROL_WIPE_DATABASE: + verify_ctdb_transdb(cd->data.transdb, cd2->data.transdb); + break; + + case CTDB_CONTROL_UPTIME: + break; + + case CTDB_CONTROL_START_RECOVERY: + break; + + case CTDB_CONTROL_END_RECOVERY: + break; + + case CTDB_CONTROL_RELOAD_NODES_FILE: + break; + + case CTDB_CONTROL_TRY_DELETE_RECORDS: + verify_ctdb_rec_buffer(cd->data.recbuf, cd2->data.recbuf); + break; + + case CTDB_CONTROL_ENABLE_MONITOR: + break; + + case CTDB_CONTROL_DISABLE_MONITOR: + break; + + case CTDB_CONTROL_ADD_PUBLIC_IP: + verify_ctdb_addr_info(cd->data.addr_info, cd2->data.addr_info); + break; + + case CTDB_CONTROL_DEL_PUBLIC_IP: + verify_ctdb_addr_info(cd->data.addr_info, cd2->data.addr_info); + break; + + case CTDB_CONTROL_RUN_EVENTSCRIPTS: + verify_ctdb_string(cd->data.event_str, cd2->data.event_str); + break; + + case CTDB_CONTROL_GET_CAPABILITIES: + break; + + case CTDB_CONTROL_START_PERSISTENT_UPDATE: + break; + + case CTDB_CONTROL_CANCEL_PERSISTENT_UPDATE: + break; + + case CTDB_CONTROL_RECD_PING: + break; + + case CTDB_CONTROL_RELEASE_IP: + verify_ctdb_public_ip(cd->data.pubip, cd2->data.pubip); + break; + + case CTDB_CONTROL_TAKEOVER_IP: + verify_ctdb_public_ip(cd->data.pubip, cd2->data.pubip); + break; + + case CTDB_CONTROL_GET_PUBLIC_IPS: + break; + + case CTDB_CONTROL_GET_NODEMAP: + break; + + case CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS: + assert(cd->data.event == cd2->data.event); + break; + + case CTDB_CONTROL_TRAVERSE_KILL: + verify_ctdb_traverse_start(cd->data.traverse_start, + cd2->data.traverse_start); + break; + + case CTDB_CONTROL_RECD_RECLOCK_LATENCY: + assert(cd->data.reclock_latency == cd2->data.reclock_latency); + break; + + case CTDB_CONTROL_GET_RECLOCK_FILE: + break; + + case CTDB_CONTROL_SET_RECLOCK_FILE: + verify_ctdb_string(cd->data.reclock_file, + cd2->data.reclock_file); + break; + + case CTDB_CONTROL_STOP_NODE: + break; + + case CTDB_CONTROL_CONTINUE_NODE: + break; + + case CTDB_CONTROL_SET_NATGWSTATE: + assert(cd->data.role == cd2->data.role); + break; + + case CTDB_CONTROL_SET_LMASTERROLE: + assert(cd->data.role == cd2->data.role); + break; + + case CTDB_CONTROL_SET_RECMASTERROLE: + assert(cd->data.role == cd2->data.role); + break; + + case CTDB_CONTROL_ENABLE_SCRIPT: + verify_ctdb_string(cd->data.script, cd2->data.script); + break; + + case CTDB_CONTROL_DISABLE_SCRIPT: + verify_ctdb_string(cd->data.script, cd2->data.script); + break; + + case CTDB_CONTROL_SET_BAN_STATE: + verify_ctdb_ban_state(cd->data.ban_state, cd2->data.ban_state); + break; + + case CTDB_CONTROL_GET_BAN_STATE: + break; + + case CTDB_CONTROL_SET_DB_PRIORITY: + verify_ctdb_db_priority(cd->data.db_prio, cd2->data.db_prio); + break; + + case CTDB_CONTROL_GET_DB_PRIORITY: + assert(cd->data.db_id == cd2->data.db_id); + break; + + case CTDB_CONTROL_TRANSACTION_CANCEL: + break; + + case CTDB_CONTROL_REGISTER_NOTIFY: + verify_ctdb_notify_data(cd->data.notify, cd2->data.notify); + break; + + case CTDB_CONTROL_DEREGISTER_NOTIFY: + assert(cd->data.srvid == cd2->data.srvid); + break; + + case CTDB_CONTROL_TRANS3_COMMIT: + verify_ctdb_rec_buffer(cd->data.recbuf, cd2->data.recbuf); + break; + + case CTDB_CONTROL_GET_DB_SEQNUM: + assert(cd->data.db_id == cd2->data.db_id); + break; + + case CTDB_CONTROL_DB_SET_HEALTHY: + assert(cd->data.db_id == cd2->data.db_id); + break; + + case CTDB_CONTROL_DB_GET_HEALTH: + assert(cd->data.db_id == cd2->data.db_id); + break; + + case CTDB_CONTROL_GET_PUBLIC_IP_INFO: + verify_ctdb_sock_addr(cd->data.addr, cd2->data.addr); + break; + + case CTDB_CONTROL_GET_IFACES: + break; + + case CTDB_CONTROL_SET_IFACE_LINK_STATE: + verify_ctdb_iface(cd->data.iface, cd2->data.iface); + break; + + case CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE: + verify_ctdb_connection(cd->data.conn, cd2->data.conn); + break; + + case CTDB_CONTROL_GET_STAT_HISTORY: + break; + + case CTDB_CONTROL_SCHEDULE_FOR_DELETION: + verify_ctdb_key_data(cd->data.key, cd2->data.key); + break; + + case CTDB_CONTROL_SET_DB_READONLY: + assert(cd->data.db_id == cd2->data.db_id); + break; + + case CTDB_CONTROL_CHECK_SRVIDS: + verify_ctdb_uint64_array(cd->data.u64_array, + cd2->data.u64_array); + break; + + case CTDB_CONTROL_TRAVERSE_START_EXT: + verify_ctdb_traverse_start_ext(cd->data.traverse_start_ext, + cd2->data.traverse_start_ext); + break; + + case CTDB_CONTROL_GET_DB_STATISTICS: + assert(cd->data.db_id == cd2->data.db_id); + break; + + case CTDB_CONTROL_SET_DB_STICKY: + assert(cd->data.db_id == cd2->data.db_id); + break; + + case CTDB_CONTROL_RELOAD_PUBLIC_IPS: + break; + + case CTDB_CONTROL_TRAVERSE_ALL_EXT: + verify_ctdb_traverse_all_ext(cd->data.traverse_all_ext, + cd2->data.traverse_all_ext); + break; + + case CTDB_CONTROL_RECEIVE_RECORDS: + verify_ctdb_rec_buffer(cd->data.recbuf, cd2->data.recbuf); + break; + + case CTDB_CONTROL_IPREALLOCATED: + break; + + case CTDB_CONTROL_GET_RUNSTATE: + break; + + case CTDB_CONTROL_DB_DETACH: + assert(cd->data.db_id == cd2->data.db_id); + break; + + case CTDB_CONTROL_GET_NODES_FILE: + break; + + } +} + +static void fill_ctdb_req_control(TALLOC_CTX *mem_ctx, + struct ctdb_req_control *c, + uint32_t opcode) +{ + c->opcode = opcode; + c->pad = rand32(); + c->srvid = rand64(); + c->client_id = rand32(); + c->flags = rand32(); + + fill_ctdb_req_control_data(mem_ctx, &c->rdata, opcode); +} + +static void verify_ctdb_req_control(struct ctdb_req_control *c, + struct ctdb_req_control *c2) +{ + assert(c->opcode == c2->opcode); + assert(c->pad == c2->pad); + assert(c->srvid == c2->srvid); + assert(c->client_id == c2->client_id); + assert(c->flags == c2->flags); + + verify_ctdb_req_control_data(&c->rdata, &c2->rdata); +} + +static void fill_ctdb_reply_control_data(TALLOC_CTX *mem_ctx, + struct ctdb_reply_control_data *cd, + uint32_t opcode) +{ + cd->opcode = opcode; + + switch (opcode) { + case CTDB_CONTROL_PROCESS_EXISTS: + break; + + case CTDB_CONTROL_STATISTICS: + cd->data.stats = talloc(mem_ctx, struct ctdb_statistics); + assert(cd->data.stats != NULL); + fill_ctdb_statistics(mem_ctx, cd->data.stats); + break; + + case CTDB_CONTROL_PING: + break; + + case CTDB_CONTROL_GETDBPATH: + fill_ctdb_string(mem_ctx, &cd->data.db_path); + assert(cd->data.db_path != NULL); + break; + + case CTDB_CONTROL_GETVNNMAP: + cd->data.vnnmap = talloc(mem_ctx, struct ctdb_vnn_map); + assert(cd->data.vnnmap != NULL); + fill_ctdb_vnn_map(mem_ctx, cd->data.vnnmap); + break; + + case CTDB_CONTROL_SETVNNMAP: + break; + + case CTDB_CONTROL_GET_DEBUG: + cd->data.loglevel = rand_int(5); + break; + + case CTDB_CONTROL_SET_DEBUG: + break; + + case CTDB_CONTROL_GET_DBMAP: + cd->data.dbmap = talloc(mem_ctx, struct ctdb_dbid_map); + assert(cd->data.dbmap != NULL); + fill_ctdb_dbid_map(mem_ctx, cd->data.dbmap); + break; + + case CTDB_CONTROL_PULL_DB: + cd->data.recbuf = talloc(mem_ctx, struct ctdb_rec_buffer); + assert(cd->data.recbuf != NULL); + fill_ctdb_rec_buffer(mem_ctx, cd->data.recbuf); + break; + + case CTDB_CONTROL_PUSH_DB: + break; + + case CTDB_CONTROL_GET_RECMODE: + break; + + case CTDB_CONTROL_SET_RECMODE: + break; + + case CTDB_CONTROL_STATISTICS_RESET: + break; + + case CTDB_CONTROL_DB_ATTACH: + cd->data.db_id = rand32(); + break; + + case CTDB_CONTROL_SET_CALL: + break; + + case CTDB_CONTROL_TRAVERSE_START: + break; + + case CTDB_CONTROL_TRAVERSE_ALL: + break; + + case CTDB_CONTROL_TRAVERSE_DATA: + break; + + case CTDB_CONTROL_REGISTER_SRVID: + break; + + case CTDB_CONTROL_DEREGISTER_SRVID: + break; + + case CTDB_CONTROL_GET_DBNAME: + fill_ctdb_string(mem_ctx, &cd->data.db_name); + assert(cd->data.db_name); + break; + + case CTDB_CONTROL_ENABLE_SEQNUM: + break; + + case CTDB_CONTROL_UPDATE_SEQNUM: + break; + + case CTDB_CONTROL_DUMP_MEMORY: + fill_ctdb_string(mem_ctx, &cd->data.mem_str); + assert(cd->data.mem_str); + break; + + case CTDB_CONTROL_GET_PID: + break; + + case CTDB_CONTROL_GET_RECMASTER: + break; + + case CTDB_CONTROL_SET_RECMASTER: + break; + + case CTDB_CONTROL_FREEZE: + break; + + case CTDB_CONTROL_THAW: + break; + + case CTDB_CONTROL_GET_PNN: + break; + + case CTDB_CONTROL_SHUTDOWN: + break; + + case CTDB_CONTROL_GET_MONMODE: + break; + + case CTDB_CONTROL_TCP_CLIENT: + break; + + case CTDB_CONTROL_TCP_ADD: + break; + + case CTDB_CONTROL_TCP_REMOVE: + break; + + case CTDB_CONTROL_STARTUP: + break; + + case CTDB_CONTROL_SET_TUNABLE: + break; + + case CTDB_CONTROL_GET_TUNABLE: + cd->data.tun_value = rand32(); + break; + + case CTDB_CONTROL_LIST_TUNABLES: + cd->data.tun_var_list = talloc(mem_ctx, struct ctdb_var_list); + assert(cd->data.tun_var_list != NULL); + fill_ctdb_var_list(mem_ctx, cd->data.tun_var_list); + break; + + case CTDB_CONTROL_MODIFY_FLAGS: + break; + + case CTDB_CONTROL_GET_ALL_TUNABLES: + cd->data.tun_list = talloc(mem_ctx, struct ctdb_tunable_list); + assert(cd->data.tun_list != NULL); + fill_ctdb_tunable_list(mem_ctx, cd->data.tun_list); + break; + + case CTDB_CONTROL_KILL_TCP: + break; + + case CTDB_CONTROL_GET_TCP_TICKLE_LIST: + cd->data.tickles = talloc(mem_ctx, struct ctdb_tickle_list); + assert(cd->data.tickles != NULL); + fill_ctdb_tickle_list(mem_ctx, cd->data.tickles); + break; + + case CTDB_CONTROL_SET_TCP_TICKLE_LIST: + break; + + case CTDB_CONTROL_REGISTER_SERVER_ID: + break; + + case CTDB_CONTROL_UNREGISTER_SERVER_ID: + break; + + case CTDB_CONTROL_CHECK_SERVER_ID: + break; + + case CTDB_CONTROL_GET_SERVER_ID_LIST: + cd->data.cid_map = talloc(mem_ctx, struct ctdb_client_id_map); + assert(cd->data.cid_map != NULL); + fill_ctdb_client_id_map(mem_ctx, cd->data.cid_map); + break; + + case CTDB_CONTROL_DB_ATTACH_PERSISTENT: + break; + + case CTDB_CONTROL_UPDATE_RECORD: + break; + + case CTDB_CONTROL_SEND_GRATUITOUS_ARP: + break; + + case CTDB_CONTROL_TRANSACTION_START: + break; + + case CTDB_CONTROL_TRANSACTION_COMMIT: + break; + + case CTDB_CONTROL_WIPE_DATABASE: + break; + + case CTDB_CONTROL_UPTIME: + cd->data.uptime = talloc(mem_ctx, struct ctdb_uptime); + assert(cd->data.uptime != NULL); + fill_ctdb_uptime(mem_ctx, cd->data.uptime); + break; + + case CTDB_CONTROL_START_RECOVERY: + break; + + case CTDB_CONTROL_END_RECOVERY: + break; + + case CTDB_CONTROL_RELOAD_NODES_FILE: + break; + + case CTDB_CONTROL_TRY_DELETE_RECORDS: + cd->data.recbuf = talloc(mem_ctx, struct ctdb_rec_buffer); + assert(cd->data.recbuf != NULL); + fill_ctdb_rec_buffer(mem_ctx, cd->data.recbuf); + break; + + case CTDB_CONTROL_ENABLE_MONITOR: + break; + + case CTDB_CONTROL_DISABLE_MONITOR: + break; + + case CTDB_CONTROL_ADD_PUBLIC_IP: + break; + + case CTDB_CONTROL_DEL_PUBLIC_IP: + break; + + case CTDB_CONTROL_RUN_EVENTSCRIPTS: + break; + + case CTDB_CONTROL_GET_CAPABILITIES: + cd->data.caps = rand32(); + break; + + case CTDB_CONTROL_START_PERSISTENT_UPDATE: + break; + + case CTDB_CONTROL_CANCEL_PERSISTENT_UPDATE: + break; + + case CTDB_CONTROL_RECD_PING: + break; + + case CTDB_CONTROL_RELEASE_IP: + break; + + case CTDB_CONTROL_TAKEOVER_IP: + break; + + case CTDB_CONTROL_GET_PUBLIC_IPS: + cd->data.pubip_list = talloc(mem_ctx, struct ctdb_public_ip_list); + assert(cd->data.pubip_list != NULL); + fill_ctdb_public_ip_list(mem_ctx, cd->data.pubip_list); + break; + + case CTDB_CONTROL_GET_NODEMAP: + cd->data.nodemap = talloc(mem_ctx, struct ctdb_node_map); + assert(cd->data.nodemap != NULL); + fill_ctdb_node_map(mem_ctx, cd->data.nodemap); + break; + + case CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS: + cd->data.script_list = talloc(mem_ctx, struct ctdb_script_list); + assert(cd->data.script_list != NULL); + fill_ctdb_script_list(mem_ctx, cd->data.script_list); + break; + + case CTDB_CONTROL_TRAVERSE_KILL: + break; + + case CTDB_CONTROL_RECD_RECLOCK_LATENCY: + break; + + case CTDB_CONTROL_GET_RECLOCK_FILE: + fill_ctdb_string(mem_ctx, &cd->data.reclock_file); + assert(cd->data.reclock_file != NULL); + break; + + case CTDB_CONTROL_SET_RECLOCK_FILE: + break; + + case CTDB_CONTROL_STOP_NODE: + break; + + case CTDB_CONTROL_CONTINUE_NODE: + break; + + case CTDB_CONTROL_SET_NATGWSTATE: + break; + + case CTDB_CONTROL_SET_LMASTERROLE: + break; + + case CTDB_CONTROL_SET_RECMASTERROLE: + break; + + case CTDB_CONTROL_ENABLE_SCRIPT: + break; + + case CTDB_CONTROL_DISABLE_SCRIPT: + break; + + case CTDB_CONTROL_SET_BAN_STATE: + break; + + case CTDB_CONTROL_GET_BAN_STATE: + cd->data.ban_state = talloc(mem_ctx, struct ctdb_ban_state); + assert(cd->data.ban_state != NULL); + fill_ctdb_ban_state(mem_ctx, cd->data.ban_state); + break; + + case CTDB_CONTROL_SET_DB_PRIORITY: + break; + + case CTDB_CONTROL_GET_DB_PRIORITY: + break; + + case CTDB_CONTROL_TRANSACTION_CANCEL: + break; + + case CTDB_CONTROL_REGISTER_NOTIFY: + break; + + case CTDB_CONTROL_DEREGISTER_NOTIFY: + break; + + case CTDB_CONTROL_TRANS3_COMMIT: + break; + + case CTDB_CONTROL_GET_DB_SEQNUM: + cd->data.seqnum = rand64(); + break; + + case CTDB_CONTROL_DB_SET_HEALTHY: + break; + + case CTDB_CONTROL_DB_GET_HEALTH: + fill_ctdb_string(mem_ctx, &cd->data.reason); + assert(cd->data.reason != NULL); + break; + + case CTDB_CONTROL_GET_PUBLIC_IP_INFO: + cd->data.ipinfo = talloc(mem_ctx, struct ctdb_public_ip_info); + assert(cd->data.ipinfo != NULL); + fill_ctdb_public_ip_info(mem_ctx, cd->data.ipinfo); + break; + + case CTDB_CONTROL_GET_IFACES: + cd->data.iface_list = talloc(mem_ctx, struct ctdb_iface_list); + assert(cd->data.iface_list != NULL); + fill_ctdb_iface_list(mem_ctx, cd->data.iface_list); + break; + + case CTDB_CONTROL_SET_IFACE_LINK_STATE: + break; + + case CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE: + break; + + case CTDB_CONTROL_GET_STAT_HISTORY: + cd->data.stats_list = talloc(mem_ctx, struct ctdb_statistics_list); + assert(cd->data.stats_list != NULL); + fill_ctdb_statistics_list(mem_ctx, cd->data.stats_list); + break; + + case CTDB_CONTROL_SCHEDULE_FOR_DELETION: + break; + + case CTDB_CONTROL_SET_DB_READONLY: + break; + + case CTDB_CONTROL_CHECK_SRVIDS: + cd->data.u8_array = talloc(mem_ctx, struct ctdb_uint8_array); + assert(cd->data.u8_array != NULL); + fill_ctdb_uint8_array(mem_ctx, cd->data.u8_array); + break; + + case CTDB_CONTROL_TRAVERSE_START_EXT: + break; + + case CTDB_CONTROL_GET_DB_STATISTICS: + cd->data.dbstats = talloc(mem_ctx, struct ctdb_db_statistics); + assert(cd->data.dbstats != NULL); + fill_ctdb_db_statistics(mem_ctx, cd->data.dbstats); + break; + + case CTDB_CONTROL_SET_DB_STICKY: + break; + + case CTDB_CONTROL_RELOAD_PUBLIC_IPS: + break; + + case CTDB_CONTROL_TRAVERSE_ALL_EXT: + break; + + case CTDB_CONTROL_RECEIVE_RECORDS: + cd->data.recbuf = talloc(mem_ctx, struct ctdb_rec_buffer); + assert(cd->data.recbuf != NULL); + fill_ctdb_rec_buffer(mem_ctx, cd->data.recbuf); + break; + + case CTDB_CONTROL_IPREALLOCATED: + break; + + case CTDB_CONTROL_GET_RUNSTATE: + cd->data.runstate = rand32(); + break; + + case CTDB_CONTROL_DB_DETACH: + break; + + case CTDB_CONTROL_GET_NODES_FILE: + cd->data.nodemap = talloc(mem_ctx, struct ctdb_node_map); + assert(cd->data.nodemap != NULL); + fill_ctdb_node_map(mem_ctx, cd->data.nodemap); + break; + + } +} + +static void verify_ctdb_reply_control_data(struct ctdb_reply_control_data *cd, + struct ctdb_reply_control_data *cd2) +{ + assert(cd->opcode == cd2->opcode); + + switch (cd->opcode) { + case CTDB_CONTROL_PROCESS_EXISTS: + break; + + case CTDB_CONTROL_STATISTICS: + verify_ctdb_statistics(cd->data.stats, cd2->data.stats); + break; + + case CTDB_CONTROL_PING: + break; + + case CTDB_CONTROL_GETDBPATH: + verify_ctdb_string(cd->data.db_path, cd2->data.db_path); + break; + + case CTDB_CONTROL_GETVNNMAP: + verify_ctdb_vnn_map(cd->data.vnnmap, cd2->data.vnnmap); + break; + + case CTDB_CONTROL_SETVNNMAP: + break; + + case CTDB_CONTROL_GET_DEBUG: + assert(cd->data.loglevel == cd2->data.loglevel); + break; + + case CTDB_CONTROL_SET_DEBUG: + break; + + case CTDB_CONTROL_GET_DBMAP: + verify_ctdb_dbid_map(cd->data.dbmap, cd2->data.dbmap); + break; + + case CTDB_CONTROL_PULL_DB: + verify_ctdb_rec_buffer(cd->data.recbuf, cd2->data.recbuf); + break; + + case CTDB_CONTROL_PUSH_DB: + break; + + case CTDB_CONTROL_GET_RECMODE: + break; + + case CTDB_CONTROL_SET_RECMODE: + break; + + case CTDB_CONTROL_STATISTICS_RESET: + break; + + case CTDB_CONTROL_DB_ATTACH: + assert(cd->data.db_id == cd2->data.db_id); + break; + + case CTDB_CONTROL_SET_CALL: + break; + + case CTDB_CONTROL_TRAVERSE_START: + break; + + case CTDB_CONTROL_TRAVERSE_ALL: + break; + + case CTDB_CONTROL_TRAVERSE_DATA: + break; + + case CTDB_CONTROL_REGISTER_SRVID: + break; + + case CTDB_CONTROL_DEREGISTER_SRVID: + break; + + case CTDB_CONTROL_GET_DBNAME: + verify_ctdb_string(cd->data.db_name, cd2->data.db_name); + break; + + case CTDB_CONTROL_ENABLE_SEQNUM: + break; + + case CTDB_CONTROL_UPDATE_SEQNUM: + break; + + case CTDB_CONTROL_DUMP_MEMORY: + verify_ctdb_string(cd->data.mem_str, cd2->data.mem_str); + break; + + case CTDB_CONTROL_GET_PID: + break; + + case CTDB_CONTROL_GET_RECMASTER: + break; + + case CTDB_CONTROL_SET_RECMASTER: + break; + + case CTDB_CONTROL_FREEZE: + break; + + case CTDB_CONTROL_THAW: + break; + + case CTDB_CONTROL_GET_PNN: + break; + + case CTDB_CONTROL_SHUTDOWN: + break; + + case CTDB_CONTROL_GET_MONMODE: + break; + + case CTDB_CONTROL_TCP_CLIENT: + break; + + case CTDB_CONTROL_TCP_ADD: + break; + + case CTDB_CONTROL_TCP_REMOVE: + break; + + case CTDB_CONTROL_STARTUP: + break; + + case CTDB_CONTROL_SET_TUNABLE: + break; + + case CTDB_CONTROL_GET_TUNABLE: + assert(cd->data.tun_value == cd2->data.tun_value); + break; + + case CTDB_CONTROL_LIST_TUNABLES: + verify_ctdb_var_list(cd->data.tun_var_list, + cd2->data.tun_var_list); + break; + + case CTDB_CONTROL_MODIFY_FLAGS: + break; + + case CTDB_CONTROL_GET_ALL_TUNABLES: + verify_ctdb_tunable_list(cd->data.tun_list, cd2->data.tun_list); + break; + + case CTDB_CONTROL_KILL_TCP: + break; + + case CTDB_CONTROL_GET_TCP_TICKLE_LIST: + verify_ctdb_tickle_list(cd->data.tickles, cd2->data.tickles); + break; + + case CTDB_CONTROL_SET_TCP_TICKLE_LIST: + break; + + case CTDB_CONTROL_REGISTER_SERVER_ID: + break; + + case CTDB_CONTROL_UNREGISTER_SERVER_ID: + break; + + case CTDB_CONTROL_CHECK_SERVER_ID: + break; + + case CTDB_CONTROL_GET_SERVER_ID_LIST: + verify_ctdb_client_id_map(cd->data.cid_map, cd2->data.cid_map); + break; + + case CTDB_CONTROL_DB_ATTACH_PERSISTENT: + break; + + case CTDB_CONTROL_UPDATE_RECORD: + break; + + case CTDB_CONTROL_SEND_GRATUITOUS_ARP: + break; + + case CTDB_CONTROL_TRANSACTION_START: + break; + + case CTDB_CONTROL_TRANSACTION_COMMIT: + break; + + case CTDB_CONTROL_WIPE_DATABASE: + break; + + case CTDB_CONTROL_UPTIME: + verify_ctdb_uptime(cd->data.uptime, cd2->data.uptime); + break; + + case CTDB_CONTROL_START_RECOVERY: + break; + + case CTDB_CONTROL_END_RECOVERY: + break; + + case CTDB_CONTROL_RELOAD_NODES_FILE: + break; + + case CTDB_CONTROL_TRY_DELETE_RECORDS: + verify_ctdb_rec_buffer(cd->data.recbuf, cd2->data.recbuf); + break; + + case CTDB_CONTROL_ENABLE_MONITOR: + break; + + case CTDB_CONTROL_DISABLE_MONITOR: + break; + + case CTDB_CONTROL_ADD_PUBLIC_IP: + break; + + case CTDB_CONTROL_DEL_PUBLIC_IP: + break; + + case CTDB_CONTROL_RUN_EVENTSCRIPTS: + break; + + case CTDB_CONTROL_GET_CAPABILITIES: + assert(cd->data.caps == cd2->data.caps); + break; + + case CTDB_CONTROL_RECD_PING: + break; + + case CTDB_CONTROL_RELEASE_IP: + break; + + case CTDB_CONTROL_TAKEOVER_IP: + break; + + case CTDB_CONTROL_GET_PUBLIC_IPS: + verify_ctdb_public_ip_list(cd->data.pubip_list, + cd2->data.pubip_list); + break; + + case CTDB_CONTROL_GET_NODEMAP: + verify_ctdb_node_map(cd->data.nodemap, cd2->data.nodemap); + break; + + case CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS: + verify_ctdb_script_list(cd->data.script_list, + cd2->data.script_list); + break; + + case CTDB_CONTROL_TRAVERSE_KILL: + break; + + case CTDB_CONTROL_RECD_RECLOCK_LATENCY: + break; + + case CTDB_CONTROL_GET_RECLOCK_FILE: + verify_ctdb_string(cd->data.reclock_file, + cd2->data.reclock_file); + break; + + case CTDB_CONTROL_SET_RECLOCK_FILE: + break; + + case CTDB_CONTROL_STOP_NODE: + break; + + case CTDB_CONTROL_CONTINUE_NODE: + break; + + case CTDB_CONTROL_SET_NATGWSTATE: + break; + + case CTDB_CONTROL_SET_LMASTERROLE: + break; + + case CTDB_CONTROL_SET_RECMASTERROLE: + break; + + case CTDB_CONTROL_ENABLE_SCRIPT: + break; + + case CTDB_CONTROL_DISABLE_SCRIPT: + break; + + case CTDB_CONTROL_SET_BAN_STATE: + break; + + case CTDB_CONTROL_GET_BAN_STATE: + verify_ctdb_ban_state(cd->data.ban_state, cd2->data.ban_state); + break; + + case CTDB_CONTROL_SET_DB_PRIORITY: + break; + + case CTDB_CONTROL_GET_DB_PRIORITY: + break; + + case CTDB_CONTROL_TRANSACTION_CANCEL: + break; + + case CTDB_CONTROL_REGISTER_NOTIFY: + break; + + case CTDB_CONTROL_DEREGISTER_NOTIFY: + break; + + case CTDB_CONTROL_TRANS3_COMMIT: + break; + + case CTDB_CONTROL_GET_DB_SEQNUM: + assert(cd->data.seqnum == cd2->data.seqnum); + break; + + case CTDB_CONTROL_DB_SET_HEALTHY: + break; + + case CTDB_CONTROL_DB_GET_HEALTH: + verify_ctdb_string(cd->data.reason, cd2->data.reason); + break; + + case CTDB_CONTROL_GET_PUBLIC_IP_INFO: + verify_ctdb_public_ip_info(cd->data.ipinfo, cd2->data.ipinfo); + break; + + case CTDB_CONTROL_GET_IFACES: + verify_ctdb_iface_list(cd->data.iface_list, + cd2->data.iface_list); + break; + + case CTDB_CONTROL_SET_IFACE_LINK_STATE: + break; + + case CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE: + break; + + case CTDB_CONTROL_GET_STAT_HISTORY: + verify_ctdb_statistics_list(cd->data.stats_list, + cd2->data.stats_list); + break; + + case CTDB_CONTROL_SCHEDULE_FOR_DELETION: + break; + + case CTDB_CONTROL_SET_DB_READONLY: + break; + + case CTDB_CONTROL_CHECK_SRVIDS: + verify_ctdb_uint8_array(cd->data.u8_array, cd2->data.u8_array); + break; + + case CTDB_CONTROL_TRAVERSE_START_EXT: + break; + + case CTDB_CONTROL_GET_DB_STATISTICS: + verify_ctdb_db_statistics(cd->data.dbstats, cd2->data.dbstats); + break; + + case CTDB_CONTROL_SET_DB_STICKY: + break; + + case CTDB_CONTROL_RELOAD_PUBLIC_IPS: + break; + + case CTDB_CONTROL_TRAVERSE_ALL_EXT: + break; + + case CTDB_CONTROL_RECEIVE_RECORDS: + verify_ctdb_rec_buffer(cd->data.recbuf, cd2->data.recbuf); + break; + + case CTDB_CONTROL_IPREALLOCATED: + break; + + case CTDB_CONTROL_GET_RUNSTATE: + assert(cd->data.runstate == cd2->data.runstate); + break; + + case CTDB_CONTROL_DB_DETACH: + break; + + case CTDB_CONTROL_GET_NODES_FILE: + verify_ctdb_node_map(cd->data.nodemap, cd2->data.nodemap); + break; + + } +} + +static void fill_ctdb_reply_control(TALLOC_CTX *mem_ctx, + struct ctdb_reply_control *c, + uint32_t opcode) +{ + c->status = -rand_int(2); + if (c->status == 0) { + c->errmsg = NULL; + fill_ctdb_reply_control_data(mem_ctx, &c->rdata, opcode); + } else { + fill_ctdb_string(mem_ctx, &c->errmsg); + } +} + +static void verify_ctdb_reply_control(struct ctdb_reply_control *c, + struct ctdb_reply_control *c2) +{ + assert(c->status == c2->status); + verify_ctdb_string(c->errmsg, c2->errmsg); + if (c->status == 0) { + verify_ctdb_reply_control_data(&c->rdata, &c2->rdata); + } +} + +static void fill_ctdb_req_message_data(TALLOC_CTX *mem_ctx, + struct ctdb_req_message_data *c) +{ + c->srvid = rand64(); + fill_tdb_data(mem_ctx, &c->data); +} + +static void verify_ctdb_req_message_data(struct ctdb_req_message_data *c, + struct ctdb_req_message_data *c2) +{ + assert(c->srvid == c2->srvid); + verify_tdb_data(&c->data, &c2->data); +} + +/* + * Functions to test marshalling + */ + +static void test_ctdb_req_header(void) +{ + TALLOC_CTX *mem_ctx; + uint8_t *pkt; + size_t pkt_len; + struct ctdb_req_header *h, h2; + int ret; + + printf("ctdb_req_header\n"); + fflush(stdout); + + mem_ctx = talloc_new(NULL); + assert(mem_ctx != NULL); + + ret = allocate_pkt(mem_ctx, sizeof(struct ctdb_req_header), + &pkt, &pkt_len); + assert(ret == 0); + + h = (struct ctdb_req_header *)pkt; + ctdb_req_header_fill(h, GENERATION, OPERATION, DESTNODE, SRCNODE, + REQID); + + ret = ctdb_req_header_pull(pkt, pkt_len, &h2); + assert(ret == 0); + + verify_ctdb_req_header(h, &h2); + + talloc_free(mem_ctx); +} + +static void test_req_call_test(void) +{ + TALLOC_CTX *mem_ctx; + uint8_t *pkt; + size_t pkt_len; + int ret; + struct ctdb_req_header h, h2; + struct ctdb_req_call c, c2; + + printf("ctdb_req_call\n"); + fflush(stdout); + + mem_ctx = talloc_new(NULL); + assert(mem_ctx != NULL); + + ctdb_req_header_fill(&h, GENERATION, CTDB_REQ_CALL, + DESTNODE, SRCNODE, REQID); + + fill_ctdb_req_call(mem_ctx, &c); + ret = ctdb_req_call_push(&h, &c, mem_ctx, &pkt, &pkt_len); + assert(ret == 0); + ret = ctdb_req_call_pull(pkt, pkt_len, &h2, mem_ctx, &c2); + assert(ret == 0); + verify_ctdb_req_header(&h, &h2); + verify_ctdb_req_call(&c, &c2); + + talloc_free(mem_ctx); +} + +static void test_reply_call_test(void) +{ + TALLOC_CTX *mem_ctx; + uint8_t *pkt; + size_t pkt_len; + int ret; + struct ctdb_req_header h, h2; + struct ctdb_reply_call c, c2; + + printf("ctdb_reply_call\n"); + fflush(stdout); + + mem_ctx = talloc_new(NULL); + assert(mem_ctx != NULL); + + ctdb_req_header_fill(&h, GENERATION, CTDB_REPLY_CALL, + DESTNODE, SRCNODE, REQID); + + fill_ctdb_reply_call(mem_ctx, &c); + ret = ctdb_reply_call_push(&h, &c, mem_ctx, &pkt, &pkt_len); + assert(ret == 0); + ret = ctdb_reply_call_pull(pkt, pkt_len, &h2, mem_ctx, &c2); + assert(ret == 0); + verify_ctdb_req_header(&h, &h2); + verify_ctdb_reply_call(&c, &c2); + + talloc_free(mem_ctx); +} + +static void test_reply_error_test(void) +{ + TALLOC_CTX *mem_ctx; + uint8_t *pkt; + size_t pkt_len; + int ret; + struct ctdb_req_header h, h2; + struct ctdb_reply_error c, c2; + + printf("ctdb_reply_error\n"); + fflush(stdout); + + mem_ctx = talloc_new(NULL); + assert(mem_ctx != NULL); + + ctdb_req_header_fill(&h, GENERATION, CTDB_REPLY_ERROR, + DESTNODE, SRCNODE, REQID); + + fill_ctdb_reply_error(mem_ctx, &c); + ret = ctdb_reply_error_push(&h, &c, mem_ctx, &pkt, &pkt_len); + assert(ret == 0); + ret = ctdb_reply_error_pull(pkt, pkt_len, &h2, mem_ctx, &c2); + assert(ret == 0); + verify_ctdb_req_header(&h, &h2); + verify_ctdb_reply_error(&c, &c2); + + talloc_free(mem_ctx); +} + +static void test_req_dmaster_test(void) +{ + TALLOC_CTX *mem_ctx; + uint8_t *pkt; + size_t pkt_len; + int ret; + struct ctdb_req_header h, h2; + struct ctdb_req_dmaster c, c2; + + printf("ctdb_req_dmaster\n"); + fflush(stdout); + + mem_ctx = talloc_new(NULL); + assert(mem_ctx != NULL); + + ctdb_req_header_fill(&h, GENERATION, CTDB_REQ_DMASTER, + DESTNODE, SRCNODE, REQID); + + fill_ctdb_req_dmaster(mem_ctx, &c); + ret = ctdb_req_dmaster_push(&h, &c, mem_ctx, &pkt, &pkt_len); + assert(ret == 0); + ret = ctdb_req_dmaster_pull(pkt, pkt_len, &h2, mem_ctx, &c2); + assert(ret == 0); + verify_ctdb_req_header(&h, &h2); + verify_ctdb_req_dmaster(&c, &c2); + + talloc_free(mem_ctx); +} + +static void test_reply_dmaster_test(void) +{ + TALLOC_CTX *mem_ctx; + uint8_t *pkt; + size_t pkt_len; + int ret; + struct ctdb_req_header h, h2; + struct ctdb_reply_dmaster c, c2; + + printf("ctdb_reply_dmaster\n"); + fflush(stdout); + + mem_ctx = talloc_new(NULL); + assert(mem_ctx != NULL); + + ctdb_req_header_fill(&h, GENERATION, CTDB_REPLY_DMASTER, + DESTNODE, SRCNODE, REQID); + + fill_ctdb_reply_dmaster(mem_ctx, &c); + ret = ctdb_reply_dmaster_push(&h, &c, mem_ctx, &pkt, &pkt_len); + assert(ret == 0); + ret = ctdb_reply_dmaster_pull(pkt, pkt_len, &h2, mem_ctx, &c2); + assert(ret == 0); + verify_ctdb_req_header(&h, &h2); + verify_ctdb_reply_dmaster(&c, &c2); + + talloc_free(mem_ctx); +} + +#define NUM_CONTROLS 141 + +static void test_req_control_data_test(void) +{ + TALLOC_CTX *mem_ctx; + size_t buflen; + int ret; + struct ctdb_req_control_data cd, cd2; + uint32_t opcode; + + printf("ctdb_req_control_data\n"); + fflush(stdout); + + for (opcode=0; opcode. +*/ + +#include "replace.h" +#include "system/network.h" + +#include + +#include "protocol/protocol_types.c" +#include "protocol/protocol_header.c" +#include "protocol/protocol_call.c" +#include "protocol/protocol_control.c" +#include "protocol/protocol_message.c" +#include "protocol/protocol_packet.c" + +uint8_t BUFFER[1024*1024]; + +/* + * Functions to generation random data + */ + +static int rand_int(int max) +{ + return random() % max; +} + +static uint8_t rand8(void) +{ + uint8_t val = rand_int(256) & 0xff; + return val; +} + +static uint32_t rand32(void) +{ + return random(); +} + +static uint64_t rand64(void) +{ + uint64_t t = random(); + t = (t << 32) | random(); + return t; +} + +static double rand_double(void) +{ + return 1.0 / rand64(); +} + +static void fill_buffer(void *p, size_t len) +{ + int i; + uint8_t *ptr = p; + + for (i=0; i 0) { + assert(memcmp(p1, p2, len) == 0); + } +} + +/* + * Functions to fill and verify data types + */ + +static void fill_tdb_data(TALLOC_CTX *mem_ctx, TDB_DATA *p) +{ + p->dsize = rand_int(1024) + 1; + p->dptr = talloc_array(mem_ctx, uint8_t, p->dsize); + assert(p->dptr != NULL); + fill_buffer(p->dptr, p->dsize); +} + +static void verify_tdb_data(TDB_DATA *p1, TDB_DATA *p2) +{ + assert(p1->dsize == p2->dsize); + verify_buffer(p1->dptr, p2->dptr, p1->dsize); +} + +static void fill_ctdb_statistics(TALLOC_CTX *mem_ctx, struct ctdb_statistics *p) +{ + fill_buffer((uint8_t *)p, sizeof(struct ctdb_statistics)); +} + +static void verify_ctdb_statistics(struct ctdb_statistics *p1, + struct ctdb_statistics *p2) +{ + verify_buffer(p1, p2, sizeof(struct ctdb_statistics)); +} + +static void fill_ctdb_vnn_map(TALLOC_CTX *mem_ctx, struct ctdb_vnn_map *p) +{ + int i; + + p->generation = rand32(); + p->size = rand_int(20) + 1; + p->map = talloc_array(mem_ctx, uint32_t, p->size); + assert(p->map != NULL); + + for (i=0; isize; i++) { + p->map[i] = rand32(); + } +} + +static void verify_ctdb_vnn_map(struct ctdb_vnn_map *p1, + struct ctdb_vnn_map *p2) +{ + int i; + + assert(p1->generation == p2->generation); + assert(p1->size == p2->size); + for (i=0; isize; i++) { + assert(p1->map[i] == p2->map[i]); + } +} + +static void fill_ctdb_dbid(TALLOC_CTX *mem_ctx, struct ctdb_dbid *p) +{ + p->db_id = rand32(); + p->flags = rand8(); +} + +static void verify_ctdb_dbid(struct ctdb_dbid *p1, struct ctdb_dbid *p2) +{ + assert(p1->db_id == p2->db_id); + assert(p1->flags == p2->flags); +} + +static void fill_ctdb_dbid_map(TALLOC_CTX *mem_ctx, struct ctdb_dbid_map *p) +{ + int i; + + p->num = rand_int(40) + 1; + p->dbs = talloc_array(mem_ctx, struct ctdb_dbid, p->num); + assert(p->dbs != NULL); + for (i=0; inum; i++) { + fill_ctdb_dbid(mem_ctx, &p->dbs[i]); + } +} + +static void verify_ctdb_dbid_map(struct ctdb_dbid_map *p1, + struct ctdb_dbid_map *p2) +{ + int i; + + assert(p1->num == p2->num); + for (i=0; inum; i++) { + verify_ctdb_dbid(&p1->dbs[i], &p2->dbs[i]); + } +} + +static void fill_ctdb_pulldb(TALLOC_CTX *mem_ctx, struct ctdb_pulldb *p) +{ + p->db_id = rand32(); + p->lmaster = rand32(); +} + +static void verify_ctdb_pulldb(struct ctdb_pulldb *p1, struct ctdb_pulldb *p2) +{ + assert(p1->db_id == p2->db_id); + assert(p1->lmaster == p2->lmaster); +} + +static void fill_ctdb_ltdb_header(TALLOC_CTX *mem_ctx, + struct ctdb_ltdb_header *p) +{ + p->rsn = rand64(); + p->dmaster = rand32(); + p->flags = rand32(); +} + +static void verify_ctdb_ltdb_header(struct ctdb_ltdb_header *p1, + struct ctdb_ltdb_header *p2) +{ + assert(p1->rsn == p2->rsn); + assert(p1->dmaster == p2->dmaster); + assert(p1->flags == p2->flags); +} + +static void fill_ctdb_rec_data(TALLOC_CTX *mem_ctx, struct ctdb_rec_data *p) +{ + p->reqid = rand32(); + if (p->reqid % 5 == 0) { + p->header = talloc(mem_ctx, struct ctdb_ltdb_header); + assert(p->header != NULL); + fill_ctdb_ltdb_header(mem_ctx, p->header); + } else { + p->header = NULL; + } + fill_tdb_data(mem_ctx, &p->key); + fill_tdb_data(mem_ctx, &p->data); +} + +static void verify_ctdb_rec_data(struct ctdb_rec_data *p1, + struct ctdb_rec_data *p2) +{ + assert(p1->reqid == p2->reqid); + if (p1->header == NULL || p2->header == NULL) { + assert(p1->header == p2->header); + } else { + verify_ctdb_ltdb_header(p1->header, p2->header); + } + verify_tdb_data(&p1->key, &p2->key); + verify_tdb_data(&p1->data, &p2->data); +} + +static void fill_ctdb_rec_buffer(TALLOC_CTX *mem_ctx, struct ctdb_rec_buffer *p) +{ + struct ctdb_rec_data rec; + int ret, i; + int count; + + p->db_id = rand32(); + p->count = 0; + p->buf = NULL; + p->buflen = 0; + + count = rand_int(100) + 1; + for (i=0; idb_id == p2->db_id); + assert(p1->count == p2->count); + assert(p1->buflen == p2->buflen); + verify_buffer(p1->buf, p2->buf, p1->buflen); +} + +static void fill_ctdb_traverse_start(TALLOC_CTX *mem_ctx, + struct ctdb_traverse_start *p) +{ + p->db_id = rand32(); + p->reqid = rand32(); + p->srvid = rand64(); +} + +static void verify_ctdb_traverse_start(struct ctdb_traverse_start *p1, + struct ctdb_traverse_start *p2) +{ + assert(p1->db_id == p2->db_id); + assert(p1->reqid == p2->reqid); + assert(p1->srvid == p2->srvid); +} + +static void fill_ctdb_traverse_all(TALLOC_CTX *mem_ctx, + struct ctdb_traverse_all *p) +{ + p->db_id = rand32(); + p->reqid = rand32(); + p->pnn = rand32(); + p->client_reqid = rand32(); + p->srvid = rand64(); +} + +static void verify_ctdb_traverse_all(struct ctdb_traverse_all *p1, + struct ctdb_traverse_all *p2) +{ + assert(p1->db_id == p2->db_id); + assert(p1->reqid == p2->reqid); + assert(p1->pnn == p2->pnn); + assert(p1->client_reqid == p2->client_reqid); + assert(p1->srvid == p2->srvid); +} + +static void fill_ctdb_traverse_start_ext(TALLOC_CTX *mem_ctx, + struct ctdb_traverse_start_ext *p) +{ + p->db_id = rand32(); + p->reqid = rand32(); + p->srvid = rand64(); + p->withemptyrecords = rand_int(2); +} + +static void verify_ctdb_traverse_start_ext(struct ctdb_traverse_start_ext *p1, + struct ctdb_traverse_start_ext *p2) +{ + assert(p1->db_id == p2->db_id); + assert(p1->reqid == p2->reqid); + assert(p1->srvid == p2->srvid); + assert(p1->withemptyrecords == p2->withemptyrecords); +} + +static void fill_ctdb_traverse_all_ext(TALLOC_CTX *mem_ctx, + struct ctdb_traverse_all_ext *p) +{ + p->db_id = rand32(); + p->reqid = rand32(); + p->pnn = rand32(); + p->client_reqid = rand32(); + p->srvid = rand64(); + p->withemptyrecords = rand_int(2); +} + +static void verify_ctdb_traverse_all_ext(struct ctdb_traverse_all_ext *p1, + struct ctdb_traverse_all_ext *p2) +{ + assert(p1->db_id == p2->db_id); + assert(p1->reqid == p2->reqid); + assert(p1->pnn == p2->pnn); + assert(p1->client_reqid == p2->client_reqid); + assert(p1->srvid == p2->srvid); + assert(p1->withemptyrecords == p2->withemptyrecords); +} + +static void fill_ctdb_sock_addr(TALLOC_CTX *mem_ctx, ctdb_sock_addr *p) +{ + if (rand_int(2) == 0) { + p->ip.sin_family = AF_INET; + p->ip.sin_port = rand_int(65535); + fill_buffer(&p->ip.sin_addr, sizeof(struct in_addr)); + } else { + p->ip6.sin6_family = AF_INET6; + p->ip6.sin6_port = rand_int(65535); + fill_buffer(&p->ip6.sin6_addr, sizeof(struct in6_addr)); + } +} + +static void verify_ctdb_sock_addr(ctdb_sock_addr *p1, ctdb_sock_addr *p2) +{ + assert(p1->sa.sa_family == p2->sa.sa_family); + if (p1->sa.sa_family == AF_INET) { + assert(p1->ip.sin_port == p2->ip.sin_port); + verify_buffer(&p1->ip.sin_addr, &p2->ip.sin_addr, + sizeof(struct in_addr)); + } else { + assert(p1->ip6.sin6_port == p2->ip6.sin6_port); + verify_buffer(&p1->ip6.sin6_addr, &p2->ip6.sin6_addr, + sizeof(struct in6_addr)); + } +} + +static void fill_ctdb_connection(TALLOC_CTX *mem_ctx, + struct ctdb_connection *p) +{ + fill_ctdb_sock_addr(mem_ctx, &p->src); + fill_ctdb_sock_addr(mem_ctx, &p->dst); +} + +static void verify_ctdb_connection(struct ctdb_connection *p1, + struct ctdb_connection *p2) +{ + verify_ctdb_sock_addr(&p1->src, &p2->src); + verify_ctdb_sock_addr(&p1->dst, &p2->dst); +} + +static void fill_ctdb_string(TALLOC_CTX *mem_ctx, const char **out) +{ + char *p; + int len, i; + + len = rand_int(1024) + 1; + p = talloc_size(mem_ctx, len+1); + assert(p != NULL); + + for (i=0; iname)); + p->value = rand32(); +} + +static void verify_ctdb_tunable(struct ctdb_tunable *p1, + struct ctdb_tunable *p2) +{ + verify_ctdb_string(discard_const(p1->name), discard_const(p2->name)); + assert(p1->value == p2->value); +} + +static void fill_ctdb_node_flag_change(TALLOC_CTX *mem_ctx, + struct ctdb_node_flag_change *p) +{ + p->pnn = rand32(); + p->new_flags = rand32(); + p->old_flags = rand32(); +} + +static void verify_ctdb_node_flag_change(struct ctdb_node_flag_change *p1, + struct ctdb_node_flag_change *p2) +{ + assert(p1->pnn == p2->pnn); + assert(p1->new_flags == p2->new_flags); + assert(p1->old_flags == p2->old_flags); +} + +static void fill_ctdb_var_list(TALLOC_CTX *mem_ctx, + struct ctdb_var_list *p) +{ + int i; + + p->count = rand_int(100) + 1; + p->var = talloc_array(mem_ctx, const char *, p->count); + for (i=0; icount; i++) { + fill_ctdb_string(p->var, discard_const(&p->var[i])); + } +} + +static void verify_ctdb_var_list(struct ctdb_var_list *p1, + struct ctdb_var_list *p2) +{ + int i; + + assert(p1->count == p2->count); + for (i=0; icount; i++) { + verify_ctdb_string(discard_const(p1->var[i]), + discard_const(p2->var[i])); + } +} + +static void fill_ctdb_tunable_list(TALLOC_CTX *mem_ctx, + struct ctdb_tunable_list *p) +{ + fill_buffer(p, sizeof(struct ctdb_tunable_list)); +} + +static void verify_ctdb_tunable_list(struct ctdb_tunable_list *p1, + struct ctdb_tunable_list *p2) +{ + verify_buffer(p1, p2, sizeof(struct ctdb_tunable_list)); +} + +static void fill_ctdb_tickle_list(TALLOC_CTX *mem_ctx, + struct ctdb_tickle_list *p) +{ + int i; + + fill_ctdb_sock_addr(mem_ctx, &p->addr); + p->num = rand_int(1000) + 1; + p->conn = talloc_array(mem_ctx, struct ctdb_connection, p->num); + assert(p->conn != NULL); + for (i=0; inum; i++) { + fill_ctdb_connection(mem_ctx, &p->conn[i]); + } +} + +static void verify_ctdb_tickle_list(struct ctdb_tickle_list *p1, + struct ctdb_tickle_list *p2) +{ + int i; + + verify_ctdb_sock_addr(&p1->addr, &p2->addr); + assert(p1->num == p2->num); + for (i=0; inum; i++) { + verify_ctdb_connection(&p1->conn[i], &p2->conn[i]); + } +} + +static void fill_ctdb_client_id(TALLOC_CTX *mem_ctx, + struct ctdb_client_id *p) +{ + p->type = rand8(); + p->pnn = rand32(); + p->server_id = rand32(); +} + +static void verify_ctdb_client_id(struct ctdb_client_id *p1, + struct ctdb_client_id *p2) +{ + assert(p1->type == p2->type); + assert(p1->pnn == p2->pnn); + assert(p1->server_id == p2->server_id); +} + +static void fill_ctdb_client_id_list(TALLOC_CTX *mem_ctx, + struct ctdb_client_id_list *p) +{ + int i; + + p->num = rand_int(1000) + 1; + p->cid = talloc_array(mem_ctx, struct ctdb_client_id, p->num); + assert(p->cid != NULL); + for (i=0; inum; i++) { + fill_ctdb_client_id(mem_ctx, &p->cid[i]); + } +} + +static void verify_ctdb_client_id_list(struct ctdb_client_id_list *p1, + struct ctdb_client_id_list *p2) +{ + int i; + + assert(p1->num == p2->num); + for (i=0; inum; i++) { + verify_ctdb_client_id(&p1->cid[i], &p2->cid[i]); + } +} + +static void fill_ctdb_client_id_map(TALLOC_CTX *mem_ctx, + struct ctdb_client_id_map *p) +{ + int i; + + p->count = rand_int(10) + 1; + p->list = talloc_array(mem_ctx, struct ctdb_client_id_list, p->count); + assert(p->list != NULL); + for (i=0; icount; i++) { + fill_ctdb_client_id_list(mem_ctx, &p->list[i]); + } +} + +static void verify_ctdb_client_id_map(struct ctdb_client_id_map *p1, + struct ctdb_client_id_map *p2) +{ + int i; + + assert(p1->count == p2->count); + for (i=0; icount; i++) { + verify_ctdb_client_id_list(&p1->list[i], &p2->list[i]); + } +} + +static void fill_ctdb_addr_info(TALLOC_CTX *mem_ctx, struct ctdb_addr_info *p) +{ + fill_ctdb_sock_addr(mem_ctx, &p->addr); + p->mask = rand_int(33); + fill_ctdb_string(mem_ctx, &p->iface); +} + +static void verify_ctdb_addr_info(struct ctdb_addr_info *p1, + struct ctdb_addr_info *p2) +{ + verify_ctdb_sock_addr(&p1->addr, &p2->addr); + assert(p1->mask == p2->mask); + verify_ctdb_string(p1->iface, p2->iface); +} + +static void fill_ctdb_transdb(TALLOC_CTX *mem_ctx, struct ctdb_transdb *p) +{ + p->db_id = rand32(); + p->tid = rand32(); +} + +static void verify_ctdb_transdb(struct ctdb_transdb *p1, struct ctdb_transdb *p2) +{ + assert(p1->db_id == p2->db_id); + assert(p1->tid == p2->tid); +} + +static void fill_ctdb_uptime(TALLOC_CTX *mem_ctx, struct ctdb_uptime *p) +{ + fill_buffer(p, sizeof(struct ctdb_uptime)); +} + +static void verify_ctdb_uptime(struct ctdb_uptime *p1, struct ctdb_uptime *p2) +{ + verify_buffer(p1, p2, sizeof(struct ctdb_uptime)); +} + +static void fill_ctdb_public_ip(TALLOC_CTX *mem_ctx, struct ctdb_public_ip *p) +{ + p->pnn = rand32(); + fill_ctdb_sock_addr(mem_ctx, &p->addr); +} + +static void verify_ctdb_public_ip(struct ctdb_public_ip *p1, + struct ctdb_public_ip *p2) +{ + assert(p1->pnn == p2->pnn); + verify_ctdb_sock_addr(&p1->addr, &p2->addr); +} + +static void fill_ctdb_public_ip_list(TALLOC_CTX *mem_ctx, + struct ctdb_public_ip_list *p) +{ + int i; + + p->num = rand_int(32) + 1; + p->ip = talloc_array(mem_ctx, struct ctdb_public_ip, p->num); + assert(p->ip != NULL); + for (i=0; inum; i++) { + fill_ctdb_public_ip(mem_ctx, &p->ip[i]); + } +} + +static void verify_ctdb_public_ip_list(struct ctdb_public_ip_list *p1, + struct ctdb_public_ip_list *p2) +{ + int i; + + assert(p1->num == p2->num); + for (i=0; inum; i++) { + verify_ctdb_public_ip(&p1->ip[i], &p2->ip[i]); + } +} + +static void fill_ctdb_node_and_flags(TALLOC_CTX *mem_ctx, + struct ctdb_node_and_flags *p) +{ + p->pnn = rand32(); + p->flags = rand32(); + fill_ctdb_sock_addr(mem_ctx, &p->addr); +} + +static void verify_ctdb_node_and_flags(struct ctdb_node_and_flags *p1, + struct ctdb_node_and_flags *p2) +{ + assert(p1->pnn == p2->pnn); + assert(p1->flags == p2->flags); + verify_ctdb_sock_addr(&p1->addr, &p2->addr); +} + +static void fill_ctdb_node_map(TALLOC_CTX *mem_ctx, struct ctdb_node_map *p) +{ + int i; + + p->num = rand_int(32) + 1; + p->node = talloc_array(mem_ctx, struct ctdb_node_and_flags, p->num); + assert(p->node != NULL); + for (i=0; inum; i++) { + fill_ctdb_node_and_flags(mem_ctx, &p->node[i]); + } +} + +static void verify_ctdb_node_map(struct ctdb_node_map *p1, + struct ctdb_node_map *p2) +{ + int i; + + assert(p1->num == p2->num); + for (i=0; inum; i++) { + verify_ctdb_node_and_flags(&p1->node[i], &p2->node[i]); + } +} + +static void fill_ctdb_script(TALLOC_CTX *mem_ctx, struct ctdb_script *p) +{ + fill_buffer(p, sizeof(struct ctdb_script)); +} + +static void verify_ctdb_script(struct ctdb_script *p1, struct ctdb_script *p2) +{ + verify_buffer(p1, p2, sizeof(struct ctdb_script)); +} + +static void fill_ctdb_script_list(TALLOC_CTX *mem_ctx, + struct ctdb_script_list *p) +{ + int i; + + p->num_scripts = rand_int(32) + 1; + p->script = talloc_array(mem_ctx, struct ctdb_script, p->num_scripts); + assert(p->script != NULL); + for (i=0; inum_scripts; i++) { + fill_ctdb_script(mem_ctx, &p->script[i]); + } +} + +static void verify_ctdb_script_list(struct ctdb_script_list *p1, + struct ctdb_script_list *p2) +{ + int i; + + assert(p1->num_scripts == p2->num_scripts); + for (i=0; inum_scripts; i++) { + verify_ctdb_script(&p1->script[i], &p2->script[i]); + } +} + +static void fill_ctdb_ban_state(TALLOC_CTX *mem_ctx, struct ctdb_ban_state *p) +{ + p->pnn = rand32(); + p->time = rand32(); +} + +static void verify_ctdb_ban_state(struct ctdb_ban_state *p1, + struct ctdb_ban_state *p2) +{ + assert(p1->pnn == p2->pnn); + assert(p1->time == p2->time); +} + +static void fill_ctdb_db_priority(TALLOC_CTX *mem_ctx, + struct ctdb_db_priority *p) +{ + p->db_id = rand32(); + p->priority = rand32(); +} + +static void verify_ctdb_db_priority(struct ctdb_db_priority *p1, + struct ctdb_db_priority *p2) +{ + assert(p1->db_id == p2->db_id); + assert(p1->priority == p2->priority); +} + +static void fill_ctdb_notify_data(TALLOC_CTX *mem_ctx, + struct ctdb_notify_data *p) +{ + p->srvid = rand64(); + fill_tdb_data(mem_ctx, &p->data); +} + +static void verify_ctdb_notify_data(struct ctdb_notify_data *p1, + struct ctdb_notify_data *p2) +{ + assert(p1->srvid == p2->srvid); + verify_tdb_data(&p1->data, &p2->data); +} + +static void fill_ctdb_iface(TALLOC_CTX *mem_ctx, struct ctdb_iface *p) +{ + fill_buffer(p, sizeof(struct ctdb_iface)); +} + +static void verify_ctdb_iface(struct ctdb_iface *p1, struct ctdb_iface *p2) +{ + verify_buffer(p1, p2, sizeof(struct ctdb_iface)); +} + +static void fill_ctdb_iface_list(TALLOC_CTX *mem_ctx, + struct ctdb_iface_list *p) +{ + int i; + + p->num = rand_int(32) + 1; + p->iface = talloc_array(mem_ctx, struct ctdb_iface, p->num); + assert(p->iface != NULL); + for (i=0; inum; i++) { + fill_ctdb_iface(mem_ctx, &p->iface[i]); + } +} + +static void verify_ctdb_iface_list(struct ctdb_iface_list *p1, + struct ctdb_iface_list *p2) +{ + int i; + + assert(p1->num == p2->num); + for (i=0; inum; i++) { + verify_ctdb_iface(&p1->iface[i], &p2->iface[i]); + } +} + +static void fill_ctdb_public_ip_info(TALLOC_CTX *mem_ctx, + struct ctdb_public_ip_info *p) +{ + fill_ctdb_public_ip(mem_ctx, &p->ip); + p->active_idx = rand_int(32) + 1; + p->ifaces = talloc(mem_ctx, struct ctdb_iface_list); + assert(p->ifaces != NULL); + fill_ctdb_iface_list(mem_ctx, p->ifaces); +} + +static void verify_ctdb_public_ip_info(struct ctdb_public_ip_info *p1, + struct ctdb_public_ip_info *p2) +{ + verify_ctdb_public_ip(&p1->ip, &p2->ip); + assert(p1->active_idx == p2->active_idx); + verify_ctdb_iface_list(p1->ifaces, p2->ifaces); +} + +static void fill_ctdb_statistics_list(TALLOC_CTX *mem_ctx, + struct ctdb_statistics_list *p) +{ + int i; + + p->num = rand_int(10) + 1; + p->stats = talloc_array(mem_ctx, struct ctdb_statistics, p->num); + assert(p->stats != NULL); + + for (i=0; inum; i++) { + fill_ctdb_statistics(mem_ctx, &p->stats[i]); + } +} + +static void verify_ctdb_statistics_list(struct ctdb_statistics_list *p1, + struct ctdb_statistics_list *p2) +{ + int i; + + assert(p1->num == p2->num); + for (i=0; inum; i++) { + verify_ctdb_statistics(&p1->stats[i], &p2->stats[i]); + } +} + +static void fill_ctdb_key_data(TALLOC_CTX *mem_ctx, struct ctdb_key_data *p) +{ + p->db_id = rand32(); + fill_ctdb_ltdb_header(mem_ctx, &p->header); + fill_tdb_data(mem_ctx, &p->key); +} + +static void verify_ctdb_key_data(struct ctdb_key_data *p1, + struct ctdb_key_data *p2) +{ + assert(p1->db_id == p2->db_id); + verify_ctdb_ltdb_header(&p1->header, &p2->header); + verify_tdb_data(&p1->key, &p2->key); +} + +static void fill_ctdb_uint8_array(TALLOC_CTX *mem_ctx, + struct ctdb_uint8_array *p) +{ + int i; + + p->num = rand_int(1024) + 1; + p->val = talloc_array(mem_ctx, uint8_t, p->num); + assert(p->val != NULL); + + for (i=0; inum; i++) { + p->val[i] = rand8(); + } +} + +static void verify_ctdb_uint8_array(struct ctdb_uint8_array *p1, + struct ctdb_uint8_array *p2) +{ + int i; + + assert(p1->num == p2->num); + for (i=0; inum; i++) { + assert(p1->val[i] == p2->val[i]); + } +} + +static void fill_ctdb_uint64_array(TALLOC_CTX *mem_ctx, + struct ctdb_uint64_array *p) +{ + int i; + + p->num = rand_int(1024) + 1; + p->val = talloc_array(mem_ctx, uint64_t, p->num); + assert(p->val != NULL); + + for (i=0; inum; i++) { + p->val[i] = rand64(); + } +} + +static void verify_ctdb_uint64_array(struct ctdb_uint64_array *p1, + struct ctdb_uint64_array *p2) +{ + int i; + + assert(p1->num == p2->num); + for (i=0; inum; i++) { + assert(p1->val[i] == p2->val[i]); + } +} + +static void fill_ctdb_db_statistics(TALLOC_CTX *mem_ctx, + struct ctdb_db_statistics *p) +{ + int i; + + fill_buffer(p, offsetof(struct ctdb_db_statistics, num_hot_keys)); + p->num_hot_keys = 10; + for (i=0; inum_hot_keys; i++) { + p->hot_keys[i].count = rand32(); + fill_tdb_data(mem_ctx, &p->hot_keys[i].key); + } +} + +static void verify_ctdb_db_statistics(struct ctdb_db_statistics *p1, + struct ctdb_db_statistics *p2) +{ + int i; + + verify_buffer(p1, p2, offsetof(struct ctdb_db_statistics, + num_hot_keys)); + assert(p1->num_hot_keys == p2->num_hot_keys); + for (i=0; inum_hot_keys; i++) { + assert(p1->hot_keys[i].count == p2->hot_keys[i].count); + verify_tdb_data(&p1->hot_keys[i].key, &p2->hot_keys[i].key); + } +} + +#ifndef PROTOCOL_TEST + +static void fill_ctdb_election_message(TALLOC_CTX *mem_ctx, + struct ctdb_election_message *p) +{ + p->num_connected = rand_int(32); + fill_buffer(&p->priority_time, sizeof(struct timeval)); + p->pnn = rand_int(32); + p->node_flags = rand32(); +} + +static void verify_ctdb_election_message(struct ctdb_election_message *p1, + struct ctdb_election_message *p2) +{ + assert(p1->num_connected == p2->num_connected); + verify_buffer(p1, p2, sizeof(struct timeval)); + assert(p1->pnn == p2->pnn); + assert(p1->node_flags == p2->node_flags); +} + +static void fill_ctdb_srvid_message(TALLOC_CTX *mem_ctx, + struct ctdb_srvid_message *p) +{ + p->pnn = rand_int(32); + p->srvid = rand64(); +} + +static void verify_ctdb_srvid_message(struct ctdb_srvid_message *p1, + struct ctdb_srvid_message *p2) +{ + assert(p1->pnn == p2->pnn); + assert(p1->srvid == p2->srvid); +} + +static void fill_ctdb_disable_message(TALLOC_CTX *mem_ctx, + struct ctdb_disable_message *p) +{ + p->pnn = rand_int(32); + p->srvid = rand64(); + p->timeout = rand32(); +} + +static void verify_ctdb_disable_message(struct ctdb_disable_message *p1, + struct ctdb_disable_message *p2) +{ + assert(p1->pnn == p2->pnn); + assert(p1->srvid == p2->srvid); + assert(p1->timeout == p2->timeout); +} + +static void fill_ctdb_server_id(TALLOC_CTX *mem_ctx, + struct ctdb_server_id *p) +{ + p->pid = rand64(); + p->task_id = rand32(); + p->vnn = rand_int(32); + p->unique_id = rand64(); +} + +static void verify_ctdb_server_id(struct ctdb_server_id *p1, + struct ctdb_server_id *p2) +{ + assert(p1->pid == p2->pid); + assert(p1->task_id == p2->task_id); + assert(p1->vnn == p2->vnn); + assert(p1->unique_id == p2->unique_id); +} + +static void fill_ctdb_g_lock(TALLOC_CTX *mem_ctx, struct ctdb_g_lock *p) +{ + p->type = rand_int(2); + fill_ctdb_server_id(mem_ctx, &p->sid); +} + +static void verify_ctdb_g_lock(struct ctdb_g_lock *p1, struct ctdb_g_lock *p2) +{ + assert(p1->type == p2->type); + verify_ctdb_server_id(&p1->sid, &p2->sid); +} + +static void fill_ctdb_g_lock_list(TALLOC_CTX *mem_ctx, + struct ctdb_g_lock_list *p) +{ + int i; + + p->num = rand_int(20) + 1; + p->lock = talloc_array(mem_ctx, struct ctdb_g_lock, p->num); + assert(p->lock != NULL); + for (i=0; inum; i++) { + fill_ctdb_g_lock(mem_ctx, &p->lock[i]); + } +} + +static void verify_ctdb_g_lock_list(struct ctdb_g_lock_list *p1, + struct ctdb_g_lock_list *p2) +{ + int i; + + assert(p1->num == p2->num); + for (i=0; inum; i++) { + verify_ctdb_g_lock(&p1->lock[i], &p2->lock[i]); + } +} + +/* + * Functions to test marshalling routines + */ + +static void test_ctdb_uint32(void) +{ + uint32_t p1, p2; + size_t buflen; + int ret; + + p1 = rand32(); + buflen = ctdb_uint32_len(p1); + ctdb_uint32_push(p1, BUFFER); + ret = ctdb_uint32_pull(BUFFER, buflen, NULL, &p2); + assert(ret == 0); + assert(p1 == p2); +} + +static void test_ctdb_uint64(void) +{ + uint64_t p1, p2; + size_t buflen; + int ret; + + p1 = rand64(); + buflen = ctdb_uint64_len(p1); + ctdb_uint64_push(p1, BUFFER); + ret = ctdb_uint64_pull(BUFFER, buflen, NULL, &p2); + assert(ret == 0); + assert(p1 == p2); +} + +static void test_ctdb_double(void) +{ + double p1, p2; + size_t buflen; + int ret; + + p1 = rand_double(); + buflen = ctdb_double_len(p1); + ctdb_double_push(p1, BUFFER); + ret = ctdb_double_pull(BUFFER, buflen, NULL, &p2); + assert(ret == 0); + assert(p1 == p2); +} + +static void test_ctdb_pid(void) +{ + pid_t p1, p2; + size_t buflen; + int ret; + + p1 = rand32(); + buflen = ctdb_pid_len(p1); + ctdb_pid_push(p1, BUFFER); + ret = ctdb_pid_pull(BUFFER, buflen, NULL, &p2); + assert(ret == 0); + assert(p1 == p2); +} + +#define TEST_FUNC(NAME) test_ ##NAME +#define FILL_FUNC(NAME) fill_ ##NAME +#define VERIFY_FUNC(NAME) verify_ ##NAME +#define LEN_FUNC(NAME) NAME## _len +#define PUSH_FUNC(NAME) NAME## _push +#define PULL_FUNC(NAME) NAME## _pull + +#define DEFINE_TEST(TYPE, NAME) \ +static void TEST_FUNC(NAME)(void) \ +{ \ + TALLOC_CTX *mem_ctx = talloc_new(NULL); \ + TYPE *p1, *p2; \ + size_t buflen; \ + int ret; \ +\ + p1 = talloc_zero(mem_ctx, TYPE); \ + assert(p1 != NULL); \ + FILL_FUNC(NAME)(p1, p1); \ + buflen = LEN_FUNC(NAME)(p1); \ + PUSH_FUNC(NAME)(p1, BUFFER); \ + ret = PULL_FUNC(NAME)(BUFFER, buflen, mem_ctx, &p2); \ + assert(ret == 0); \ + VERIFY_FUNC(NAME)(p1, p2); \ + talloc_free(mem_ctx); \ +} + + +static void test_ctdb_string(void) +{ + TALLOC_CTX *mem_ctx = talloc_new(NULL); + const char *p1, *p2; + size_t buflen; + int ret; + + fill_ctdb_string(mem_ctx, &p1); + buflen = ctdb_string_len(p1); + ctdb_string_push(p1, BUFFER); + ret = ctdb_string_pull(BUFFER, buflen, mem_ctx, &p2); + assert(ret == 0); + verify_ctdb_string(p1, p2); + talloc_free(mem_ctx); +} + +static void test_ctdb_stringn(void) +{ + TALLOC_CTX *mem_ctx = talloc_new(NULL); + const char *p1, *p2; + size_t buflen; + int ret; + + fill_ctdb_string(mem_ctx, &p1); + buflen = ctdb_stringn_len(p1); + ctdb_stringn_push(p1, BUFFER); + ret = ctdb_stringn_pull(BUFFER, buflen, mem_ctx, &p2); + assert(ret == 0); + verify_ctdb_string(p1, p2); + talloc_free(mem_ctx); +} + +static void test_ctdb_ltdb_header(void) +{ + TALLOC_CTX *mem_ctx = talloc_new(NULL); + struct ctdb_ltdb_header p1, p2; + size_t buflen; + int ret; + + fill_ctdb_ltdb_header(mem_ctx, &p1); + buflen = ctdb_ltdb_header_len(&p1); + ctdb_ltdb_header_push(&p1, BUFFER); + ret = ctdb_ltdb_header_pull(BUFFER, buflen, &p2); + assert(ret == 0); + verify_ctdb_ltdb_header(&p1, &p2); + talloc_free(mem_ctx); +} + +static void test_ctdb_g_lock(void) +{ + TALLOC_CTX *mem_ctx = talloc_new(NULL); + struct ctdb_g_lock p1, p2; + size_t buflen; + int ret; + + fill_ctdb_g_lock(mem_ctx, &p1); + buflen = ctdb_g_lock_len(&p1); + ctdb_g_lock_push(&p1, BUFFER); + ret = ctdb_g_lock_pull(BUFFER, buflen, &p2); + assert(ret == 0); + verify_ctdb_g_lock(&p1, &p2); + talloc_free(mem_ctx); +} + +DEFINE_TEST(struct ctdb_statistics, ctdb_statistics); +DEFINE_TEST(struct ctdb_vnn_map, ctdb_vnn_map); +DEFINE_TEST(struct ctdb_dbid_map, ctdb_dbid_map); +DEFINE_TEST(struct ctdb_pulldb, ctdb_pulldb); +DEFINE_TEST(struct ctdb_rec_data, ctdb_rec_data); +DEFINE_TEST(struct ctdb_rec_buffer, ctdb_rec_buffer); +DEFINE_TEST(struct ctdb_traverse_start, ctdb_traverse_start); +DEFINE_TEST(struct ctdb_traverse_all, ctdb_traverse_all); +DEFINE_TEST(struct ctdb_traverse_start_ext, ctdb_traverse_start_ext); +DEFINE_TEST(struct ctdb_traverse_all_ext, ctdb_traverse_all_ext); +DEFINE_TEST(ctdb_sock_addr, ctdb_sock_addr); +DEFINE_TEST(struct ctdb_connection, ctdb_connection); +DEFINE_TEST(struct ctdb_tunable, ctdb_tunable); +DEFINE_TEST(struct ctdb_node_flag_change, ctdb_node_flag_change); +DEFINE_TEST(struct ctdb_var_list, ctdb_var_list); +DEFINE_TEST(struct ctdb_tunable_list, ctdb_tunable_list); +DEFINE_TEST(struct ctdb_tickle_list, ctdb_tickle_list); +DEFINE_TEST(struct ctdb_client_id, ctdb_client_id); +DEFINE_TEST(struct ctdb_client_id_list, ctdb_client_id_list); +DEFINE_TEST(struct ctdb_client_id_map, ctdb_client_id_map); +DEFINE_TEST(struct ctdb_addr_info, ctdb_addr_info); +DEFINE_TEST(struct ctdb_transdb, ctdb_transdb); +DEFINE_TEST(struct ctdb_uptime, ctdb_uptime); +DEFINE_TEST(struct ctdb_public_ip, ctdb_public_ip); +DEFINE_TEST(struct ctdb_public_ip_list, ctdb_public_ip_list); +DEFINE_TEST(struct ctdb_node_and_flags, ctdb_node_and_flags); +DEFINE_TEST(struct ctdb_node_map, ctdb_node_map); +DEFINE_TEST(struct ctdb_script, ctdb_script); +DEFINE_TEST(struct ctdb_script_list, ctdb_script_list); +DEFINE_TEST(struct ctdb_ban_state, ctdb_ban_state); +DEFINE_TEST(struct ctdb_db_priority, ctdb_db_priority); +DEFINE_TEST(struct ctdb_notify_data, ctdb_notify_data); +DEFINE_TEST(struct ctdb_iface, ctdb_iface); +DEFINE_TEST(struct ctdb_iface_list, ctdb_iface_list); +DEFINE_TEST(struct ctdb_public_ip_info, ctdb_public_ip_info); +DEFINE_TEST(struct ctdb_statistics_list, ctdb_statistics_list); +DEFINE_TEST(struct ctdb_key_data, ctdb_key_data); +DEFINE_TEST(struct ctdb_uint8_array, ctdb_uint8_array); +DEFINE_TEST(struct ctdb_uint64_array, ctdb_uint64_array); +DEFINE_TEST(struct ctdb_db_statistics, ctdb_db_statistics); +DEFINE_TEST(struct ctdb_election_message, ctdb_election_message); +DEFINE_TEST(struct ctdb_srvid_message, ctdb_srvid_message); +DEFINE_TEST(struct ctdb_disable_message, ctdb_disable_message); +DEFINE_TEST(struct ctdb_g_lock_list, ctdb_g_lock_list); + +int main(int argc, char *argv[]) +{ + if (argc == 2) { + int seed = atoi(argv[1]); + srandom(seed); + } + + test_ctdb_uint32(); + test_ctdb_uint64(); + test_ctdb_double(); + test_ctdb_pid(); + + test_ctdb_string(); + test_ctdb_stringn(); + + test_ctdb_ltdb_header(); + test_ctdb_g_lock(); + + TEST_FUNC(ctdb_statistics)(); + TEST_FUNC(ctdb_vnn_map)(); + TEST_FUNC(ctdb_dbid_map)(); + TEST_FUNC(ctdb_pulldb)(); + TEST_FUNC(ctdb_rec_data)(); + TEST_FUNC(ctdb_rec_buffer)(); + TEST_FUNC(ctdb_traverse_start)(); + TEST_FUNC(ctdb_traverse_all)(); + TEST_FUNC(ctdb_traverse_start_ext)(); + TEST_FUNC(ctdb_traverse_all_ext)(); + TEST_FUNC(ctdb_sock_addr)(); + TEST_FUNC(ctdb_connection)(); + TEST_FUNC(ctdb_tunable)(); + TEST_FUNC(ctdb_node_flag_change)(); + TEST_FUNC(ctdb_var_list)(); + TEST_FUNC(ctdb_tunable_list)(); + TEST_FUNC(ctdb_tickle_list)(); + TEST_FUNC(ctdb_client_id)(); + TEST_FUNC(ctdb_client_id_list)(); + TEST_FUNC(ctdb_client_id_map)(); + TEST_FUNC(ctdb_addr_info)(); + TEST_FUNC(ctdb_transdb)(); + TEST_FUNC(ctdb_uptime)(); + TEST_FUNC(ctdb_public_ip)(); + TEST_FUNC(ctdb_public_ip_list)(); + TEST_FUNC(ctdb_node_and_flags)(); + TEST_FUNC(ctdb_node_map)(); + TEST_FUNC(ctdb_script)(); + TEST_FUNC(ctdb_script_list)(); + TEST_FUNC(ctdb_ban_state)(); + TEST_FUNC(ctdb_db_priority)(); + TEST_FUNC(ctdb_notify_data)(); + TEST_FUNC(ctdb_iface)(); + TEST_FUNC(ctdb_iface_list)(); + TEST_FUNC(ctdb_public_ip_info)(); + TEST_FUNC(ctdb_statistics_list)(); + TEST_FUNC(ctdb_key_data)(); + TEST_FUNC(ctdb_uint8_array)(); + TEST_FUNC(ctdb_uint64_array)(); + TEST_FUNC(ctdb_db_statistics)(); + TEST_FUNC(ctdb_election_message)(); + TEST_FUNC(ctdb_srvid_message)(); + TEST_FUNC(ctdb_disable_message)(); + TEST_FUNC(ctdb_g_lock_list)(); + + return 0; +} + +#endif diff --git a/ctdb/wscript b/ctdb/wscript index 243ac9b..3d86642 100755 --- a/ctdb/wscript +++ b/ctdb/wscript @@ -340,6 +340,17 @@ def build(bld): logging.c'''), deps='replace talloc tevent tdb tevent-unix-util') + bld.SAMBA_SUBSYSTEM('ctdb-protocol', + source=bld.SUBDIR('protocol', + '''protocol_header.c protocol_packet.c + protocol_types.c protocol_call.c + protocol_message.c + protocol_control.c + protocol_client.c + protocol_util.c'''), + includes='include', + deps='replace talloc tdb') + bld.SAMBA_SUBSYSTEM('ctdb-client', source=bld.SUBDIR('client', 'ctdb_client.c'), includes='include include/internal', @@ -584,6 +595,8 @@ def build(bld): 'comm_test', 'comm_server_test', 'comm_client_test', + 'protocol_types_test', + 'protocol_client_test', ] for target in ctdb_unit_tests: From c6a50b97d4c91967c480e7077b66e149bc38dcf4 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Wed, 15 Apr 2015 00:14:25 +1000 Subject: [PATCH 063/136] ctdb-client: Add new client API implementation Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/client/client.h | 807 ++++++++++ ctdb/client/client_call.c | 177 +++ ctdb/client/client_connect.c | 310 ++++ ctdb/client/client_control.c | 430 ++++++ ctdb/client/client_control_sync.c | 2972 +++++++++++++++++++++++++++++++++++++ ctdb/client/client_db.c | 2137 ++++++++++++++++++++++++++ ctdb/client/client_message.c | 227 +++ ctdb/client/client_message_sync.c | 195 +++ ctdb/client/client_private.h | 79 + ctdb/client/client_util.c | 154 ++ ctdb/wscript | 11 + 11 files changed, 7499 insertions(+) create mode 100644 ctdb/client/client.h create mode 100644 ctdb/client/client_call.c create mode 100644 ctdb/client/client_connect.c create mode 100644 ctdb/client/client_control.c create mode 100644 ctdb/client/client_control_sync.c create mode 100644 ctdb/client/client_db.c create mode 100644 ctdb/client/client_message.c create mode 100644 ctdb/client/client_message_sync.c create mode 100644 ctdb/client/client_private.h create mode 100644 ctdb/client/client_util.c diff --git a/ctdb/client/client.h b/ctdb/client/client.h new file mode 100644 index 0000000..ba40202 --- /dev/null +++ b/ctdb/client/client.h @@ -0,0 +1,807 @@ +/* + CTDB client code + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#ifndef __CTDB_CLIENT_H__ +#define __CTDB_CLIENT_H__ + +#include "protocol/protocol.h" +#include "common/srvid.h" + +struct ctdb_client_context; +struct ctdb_db_context; +struct ctdb_record_handle; + +/* from client/client_connect.c */ + +int ctdb_client_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + const char *sockpath, struct ctdb_client_context **ret); + +uint32_t ctdb_client_pnn(struct ctdb_client_context *client); + +void ctdb_client_wait(struct tevent_context *ev, bool *done); + +struct tevent_req *ctdb_recovery_wait_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client); + +bool ctdb_recovery_wait_recv(struct tevent_req *req, int *perr); + +/* from client/client_call.c */ + +struct tevent_req *ctdb_client_call_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + struct ctdb_req_call *request); + +bool ctdb_client_call_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + struct ctdb_reply_call **reply, int *perr); + + +/* from client/client_message.c */ + +struct tevent_req *ctdb_client_message_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + uint32_t destnode, + struct ctdb_req_message *message); + +bool ctdb_client_message_recv(struct tevent_req *req, int *perr); + +int ctdb_client_message(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + uint32_t destnode, struct ctdb_req_message *message); + +int ctdb_client_set_message_handler(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + uint64_t srvid, srvid_handler_fn handler, + void *private_data); + +int ctdb_client_remove_message_handler(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + uint64_t srvid, void *private_data); + +/* from client/client_message_sync.c */ + +int ctdb_message_recd_update_ip(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct ctdb_public_ip *pubip); + +int ctdb_message_mem_dump(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct ctdb_srvid_message *msg); + +int ctdb_message_reload_nodes(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode); + +int ctdb_message_takeover_run(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct ctdb_srvid_message *msg); + +int ctdb_message_rebalance_node(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, uint32_t pnn); + +int ctdb_message_disable_takeover_runs(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, + struct ctdb_disable_message *disable); + +int ctdb_message_disable_recoveries(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, + struct ctdb_disable_message *disable); + +int ctdb_message_disable_ip_check(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, uint32_t timeout); + +/* from client/client_control.c */ + +struct tevent_req *ctdb_client_control_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + uint32_t destnode, + struct timeval timeout, + struct ctdb_req_control *request); + +bool ctdb_client_control_recv(struct tevent_req *req, int *perr, + TALLOC_CTX *mem_ctx, + struct ctdb_reply_control **preply); + +struct tevent_req *ctdb_client_control_multi_send( + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + uint32_t *pnn_list, int count, + struct timeval timeout, + struct ctdb_req_control *request); + +bool ctdb_client_control_multi_recv(struct tevent_req *req, int *perr, + TALLOC_CTX *mem_ctx, int **perr_list, + struct ctdb_reply_control ***preply); + +int ctdb_client_control_multi_error(uint32_t *pnn_list, int count, + int *err_list, uint32_t *pnn); + +int ctdb_client_control(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + uint32_t destnode, + struct timeval timeout, + struct ctdb_req_control *c, + struct ctdb_reply_control **preply); + +int ctdb_client_control_multi(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + uint32_t *pnn_list, int count, + struct timeval timeout, + struct ctdb_req_control *request, + int **perr, + struct ctdb_reply_control ***preply); + +/* from client/client_control_sync.c */ + +int ctdb_ctrl_process_exists(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + pid_t pid, int *status); + +int ctdb_ctrl_statistics(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_statistics **stats); + +int ctdb_ctrl_ping(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + int *num_clients); + +int ctdb_ctrl_getdbpath(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t db_id, const char **db_path); + +int ctdb_ctrl_getvnnmap(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_vnn_map **vnnmap); + +int ctdb_ctrl_getdebug(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t *loglevel); + +int ctdb_ctrl_setdebug(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t loglevel); + +int ctdb_ctrl_get_dbmap(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_dbid_map **dbmap); + +int ctdb_ctrl_pull_db(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, int destnode, + struct timeval timeout, struct ctdb_pulldb *pulldb, + struct ctdb_rec_buffer **recbuf); + +int ctdb_ctrl_push_db(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, int destnode, + struct timeval timeout, struct ctdb_rec_buffer *recbuf); + +int ctdb_ctrl_get_recmode(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + int *recmode); + +int ctdb_ctrl_set_recmode(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + int recmode); + +int ctdb_ctrl_statistics_reset(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout); + +int ctdb_ctrl_db_attach(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + const char *db_name, uint32_t tdb_flags, + uint32_t *db_id); + +int ctdb_ctrl_traverse_start(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_traverse_start *traverse); + +int ctdb_ctrl_register_srvid(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint64_t srvid); + +int ctdb_ctrl_deregister_srvid(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint64_t srvid); + +int ctdb_ctrl_get_dbname(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t db_id, const char **db_name); + +int ctdb_ctrl_enable_seqnum(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t db_id); + +int ctdb_ctrl_update_seqnum(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t db_id); + +int ctdb_ctrl_dump_memory(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + const char **mem_str); + +int ctdb_ctrl_get_pid(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + pid_t *pid); + +int ctdb_ctrl_get_recmaster(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t *recmaster); + +int ctdb_ctrl_set_recmaster(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t recmaster); + +int ctdb_ctrl_freeze(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + int priority); + +int ctdb_ctrl_thaw(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + int priority); + +int ctdb_ctrl_get_pnn(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t *pnn); + +int ctdb_ctrl_shutdown(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout); + +int ctdb_ctrl_get_monmode(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + int *mon_mode); + +int ctdb_ctrl_tcp_add(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_connection *conn); + +int ctdb_ctrl_tcp_remove(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_connection *conn); + +int ctdb_ctrl_set_tunable(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_tunable *tunable); + +int ctdb_ctrl_get_tunable(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + const char *var, uint32_t *value); + +int ctdb_ctrl_list_tunables(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_var_list **var_list); + +int ctdb_ctrl_modify_flags(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t pnn, uint32_t old_flags, + uint32_t new_flags); + +int ctdb_ctrl_get_all_tunables(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_tunable_list **tun_list); + +int ctdb_ctrl_kill_tcp(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_connection *conn); + +int ctdb_ctrl_get_tcp_tickle_list(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + ctdb_sock_addr *addr, + struct ctdb_tickle_list **tickles); + +int ctdb_ctrl_set_tcp_tickle_list(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_tickle_list *tickles); + +int ctdb_ctrl_register_server_id(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_client_id *cid); + +int ctdb_ctrl_unregister_server_id(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_client_id *cid); + +int ctdb_ctrl_check_server_id(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_client_id *cid); + +int ctdb_ctrl_get_server_id_list(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_client_id_map **cid_map); + +int ctdb_ctrl_db_attach_persistent(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + const char *db_name, int tdb_flags, + uint32_t *db_id); + +int ctdb_ctrl_send_gratuitous_arp(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_addr_info *addr_info); + +int ctdb_ctrl_transaction_start(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t tid); + +int ctdb_ctrl_transaction_commit(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t tid); + +int ctdb_ctrl_wipe_database(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t db_id, uint32_t tid); + +int ctdb_ctrl_uptime(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_uptime **uptime); + +int ctdb_ctrl_start_recovery(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout); + +int ctdb_ctrl_end_recovery(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout); + +int ctdb_ctrl_reload_nodes_file(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout); + +int ctdb_ctrl_enable_monitor(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout); + +int ctdb_ctrl_disable_monitor(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout); + +int ctdb_ctrl_add_public_ip(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_addr_info *addr_info); + +int ctdb_ctrl_del_public_ip(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_addr_info *addr_info); + +int ctdb_ctrl_run_eventscripts(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + const char *event); + +int ctdb_ctrl_get_capabilities(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t *caps); + +int ctdb_ctrl_release_ip(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_public_ip *pubip); + +int ctdb_ctrl_takeover_ip(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_public_ip *pubip); + +int ctdb_ctrl_get_public_ips(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_public_ip_list **pubip_list); + +int ctdb_ctrl_get_nodemap(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_node_map **nodemap); + +int ctdb_ctrl_get_event_script_status(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + enum ctdb_event event, + struct ctdb_script_list **slist); + +int ctdb_ctrl_traverse_kill(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_traverse_start *traverse); + +int ctdb_ctrl_get_reclock_file(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + const char **reclock_file); + +int ctdb_ctrl_set_reclock_file(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + const char *reclock_file); + +int ctdb_ctrl_stop_node(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout); + +int ctdb_ctrl_continue_node(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout); + +int ctdb_ctrl_set_natgwstate(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t natgw_role); + +int ctdb_ctrl_set_lmasterrole(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t lmaster_role); + +int ctdb_ctrl_set_recmasterrole(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t recmaster_role); + +int ctdb_ctrl_enable_script(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + const char *script); + +int ctdb_ctrl_disable_script(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + const char *script); + +int ctdb_ctrl_set_ban_state(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_ban_state *ban_state); + +int ctdb_ctrl_get_ban_state(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_ban_state **ban_state); + +int ctdb_ctrl_set_db_priority(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t db_id, int priority); + +int ctdb_ctrl_get_db_priority(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t db_id, uint32_t *priority); + +int ctdb_ctrl_transaction_cancel(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t tid); + +int ctdb_ctrl_register_notify(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_notify_data *notify); + +int ctdb_ctrl_deregister_notify(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint64_t srvid); + +int ctdb_ctrl_trans3_commit(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_rec_buffer *recbuf); + +int ctdb_ctrl_get_db_seqnum(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t db_id, uint64_t *seqnum); + +int ctdb_ctrl_db_set_healthy(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t db_id); + +int ctdb_ctrl_db_get_health(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t db_id, const char **reason); + +int ctdb_ctrl_get_public_ip_info(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + ctdb_sock_addr *addr, + struct ctdb_public_ip_info **ipinfo); + +int ctdb_ctrl_get_ifaces(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_iface_list **iface_list); + +int ctdb_ctrl_set_iface_link_state(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_iface *iface); + +int ctdb_ctrl_tcp_add_delayed_update(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_connection *conn); + +int ctdb_ctrl_get_stat_history(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_statistics_list **stats_list); + +int ctdb_ctrl_schedule_for_deletion(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_key_data *key); + +int ctdb_ctrl_set_db_readonly(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t db_id); + +int ctdb_ctrl_check_srvids(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint64_t *srvid, int count, uint8_t **result); + +int ctdb_ctrl_traverse_start_ext(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_traverse_start_ext *traverse); + +int ctdb_ctrl_get_db_statistics(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t db_id, + struct ctdb_db_statistics **dbstats); + +int ctdb_ctrl_set_db_sticky(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t db_id); + +int ctdb_ctrl_reload_public_ips(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout); + +int ctdb_ctrl_ipreallocated(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout); + +int ctdb_ctrl_get_runstate(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + enum ctdb_runstate *runstate); + +int ctdb_ctrl_db_detach(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t db_id); + +int ctdb_ctrl_get_nodes_file(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_node_map **nodemap); + +/* from client/client_db.c */ + +struct tevent_req *ctdb_attach_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + struct timeval timeout, + const char *db_name, uint8_t db_flags); + +bool ctdb_attach_recv(struct tevent_req *req, int *perr, + struct ctdb_db_context **out); + +int ctdb_attach(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + struct timeval timeout, + const char *db_name, uint8_t db_flags, + struct ctdb_db_context **out); + +int ctdb_detach(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + struct timeval timeout, uint32_t db_id); + +uint32_t ctdb_db_id(struct ctdb_db_context *db); + +int ctdb_db_traverse(struct ctdb_db_context *db, bool readonly, + bool extract_header, + ctdb_rec_parser_func_t parser, void *private_data); + +struct tevent_req *ctdb_fetch_lock_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + struct ctdb_db_context *db, + TDB_DATA key, bool readonly); + +struct ctdb_record_handle *ctdb_fetch_lock_recv(struct tevent_req *req, + struct ctdb_ltdb_header *header, + TALLOC_CTX *mem_ctx, + TDB_DATA *data, int *perr); + +int ctdb_fetch_lock(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + struct ctdb_db_context *db, TDB_DATA key, bool readonly, + struct ctdb_record_handle **out, + struct ctdb_ltdb_header *header, TDB_DATA *data); + +int ctdb_store_record(struct ctdb_record_handle *h, TDB_DATA data); + +int ctdb_delete_record(struct ctdb_record_handle *h); + +struct tevent_req *ctdb_g_lock_lock_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + struct ctdb_db_context *db, + const char *keyname, + struct ctdb_server_id *sid, + bool readonly); + +bool ctdb_g_lock_lock_recv(struct tevent_req *req, int *perr); + +struct tevent_req *ctdb_g_lock_unlock_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + struct ctdb_db_context *db, + const char *keyname, + struct ctdb_server_id sid); + +bool ctdb_g_lock_unlock_recv(struct tevent_req *req, int *perr); + +struct tevent_req *ctdb_transaction_start_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + struct timeval timeout, + struct ctdb_db_context *db, + bool readonly); + +struct ctdb_transaction_handle *ctdb_transaction_start_recv( + struct tevent_req *req, + int *perr); + +int ctdb_transaction_start(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + struct timeval timeout, + struct ctdb_db_context *db, bool readonly, + struct ctdb_transaction_handle **out); + +int ctdb_transaction_fetch_record(struct ctdb_transaction_handle *h, + TDB_DATA key, + TALLOC_CTX *mem_ctx, TDB_DATA *data); + +int ctdb_transaction_store_record(struct ctdb_transaction_handle *h, + TDB_DATA key, TDB_DATA data); + +int ctdb_transaction_delete_record(struct ctdb_transaction_handle *h, + TDB_DATA key); + +struct tevent_req *ctdb_transaction_commit_send( + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_transaction_handle *h); + +bool ctdb_transaction_commit_recv(struct tevent_req *req, int *perr); + +int ctdb_transaction_commit(struct ctdb_transaction_handle *h); + +int ctdb_transaction_cancel(struct ctdb_transaction_handle *h); + +/* from client/client_util.c */ + +int list_of_nodes(struct ctdb_node_map *nodemap, + uint32_t flags_mask, uint32_t exclude_pnn, + TALLOC_CTX *mem_ctx, uint32_t **pnn_list); + +int list_of_active_nodes(struct ctdb_node_map *nodemap, uint32_t exclude_pnn, + TALLOC_CTX *mem_ctx, uint32_t **pnn_list); + +int list_of_connected_nodes(struct ctdb_node_map *nodemap, + uint32_t exclude_pnn, + TALLOC_CTX *mem_ctx, uint32_t **pnn_list); + +int ctdb_ctrl_modflags(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + uint32_t destnode, struct timeval timeout, + uint32_t set, uint32_t clear); + +bool ctdb_server_id_equal(struct ctdb_server_id *sid1, + struct ctdb_server_id *sid2); + +int ctdb_server_id_exists(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + struct ctdb_server_id *sid, bool *exists); + +#endif /* __CTDB_CLIENT_H__ */ diff --git a/ctdb/client/client_call.c b/ctdb/client/client_call.c new file mode 100644 index 0000000..aa8a05b --- /dev/null +++ b/ctdb/client/client_call.c @@ -0,0 +1,177 @@ +/* + CTDB client code + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include "replace.h" +#include "system/network.h" +#include "system/filesys.h" + +#include +#include +#include + +#include "lib/util/tevent_unix.h" + +#include "common/reqid.h" +#include "common/srvid.h" +#include "common/comm.h" + +#include "protocol/protocol.h" +#include "protocol/protocol_api.h" + +#include "client/client_private.h" +#include "client/client.h" + + +/* + * Handle REQ_CALL and REPLY_CALL + */ + +struct ctdb_client_call_state { + struct ctdb_client_context *client; + uint32_t reqid; + struct ctdb_reply_call *reply; + struct tevent_req *req; +}; + +static int ctdb_client_call_state_destructor( + struct ctdb_client_call_state *state); +static void ctdb_client_call_done(struct tevent_req *subreq); + +struct tevent_req *ctdb_client_call_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + struct ctdb_req_call *request) +{ + struct ctdb_req_header h; + struct tevent_req *req, *subreq; + struct ctdb_client_call_state *state; + uint32_t reqid; + uint8_t *buf; + size_t buflen; + int ret; + + req = tevent_req_create(mem_ctx, &state, + struct ctdb_client_call_state); + if (req == NULL) { + return NULL; + } + + reqid = reqid_new(client->idr, state); + if (reqid == REQID_INVALID) { + talloc_free(req); + return NULL; + } + + state->client = client; + state->reqid = reqid; + state->req = req; + state->reply = talloc_zero(state, struct ctdb_reply_call); + if (tevent_req_nomem(state->reply, req)) { + return tevent_req_post(req, ev); + } + + talloc_set_destructor(state, ctdb_client_call_state_destructor); + + ctdb_req_header_fill(&h, 0, CTDB_REQ_CALL, CTDB_CURRENT_NODE, + client->pnn, reqid); + + ret = ctdb_req_call_push(&h, request, state, &buf, &buflen); + if (ret != 0) { + tevent_req_error(req, ret); + return tevent_req_post(req, ev); + } + + subreq = comm_write_send(state, ev, client->comm, buf, buflen); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, ctdb_client_call_done, req); + + return req; +} + +static int ctdb_client_call_state_destructor( + struct ctdb_client_call_state *state) +{ + reqid_remove(state->client->idr, state->reqid); + return 0; +} + +static void ctdb_client_call_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + bool status; + int ret; + + status = comm_write_recv(subreq, &ret); + TALLOC_FREE(subreq); + if (! status) { + tevent_req_error(req, ret); + return; + } + + /* wait for the reply */ +} + +void ctdb_client_reply_call(struct ctdb_client_context *client, + uint8_t *buf, size_t buflen, uint32_t reqid) +{ + struct ctdb_req_header h; + struct ctdb_client_call_state *state; + int ret; + + state = reqid_find(client->idr, reqid, struct ctdb_client_call_state); + if (state == NULL) { + return; + } + + if (reqid != state->reqid) { + return; + } + + ret = ctdb_reply_call_pull(buf, buflen, &h, state, state->reply); + if (ret != 0) { + tevent_req_error(state->req, ret); + return; + } + + tevent_req_done(state->req); +} + +bool ctdb_client_call_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + struct ctdb_reply_call **reply, int *perr) +{ + struct ctdb_client_call_state *state = tevent_req_data( + req, struct ctdb_client_call_state); + int err; + + if (tevent_req_is_unix_error(req, &err)) { + if (perr != NULL) { + *perr = err; + } + return false; + } + + if (reply != NULL) { + *reply = talloc_steal(mem_ctx, state->reply); + } + + return true; +} diff --git a/ctdb/client/client_connect.c b/ctdb/client/client_connect.c new file mode 100644 index 0000000..5f2b62e --- /dev/null +++ b/ctdb/client/client_connect.c @@ -0,0 +1,310 @@ +/* + CTDB client code + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include "replace.h" +#include "system/network.h" +#include "system/filesys.h" + +#include +#include +#include + +#include "common/reqid.h" +#include "common/srvid.h" +#include "common/comm.h" + +#include "lib/util/tevent_unix.h" +#include "lib/util/debug.h" +#include "ctdb_logging.h" + +#include "protocol/protocol.h" +#include "protocol/protocol_api.h" + +#include "client/client_private.h" +#include "client/client.h" + +static int ctdb_client_connect(struct ctdb_client_context *client, + struct tevent_context *ev, + const char *sockpath); + +int ctdb_client_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + const char *sockpath, struct ctdb_client_context **out) +{ + struct ctdb_client_context *client; + int ret; + + client = talloc_zero(mem_ctx, struct ctdb_client_context); + if (client == NULL) { + DEBUG(DEBUG_ERR, (__location__ " memory allocation error\n")); + return ENOMEM; + } + + ret = reqid_init(client, INT_MAX-200, &client->idr); + if (ret != 0) { + DEBUG(DEBUG_ERR, ("reqid_init() failed, ret=%d\n", ret)); + talloc_free(client); + return ret; + } + + ret = srvid_init(client, &client->srv); + if (ret != 0) { + DEBUG(DEBUG_ERR, ("srvid_init() failed, ret=%d\n", ret)); + talloc_free(client); + return ret; + } + + client->fd = -1; + client->pnn = CTDB_UNKNOWN_PNN; + + ret = ctdb_client_connect(client, ev, sockpath); + if (ret != 0) { + talloc_free(client); + return ret; + } + + *out = client; + return 0; +} + +static void client_read_handler(uint8_t *buf, size_t buflen, + void *private_data); +static void client_dead_handler(void *private_data); + +static int ctdb_client_connect(struct ctdb_client_context *client, + struct tevent_context *ev, const char *sockpath) +{ + struct sockaddr_un addr; + size_t len; + int fd, ret; + + if (sockpath == NULL) { + DEBUG(DEBUG_ERR, ("socket path cannot be NULL\n")); + return EINVAL; + } + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + len = strlcpy(addr.sun_path, sockpath, sizeof(addr.sun_path)); + if (len != strlen(sockpath)) { + DEBUG(DEBUG_ERR, ("socket path too long, len=%zu\n", + strlen(sockpath))); + return ENAMETOOLONG; + } + + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd == -1) { + ret = errno; + DEBUG(DEBUG_ERR, ("socket() failed, errno=%d\n", ret)); + return ret; + } + + ret = connect(fd, (struct sockaddr *)&addr, sizeof(addr)); + if (ret == -1) { + ret = errno; + DEBUG(DEBUG_ERR, ("connect() failed, errno=%d\n", ret)); + close(fd); + return ret; + } + client->fd = fd; + + ret = comm_setup(client, ev, fd, client_read_handler, client, + client_dead_handler, client, &client->comm); + if (ret != 0) { + DEBUG(DEBUG_ERR, ("comm_setup() failed, ret=%d\n", ret)); + close(fd); + client->fd = -1; + return ret; + } + + ret = ctdb_ctrl_get_pnn(client, ev, client, CTDB_CURRENT_NODE, + tevent_timeval_zero(), &client->pnn); + if (ret != 0) { + DEBUG(DEBUG_ERR, ("failed to get current node pnn\n")); + close(fd); + client->fd = -1; + TALLOC_FREE(client->comm); + return ret; + } + + return 0; +} + +static void client_read_handler(uint8_t *buf, size_t buflen, + void *private_data) +{ + struct ctdb_client_context *client = talloc_get_type_abort( + private_data, struct ctdb_client_context); + struct ctdb_req_header hdr; + int ret; + + ret = ctdb_req_header_pull(discard_const(buf), buflen, &hdr); + if (ret != 0) { + DEBUG(DEBUG_WARNING, ("invalid header, ret=%d\n", ret)); + return; + } + + if (buflen != hdr.length) { + DEBUG(DEBUG_WARNING, ("packet size mismatch %zu != %d\n", + buflen, hdr.length)); + return; + } + + ret = ctdb_req_header_verify(&hdr, 0); + if (ret != 0) { + DEBUG(DEBUG_WARNING, ("invalid header, ret=%d\n", ret)); + return; + } + + switch (hdr.operation) { + case CTDB_REPLY_CALL: + ctdb_client_reply_call(client, buf, buflen, hdr.reqid); + break; + + case CTDB_REQ_MESSAGE: + ctdb_client_req_message(client, buf, buflen, hdr.reqid); + break; + + case CTDB_REPLY_CONTROL: + ctdb_client_reply_control(client, buf, buflen, hdr.reqid); + break; + + default: + break; + } +} + +static void client_dead_handler(void *private_data) +{ + struct ctdb_client_context *client = talloc_get_type_abort( + private_data, struct ctdb_client_context); + + DEBUG(DEBUG_NOTICE, ("connection to daemon closed, exiting\n")); + talloc_free(client); + exit(1); +} + +uint32_t ctdb_client_pnn(struct ctdb_client_context *client) +{ + return client->pnn; +} + +void ctdb_client_wait(struct tevent_context *ev, bool *done) +{ + while (! (*done)) { + tevent_loop_once(ev); + } +} + +struct ctdb_recovery_wait_state { + struct tevent_context *ev; + struct ctdb_client_context *client; +}; + +static void ctdb_recovery_wait_retry(struct tevent_req *subreq); + +struct tevent_req *ctdb_recovery_wait_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client) +{ + struct tevent_req *req, *subreq; + struct ctdb_recovery_wait_state *state; + int recmode; + int ret; + + req = tevent_req_create(mem_ctx, &state, + struct ctdb_recovery_wait_state); + if (req == NULL) { + return NULL; + } + + state->ev = ev; + state->client = client; + + ret = ctdb_ctrl_get_recmode(client, ev, client, client->pnn, + tevent_timeval_zero(), &recmode); + if (ret != 0) { + tevent_req_error(req, ret); + return tevent_req_post(req, ev); + } + + if (recmode == CTDB_RECOVERY_NORMAL) { + tevent_req_done(req); + return tevent_req_post(req, ev); + } + + subreq = tevent_wakeup_send(state, ev, + tevent_timeval_current_ofs(1, 0)); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, ctdb_recovery_wait_retry, req); + + return req; +} + +static void ctdb_recovery_wait_retry(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct ctdb_recovery_wait_state *state = tevent_req_data( + req, struct ctdb_recovery_wait_state); + int ret, recmode; + bool status; + + status = tevent_wakeup_recv(subreq); + TALLOC_FREE(subreq); + if (! status) { + tevent_req_error(req, ENOMEM); + return; + } + + ret = ctdb_ctrl_get_recmode(state, state->ev, state->client, + ctdb_client_pnn(state->client), + tevent_timeval_zero(), &recmode); + if (ret != 0) { + tevent_req_error(req, ret); + return; + } + + if (recmode == CTDB_RECOVERY_NORMAL) { + tevent_req_done(req); + return; + } + + subreq = tevent_wakeup_send(state, state->ev, + tevent_timeval_current_ofs(1, 0)); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, ctdb_recovery_wait_retry, req); +} + +bool ctdb_recovery_wait_recv(struct tevent_req *req, int *perr) +{ + int err; + + if (tevent_req_is_unix_error(req, &err)) { + if (perr != NULL) { + *perr = err; + } + return false; + } + + return true; +} diff --git a/ctdb/client/client_control.c b/ctdb/client/client_control.c new file mode 100644 index 0000000..4249bfb --- /dev/null +++ b/ctdb/client/client_control.c @@ -0,0 +1,430 @@ +/* + CTDB client code + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include "replace.h" +#include "system/network.h" +#include "system/filesys.h" + +#include +#include +#include + +#include "lib/util/tevent_unix.h" + +#include "common/reqid.h" +#include "common/srvid.h" +#include "common/comm.h" + +#include "protocol/protocol.h" +#include "protocol/protocol_api.h" + +#include "client/client_private.h" +#include "client/client.h" + + +/* + * Handle REQ_CONTROL and REPLY_CONTROL + */ + +struct ctdb_client_control_state { + struct ctdb_client_context *client; + uint32_t opcode; + uint32_t flags; + uint32_t reqid; + struct ctdb_reply_control *reply; + struct tevent_req *req; +}; + +static int ctdb_client_control_state_destructor( + struct ctdb_client_control_state *state); +static void ctdb_client_control_done(struct tevent_req *subreq); + +struct tevent_req *ctdb_client_control_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + uint32_t destnode, + struct timeval timeout, + struct ctdb_req_control *request) +{ + struct ctdb_req_header h; + struct tevent_req *req, *subreq; + struct ctdb_client_control_state *state; + uint32_t reqid; + uint8_t *buf; + size_t buflen; + int ret; + + req = tevent_req_create(mem_ctx, &state, + struct ctdb_client_control_state); + if (req == NULL) { + return NULL; + } + + reqid = reqid_new(client->idr, state); + if (reqid == REQID_INVALID) { + talloc_free(req); + return NULL; + } + + state->client = client; + state->flags = request->flags; + state->opcode = request->opcode; + state->reqid = reqid; + state->req = req; + state->reply = talloc_zero(state, struct ctdb_reply_control); + if (tevent_req_nomem(state->reply, req)) { + return tevent_req_post(req, ev); + } + + talloc_set_destructor(state, ctdb_client_control_state_destructor); + + ctdb_req_header_fill(&h, 0, CTDB_REQ_CONTROL, destnode, + client->pnn, reqid); + + ret = ctdb_req_control_push(&h, request, state, &buf, &buflen); + if (ret != 0) { + tevent_req_error(req, ret); + return tevent_req_post(req, ev); + } + + if (!tevent_timeval_is_zero(&timeout)) { + tevent_req_set_endtime(req, ev, timeout); + } + + subreq = comm_write_send(state, ev, client->comm, buf, buflen); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, ctdb_client_control_done, req); + + return req; +} + +static int ctdb_client_control_state_destructor( + struct ctdb_client_control_state *state) +{ + reqid_remove(state->client->idr, state->reqid); + return 0; +} + +static void ctdb_client_control_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct ctdb_client_control_state *state = tevent_req_data( + req, struct ctdb_client_control_state); + bool status; + int ret; + + status = comm_write_recv(subreq, &ret); + TALLOC_FREE(subreq); + if (! status) { + tevent_req_error(req, ret); + return; + } + + /* Daemon will not reply, so we set status to 0 */ + if (state->flags & CTDB_CTRL_FLAG_NOREPLY) { + reqid_remove(state->client->idr, state->reqid); + state->reply->status = 0; + tevent_req_done(req); + } + + /* wait for the reply or timeout */ +} + +void ctdb_client_reply_control(struct ctdb_client_context *client, + uint8_t *buf, size_t buflen, uint32_t reqid) +{ + struct ctdb_req_header h; + struct ctdb_client_control_state *state; + int ret; + + state = reqid_find(client->idr, reqid, + struct ctdb_client_control_state); + if (state == NULL) { + return; + } + + if (reqid != state->reqid) { + return; + } + + ret = ctdb_reply_control_pull(buf, buflen, state->opcode, &h, + state->reply, state->reply); + if (ret != 0) { + tevent_req_error(state->req, ret); + return; + } + + tevent_req_done(state->req); +} + +bool ctdb_client_control_recv(struct tevent_req *req, int *perr, + TALLOC_CTX *mem_ctx, + struct ctdb_reply_control **reply) +{ + struct ctdb_client_control_state *state = tevent_req_data( + req, struct ctdb_client_control_state); + int err; + + if (tevent_req_is_unix_error(req, &err)) { + if (perr != NULL) { + *perr = err; + } + return false; + } + + if (reply != NULL) { + *reply = talloc_steal(mem_ctx, state->reply); + } + + return true; +} + +/* + * Handle multiple nodes - there cannot be any return data + */ + +struct ctdb_client_control_multi_state { + uint32_t *pnn_list; + int count; + int done; + int err; + int *err_list; + struct ctdb_reply_control **reply; +}; + +struct control_index_state { + struct tevent_req *req; + int index; +}; + +static void ctdb_client_control_multi_done(struct tevent_req *subreq); + +struct tevent_req *ctdb_client_control_multi_send( + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + uint32_t *pnn_list, int count, + struct timeval timeout, + struct ctdb_req_control *request) +{ + struct tevent_req *req, *subreq; + struct ctdb_client_control_multi_state *state; + int i; + + if (pnn_list == NULL || count == 0) { + return NULL; + } + + req = tevent_req_create(mem_ctx, &state, + struct ctdb_client_control_multi_state); + if (req == NULL) { + return NULL; + } + + state->pnn_list = pnn_list; + state->count = count; + state->done = 0; + state->err = 0; + state->err_list = talloc_zero_array(state, int, count); + if (tevent_req_nomem(state->err_list, req)) { + return tevent_req_post(req, ev); + } + state->reply = talloc_zero_array(state, struct ctdb_reply_control *, + count); + if (tevent_req_nomem(state->reply, req)) { + return tevent_req_post(req, ev); + } + + for (i=0; ireq = req; + substate->index = i; + + tevent_req_set_callback(subreq, ctdb_client_control_multi_done, + substate); + } + + return req; +} + +static void ctdb_client_control_multi_done(struct tevent_req *subreq) +{ + struct control_index_state *substate = tevent_req_callback_data( + subreq, struct control_index_state); + struct tevent_req *req = substate->req; + int idx = substate->index; + struct ctdb_client_control_multi_state *state = tevent_req_data( + req, struct ctdb_client_control_multi_state); + bool status; + int ret; + + status = ctdb_client_control_recv(subreq, &ret, state->reply, + &state->reply[idx]); + TALLOC_FREE(subreq); + if (! status) { + if (state->err == 0) { + state->err = ret; + state->err_list[idx] = state->err; + } + } else { + if (state->reply[idx]->status != 0) { + if (state->err == 0) { + state->err = state->reply[idx]->status; + state->err_list[idx] = state->err; + } + } + } + + state->done += 1; + + if (state->done == state->count) { + tevent_req_done(req); + } +} + +bool ctdb_client_control_multi_recv(struct tevent_req *req, int *perr, + TALLOC_CTX *mem_ctx, int **perr_list, + struct ctdb_reply_control ***preply) +{ + struct ctdb_client_control_multi_state *state = tevent_req_data( + req, struct ctdb_client_control_multi_state); + int err; + + if (tevent_req_is_unix_error(req, &err)) { + if (perr != NULL) { + *perr = err; + } + if (perr_list != NULL) { + *perr_list = talloc_steal(mem_ctx, state->err_list); + } + return false; + } + + if (perr != NULL) { + *perr = state->err; + } + + if (perr_list != NULL) { + *perr_list = talloc_steal(mem_ctx, state->err_list); + } + + if (preply != NULL) { + *preply = talloc_steal(mem_ctx, state->reply); + } + + if (state->err != 0) { + return false; + } + + return true; +} + +int ctdb_client_control_multi_error(uint32_t *pnn_list, int count, + int *err_list, uint32_t *pnn) +{ + int ret = 0, i; + + for (i=0; i. +*/ + +#include "replace.h" +#include "system/network.h" +#include "system/filesys.h" + +#include +#include +#include + +#include "lib/util/debug.h" +#include "ctdb_logging.h" + +#include "protocol/protocol.h" +#include "protocol/protocol_api.h" +#include "client/client_private.h" +#include "client/client.h" + +int ctdb_ctrl_process_exists(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + pid_t pid, int *status) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_process_exists(&request, pid); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control PROCESS_EXISTS failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_process_exists(reply, status); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control PROCESS_EXISTS failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_statistics(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_statistics **stats) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_statistics(&request); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control STATISTICS failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_statistics(reply, mem_ctx, stats); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control STATISTICS failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_ping(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + int *num_clients) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_ping(&request); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control PING failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_ping(reply, num_clients); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control PING failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_getdbpath(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t db_id, + const char **db_path) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_getdbpath(&request, db_id); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GETDBPATH failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_getdbpath(reply, mem_ctx, db_path); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GETDBPATH failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_getvnnmap(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_vnn_map **vnnmap) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_getvnnmap(&request); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GETVNNMAP failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_getvnnmap(reply, mem_ctx, vnnmap); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GETVNNMAP failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_getdebug(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t *loglevel) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_get_debug(&request); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_DEBUG failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_get_debug(reply, loglevel); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_DEBUG failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_setdebug(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t loglevel) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_set_debug(&request, loglevel); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control SET_DEBUG failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_set_debug(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control SET_DEBUG failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_get_dbmap(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_dbid_map **dbmap) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_get_dbmap(&request); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_DBMAP failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_get_dbmap(reply, mem_ctx, dbmap); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_DBMAP failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_pull_db(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, int destnode, + struct timeval timeout, struct ctdb_pulldb *pulldb, + struct ctdb_rec_buffer **recbuf) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_pull_db(&request, pulldb); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control PULL_DB failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_pull_db(reply, mem_ctx, recbuf); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control PULL_DB failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_push_db(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, int destnode, + struct timeval timeout, struct ctdb_rec_buffer *recbuf) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_push_db(&request, recbuf); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control PUSH_DB failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_push_db(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control PUSH_DB failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + + +int ctdb_ctrl_get_recmode(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + int *recmode) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_get_recmode(&request); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_RECMODE failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_get_recmode(reply, recmode); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_RECMODE failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_set_recmode(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + int recmode) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_set_recmode(&request, recmode); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control SET_RECMODE failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_set_recmode(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control SET_RECMODE failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_statistics_reset(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_statistics_reset(&request); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control STATISTICS_RESET failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_statistics_reset(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control STATISTICS_RESET failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_db_attach(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + const char *db_name, uint32_t tdb_flags, + uint32_t *db_id) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_db_attach(&request, db_name, tdb_flags); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control DB_ATTACH failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_db_attach(reply, db_id); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control DB_ATTACH failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_traverse_start(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_traverse_start *traverse) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_traverse_start(&request, traverse); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control TRAVERSE_START failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_traverse_start(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control TRAVERSE_START failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_register_srvid(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint64_t srvid) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_register_srvid(&request, srvid); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control REGISTER_SRVID failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_register_srvid(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control REGISTER_SRVID failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_deregister_srvid(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint64_t srvid) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_deregister_srvid(&request, srvid); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control DEREGISTER_SRVID failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_deregister_srvid(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control DEREGISTER_SRVID failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_get_dbname(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t db_id, const char **db_name) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_get_dbname(&request, db_id); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_DBNAME failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_get_dbname(reply, mem_ctx, db_name); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_DBNAME failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_enable_seqnum(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t db_id) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_enable_seqnum(&request, db_id); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control ENABLE_SEQNUM failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_enable_seqnum(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control ENABLE_SEQNUM failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_update_seqnum(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t db_id) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_update_seqnum(&request, db_id); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control UPDATE_SEQNUM failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_update_seqnum(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control UPDATE_SEQNUM failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_dump_memory(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + const char **mem_str) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_dump_memory(&request); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control DUMP_MEMORY failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_dump_memory(reply, mem_ctx, mem_str); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control DUMP_MEMORY failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_get_pid(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + pid_t *pid) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_get_pid(&request); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_PID failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_get_pid(reply, pid); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_PID failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_get_recmaster(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t *recmaster) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_get_recmaster(&request); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_RECMASTER failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_get_recmaster(reply, recmaster); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_RECMASTER failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_set_recmaster(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t recmaster) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_set_recmaster(&request, recmaster); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control SET_RECMASTER failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_set_recmaster(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control SET_RECMASTER failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_freeze(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + int priority) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_freeze(&request, priority); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control FREEZE failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_freeze(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control FREEZE failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_thaw(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + int priority) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_thaw(&request, priority); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control THAW failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_thaw(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control THAW failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_get_pnn(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t *pnn) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_get_pnn(&request); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_PNN failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_get_pnn(reply, pnn); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_PNN failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_shutdown(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_shutdown(&request); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control SHUTDOWN failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_shutdown(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control SHUTDOWN failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_get_monmode(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + int *mon_mode) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_get_monmode(&request); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_MONMODE failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_get_monmode(reply, mon_mode); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_MONMODE failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_tcp_add(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_connection *conn) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_tcp_add(&request, conn); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control TCP_ADD failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_tcp_add(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control TCP_ADD failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_tcp_remove(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_connection *conn) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_tcp_remove(&request, conn); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control TCP_REMOVE failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_tcp_remove(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control TCP_REMOVE failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_set_tunable(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_tunable *tunable) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_set_tunable(&request, tunable); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control SET_TUNABLE failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_set_tunable(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control SET_TUNABLE failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_get_tunable(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + const char *var, uint32_t *value) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_get_tunable(&request, var); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_TUNABLE failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_get_tunable(reply, value); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_TUNABLE failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_list_tunables(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_var_list **var_list) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_list_tunables(&request); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control LIST_TUNABLES failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_list_tunables(reply, mem_ctx, var_list); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control LIST_TUNABLES failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_modify_flags(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t pnn, uint32_t old_flags, + uint32_t new_flags) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + struct ctdb_node_flag_change flag_change; + int ret; + + flag_change.pnn = pnn; + flag_change.old_flags = old_flags; + flag_change.new_flags = new_flags; + + ctdb_req_control_modify_flags(&request, &flag_change); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control MODIFY_FLAGS failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_modify_flags(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control MODIFY_FLAGS failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_get_all_tunables(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_tunable_list **tun_list) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_get_all_tunables(&request); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_ALL_TUNABLES failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_get_all_tunables(reply, mem_ctx, tun_list); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_ALL_TUNABLES failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_kill_tcp(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_connection *conn) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_kill_tcp(&request, conn); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control KILL_TCP failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_kill_tcp(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control KILL_TCP failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_get_tcp_tickle_list(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + ctdb_sock_addr *addr, + struct ctdb_tickle_list **tickles) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_get_tcp_tickle_list(&request, addr); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_TCP_TICKLE_LIST failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_get_tcp_tickle_list(reply, mem_ctx, tickles); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_TCP_TICKLE_LIST failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_set_tcp_tickle_list(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_tickle_list *tickles) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_set_tcp_tickle_list(&request, tickles); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control SET_TCP_TICKLE_LIST failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_set_tcp_tickle_list(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control SET_TCP_TICKLE_LIST failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_register_server_id(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_client_id *cid) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_register_server_id(&request, cid); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control REGISTER_SERVER_ID failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_register_server_id(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control REGISTER_SERVER_ID failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_unregister_server_id(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_client_id *cid) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_unregister_server_id(&request, cid); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control UNREGISTER_SERVER_ID failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_unregister_server_id(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control UNREGISTER_SERVER_ID failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_check_server_id(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_client_id *cid) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_check_server_id(&request, cid); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control CHECK_SERVER_ID failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_check_server_id(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control CHECK_SERVER_ID failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_get_server_id_list(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_client_id_map **cid_map) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_get_server_id_list(&request); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_SERVER_ID_LIST failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_get_server_id_list(reply, mem_ctx, cid_map); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_SERVER_ID_LIST failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_db_attach_persistent(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + const char *db_name, int tdb_flags, + uint32_t *db_id) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_db_attach_persistent(&request, db_name, tdb_flags); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control DB_ATTACH_PERSISTENT failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_db_attach_persistent(reply, db_id); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control DB_ATTACH_PERSISTENT failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_send_gratuitous_arp(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_addr_info *addr_info) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_send_gratuitous_arp(&request, addr_info); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control SEND_GRATUITOUS_ARP failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_send_gratuitous_arp(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control SEND_GRATUITOUS_ARP failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_transaction_start(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t tid) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_transaction_start(&request, tid); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control TRANSACTION_START failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_transaction_start(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control TRANSACTION_START failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_transaction_commit(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t tid) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_transaction_commit(&request, tid); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control TRANSACTION_COMMIT failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_transaction_commit(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control TRANSACTION_COMMIT failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_wipe_database(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t db_id, uint32_t tid) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + struct ctdb_transdb transdb; + int ret; + + transdb.db_id = db_id; + transdb.tid = tid; + + ctdb_req_control_wipe_database(&request, &transdb); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control WIPE_DATABASE failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_wipe_database(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control WIPE_DATABASE failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_uptime(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_uptime **uptime) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_uptime(&request); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control UPTIME failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_uptime(reply, mem_ctx, uptime); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control UPTIME failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_start_recovery(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_start_recovery(&request); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control START_RECOVERY failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_start_recovery(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control START_RECOVERY failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_end_recovery(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_end_recovery(&request); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control END_RECOVERY failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_end_recovery(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control END_RECOVERY failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_reload_nodes_file(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_reload_nodes_file(&request); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control RELOAD_NODES_FILE failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_reload_nodes_file(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control RELOAD_NODES_FILE failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_enable_monitor(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_enable_monitor(&request); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control ENABLE_MONITOR failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_enable_monitor(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control ENABLE_MONITOR failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_disable_monitor(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_disable_monitor(&request); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control DISABLE_MONITOR failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_disable_monitor(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control DISABLE_MONITOR failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_add_public_ip(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_addr_info *addr_info) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_add_public_ip(&request, addr_info); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control ADD_PUBLIC_IP failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_add_public_ip(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control ADD_PUBLIC_IP failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_del_public_ip(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_addr_info *addr_info) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_del_public_ip(&request, addr_info); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control DEL_PUBLIC_IP failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_del_public_ip(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control DEL_PUBLIC_IP failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_run_eventscripts(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + const char *event) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_run_eventscripts(&request, event); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control RUN_EVENTSCRIPTS failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_run_eventscripts(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control RUN_EVENTSCRIPTS failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_get_capabilities(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t *caps) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_get_capabilities(&request); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_CAPABILITIES failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_get_capabilities(reply, caps); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_CAPABILITIES failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_release_ip(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_public_ip *pubip) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_release_ip(&request, pubip); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control RELEASE_IP failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_release_ip(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control RELEASE_IP failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_takeover_ip(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_public_ip *pubip) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_takeover_ip(&request, pubip); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control TAKEOVER_IP failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_takeover_ip(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control TAKEOVER_IP failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_get_public_ips(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_public_ip_list **pubip_list) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_get_public_ips(&request); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_PUBLIC_IPS failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_get_public_ips(reply, mem_ctx, pubip_list); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_PUBLIC_IPS failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_get_nodemap(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_node_map **nodemap) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_get_nodemap(&request); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_NODEMAP failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_get_nodemap(reply, mem_ctx, nodemap); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_NODEMAP failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_get_event_script_status(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + enum ctdb_event event, + struct ctdb_script_list **slist) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_get_event_script_status(&request, event); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_EVENT_SCRIPT_STATUS failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_get_event_script_status(reply, mem_ctx, slist); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_EVENT_SCRIPT_STATUS failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_traverse_kill(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_traverse_start *traverse) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_traverse_kill(&request, traverse); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control TRAVERSE_KILL failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_traverse_kill(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control TRAVERSE_KILL failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_get_reclock_file(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + const char **reclock_file) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_get_reclock_file(&request); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_RECLOCK_FILE failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_get_reclock_file(reply, mem_ctx, reclock_file); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_RECLOCK_FILE failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_set_reclock_file(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + const char *reclock_file) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_set_reclock_file(&request, reclock_file); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control SET_RECLOCK_FILE failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_set_reclock_file(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control SET_RECLOCK_FILE failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_stop_node(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_stop_node(&request); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control STOP_NODE failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_stop_node(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control STOP_NODE failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_continue_node(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_continue_node(&request); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control CONTINUE_NODE failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_continue_node(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control CONTINUE_NODE failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_set_natgwstate(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t natgw_role) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_set_natgwstate(&request, natgw_role); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control SET_NATGWSTATE failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_set_natgwstate(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control SET_NATGWSTATE failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_set_lmasterrole(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t lmaster_role) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_set_lmasterrole(&request, lmaster_role); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control SET_LMASTERROLE failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_set_lmasterrole(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control SET_LMASTERROLE failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_set_recmasterrole(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t recmaster_role) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_set_recmasterrole(&request, recmaster_role); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control SET_RECMASTERROLE failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_set_recmasterrole(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control SET_RECMASTERROLE failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_enable_script(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + const char *script) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_enable_script(&request, script); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control ENABLE_SCRIPT failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_enable_script(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control ENABLE_SCRIPT failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_disable_script(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + const char *script) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_disable_script(&request, script); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control DISABLE_SCRIPT failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_disable_script(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control DISABLE_SCRIPT failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_set_ban_state(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_ban_state *ban_state) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_set_ban_state(&request, ban_state); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control SET_BAN_STATE failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_set_ban_state(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control SET_BAN_STATE failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_get_ban_state(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_ban_state **ban_state) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_get_ban_state(&request); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_BAN_STATE failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_get_ban_state(reply, mem_ctx, ban_state); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_BAN_STATE failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_set_db_priority(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t db_id, int priority) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + struct ctdb_db_priority db_prio; + int ret; + + db_prio.db_id = db_id; + db_prio.priority = priority; + + ctdb_req_control_set_db_priority(&request, &db_prio); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control SET_DB_PRIORITY failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_set_db_priority(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control SET_DB_PRIORITY failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_get_db_priority(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t db_id, uint32_t *priority) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_get_db_priority(&request, db_id); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_DB_PRIORITY failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_get_db_priority(reply, priority); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_DB_PRIORITY failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_transaction_cancel(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t tid) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_transaction_cancel(&request, tid); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control TRANSACTION_CANCEL failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_transaction_cancel(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control TRANSACTION_CANCEL failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_register_notify(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_notify_data *notify) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_register_notify(&request, notify); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control REGISTER_NOTIFY failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_register_notify(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control REGISTER_NOTIFY failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_deregister_notify(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint64_t srvid) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_deregister_notify(&request, srvid); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control DEREGISTER_NOTIFY failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_deregister_notify(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control DEREGISTER_NOTIFY failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_trans3_commit(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_rec_buffer *recbuf) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_trans3_commit(&request, recbuf); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control TRANS3_COMMIT failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_trans3_commit(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control TRANS3_COMMIT failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_get_db_seqnum(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t db_id, uint64_t *seqnum) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_get_db_seqnum(&request, db_id); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_DB_SEQNUM failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_get_db_seqnum(reply, seqnum); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_DB_SEQNUM failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_db_set_healthy(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t db_id) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_db_set_healthy(&request, db_id); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control DB_SET_HEALTHY failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_db_set_healthy(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control DB_SET_HEALTHY failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_db_get_health(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t db_id, const char **reason) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_db_get_health(&request, db_id); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control DB_GET_HEALTH failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_db_get_health(reply, mem_ctx, reason); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control DB_GET_HEALTH failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_get_public_ip_info(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + ctdb_sock_addr *addr, + struct ctdb_public_ip_info **ipinfo) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_get_public_ip_info(&request, addr); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_PUBLIC_IP_INFO failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_get_public_ip_info(reply, mem_ctx, ipinfo); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_PUBLIC_IP_INFO failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_get_ifaces(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_iface_list **iface_list) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_get_ifaces(&request); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_IFACES failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_get_ifaces(reply, mem_ctx, iface_list); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_IFACES failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_set_iface_link_state(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_iface *iface) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_set_iface_link_state(&request, iface); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control SET_IFACE_LINK_STATE failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_set_iface_link_state(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control SET_IFACE_LINK_STATE failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_tcp_add_delayed_update(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_connection *conn) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_tcp_add_delayed_update(&request, conn); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control TCP_ADD_DELAYED_UPDATE failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_tcp_add_delayed_update(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control TCP_ADD_DELAYED_UDATE failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_get_stat_history(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_statistics_list **stats_list) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_get_stat_history(&request); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_STAT_HISTORY failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_get_stat_history(reply, mem_ctx, stats_list); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_STAT_HISTORY failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_schedule_for_deletion(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_key_data *key) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_schedule_for_deletion(&request, key); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control SCHEDULE_FOR_DELETION failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_schedule_for_deletion(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control SCHEDULE_FOR_DELETION failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_set_db_readonly(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t db_id) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_set_db_readonly(&request, db_id); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control SET_DB_READONY failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_set_db_readonly(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control SET_DB_READONY failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_check_srvids(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint64_t *srvid, int count, uint8_t **result) +{ + struct ctdb_uint64_array srvid_list; + struct ctdb_uint8_array *u8_array; + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + srvid_list.num = count; + srvid_list.val = srvid; + + ctdb_req_control_check_srvids(&request, &srvid_list); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control CHECK_SRVIDS failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_check_srvids(reply, &request, &u8_array); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control CHECK_SRVIDS failed, ret=%d\n", ret)); + return ret; + } + + if (u8_array->num != count) { + DEBUG(DEBUG_ERR, + ("Control CHECK_SRVIDS returned invalid data %d != %d\n", + u8_array->num, count)); + return ret; + } + + *result = talloc_steal(mem_ctx, u8_array->val); + return 0; +} + +int ctdb_ctrl_traverse_start_ext(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_traverse_start_ext *traverse) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_traverse_start_ext(&request, traverse); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control TRAVERSE_START_EXT failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_traverse_start_ext(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control TRAVERSE_START_EXT failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_get_db_statistics(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t db_id, + struct ctdb_db_statistics **dbstats) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_get_db_statistics(&request, db_id); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_DB_STATISTICS failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_get_db_statistics(reply, mem_ctx, dbstats); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_DB_STATISTICS failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_set_db_sticky(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t db_id) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_set_db_sticky(&request, db_id); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control SET_DB_STICKY failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_set_db_sticky(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control SET_DB_STICKY failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_reload_public_ips(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_reload_public_ips(&request); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control RELOAD_PUBLIC_IPS failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_reload_public_ips(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control RELOAD_PUBLIC_IPS failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_ipreallocated(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_ipreallocated(&request); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control IPREALLOCATED failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_ipreallocated(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control IPREALLOCATED failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_get_runstate(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + enum ctdb_runstate *runstate) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_get_runstate(&request); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_RUNSTATE failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_get_runstate(reply, runstate); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_RUNSTATE failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_db_detach(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t db_id) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_db_detach(&request, db_id); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control DB_DETACH failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_db_detach(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control DB_DETACH failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_get_nodes_file(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_node_map **nodemap) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_get_nodes_file(&request); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_NODES_FILE failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_get_nodes_file(reply, mem_ctx, nodemap); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control GET_NODES_FILE failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} diff --git a/ctdb/client/client_db.c b/ctdb/client/client_db.c new file mode 100644 index 0000000..97ec1f4 --- /dev/null +++ b/ctdb/client/client_db.c @@ -0,0 +1,2137 @@ +/* + CTDB client code + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include "replace.h" +#include "system/network.h" +#include "system/filesys.h" + +#include +#include +#include + +#include "lib/tdb_wrap/tdb_wrap.h" +#include "lib/util/tevent_unix.h" +#include "lib/util/dlinklist.h" +#include "lib/util/debug.h" +#include "ctdb_logging.h" + +#include "protocol/protocol.h" +#include "protocol/protocol_api.h" +#include "client/client_private.h" +#include "client/client.h" + +static struct ctdb_db_context *client_db_handle( + struct ctdb_client_context *client, + const char *db_name) +{ + struct ctdb_db_context *db; + + for (db = client->db; db != NULL; db = db->next) { + if (strcmp(db_name, db->db_name) == 0) { + return db; + } + } + + return NULL; +} + +struct ctdb_set_db_flags_state { + struct tevent_context *ev; + struct ctdb_client_context *client; + struct timeval timeout; + uint32_t db_id; + uint8_t db_flags; + bool readonly_done, sticky_done; + uint32_t *pnn_list; + int count; +}; + +static void ctdb_set_db_flags_nodemap_done(struct tevent_req *subreq); +static void ctdb_set_db_flags_readonly_done(struct tevent_req *subreq); +static void ctdb_set_db_flags_sticky_done(struct tevent_req *subreq); + +static struct tevent_req *ctdb_set_db_flags_send( + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + uint32_t destnode, struct timeval timeout, + uint32_t db_id, uint8_t db_flags) +{ + struct tevent_req *req, *subreq; + struct ctdb_set_db_flags_state *state; + struct ctdb_req_control request; + + req = tevent_req_create(mem_ctx, &state, + struct ctdb_set_db_flags_state); + if (req == NULL) { + return NULL; + } + + if (! (db_flags & (CTDB_DB_FLAGS_READONLY | CTDB_DB_FLAGS_STICKY))) { + tevent_req_done(req); + return tevent_req_post(req, ev); + } + + state->ev = ev; + state->client = client; + state->timeout = timeout; + state->db_id = db_id; + state->db_flags = db_flags; + + ctdb_req_control_get_nodemap(&request); + subreq = ctdb_client_control_send(state, ev, client, destnode, timeout, + &request); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, ctdb_set_db_flags_nodemap_done, req); + + return req; +} + +static void ctdb_set_db_flags_nodemap_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct ctdb_set_db_flags_state *state = tevent_req_data( + req, struct ctdb_set_db_flags_state); + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + struct ctdb_node_map *nodemap; + int ret; + bool status; + + status = ctdb_client_control_recv(subreq, &ret, state, &reply); + TALLOC_FREE(subreq); + if (! status) { + tevent_req_error(req, ret); + return; + } + + ret = ctdb_reply_control_get_nodemap(reply, state, &nodemap); + talloc_free(reply); + if (ret != 0) { + tevent_req_error(req, ret); + return; + } + + state->count = list_of_connected_nodes(nodemap, CTDB_UNKNOWN_PNN, + state, &state->pnn_list); + talloc_free(nodemap); + if (state->count <= 0) { + tevent_req_error(req, ENOMEM); + return; + } + + if (state->db_flags & CTDB_DB_FLAGS_READONLY) { + ctdb_req_control_set_db_readonly(&request, state->db_id); + subreq = ctdb_client_control_multi_send( + state, state->ev, state->client, + state->pnn_list, state->count, + state->timeout, &request); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, + ctdb_set_db_flags_readonly_done, req); + } else { + state->readonly_done = true; + } + + if (state->db_flags & CTDB_DB_FLAGS_STICKY) { + ctdb_req_control_set_db_sticky(&request, state->db_id); + subreq = ctdb_client_control_multi_send( + state, state->ev, state->client, + state->pnn_list, state->count, + state->timeout, &request); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, ctdb_set_db_flags_sticky_done, + req); + } else { + state->sticky_done = true; + } +} + +static void ctdb_set_db_flags_readonly_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct ctdb_set_db_flags_state *state = tevent_req_data( + req, struct ctdb_set_db_flags_state); + int ret; + bool status; + + status = ctdb_client_control_multi_recv(subreq, &ret, NULL, NULL, + NULL); + TALLOC_FREE(subreq); + if (! status) { + tevent_req_error(req, ret); + return; + } + + state->readonly_done = true; + + if (state->readonly_done && state->sticky_done) { + tevent_req_done(req); + } +} + +static void ctdb_set_db_flags_sticky_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct ctdb_set_db_flags_state *state = tevent_req_data( + req, struct ctdb_set_db_flags_state); + int ret; + bool status; + + status = ctdb_client_control_multi_recv(subreq, &ret, NULL, NULL, + NULL); + TALLOC_FREE(subreq); + if (! status) { + tevent_req_error(req, ret); + return; + } + + state->sticky_done = true; + + if (state->readonly_done && state->sticky_done) { + tevent_req_done(req); + } +} + +static bool ctdb_set_db_flags_recv(struct tevent_req *req, int *perr) +{ + int err; + + if (tevent_req_is_unix_error(req, &err)) { + if (perr != NULL) { + *perr = err; + } + return false; + } + return true; +} + +struct ctdb_attach_state { + struct tevent_context *ev; + struct ctdb_client_context *client; + struct timeval timeout; + uint32_t destnode; + uint8_t db_flags; + uint32_t tdb_flags; + struct ctdb_db_context *db; +}; + +static void ctdb_attach_mutex_done(struct tevent_req *subreq); +static void ctdb_attach_dbid_done(struct tevent_req *subreq); +static void ctdb_attach_dbpath_done(struct tevent_req *subreq); +static void ctdb_attach_health_done(struct tevent_req *subreq); +static void ctdb_attach_flags_done(struct tevent_req *subreq); + +struct tevent_req *ctdb_attach_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + struct timeval timeout, + const char *db_name, uint8_t db_flags) +{ + struct tevent_req *req, *subreq; + struct ctdb_attach_state *state; + struct ctdb_req_control request; + + req = tevent_req_create(mem_ctx, &state, struct ctdb_attach_state); + if (req == NULL) { + return NULL; + } + + state->db = client_db_handle(client, db_name); + if (state->db != NULL) { + tevent_req_done(req); + return tevent_req_post(req, ev); + } + + state->ev = ev; + state->client = client; + state->timeout = timeout; + state->destnode = ctdb_client_pnn(client); + state->db_flags = db_flags; + + state->db = talloc_zero(client, struct ctdb_db_context); + if (tevent_req_nomem(state->db, req)) { + return tevent_req_post(req, ev); + } + + state->db->db_name = talloc_strdup(state->db, db_name); + if (tevent_req_nomem(state->db, req)) { + return tevent_req_post(req, ev); + } + + if (db_flags & CTDB_DB_FLAGS_PERSISTENT) { + state->db->persistent = true; + } + + ctdb_req_control_get_tunable(&request, "TDBMutexEnabled"); + subreq = ctdb_client_control_send(state, ev, client, + ctdb_client_pnn(client), timeout, + &request); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, ctdb_attach_mutex_done, req); + + return req; +} + +static void ctdb_attach_mutex_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct ctdb_attach_state *state = tevent_req_data( + req, struct ctdb_attach_state); + struct ctdb_reply_control *reply; + struct ctdb_req_control request; + uint32_t mutex_enabled; + int ret; + bool status; + + status = ctdb_client_control_recv(subreq, &ret, state, &reply); + TALLOC_FREE(subreq); + if (! status) { + tevent_req_error(req, ret); + return; + } + + ret = ctdb_reply_control_get_tunable(reply, &mutex_enabled); + if (ret != 0) { + /* Treat error as mutex support not available */ + mutex_enabled = 0; + } + + state->tdb_flags = TDB_DEFAULT; + if (! state->db->persistent) { + state->tdb_flags |= (TDB_INCOMPATIBLE_HASH | + TDB_CLEAR_IF_FIRST); + } + if (mutex_enabled == 1) { + state->tdb_flags |= TDB_MUTEX_LOCKING; + } + + if (state->db->persistent) { + ctdb_req_control_db_attach_persistent(&request, + state->db->db_name, + state->tdb_flags); + } else { + ctdb_req_control_db_attach(&request, state->db->db_name, + state->tdb_flags); + } + + subreq = ctdb_client_control_send(state, state->ev, state->client, + state->destnode, state->timeout, + &request); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, ctdb_attach_dbid_done, req); +} + +static void ctdb_attach_dbid_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct ctdb_attach_state *state = tevent_req_data( + req, struct ctdb_attach_state); + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + bool status; + int ret; + + status = ctdb_client_control_recv(subreq, &ret, state, &reply); + TALLOC_FREE(subreq); + if (! status) { + tevent_req_error(req, ret); + return; + } + + if (state->db->persistent) { + ret = ctdb_reply_control_db_attach_persistent( + reply, &state->db->db_id); + } else { + ret = ctdb_reply_control_db_attach(reply, &state->db->db_id); + } + talloc_free(reply); + if (ret != 0) { + tevent_req_error(req, ret); + return; + } + + ctdb_req_control_getdbpath(&request, state->db->db_id); + subreq = ctdb_client_control_send(state, state->ev, state->client, + state->destnode, state->timeout, + &request); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, ctdb_attach_dbpath_done, req); +} + +static void ctdb_attach_dbpath_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct ctdb_attach_state *state = tevent_req_data( + req, struct ctdb_attach_state); + struct ctdb_reply_control *reply; + struct ctdb_req_control request; + bool status; + int ret; + + status = ctdb_client_control_recv(subreq, &ret, state, &reply); + TALLOC_FREE(subreq); + if (! status) { + tevent_req_error(req, ret); + return; + } + + ret = ctdb_reply_control_getdbpath(reply, state->db, + &state->db->db_path); + talloc_free(reply); + if (ret != 0) { + tevent_req_error(req, ret); + return; + } + + ctdb_req_control_db_get_health(&request, state->db->db_id); + subreq = ctdb_client_control_send(state, state->ev, state->client, + state->destnode, state->timeout, + &request); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, ctdb_attach_health_done, req); +} + +static void ctdb_attach_health_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct ctdb_attach_state *state = tevent_req_data( + req, struct ctdb_attach_state); + struct ctdb_reply_control *reply; + const char *reason; + bool status; + int ret; + + status = ctdb_client_control_recv(subreq, &ret, state, &reply); + TALLOC_FREE(subreq); + if (! status) { + tevent_req_error(req, ret); + return; + } + + ret = ctdb_reply_control_db_get_health(reply, state, &reason); + if (ret != 0) { + tevent_req_error(req, ret); + return; + } + + if (reason != NULL) { + /* Database unhealthy, avoid attach */ + /* FIXME: Log here */ + tevent_req_error(req, EIO); + return; + } + + subreq = ctdb_set_db_flags_send(state, state->ev, state->client, + state->destnode, state->timeout, + state->db->db_id, state->db_flags); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, ctdb_attach_flags_done, req); +} + +static void ctdb_attach_flags_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct ctdb_attach_state *state = tevent_req_data( + req, struct ctdb_attach_state); + bool status; + int ret; + + status = ctdb_set_db_flags_recv(subreq, &ret); + TALLOC_FREE(subreq); + if (! status) { + tevent_req_error(req, ret); + return; + } + + state->db->ltdb = tdb_wrap_open(state->db, state->db->db_path, 0, + state->tdb_flags, O_RDWR, 0); + if (tevent_req_nomem(state->db->ltdb, req)) { + return; + } + DLIST_ADD(state->client->db, state->db); + + tevent_req_done(req); +} + +bool ctdb_attach_recv(struct tevent_req *req, int *perr, + struct ctdb_db_context **out) +{ + struct ctdb_attach_state *state = tevent_req_data( + req, struct ctdb_attach_state); + int err; + + if (tevent_req_is_unix_error(req, &err)) { + if (perr != NULL) { + *perr = err; + } + return false; + } + + if (out != NULL) { + *out = state->db; + } + return true; +} + +int ctdb_attach(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + struct timeval timeout, + const char *db_name, uint8_t db_flags, + struct ctdb_db_context **out) +{ + struct tevent_req *req; + bool status; + int ret; + + req = ctdb_attach_send(mem_ctx, ev, client, timeout, + db_name, db_flags); + if (req == NULL) { + return ENOMEM; + } + + tevent_req_poll(req, ev); + + status = ctdb_attach_recv(req, &ret, out); + if (! status) { + return ret; + } + + /* + ctdb_set_call(db, CTDB_NULL_FUNC, ctdb_null_func); + ctdb_set_call(db, CTDB_FETCH_FUNC, ctdb_fetch_func); + ctdb_set_call(db, CTDB_FETCH_WITH_HEADER_FUNC, ctdb_fetch_with_header_func); + */ + + return 0; +} + +int ctdb_detach(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + struct timeval timeout, uint32_t db_id) +{ + struct ctdb_db_context *db; + int ret; + + ret = ctdb_ctrl_db_detach(mem_ctx, ev, client, client->pnn, timeout, + db_id); + if (ret != 0) { + return ret; + } + + for (db = client->db; db != NULL; db = db->next) { + if (db->db_id == db_id) { + DLIST_REMOVE(client->db, db); + break; + } + } + + return 0; +} + +uint32_t ctdb_db_id(struct ctdb_db_context *db) +{ + return db->db_id; +} + +struct ctdb_db_traverse_state { + ctdb_rec_parser_func_t parser; + void *private_data; + bool extract_header; + int error; +}; + +static int ctdb_db_traverse_handler(struct tdb_context *tdb, TDB_DATA key, + TDB_DATA data, void *private_data) +{ + struct ctdb_db_traverse_state *state = + (struct ctdb_db_traverse_state *)private_data; + int ret; + + if (state->extract_header) { + struct ctdb_ltdb_header header; + size_t len; + + ret = ctdb_ltdb_header_pull(data.dptr, data.dsize, &header); + if (ret != 0) { + state->error = ret; + return 1; + } + + len = ctdb_ltdb_header_len(&header); + + data.dptr += len; + data.dsize -= len; + + ret = state->parser(0, &header, key, data, state->private_data); + } else { + ret = state->parser(0, NULL, key, data, state->private_data); + } + + if (ret != 0) { + state->error = ret; + return 1; + } + + return 0; +} + +int ctdb_db_traverse(struct ctdb_db_context *db, bool readonly, + bool extract_header, + ctdb_rec_parser_func_t parser, void *private_data) +{ + struct ctdb_db_traverse_state state; + int ret; + + state.parser = parser; + state.private_data = private_data; + state.extract_header = extract_header; + state.error = 0; + + if (readonly) { + ret = tdb_traverse_read(db->ltdb->tdb, + ctdb_db_traverse_handler, &state); + } else { + ret = tdb_traverse(db->ltdb->tdb, + ctdb_db_traverse_handler, &state); + } + + if (ret == -1) { + return EIO; + } + + return state.error; +} + +static int ctdb_ltdb_fetch(struct ctdb_db_context *db, TDB_DATA key, + struct ctdb_ltdb_header *header, + TALLOC_CTX *mem_ctx, TDB_DATA *data) +{ + TDB_DATA rec; + int ret; + + rec = tdb_fetch(db->ltdb->tdb, key); + if (rec.dsize < sizeof(struct ctdb_ltdb_header)) { + /* No record present */ + if (rec.dptr != NULL) { + free(rec.dptr); + } + + if (tdb_error(db->ltdb->tdb) != TDB_ERR_NOEXIST) { + return EIO; + } + + header->rsn = 0; + header->dmaster = CTDB_UNKNOWN_PNN; + header->flags = 0; + + if (data != NULL) { + *data = tdb_null; + } + return 0; + } + + ret = ctdb_ltdb_header_pull(rec.dptr, rec.dsize, header); + if (ret != 0) { + return ret; + } + + ret = 0; + if (data != NULL) { + size_t offset = ctdb_ltdb_header_len(header); + + data->dsize = rec.dsize - offset; + data->dptr = talloc_memdup(mem_ctx, rec.dptr + offset, + data->dsize); + if (data->dptr == NULL) { + ret = ENOMEM; + } + } + + free(rec.dptr); + return ret; +} + +/* + * Fetch a record from volatile database + * + * Steps: + * 1. Get a lock on the hash chain + * 2. If the record does not exist, migrate the record + * 3. If readonly=true and delegations do not exist, migrate the record. + * 4. If readonly=false and delegations exist, migrate the record. + * 5. If the local node is not dmaster, migrate the record. + * 6. Return record + */ + +struct ctdb_fetch_lock_state { + struct tevent_context *ev; + struct ctdb_client_context *client; + struct ctdb_record_handle *h; + bool readonly; + uint32_t pnn; +}; + +static int ctdb_fetch_lock_check(struct tevent_req *req); +static void ctdb_fetch_lock_migrate(struct tevent_req *req); +static void ctdb_fetch_lock_migrate_done(struct tevent_req *subreq); + +struct tevent_req *ctdb_fetch_lock_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + struct ctdb_db_context *db, + TDB_DATA key, bool readonly) +{ + struct ctdb_fetch_lock_state *state; + struct tevent_req *req; + int ret; + + req = tevent_req_create(mem_ctx, &state, struct ctdb_fetch_lock_state); + if (req == NULL) { + return NULL; + } + + state->ev = ev; + state->client = client; + + state->h = talloc_zero(db, struct ctdb_record_handle); + if (tevent_req_nomem(state->h, req)) { + return tevent_req_post(req, ev); + } + state->h->client = client; + state->h->db = db; + state->h->key.dptr = talloc_memdup(state->h, key.dptr, key.dsize); + if (tevent_req_nomem(state->h->key.dptr, req)) { + return tevent_req_post(req, ev); + } + state->h->key.dsize = key.dsize; + state->h->readonly = false; + + state->readonly = readonly; + state->pnn = ctdb_client_pnn(client); + + /* Check that database is not persistent */ + if (db->persistent) { + tevent_req_error(req, EINVAL); + return tevent_req_post(req, ev); + } + + ret = ctdb_fetch_lock_check(req); + if (ret == 0) { + tevent_req_done(req); + return tevent_req_post(req, ev); + } + if (ret != EAGAIN) { + tevent_req_error(req, ret); + return tevent_req_post(req, ev); + } + return req; +} + +static int ctdb_fetch_lock_check(struct tevent_req *req) +{ + struct ctdb_fetch_lock_state *state = tevent_req_data( + req, struct ctdb_fetch_lock_state); + struct ctdb_record_handle *h = state->h; + struct ctdb_ltdb_header header; + TDB_DATA data = tdb_null; + int ret, err = 0; + bool do_migrate = false; + + ret = tdb_chainlock(state->h->db->ltdb->tdb, state->h->key); + if (ret != 0) { + err = EIO; + goto failed; + } + + data = tdb_fetch(h->db->ltdb->tdb, h->key); + if (data.dptr == NULL) { + if (tdb_error(h->db->ltdb->tdb) == TDB_ERR_NOEXIST) { + goto migrate; + } else { + err = EIO; + goto failed; + } + } + + /* Got the record */ + ret = ctdb_ltdb_header_pull(data.dptr, data.dsize, &header); + if (ret != 0) { + err = ret; + goto failed; + } + + if (! state->readonly) { + /* Read/write access */ + if (header.dmaster == state->pnn && + header.flags & CTDB_REC_RO_HAVE_DELEGATIONS) { + goto migrate; + } + + if (header.dmaster != state->pnn) { + goto migrate; + } + } else { + /* Readonly access */ + if (header.dmaster != state->pnn && + ! (header.flags & (CTDB_REC_RO_HAVE_READONLY | + CTDB_REC_RO_HAVE_DELEGATIONS))) { + goto migrate; + } + } + + /* We are the dmaster or readonly delegation */ + h->header = header; + h->data = data; + if (header.flags & (CTDB_REC_RO_HAVE_READONLY | + CTDB_REC_RO_HAVE_DELEGATIONS)) { + h->readonly = true; + } + return 0; + +migrate: + do_migrate = true; + err = EAGAIN; + +failed: + if (data.dptr != NULL) { + free(data.dptr); + } + ret = tdb_chainunlock(h->db->ltdb->tdb, h->key); + if (ret != 0) { + DEBUG(DEBUG_ERR, ("tdb_chainunlock failed on %s\n", + h->db->db_name)); + return EIO; + } + + if (do_migrate) { + ctdb_fetch_lock_migrate(req); + } + return err; +} + +static void ctdb_fetch_lock_migrate(struct tevent_req *req) +{ + struct ctdb_fetch_lock_state *state = tevent_req_data( + req, struct ctdb_fetch_lock_state); + struct ctdb_req_call request; + struct tevent_req *subreq; + + ZERO_STRUCT(request); + request.flags = CTDB_IMMEDIATE_MIGRATION; + if (state->readonly) { + request.flags |= CTDB_WANT_READONLY; + } + request.db_id = state->h->db->db_id; + request.callid = CTDB_NULL_FUNC; + request.key = state->h->key; + + subreq = ctdb_client_call_send(state, state->ev, state->client, + &request); + if (tevent_req_nomem(subreq, req)) { + return; + } + + tevent_req_set_callback(subreq, ctdb_fetch_lock_migrate_done, req); +} + +static void ctdb_fetch_lock_migrate_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct ctdb_fetch_lock_state *state = tevent_req_data( + req, struct ctdb_fetch_lock_state); + struct ctdb_reply_call *reply; + int ret; + bool status; + + status = ctdb_client_call_recv(subreq, state, &reply, &ret); + TALLOC_FREE(subreq); + if (! status) { + tevent_req_error(req, ret); + return; + } + + if (reply->status != 0) { + tevent_req_error(req, EIO); + return; + } + talloc_free(reply); + + ret = ctdb_fetch_lock_check(req); + if (ret != 0) { + tevent_req_error(req, ret); + return; + } + + tevent_req_done(req); +} + +static int ctdb_record_handle_destructor(struct ctdb_record_handle *h) +{ + tdb_chainunlock(h->db->ltdb->tdb, h->key); + free(h->data.dptr); + return 0; +} + +struct ctdb_record_handle *ctdb_fetch_lock_recv(struct tevent_req *req, + struct ctdb_ltdb_header *header, + TALLOC_CTX *mem_ctx, + TDB_DATA *data, int *perr) +{ + struct ctdb_fetch_lock_state *state = tevent_req_data( + req, struct ctdb_fetch_lock_state); + struct ctdb_record_handle *h = state->h; + int err; + + if (tevent_req_is_unix_error(req, &err)) { + if (perr != NULL) { + *perr = err; + } + return NULL; + } + + if (header != NULL) { + *header = h->header; + } + if (data != NULL) { + size_t offset; + + offset = ctdb_ltdb_header_len(&h->header); + + data->dsize = h->data.dsize - offset; + data->dptr = talloc_memdup(mem_ctx, h->data.dptr + offset, + data->dsize); + if (data->dptr == NULL) { + TALLOC_FREE(state->h); + if (perr != NULL) { + *perr = ENOMEM; + } + return NULL; + } + } + + talloc_set_destructor(h, ctdb_record_handle_destructor); + return h; +} + +int ctdb_fetch_lock(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + struct ctdb_db_context *db, TDB_DATA key, bool readonly, + struct ctdb_record_handle **out, + struct ctdb_ltdb_header *header, TDB_DATA *data) +{ + struct tevent_req *req; + struct ctdb_record_handle *h; + int ret; + + req = ctdb_fetch_lock_send(mem_ctx, ev, client, db, key, readonly); + if (req == NULL) { + return ENOMEM; + } + + tevent_req_poll(req, ev); + + h = ctdb_fetch_lock_recv(req, header, mem_ctx, data, &ret); + if (h == NULL) { + return ret; + } + + *out = h; + return 0; +} + +int ctdb_store_record(struct ctdb_record_handle *h, TDB_DATA data) +{ + TDB_DATA rec; + size_t offset; + int ret; + + /* Cannot modify the record if it was obtained as a readonly copy */ + if (h->readonly) { + return EINVAL; + } + + /* Check if the new data is same */ + if (h->data.dsize == data.dsize && + memcmp(h->data.dptr, data.dptr, data.dsize) == 0) { + /* No need to do anything */ + return 0; + } + + offset = ctdb_ltdb_header_len(&h->header); + rec.dsize = offset + data.dsize; + rec.dptr = talloc_size(h, rec.dsize); + if (rec.dptr == NULL) { + return ENOMEM; + } + + ctdb_ltdb_header_push(&h->header, rec.dptr); + memcpy(rec.dptr + offset, data.dptr, data.dsize); + + ret = tdb_store(h->db->ltdb->tdb, h->key, rec, TDB_REPLACE); + if (ret != 0) { + DEBUG(DEBUG_ERR, ("Failed to store record in DB %s\n", + h->db->db_name)); + return EIO; + } + + talloc_free(rec.dptr); + return 0; +} + +int ctdb_delete_record(struct ctdb_record_handle *h) +{ + TDB_DATA rec; + struct ctdb_key_data key; + int ret; + + /* Cannot delete the record if it was obtained as a readonly copy */ + if (h->readonly) { + return EINVAL; + } + + rec.dsize = ctdb_ltdb_header_len(&h->header); + rec.dptr = talloc_size(h, rec.dsize); + if (rec.dptr == NULL) { + return ENOMEM; + } + + ctdb_ltdb_header_push(&h->header, rec.dptr); + + ret = tdb_store(h->db->ltdb->tdb, h->key, rec, TDB_REPLACE); + talloc_free(rec.dptr); + if (ret != 0) { + DEBUG(DEBUG_ERR, ("Failed to delete record in DB %s\n", + h->db->db_name)); + return EIO; + } + + key.db_id = h->db->db_id; + key.header = h->header; + key.key = h->key; + + ret = ctdb_ctrl_schedule_for_deletion(h, h->ev, h->client, + h->client->pnn, + tevent_timeval_zero(), &key); + if (ret != 0) { + DEBUG(DEBUG_WARNING, + ("Failed to mark record to be deleted in DB %s\n", + h->db->db_name)); + return ret; + } + + return 0; +} + +/* + * Global lock functions + */ + +struct ctdb_g_lock_lock_state { + struct tevent_context *ev; + struct ctdb_client_context *client; + struct ctdb_db_context *db; + TDB_DATA key; + struct ctdb_server_id my_sid; + enum ctdb_g_lock_type lock_type; + struct ctdb_record_handle *h; + /* state for verification of active locks */ + struct ctdb_g_lock_list *lock_list; + unsigned int current; +}; + +static void ctdb_g_lock_lock_fetched(struct tevent_req *subreq); +static void ctdb_g_lock_lock_process_locks(struct tevent_req *req); +static void ctdb_g_lock_lock_checked(struct tevent_req *subreq); +static int ctdb_g_lock_lock_update(struct tevent_req *req); +static void ctdb_g_lock_lock_retry(struct tevent_req *subreq); + +static bool ctdb_g_lock_conflicts(enum ctdb_g_lock_type l1, + enum ctdb_g_lock_type l2) +{ + if ((l1 == G_LOCK_READ) && (l2 == G_LOCK_READ)) { + return false; + } + return true; +} + +struct tevent_req *ctdb_g_lock_lock_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + struct ctdb_db_context *db, + const char *keyname, + struct ctdb_server_id *sid, + bool readonly) +{ + struct tevent_req *req, *subreq; + struct ctdb_g_lock_lock_state *state; + + req = tevent_req_create(mem_ctx, &state, + struct ctdb_g_lock_lock_state); + if (req == NULL) { + return NULL; + } + + state->ev = ev; + state->client = client; + state->db = db; + state->key.dptr = discard_const(keyname); + state->key.dsize = strlen(keyname) + 1; + state->my_sid = *sid; + state->lock_type = (readonly ? G_LOCK_READ : G_LOCK_WRITE); + + subreq = ctdb_fetch_lock_send(state, ev, client, db, state->key, + false); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, ctdb_g_lock_lock_fetched, req); + + return req; +} + +static void ctdb_g_lock_lock_fetched(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct ctdb_g_lock_lock_state *state = tevent_req_data( + req, struct ctdb_g_lock_lock_state); + TDB_DATA data; + int ret = 0; + + state->h = ctdb_fetch_lock_recv(subreq, NULL, state, &data, &ret); + TALLOC_FREE(subreq); + if (state->h == NULL) { + tevent_req_error(req, ret); + return; + } + + if (state->lock_list != NULL) { + TALLOC_FREE(state->lock_list); + state->current = 0; + } + + ret = ctdb_g_lock_list_pull(data.dptr, data.dsize, state, + &state->lock_list); + talloc_free(data.dptr); + if (ret != 0) { + tevent_req_error(req, ret); + return; + } + + ctdb_g_lock_lock_process_locks(req); +} + +static void ctdb_g_lock_lock_process_locks(struct tevent_req *req) +{ + struct ctdb_g_lock_lock_state *state = tevent_req_data( + req, struct ctdb_g_lock_lock_state); + struct tevent_req *subreq; + struct ctdb_g_lock *lock; + bool check_server = false; + int ret; + + while (state->current < state->lock_list->num) { + lock = &state->lock_list->lock[state->current]; + + /* We should not ask for the same lock more than once */ + if (ctdb_server_id_equal(&lock->sid, &state->my_sid)) { + tevent_req_error(req, EDEADLK); + return; + } + + if (ctdb_g_lock_conflicts(lock->type, state->lock_type)) { + check_server = true; + break; + } + + state->current += 1; + } + + if (check_server) { + struct ctdb_req_control request; + struct ctdb_uint64_array u64_array; + + u64_array.num = 1; + u64_array.val = &lock->sid.unique_id; + + ctdb_req_control_check_srvids(&request, &u64_array); + subreq = ctdb_client_control_send(state, state->ev, + state->client, + state->client->pnn, + tevent_timeval_zero(), + &request); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, ctdb_g_lock_lock_checked, req); + return; + } + + /* There is no conflict, add ourself to the lock_list */ + state->lock_list->lock = talloc_realloc(state->lock_list, + state->lock_list->lock, + struct ctdb_g_lock, + state->lock_list->num + 1); + if (state->lock_list->lock == NULL) { + tevent_req_error(req, ENOMEM); + return; + } + + lock = &state->lock_list->lock[state->lock_list->num]; + lock->type = state->lock_type; + lock->sid = state->my_sid; + state->lock_list->num += 1; + + ret = ctdb_g_lock_lock_update(req); + if (ret != 0) { + tevent_req_error(req, ret); + return; + } + + tevent_req_done(req); +} + +static void ctdb_g_lock_lock_checked(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct ctdb_g_lock_lock_state *state = tevent_req_data( + req, struct ctdb_g_lock_lock_state); + struct ctdb_reply_control *reply; + struct ctdb_uint8_array *u8_array; + int ret; + bool status; + int8_t val; + + status = ctdb_client_control_recv(subreq, &ret, state, &reply); + TALLOC_FREE(subreq); + if (! status) { + tevent_req_error(req, ret); + return; + } + + ret = ctdb_reply_control_check_srvids(reply, state, &u8_array); + if (ret != 0) { + tevent_req_error(req, ENOMEM); + return; + } + + if (u8_array->num != 1) { + talloc_free(u8_array); + tevent_req_error(req, EIO); + return; + } + + val = u8_array->val[0]; + talloc_free(u8_array); + + if (val == 1) { + /* server process exists, need to retry */ + subreq = tevent_wakeup_send(state, state->ev, + tevent_timeval_current_ofs(1,0)); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, ctdb_g_lock_lock_retry, req); + return; + } + + /* server process does not exist, remove conflicting entry */ + state->lock_list->lock[state->current] = + state->lock_list->lock[state->lock_list->num-1]; + state->lock_list->num -= 1; + + ret = ctdb_g_lock_lock_update(req); + if (ret != 0) { + tevent_req_error(req, ret); + return; + } + + ctdb_g_lock_lock_process_locks(req); +} + +static int ctdb_g_lock_lock_update(struct tevent_req *req) +{ + struct ctdb_g_lock_lock_state *state = tevent_req_data( + req, struct ctdb_g_lock_lock_state); + TDB_DATA data; + int ret; + + data.dsize = ctdb_g_lock_list_len(state->lock_list); + data.dptr = talloc_size(state, data.dsize); + if (data.dptr == NULL) { + return ENOMEM; + } + + ctdb_g_lock_list_push(state->lock_list, data.dptr); + ret = ctdb_store_record(state->h, data); + talloc_free(data.dptr); + return ret; +} + +#if 0 +static int ctdb_g_lock_lock_update(struct ctdb_g_lock_lock_state *state, + struct ctdb_g_lock_list *lock_list, + struct ctdb_record_handle *h) +{ + struct ctdb_g_lock *lock; + bool conflict = false; + bool modified = false; + int ret, i; + + for (i=0; inum; i++) { + lock = &lock_list->lock[i]; + + /* We should not ask for lock more than once */ + if (ctdb_server_id_equal(&lock->sid, &state->my_sid)) { + return EDEADLK; + } + + if (ctdb_g_lock_conflicts(lock->type, state->lock_type)) { + bool exists; + + conflict = true; + ret = ctdb_server_id_exists(state->client, &lock->sid, + &exists); + if (ret != 0) { + return ret; + } + + if (exists) { + break; + } + + /* Server does not exist, delete conflicting entry */ + lock_list->lock[i] = lock_list->lock[lock_list->num-1]; + lock_list->num -= 1; + modified = true; + } + } + + if (! conflict) { + lock = talloc_realloc(lock_list, lock_list->lock, + struct ctdb_g_lock, lock_list->num+1); + if (lock == NULL) { + return ENOMEM; + } + + lock[lock_list->num].type = state->lock_type; + lock[lock_list->num].sid = state->my_sid; + lock_list->lock = lock; + lock_list->num += 1; + modified = true; + } + + if (modified) { + TDB_DATA data; + + data.dsize = ctdb_g_lock_list_len(lock_list); + data.dptr = talloc_size(state, data.dsize); + if (data.dptr == NULL) { + return ENOMEM; + } + + ctdb_g_lock_list_push(lock_list, data.dptr); + ret = ctdb_store_record(h, data); + talloc_free(data.dptr); + if (ret != 0) { + return ret; + } + } + + if (conflict) { + return EAGAIN; + } + return 0; +} +#endif + +static void ctdb_g_lock_lock_retry(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct ctdb_g_lock_lock_state *state = tevent_req_data( + req, struct ctdb_g_lock_lock_state); + bool success; + + success = tevent_wakeup_recv(subreq); + TALLOC_FREE(subreq); + if (! success) { + tevent_req_error(req, ENOMEM); + return; + } + + subreq = ctdb_fetch_lock_send(state, state->ev, state->client, + state->db, state->key, false); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, ctdb_g_lock_lock_fetched, req); +} + +bool ctdb_g_lock_lock_recv(struct tevent_req *req, int *perr) +{ + struct ctdb_g_lock_lock_state *state = tevent_req_data( + req, struct ctdb_g_lock_lock_state); + int err; + + TALLOC_FREE(state->h); + + if (tevent_req_is_unix_error(req, &err)) { + if (perr != NULL) { + *perr = err; + } + return false; + } + + return true; +} + +struct ctdb_g_lock_unlock_state { + struct tevent_context *ev; + struct ctdb_client_context *client; + struct ctdb_db_context *db; + TDB_DATA key; + struct ctdb_server_id my_sid; + struct ctdb_record_handle *h; + struct ctdb_g_lock_list *lock_list; +}; + +static void ctdb_g_lock_unlock_fetched(struct tevent_req *subreq); +static int ctdb_g_lock_unlock_update(struct tevent_req *req); + +struct tevent_req *ctdb_g_lock_unlock_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + struct ctdb_db_context *db, + const char *keyname, + struct ctdb_server_id sid) +{ + struct tevent_req *req, *subreq; + struct ctdb_g_lock_unlock_state *state; + + req = tevent_req_create(mem_ctx, &state, + struct ctdb_g_lock_unlock_state); + if (req == NULL) { + return NULL; + } + + state->ev = ev; + state->client = client; + state->db = db; + state->key.dptr = discard_const(keyname); + state->key.dsize = strlen(keyname) + 1; + state->my_sid = sid; + + subreq = ctdb_fetch_lock_send(state, ev, client, db, state->key, + false); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, ctdb_g_lock_unlock_fetched, req); + + return req; +} + +static void ctdb_g_lock_unlock_fetched(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct ctdb_g_lock_unlock_state *state = tevent_req_data( + req, struct ctdb_g_lock_unlock_state); + TDB_DATA data; + int ret = 0; + + state->h = ctdb_fetch_lock_recv(subreq, NULL, state, &data, &ret); + TALLOC_FREE(subreq); + if (state->h == NULL) { + tevent_req_error(req, ret); + return; + } + + ret = ctdb_g_lock_list_pull(data.dptr, data.dsize, state, + &state->lock_list); + if (ret != 0) { + tevent_req_error(req, ret); + return; + } + + ret = ctdb_g_lock_unlock_update(req); + if (ret != 0) { + tevent_req_error(req, ret); + return; + } + + tevent_req_done(req); +} + +static int ctdb_g_lock_unlock_update(struct tevent_req *req) +{ + struct ctdb_g_lock_unlock_state *state = tevent_req_data( + req, struct ctdb_g_lock_unlock_state); + struct ctdb_g_lock *lock; + int ret, i; + + for (i=0; ilock_list->num; i++) { + lock = &state->lock_list->lock[i]; + + if (ctdb_server_id_equal(&lock->sid, &state->my_sid)) { + break; + } + } + + if (i < state->lock_list->num) { + state->lock_list->lock[i] = + state->lock_list->lock[state->lock_list->num-1]; + state->lock_list->num -= 1; + } + + if (state->lock_list->num == 0) { + ctdb_delete_record(state->h); + } else { + TDB_DATA data; + + data.dsize = ctdb_g_lock_list_len(state->lock_list); + data.dptr = talloc_size(state, data.dsize); + if (data.dptr == NULL) { + return ENOMEM; + } + + ctdb_g_lock_list_push(state->lock_list, data.dptr); + ret = ctdb_store_record(state->h, data); + talloc_free(data.dptr); + if (ret != 0) { + return ret; + } + } + + return 0; +} + +bool ctdb_g_lock_unlock_recv(struct tevent_req *req, int *perr) +{ + struct ctdb_g_lock_unlock_state *state = tevent_req_data( + req, struct ctdb_g_lock_unlock_state); + int err; + + TALLOC_FREE(state->h); + + if (tevent_req_is_unix_error(req, &err)) { + if (perr != NULL) { + *perr = err; + } + return false; + } + + return true; +} + +/* + * Persistent database functions + */ +struct ctdb_transaction_start_state { + struct tevent_context *ev; + struct ctdb_client_context *client; + struct timeval timeout; + struct ctdb_transaction_handle *h; + uint32_t destnode; +}; + +static void ctdb_transaction_g_lock_attached(struct tevent_req *subreq); +static void ctdb_transaction_register_done(struct tevent_req *subreq); +static void ctdb_transaction_g_lock_done(struct tevent_req *subreq); +static int ctdb_transaction_handle_destructor(struct ctdb_transaction_handle *h); + +struct tevent_req *ctdb_transaction_start_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + struct timeval timeout, + struct ctdb_db_context *db, + bool readonly) +{ + struct ctdb_transaction_start_state *state; + struct tevent_req *req, *subreq; + struct ctdb_transaction_handle *h; + + req = tevent_req_create(mem_ctx, &state, + struct ctdb_transaction_start_state); + if (req == NULL) { + return NULL; + } + + if (! db->persistent) { + tevent_req_error(req, EINVAL); + return tevent_req_post(req, ev); + } + + state->ev = ev; + state->client = client; + state->destnode = ctdb_client_pnn(client); + + h = talloc_zero(db, struct ctdb_transaction_handle); + if (tevent_req_nomem(h, req)) { + return tevent_req_post(req, ev); + } + + h->client = client; + h->db = db; + h->readonly = readonly; + h->updated = false; + + /* SRVID is unique for databases, so client can have transactions active + * for multiple databases */ + h->sid.pid = getpid(); + h->sid.task_id = db->db_id; + h->sid.vnn = state->destnode; + h->sid.unique_id = h->sid.task_id; + h->sid.unique_id = (h->sid.unique_id << 32) | h->sid.pid; + + h->recbuf = talloc_zero(h, struct ctdb_rec_buffer); + if (tevent_req_nomem(h->recbuf, req)) { + return tevent_req_post(req, ev); + } + + h->lock_name = talloc_asprintf(h, "transaction_db_0x%08x", db->db_id); + if (tevent_req_nomem(h->lock_name, req)) { + return tevent_req_post(req, ev); + } + + state->h = h; + + subreq = ctdb_attach_send(state, ev, client, timeout, "g_lock.tdb", 0); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, ctdb_transaction_g_lock_attached, req); + + return req; +} + +static void ctdb_transaction_g_lock_attached(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct ctdb_transaction_start_state *state = tevent_req_data( + req, struct ctdb_transaction_start_state); + struct ctdb_req_control request; + bool status; + int ret; + + status = ctdb_attach_recv(subreq, &ret, &state->h->db_g_lock); + TALLOC_FREE(subreq); + if (! status) { + tevent_req_error(req, ret); + return; + } + + ctdb_req_control_register_srvid(&request, state->h->sid.unique_id); + subreq = ctdb_client_control_send(state, state->ev, state->client, + state->destnode, state->timeout, + &request); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, ctdb_transaction_register_done, req); +} + +static void ctdb_transaction_register_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct ctdb_transaction_start_state *state = tevent_req_data( + req, struct ctdb_transaction_start_state); + struct ctdb_reply_control *reply; + bool status; + int ret; + + status = ctdb_client_control_recv(subreq, &ret, state, &reply); + TALLOC_FREE(subreq); + if (! status) { + tevent_req_error(req, ret); + return; + } + + ret = ctdb_reply_control_register_srvid(reply); + talloc_free(reply); + if (ret != 0) { + tevent_req_error(req, ret); + return; + } + + subreq = ctdb_g_lock_lock_send(state, state->ev, state->client, + state->h->db_g_lock, state->h->lock_name, + &state->h->sid, state->h->readonly); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, ctdb_transaction_g_lock_done, req); +} + +static void ctdb_transaction_g_lock_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + int ret; + bool status; + + status = ctdb_g_lock_lock_recv(subreq, &ret); + TALLOC_FREE(subreq); + if (! status) { + tevent_req_error(req, ret); + return; + } + + tevent_req_done(req); +} + +struct ctdb_transaction_handle *ctdb_transaction_start_recv( + struct tevent_req *req, + int *perr) +{ + struct ctdb_transaction_start_state *state = tevent_req_data( + req, struct ctdb_transaction_start_state); + struct ctdb_transaction_handle *h = state->h; + int err; + + if (tevent_req_is_unix_error(req, &err)) { + if (perr != NULL) { + *perr = err; + } + return NULL; + } + + talloc_set_destructor(h, ctdb_transaction_handle_destructor); + return h; +} + +static int ctdb_transaction_handle_destructor(struct ctdb_transaction_handle *h) +{ + int ret; + + ret = ctdb_ctrl_deregister_srvid(h, h->ev, h->client, h->client->pnn, + tevent_timeval_zero(), + h->sid.unique_id); + if (ret != 0) { + DEBUG(DEBUG_WARNING, ("Failed to deregister SRVID\n")); + } + + return 0; +} + +int ctdb_transaction_start(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + struct timeval timeout, + struct ctdb_db_context *db, bool readonly, + struct ctdb_transaction_handle **out) +{ + struct tevent_req *req; + struct ctdb_transaction_handle *h; + int ret; + + req = ctdb_transaction_start_send(mem_ctx, ev, client, timeout, db, + readonly); + if (req == NULL) { + return ENOMEM; + } + + tevent_req_poll(req, ev); + + h = ctdb_transaction_start_recv(req, &ret); + if (h == NULL) { + return ret; + } + + *out = h; + return 0; +} + +struct ctdb_transaction_record_fetch_state { + TDB_DATA key, data; + struct ctdb_ltdb_header header; + bool found; +}; + +static int ctdb_transaction_record_fetch_traverse(uint32_t reqid, + struct ctdb_ltdb_header *header, + TDB_DATA key, + TDB_DATA data, + void *private_data) +{ + struct ctdb_transaction_record_fetch_state *state = + (struct ctdb_transaction_record_fetch_state *)private_data; + + if (state->key.dsize == key.dsize && + memcmp(state->key.dptr, key.dptr, key.dsize) == 0) { + state->data = data; + state->header = *header; + state->found = true; + } + + return 0; +} + +static int ctdb_transaction_record_fetch(struct ctdb_transaction_handle *h, + TDB_DATA key, + struct ctdb_ltdb_header *header, + TDB_DATA *data) +{ + struct ctdb_transaction_record_fetch_state state; + int ret; + + state.key = key; + state.found = false; + + ret = ctdb_rec_buffer_traverse(h->recbuf, + ctdb_transaction_record_fetch_traverse, + &state); + if (ret != 0) { + return ret; + } + + if (state.found) { + if (header != NULL) { + *header = state.header; + } + if (data != NULL) { + *data = state.data; + } + return 0; + } + + return ENOENT; +} + +int ctdb_transaction_fetch_record(struct ctdb_transaction_handle *h, + TDB_DATA key, + TALLOC_CTX *mem_ctx, TDB_DATA *data) +{ + TDB_DATA tmp_data; + struct ctdb_ltdb_header header; + int ret; + + ret = ctdb_transaction_record_fetch(h, key, NULL, &tmp_data); + if (ret == 0) { + data->dptr = talloc_memdup(mem_ctx, tmp_data.dptr, + tmp_data.dsize); + if (data->dptr == NULL) { + return ENOMEM; + } + data->dsize = tmp_data.dsize; + return 0; + } + + ret = ctdb_ltdb_fetch(h->db, key, &header, mem_ctx, data); + if (ret != 0) { + return ret; + } + + ret = ctdb_rec_buffer_add(h, h->recbuf, 0, &header, key, *data); + if (ret != 0) { + return ret; + } + + return 0; +} + +int ctdb_transaction_store_record(struct ctdb_transaction_handle *h, + TDB_DATA key, TDB_DATA data) +{ + TALLOC_CTX *tmp_ctx; + struct ctdb_ltdb_header header; + TDB_DATA old_data; + int ret; + + if (h->readonly) { + return EINVAL; + } + + tmp_ctx = talloc_new(h); + if (tmp_ctx == NULL) { + return ENOMEM; + } + + ret = ctdb_transaction_record_fetch(h, key, &header, &old_data); + if (ret != 0) { + ret = ctdb_ltdb_fetch(h->db, key, &header, tmp_ctx, &old_data); + if (ret != 0) { + return ret; + } + } + + if (old_data.dsize == data.dsize && + memcmp(old_data.dptr, data.dptr, data.dsize) == 0) { + talloc_free(tmp_ctx); + return 0; + } + + header.dmaster = ctdb_client_pnn(h->client); + header.rsn += 1; + + ret = ctdb_rec_buffer_add(h, h->recbuf, 0, &header, key, data); + talloc_free(tmp_ctx); + if (ret != 0) { + return ret; + } + h->updated = true; + + return 0; +} + +int ctdb_transaction_delete_record(struct ctdb_transaction_handle *h, + TDB_DATA key) +{ + return ctdb_transaction_store_record(h, key, tdb_null); +} + +static int ctdb_transaction_store_db_seqnum(struct ctdb_transaction_handle *h, + uint64_t seqnum) +{ + const char *keyname = CTDB_DB_SEQNUM_KEY; + TDB_DATA key, data; + + key.dptr = discard_const(keyname); + key.dsize = strlen(keyname) + 1; + + data.dptr = (uint8_t *)&seqnum; + data.dsize = sizeof(seqnum); + + return ctdb_transaction_store_record(h, key, data); +} + +struct ctdb_transaction_commit_state { + struct tevent_context *ev; + struct ctdb_transaction_handle *h; + uint64_t seqnum; +}; + +static void ctdb_transaction_commit_done(struct tevent_req *subreq); +static void ctdb_transaction_commit_try(struct tevent_req *subreq); + +struct tevent_req *ctdb_transaction_commit_send( + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_transaction_handle *h) +{ + struct tevent_req *req, *subreq; + struct ctdb_transaction_commit_state *state; + int ret; + + req = tevent_req_create(mem_ctx, &state, + struct ctdb_transaction_commit_state); + if (req == NULL) { + return NULL; + } + + state->ev = ev; + state->h = h; + + ret = ctdb_ctrl_get_db_seqnum(state, ev, h->client, + h->client->pnn, tevent_timeval_zero(), + h->db->db_id, &state->seqnum); + if (ret != 0) { + tevent_req_error(req, ret); + return tevent_req_post(req, ev); + } + + ret = ctdb_transaction_store_db_seqnum(h, state->seqnum+1); + if (ret != 0) { + tevent_req_error(req, ret); + return tevent_req_post(req, ev); + } + + subreq = ctdb_recovery_wait_send(state, ev, h->client); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, ctdb_transaction_commit_try, req); + + return req; +} + +static void ctdb_transaction_commit_try(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct ctdb_transaction_commit_state *state = tevent_req_data( + req, struct ctdb_transaction_commit_state); + struct ctdb_req_control request; + int ret; + bool status; + + status = ctdb_recovery_wait_recv(subreq, &ret); + TALLOC_FREE(subreq); + if (! status) { + tevent_req_error(req, ret); + return; + } + + ctdb_req_control_trans3_commit(&request, state->h->recbuf); + subreq = ctdb_client_control_send(state, state->ev, state->h->client, + state->h->client->pnn, + tevent_timeval_zero(), &request); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, ctdb_transaction_commit_done, req); +} + +static void ctdb_transaction_commit_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct ctdb_transaction_commit_state *state = tevent_req_data( + req, struct ctdb_transaction_commit_state); + struct ctdb_reply_control *reply; + uint64_t seqnum; + int ret; + bool status; + + status = ctdb_client_control_recv(subreq, &ret, state, &reply); + TALLOC_FREE(subreq); + if (! status) { + tevent_req_error(req, ret); + return; + } + + ret = ctdb_reply_control_trans3_commit(reply); + if (ret < 0) { + /* Control failed due to recovery */ + subreq = ctdb_recovery_wait_send(state, state->ev, + state->h->client); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, ctdb_transaction_commit_try, + req); + return; + } + + ret = ctdb_ctrl_get_db_seqnum(state, state->ev, state->h->client, + state->h->client->pnn, + tevent_timeval_zero(), + state->h->db->db_id, &seqnum); + if (ret != 0) { + tevent_req_error(req, ret); + return; + } + + if (seqnum == state->seqnum) { + subreq = ctdb_recovery_wait_send(state, state->ev, + state->h->client); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, ctdb_transaction_commit_try, + req); + return; + } + + if (seqnum != state->seqnum + 1) { + tevent_req_error(req, EIO); + return; + } + + tevent_req_done(req); +} + +bool ctdb_transaction_commit_recv(struct tevent_req *req, int *perr) +{ + struct ctdb_transaction_commit_state *state = tevent_req_data( + req, struct ctdb_transaction_commit_state); + int err; + + if (tevent_req_is_unix_error(req, &err)) { + if (perr != NULL) { + *perr = err; + } + TALLOC_FREE(state->h); + return false; + } + + TALLOC_FREE(state->h); + return true; +} + +int ctdb_transaction_commit(struct ctdb_transaction_handle *h) +{ + struct tevent_req *req; + int ret; + bool status; + + if (h->readonly || ! h->updated) { + talloc_free(h); + return 0; + } + + req = ctdb_transaction_commit_send(h, h->ev, h); + if (req == NULL) { + talloc_free(h); + return ENOMEM; + } + + tevent_req_poll(req, h->ev); + + status = ctdb_transaction_commit_recv(req, &ret); + if (! status) { + talloc_free(h); + return ret; + } + + talloc_free(h); + return 0; +} + +int ctdb_transaction_cancel(struct ctdb_transaction_handle *h) +{ + talloc_free(h); + return 0; +} + +/* + * TODO: + * + * In future Samba should register SERVER_ID. + * Make that structure same as struct srvid {}. + */ diff --git a/ctdb/client/client_message.c b/ctdb/client/client_message.c new file mode 100644 index 0000000..bfa9ba2 --- /dev/null +++ b/ctdb/client/client_message.c @@ -0,0 +1,227 @@ +/* + CTDB client code + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include "replace.h" +#include "system/network.h" +#include "system/filesys.h" + +#include +#include +#include + +#include "lib/util/tevent_unix.h" + +#include "common/reqid.h" +#include "common/srvid.h" +#include "common/comm.h" + +#include "protocol/protocol.h" +#include "protocol/protocol_api.h" + +#include "client/client_private.h" +#include "client/client.h" + + +/* + * Handle REQ_MESSAGE + */ + +struct ctdb_client_message_state { + struct ctdb_client_context *client; + uint32_t reqid; +}; + +static int ctdb_client_message_state_destructor( + struct ctdb_client_message_state *state); +static void ctdb_client_message_done(struct tevent_req *subreq); + +struct tevent_req *ctdb_client_message_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + uint32_t destnode, + struct ctdb_req_message *message) +{ + struct tevent_req *req, *subreq; + struct ctdb_client_message_state *state; + struct ctdb_req_header h; + uint32_t reqid; + uint8_t *buf; + size_t buflen; + int ret; + + req = tevent_req_create(mem_ctx, &state, + struct ctdb_client_message_state); + if (req == NULL) { + return NULL; + } + + reqid = reqid_new(client->idr, state); + if (reqid == REQID_INVALID) { + talloc_free(req); + return NULL; + } + + state->client = client; + state->reqid = reqid; + + talloc_set_destructor(state, ctdb_client_message_state_destructor); + + ctdb_req_header_fill(&h, 0, CTDB_REQ_MESSAGE, destnode, + client->pnn, reqid); + + ret = ctdb_req_message_push(&h, message, state, &buf, &buflen); + if (ret != 0) { + tevent_req_error(req, ret); + return tevent_req_post(req, ev); + } + + subreq = comm_write_send(state, ev, client->comm, buf, buflen); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, ctdb_client_message_done, req); + + return req; +} + +static int ctdb_client_message_state_destructor( + struct ctdb_client_message_state *state) +{ + reqid_remove(state->client->idr, state->reqid); + return 0; +} + +static void ctdb_client_message_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + int ret; + bool status; + + status = comm_write_recv(subreq, &ret); + TALLOC_FREE(subreq); + if (! status) { + tevent_req_error(req, ret); + return; + } + + tevent_req_done(req); +} + +bool ctdb_client_message_recv(struct tevent_req *req, int *perr) +{ + int err; + + if (tevent_req_is_unix_error(req, &err)) { + if (perr != NULL) { + *perr = err; + } + return false; + } + + return true; +} + +void ctdb_client_req_message(struct ctdb_client_context *client, + uint8_t *buf, size_t buflen, uint32_t reqid) +{ + struct ctdb_req_header h; + struct ctdb_req_message_data message; + TALLOC_CTX *tmp_ctx = talloc_new(client); + int ret; + + ret = ctdb_req_message_data_pull(buf, buflen, &h, tmp_ctx, &message); + if (ret != 0) { + return; + } + + srvid_dispatch(client->srv, message.srvid, CTDB_SRVID_ALL, + message.data); + talloc_free(tmp_ctx); +} + +/* + * sync version of message send + */ + +int ctdb_client_message(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + uint32_t destnode, struct ctdb_req_message *message) +{ + TALLOC_CTX *tmp_ctx; + struct tevent_req *req; + int ret; + bool status; + + tmp_ctx = talloc_new(client); + if (tmp_ctx == NULL) { + return ENOMEM; + } + + req = ctdb_client_message_send(tmp_ctx, ev, client, destnode, message); + if (req == NULL) { + talloc_free(tmp_ctx); + return ENOMEM; + } + + tevent_req_poll(req, ev); + + status = ctdb_client_message_recv(req, &ret); + if (! status) { + talloc_free(tmp_ctx); + return ret; + } + + talloc_free(tmp_ctx); + return 0; +} + +int ctdb_client_set_message_handler(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + uint64_t srvid, srvid_handler_fn handler, + void *private_data) +{ + int ret; + + ret = ctdb_ctrl_register_srvid(mem_ctx, ev, client, client->pnn, + tevent_timeval_zero(), srvid); + if (ret != 0) { + return ret; + } + + return srvid_register(client->srv, client, srvid, + handler, private_data); +} + +int ctdb_client_remove_message_handler(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + uint64_t srvid, void *private_data) +{ + int ret; + + ret = ctdb_ctrl_deregister_srvid(mem_ctx, ev, client, client->pnn, + tevent_timeval_zero(), srvid); + if (ret != 0) { + return ret; + } + + return srvid_deregister(client->srv, srvid, private_data); +} diff --git a/ctdb/client/client_message_sync.c b/ctdb/client/client_message_sync.c new file mode 100644 index 0000000..b6e53f3 --- /dev/null +++ b/ctdb/client/client_message_sync.c @@ -0,0 +1,195 @@ +/* + CTDB client code + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include "replace.h" +#include "system/network.h" +#include "system/filesys.h" + +#include +#include +#include + +#include "lib/util/debug.h" +#include "ctdb_logging.h" + +#include "protocol/protocol.h" +#include "protocol/protocol_api.h" +#include "client/client_private.h" +#include "client/client.h" + +int ctdb_message_recd_update_ip(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct ctdb_public_ip *pubip) +{ + struct ctdb_req_message message; + int ret; + + message.srvid = CTDB_SRVID_RECD_UPDATE_IP; + message.data.pubip = pubip; + + ret = ctdb_client_message(mem_ctx, ev, client, destnode, &message); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Message RECD_UPDATE_IP failed to node %u\n", + destnode)); + } + + return ret; +} + +int ctdb_message_mem_dump(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct ctdb_srvid_message *msg) +{ + struct ctdb_req_message message; + int ret; + + message.srvid = CTDB_SRVID_MEM_DUMP; + message.data.msg = msg; + + ret = ctdb_client_message(mem_ctx, ev, client, destnode, &message); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Message MEM_DUMP failed to node %u\n", destnode)); + } + + return ret; +} + +int ctdb_message_reload_nodes(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode) +{ + struct ctdb_req_message message; + int ret; + + message.srvid = CTDB_SRVID_RELOAD_NODES; + + ret = ctdb_client_message(mem_ctx, ev, client, destnode, &message); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Message RELOAD_NODES failed to node %u\n", destnode)); + } + + return ret; +} + +int ctdb_message_takeover_run(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct ctdb_srvid_message *msg) +{ + struct ctdb_req_message message; + int ret; + + message.srvid = CTDB_SRVID_TAKEOVER_RUN; + message.data.msg = msg; + + ret = ctdb_client_message(mem_ctx, ev, client, destnode, &message); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Message TAKEOVER_RUN failed to node %u\n", destnode)); + } + + return ret; +} + +int ctdb_message_rebalance_node(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, uint32_t pnn) +{ + struct ctdb_req_message message; + int ret; + + message.srvid = CTDB_SRVID_REBALANCE_NODE; + message.data.pnn = pnn; + + ret = ctdb_client_message(mem_ctx, ev, client, destnode, &message); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Message REBALANCE_NODE failed to node %u\n", + destnode)); + } + + return ret; +} + +int ctdb_message_disable_takeover_runs(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, + struct ctdb_disable_message *disable) +{ + struct ctdb_req_message message; + int ret; + + message.srvid = CTDB_SRVID_DISABLE_TAKEOVER_RUNS; + message.data.disable = disable; + + ret = ctdb_client_message(mem_ctx, ev, client, destnode, &message); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Message DISABLE_TAKEOVER_RUNS failed to node %u\n", + destnode)); + } + + return ret; +} + +int ctdb_message_disable_recoveries(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, + struct ctdb_disable_message *disable) +{ + struct ctdb_req_message message; + int ret; + + message.srvid = CTDB_SRVID_DISABLE_RECOVERIES; + message.data.disable = disable; + + ret = ctdb_client_message(mem_ctx, ev, client, destnode, &message); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Message DISABLE_RECOVERIES failed to node %u\n", + destnode)); + } + + return ret; +} + +int ctdb_message_disable_ip_check(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, uint32_t timeout) +{ + struct ctdb_req_message message; + int ret; + + message.srvid = CTDB_SRVID_DISABLE_IP_CHECK; + message.data.timeout = timeout; + + ret = ctdb_client_message(mem_ctx, ev, client, destnode, &message); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Message DISABLE_IP_CHECK failed to node %u\n", + destnode)); + } + + return ret; +} diff --git a/ctdb/client/client_private.h b/ctdb/client/client_private.h new file mode 100644 index 0000000..b1d8d4b --- /dev/null +++ b/ctdb/client/client_private.h @@ -0,0 +1,79 @@ +/* + CTDB client code + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#ifndef __CTDB_CLIENT_PRIVATE_H__ +#define __CTDB_CLIENT_PRIVATE_H__ + +#include "protocol/protocol.h" + +struct ctdb_db_context { + struct ctdb_db_context *prev, *next; + uint32_t db_id; + const char *db_name; + const char *db_path; + struct tdb_wrap *ltdb; + bool persistent; +}; + +struct ctdb_client_context { + struct reqid_context *idr; + struct srvid_context *srv; + struct comm_context *comm; + int fd; + uint32_t pnn; + struct ctdb_db_context *db; +}; + +struct ctdb_record_handle { + struct tevent_context *ev; + struct ctdb_client_context *client; + struct ctdb_db_context *db; + struct ctdb_ltdb_header header; + TDB_DATA key; + TDB_DATA data; /* This is returned from tdb_fetch() */ + bool readonly; +}; + +struct ctdb_transaction_handle { + struct tevent_context *ev; + struct ctdb_client_context *client; + struct ctdb_db_context *db, *db_g_lock; + struct ctdb_rec_buffer *recbuf; + struct ctdb_server_id sid; + const char *lock_name; + bool readonly; + bool updated; +}; + +/* From client_call.c */ + +void ctdb_client_reply_call(struct ctdb_client_context *client, + uint8_t *buf, size_t buflen, uint32_t reqid); + +/* From client_message.c */ + +void ctdb_client_req_message(struct ctdb_client_context *client, + uint8_t *buf, size_t buflen, uint32_t reqid); + +/* From client_control.c */ + +void ctdb_client_reply_control(struct ctdb_client_context *client, + uint8_t *buf, size_t buflen, uint32_t reqid); + +#endif /* __CTDB_CLIENT_PRIVATE_H__ */ diff --git a/ctdb/client/client_util.c b/ctdb/client/client_util.c new file mode 100644 index 0000000..bb2dd6e --- /dev/null +++ b/ctdb/client/client_util.c @@ -0,0 +1,154 @@ +/* + CTDB client code + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include "replace.h" +#include "system/network.h" +#include "system/filesys.h" + +#include +#include +#include + +#include "lib/util/debug.h" +#include "ctdb_logging.h" + +#include "protocol/protocol.h" +#include "protocol/protocol_api.h" +#include "client/client_private.h" +#include "client/client.h" + +int list_of_nodes(struct ctdb_node_map *nodemap, + uint32_t flags_mask, uint32_t exclude_pnn, + TALLOC_CTX *mem_ctx, uint32_t **pnn_list) +{ + int num_nodes = 0; + uint32_t *list; + int i; + + /* Allocate the list of same number of nodes */ + list = talloc_array(mem_ctx, uint32_t, nodemap->num); + if (list == NULL) { + return -1; + } + + for (i=0; inum; i++) { + if (nodemap->node[i].flags & flags_mask) { + continue; + } + if (nodemap->node[i].pnn == exclude_pnn) { + continue; + } + list[num_nodes] = nodemap->node[i].pnn; + num_nodes++; + } + + *pnn_list = list; + return num_nodes; +} + +int list_of_active_nodes(struct ctdb_node_map *nodemap, uint32_t exclude_pnn, + TALLOC_CTX *mem_ctx, uint32_t **pnn_list) +{ + return list_of_nodes(nodemap, NODE_FLAGS_INACTIVE, exclude_pnn, + mem_ctx, pnn_list); +} + +int list_of_connected_nodes(struct ctdb_node_map *nodemap, + uint32_t exclude_pnn, + TALLOC_CTX *mem_ctx, uint32_t **pnn_list) +{ + return list_of_nodes(nodemap, NODE_FLAGS_DISCONNECTED, exclude_pnn, + mem_ctx, pnn_list); +} + +int ctdb_ctrl_modflags(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + uint32_t destnode, struct timeval timeout, + uint32_t set, uint32_t clear) +{ + struct ctdb_node_map *nodemap; + struct ctdb_node_flag_change flag_change; + struct ctdb_req_control request; + uint32_t *pnn_list; + int ret, count; + + ret = ctdb_ctrl_get_nodemap(mem_ctx, ev, client, destnode, + tevent_timeval_zero(), &nodemap); + if (ret != 0) { + return ret; + } + + flag_change.pnn = destnode; + flag_change.old_flags = nodemap->node[destnode].flags; + flag_change.new_flags = flag_change.old_flags | set; + flag_change.new_flags &= ~clear; + + count = list_of_connected_nodes(nodemap, -1, mem_ctx, &pnn_list); + if (count == -1) { + return ENOMEM; + } + + ctdb_req_control_modify_flags(&request, &flag_change); + ret = ctdb_client_control_multi(mem_ctx, ev, client, pnn_list, count, + tevent_timeval_zero(), &request, + NULL, NULL); + return ret; +} + +bool ctdb_server_id_equal(struct ctdb_server_id *sid1, + struct ctdb_server_id *sid2) +{ + if (sid1->pid != sid2->pid) { + return false; + } + if (sid1->task_id != sid2->task_id) { + return false; + } + if (sid1->vnn != sid2->vnn) { + return false; + } + if (sid1->unique_id != sid2->unique_id) { + return false; + } + + return true; +} + +int ctdb_server_id_exists(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + struct ctdb_server_id *sid, bool *exists) +{ + uint8_t *result; + int ret; + + ret = ctdb_ctrl_check_srvids(mem_ctx, ev, client, sid->vnn, + tevent_timeval_zero(), + &sid->unique_id, 1, &result); + if (ret != 0) { + return ret; + } + + if (result[0] == 1) { + *exists = true; + } else { + *exists = false; + } + + return 0; +} diff --git a/ctdb/wscript b/ctdb/wscript index 3d86642..fcdb7c0 100755 --- a/ctdb/wscript +++ b/ctdb/wscript @@ -357,6 +357,17 @@ def build(bld): deps='''replace popt talloc tevent tdb samba-util tdb-wrap ctdb-util''') + bld.SAMBA_SUBSYSTEM('ctdb-client2', + source=bld.SUBDIR('client', + '''client_connect.c client_call.c + client_message.c client_control.c + client_message_sync.c + client_control_sync.c + client_db.c client_util.c + '''), + includes='include include/internal', + deps='replace talloc tevent tdb tdb-wrap') + bld.SAMBA_SUBSYSTEM('ctdb-server', source='server/ctdbd.c ' + bld.SUBDIR('server', From 81ac247c10c362b643c2b3ce57df4fe6ecae78dd Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Sat, 1 Aug 2015 01:47:22 +1000 Subject: [PATCH 064/136] ctdb-protocol: Add controls for parallel DB recovery Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/protocol/protocol.h | 5 ++ ctdb/protocol/protocol_api.h | 20 +++++++ ctdb/protocol/protocol_client.c | 100 ++++++++++++++++++++++++++++++++++ ctdb/protocol/protocol_control.c | 80 +++++++++++++++++++++++++++ ctdb/tests/cunit/protocol_test_002.sh | 2 +- ctdb/tests/src/protocol_client_test.c | 44 ++++++++++++++- 6 files changed, 249 insertions(+), 2 deletions(-) diff --git a/ctdb/protocol/protocol.h b/ctdb/protocol/protocol.h index 805fdd1..f740587 100644 --- a/ctdb/protocol/protocol.h +++ b/ctdb/protocol/protocol.h @@ -348,6 +348,11 @@ enum ctdb_controls {CTDB_CONTROL_PROCESS_EXISTS = 0, CTDB_CONTROL_GET_RUNSTATE = 138, CTDB_CONTROL_DB_DETACH = 139, CTDB_CONTROL_GET_NODES_FILE = 140, + CTDB_CONTROL_DB_FREEZE = 141, + CTDB_CONTROL_DB_THAW = 142, + CTDB_CONTROL_DB_TRANSACTION_START = 143, + CTDB_CONTROL_DB_TRANSACTION_COMMIT = 144, + CTDB_CONTROL_DB_TRANSACTION_CANCEL = 145, }; #define CTDB_MONITORING_ACTIVE 0 diff --git a/ctdb/protocol/protocol_api.h b/ctdb/protocol/protocol_api.h index 3628c3e..cc00b44 100644 --- a/ctdb/protocol/protocol_api.h +++ b/ctdb/protocol/protocol_api.h @@ -610,6 +610,26 @@ int ctdb_reply_control_get_nodes_file(struct ctdb_reply_control *reply, TALLOC_CTX *mem_ctx, struct ctdb_node_map **nodemap); +void ctdb_req_control_db_freeze(struct ctdb_req_control *request, + uint32_t db_id); +int ctdb_reply_control_db_freeze(struct ctdb_reply_control *reply); + +void ctdb_req_control_db_thaw(struct ctdb_req_control *request, + uint32_t db_id); +int ctdb_reply_control_db_thaw(struct ctdb_reply_control *reply); + +void ctdb_req_control_db_transaction_start(struct ctdb_req_control *request, + struct ctdb_transdb *transdb); +int ctdb_reply_control_db_transaction_start(struct ctdb_reply_control *reply); + +void ctdb_req_control_db_transaction_commit(struct ctdb_req_control *request, + struct ctdb_transdb *transdb); +int ctdb_reply_control_db_transaction_commit(struct ctdb_reply_control *reply); + +void ctdb_req_control_db_transaction_cancel(struct ctdb_req_control *request, + uint32_t db_id); +int ctdb_reply_control_db_transaction_cancel(struct ctdb_reply_control *reply); + /* From protocol/protocol_message.c */ int ctdb_req_message_push(struct ctdb_req_header *h, diff --git a/ctdb/protocol/protocol_client.c b/ctdb/protocol/protocol_client.c index f4bfe19..3bfcef8 100644 --- a/ctdb/protocol/protocol_client.c +++ b/ctdb/protocol/protocol_client.c @@ -2368,3 +2368,103 @@ int ctdb_reply_control_get_nodes_file(struct ctdb_reply_control *reply, } return reply->status; } + +/* CTDB_CONTROL_DB_FREEZE */ + +void ctdb_req_control_db_freeze(struct ctdb_req_control *request, + uint32_t db_id) +{ + request->opcode = CTDB_CONTROL_DB_FREEZE; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_DB_FREEZE; + request->rdata.data.db_id = db_id; +} + +int ctdb_reply_control_db_freeze(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_DB_THAW */ + +void ctdb_req_control_db_thaw(struct ctdb_req_control *request, + uint32_t db_id) +{ + request->opcode = CTDB_CONTROL_DB_THAW; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_DB_THAW; + request->rdata.data.db_id = db_id; +} + +int ctdb_reply_control_db_thaw(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_DB_TRANSACTION_START */ + +void ctdb_req_control_db_transaction_start(struct ctdb_req_control *request, + struct ctdb_transdb *transdb) +{ + request->opcode = CTDB_CONTROL_DB_TRANSACTION_START; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_DB_TRANSACTION_START; + request->rdata.data.transdb = transdb; +} + +int ctdb_reply_control_db_transaction_start(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_DB_TRANSACTION_COMMIT */ + +void ctdb_req_control_db_transaction_commit(struct ctdb_req_control *request, + struct ctdb_transdb *transdb) +{ + request->opcode = CTDB_CONTROL_DB_TRANSACTION_COMMIT; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_DB_TRANSACTION_COMMIT; + request->rdata.data.transdb = transdb; +} + +int ctdb_reply_control_db_transaction_commit(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} + +/* CTDB_CONTROL_DB_TRANSACTION_CANCEL */ + +void ctdb_req_control_db_transaction_cancel(struct ctdb_req_control *request, + uint32_t db_id) +{ + request->opcode = CTDB_CONTROL_DB_TRANSACTION_CANCEL; + request->pad = 0; + request->srvid = 0; + request->client_id = 0; + request->flags = 0; + + request->rdata.opcode = CTDB_CONTROL_DB_TRANSACTION_CANCEL; + request->rdata.data.db_id = db_id; +} + +int ctdb_reply_control_db_transaction_cancel(struct ctdb_reply_control *reply) +{ + return ctdb_reply_control_generic(reply); +} diff --git a/ctdb/protocol/protocol_control.c b/ctdb/protocol/protocol_control.c index da87351..486a1f2 100644 --- a/ctdb/protocol/protocol_control.c +++ b/ctdb/protocol/protocol_control.c @@ -461,6 +461,26 @@ static size_t ctdb_req_control_data_len(struct ctdb_req_control_data *cd) case CTDB_CONTROL_GET_NODES_FILE: break; + + case CTDB_CONTROL_DB_FREEZE: + len = ctdb_uint32_len(cd->data.db_id); + break; + + case CTDB_CONTROL_DB_THAW: + len = ctdb_uint32_len(cd->data.db_id); + break; + + case CTDB_CONTROL_DB_TRANSACTION_START: + len = ctdb_transdb_len(cd->data.transdb); + break; + + case CTDB_CONTROL_DB_TRANSACTION_COMMIT: + len = ctdb_transdb_len(cd->data.transdb); + break; + + case CTDB_CONTROL_DB_TRANSACTION_CANCEL: + len = ctdb_uint32_len(cd->data.db_id); + break; } return len; @@ -751,6 +771,26 @@ static void ctdb_req_control_data_push(struct ctdb_req_control_data *cd, case CTDB_CONTROL_DB_DETACH: ctdb_uint32_push(cd->data.db_id, buf); break; + + case CTDB_CONTROL_DB_FREEZE: + ctdb_uint32_push(cd->data.db_id, buf); + break; + + case CTDB_CONTROL_DB_THAW: + ctdb_uint32_push(cd->data.db_id, buf); + break; + + case CTDB_CONTROL_DB_TRANSACTION_START: + ctdb_transdb_push(cd->data.transdb, buf); + break; + + case CTDB_CONTROL_DB_TRANSACTION_COMMIT: + ctdb_transdb_push(cd->data.transdb, buf); + break; + + case CTDB_CONTROL_DB_TRANSACTION_CANCEL: + ctdb_uint32_push(cd->data.db_id, buf); + break; } } @@ -1112,6 +1152,31 @@ static int ctdb_req_control_data_pull(uint8_t *buf, size_t buflen, ret = ctdb_uint32_pull(buf, buflen, mem_ctx, &cd->data.db_id); break; + + case CTDB_CONTROL_DB_FREEZE: + ret = ctdb_uint32_pull(buf, buflen, mem_ctx, + &cd->data.db_id); + break; + + case CTDB_CONTROL_DB_THAW: + ret = ctdb_uint32_pull(buf, buflen, mem_ctx, + &cd->data.db_id); + break; + + case CTDB_CONTROL_DB_TRANSACTION_START: + ret = ctdb_transdb_pull(buf, buflen, mem_ctx, + &cd->data.transdb); + break; + + case CTDB_CONTROL_DB_TRANSACTION_COMMIT: + ret = ctdb_transdb_pull(buf, buflen, mem_ctx, + &cd->data.transdb); + break; + + case CTDB_CONTROL_DB_TRANSACTION_CANCEL: + ret = ctdb_uint32_pull(buf, buflen, mem_ctx, + &cd->data.db_id); + break; } return ret; @@ -1494,6 +1559,21 @@ static size_t ctdb_reply_control_data_len(struct ctdb_reply_control_data *cd) case CTDB_CONTROL_GET_NODES_FILE: len = ctdb_node_map_len(cd->data.nodemap); break; + + case CTDB_CONTROL_DB_FREEZE: + break; + + case CTDB_CONTROL_DB_THAW: + break; + + case CTDB_CONTROL_DB_TRANSACTION_START: + break; + + case CTDB_CONTROL_DB_TRANSACTION_COMMIT: + break; + + case CTDB_CONTROL_DB_TRANSACTION_CANCEL: + break; } return len; diff --git a/ctdb/tests/cunit/protocol_test_002.sh b/ctdb/tests/cunit/protocol_test_002.sh index 47410be..a654f74 100755 --- a/ctdb/tests/cunit/protocol_test_002.sh +++ b/ctdb/tests/cunit/protocol_test_002.sh @@ -2,7 +2,7 @@ . "${TEST_SCRIPTS_DIR}/unit.sh" -last_control=140 +last_control=145 control_output=$( for i in $(seq 0 $last_control) ; do diff --git a/ctdb/tests/src/protocol_client_test.c b/ctdb/tests/src/protocol_client_test.c index a17fac0..f5a3c35 100644 --- a/ctdb/tests/src/protocol_client_test.c +++ b/ctdb/tests/src/protocol_client_test.c @@ -633,6 +633,29 @@ static void fill_ctdb_req_control_data(TALLOC_CTX *mem_ctx, case CTDB_CONTROL_GET_NODES_FILE: break; + case CTDB_CONTROL_DB_FREEZE: + cd->data.db_id = rand32(); + break; + + case CTDB_CONTROL_DB_THAW: + cd->data.db_id = rand32(); + break; + + case CTDB_CONTROL_DB_TRANSACTION_START: + cd->data.transdb = talloc(mem_ctx, struct ctdb_transdb); + assert(cd->data.transdb != NULL); + fill_ctdb_transdb(mem_ctx, cd->data.transdb); + break; + + case CTDB_CONTROL_DB_TRANSACTION_COMMIT: + cd->data.transdb = talloc(mem_ctx, struct ctdb_transdb); + assert(cd->data.transdb != NULL); + fill_ctdb_transdb(mem_ctx, cd->data.transdb); + break; + + case CTDB_CONTROL_DB_TRANSACTION_CANCEL: + cd->data.db_id = rand32(); + break; } } @@ -1061,6 +1084,25 @@ static void verify_ctdb_req_control_data(struct ctdb_req_control_data *cd, case CTDB_CONTROL_GET_NODES_FILE: break; + case CTDB_CONTROL_DB_FREEZE: + assert(cd->data.db_id == cd2->data.db_id); + break; + + case CTDB_CONTROL_DB_THAW: + assert(cd->data.db_id == cd2->data.db_id); + break; + + case CTDB_CONTROL_DB_TRANSACTION_START: + verify_ctdb_transdb(cd->data.transdb, cd2->data.transdb); + break; + + case CTDB_CONTROL_DB_TRANSACTION_COMMIT: + verify_ctdb_transdb(cd->data.transdb, cd2->data.transdb); + break; + + case CTDB_CONTROL_DB_TRANSACTION_CANCEL: + assert(cd->data.db_id == cd2->data.db_id); + break; } } @@ -2119,7 +2161,7 @@ static void test_reply_dmaster_test(void) talloc_free(mem_ctx); } -#define NUM_CONTROLS 141 +#define NUM_CONTROLS 146 static void test_req_control_data_test(void) { From b04c48d2f5f0a5e64ccf75e7773b880c521ffef3 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Wed, 9 Sep 2015 12:29:54 +1000 Subject: [PATCH 065/136] ctdb-client: Add client API for new database controls Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/client/client.h | 26 +++++++ ctdb/client/client_control_sync.c | 146 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 172 insertions(+) diff --git a/ctdb/client/client.h b/ctdb/client/client.h index ba40202..3f720fc 100644 --- a/ctdb/client/client.h +++ b/ctdb/client/client.h @@ -674,6 +674,32 @@ int ctdb_ctrl_get_nodes_file(TALLOC_CTX *mem_ctx, struct tevent_context *ev, int destnode, struct timeval timeout, struct ctdb_node_map **nodemap); +int ctdb_ctrl_db_freeze(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, uint32_t db_id); + +int ctdb_ctrl_db_thaw(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, uint32_t db_id); + +int ctdb_ctrl_db_transaction_start(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_transdb *transdb); + +int ctdb_ctrl_db_transaction_commit(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_transdb *transdb); + +int ctdb_ctrl_db_transaction_cancel(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t db_id); + /* from client/client_db.c */ struct tevent_req *ctdb_attach_send(TALLOC_CTX *mem_ctx, diff --git a/ctdb/client/client_control_sync.c b/ctdb/client/client_control_sync.c index 0050b74..3f5ffb8 100644 --- a/ctdb/client/client_control_sync.c +++ b/ctdb/client/client_control_sync.c @@ -2970,3 +2970,149 @@ int ctdb_ctrl_get_nodes_file(TALLOC_CTX *mem_ctx, struct tevent_context *ev, return 0; } + +int ctdb_ctrl_db_freeze(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, uint32_t db_id) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_db_freeze(&request, db_id); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control DB_FREEZE failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_db_freeze(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control DB_FREEZE failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_db_thaw(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, uint32_t db_id) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_db_thaw(&request, db_id); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control DB_THAW failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_db_thaw(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control DB_THAW failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_db_transaction_start(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_transdb *transdb) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_db_transaction_start(&request, transdb); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control DB_TRANSACTION_START failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_db_transaction_start(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control DB_TRANSACTION_START failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_db_transaction_commit(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + struct ctdb_transdb *transdb) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_db_transaction_commit(&request, transdb); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control DB_TRANSACTION_COMMIT failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_db_transaction_commit(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control DB_TRANSACTION_COMMIT failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} + +int ctdb_ctrl_db_transaction_cancel(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int destnode, struct timeval timeout, + uint32_t db_id) +{ + struct ctdb_req_control request; + struct ctdb_reply_control *reply; + int ret; + + ctdb_req_control_db_transaction_cancel(&request, db_id); + ret = ctdb_client_control(mem_ctx, ev, client, destnode, timeout, + &request, &reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control DB_TRANSACTION_CANCEL failed to node %u, ret=%d\n", + destnode, ret)); + return ret; + } + + ret = ctdb_reply_control_db_transaction_cancel(reply); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Control DB_TRANSACTION_CANCEL failed, ret=%d\n", ret)); + return ret; + } + + return 0; +} From 951431910dc6d00815c19e087bc2546b1daa591b Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Mon, 29 Jun 2015 14:56:53 +1000 Subject: [PATCH 066/136] ctdb-recoverd: Add parallel database recovery helper Parallel database recovery fixes the samba/ctdb deadlock during recovery. Many times samba tries to grab multiple record locks in sequence. Consider a case when samba is already holding a record lock on a database and tries to get a record lock on second database. If the second record is not available on the local node, samba asks ctdb to migrate the record. If recovery occurs at this time (e.g. node becoming inactive), ctdb cannot freeze all the databases since samba is already holding a lock and waiting for the second lock. CTDB can process the second record request only after the recovery is complete, thus causing a deadlock. In parallel database recovery, each database is frozen and recovered independent from each other. So as soon as the second database is recovered, CTDB will resend all the pending migration requests and Samba can get the second lock. Once samba releases both the locks, ctdb can freeze the first database and recover it completing recovery process. Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/packaging/RPM/ctdb.spec.in | 1 + ctdb/server/ctdb_recovery_helper.c | 1888 ++++++++++++++++++++++++++++++++++++ ctdb/wscript | 6 + 3 files changed, 1895 insertions(+) create mode 100644 ctdb/server/ctdb_recovery_helper.c diff --git a/ctdb/packaging/RPM/ctdb.spec.in b/ctdb/packaging/RPM/ctdb.spec.in index 5db2e3a..00e7f17 100644 --- a/ctdb/packaging/RPM/ctdb.spec.in +++ b/ctdb/packaging/RPM/ctdb.spec.in @@ -197,6 +197,7 @@ rm -rf $RPM_BUILD_ROOT %{_bindir}/ctdb %{_bindir}/ctdb_lock_helper %{_bindir}/ctdb_event_helper +%{_bindir}/ctdb_recovery_helper %{_bindir}/smnotify %{_bindir}/ping_pong %{_bindir}/ltdbtool diff --git a/ctdb/server/ctdb_recovery_helper.c b/ctdb/server/ctdb_recovery_helper.c new file mode 100644 index 0000000..194b373 --- /dev/null +++ b/ctdb/server/ctdb_recovery_helper.c @@ -0,0 +1,1888 @@ +/* + ctdb parallel database recovery + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include "replace.h" +#include "system/network.h" +#include "system/filesys.h" + +#include +#include +#include +#include + +#include "lib/tdb_wrap/tdb_wrap.h" +#include "lib/util/time.h" +#include "lib/util/tevent_unix.h" + +#include "protocol/protocol.h" +#include "protocol/protocol_api.h" +#include "client/client.h" + +#define TIMEOUT() timeval_current_ofs(10, 0) + +static void LOG(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); +} + +/* + * Utility functions + */ + +static ssize_t sys_write(int fd, const void *buf, size_t count) +{ + ssize_t ret; + + do { + ret = write(fd, buf, count); +#if defined(EWOULDBLOCK) + } while (ret == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)); +#else + } while (ret == -1 && (errno == EINTR || errno == EAGAIN)); +#endif + return ret; +} + +/* + * Recovery database functions + */ + +struct recdb_context { + uint32_t db_id; + const char *db_name; + const char *db_path; + struct tdb_wrap *db; + bool persistent; +}; + +static struct recdb_context *recdb_create(TALLOC_CTX *mem_ctx, uint32_t db_id, + const char *db_name, + const char *db_path, + uint32_t hash_size, bool persistent) +{ + struct recdb_context *recdb; + unsigned int tdb_flags; + + recdb = talloc(mem_ctx, struct recdb_context); + if (recdb == NULL) { + return NULL; + } + + recdb->db_name = db_name; + recdb->db_id = db_id; + recdb->db_path = talloc_asprintf(recdb, "%s/recdb.%s", + dirname(discard_const(db_path)), + db_name); + if (recdb->db_path == NULL) { + talloc_free(recdb); + return NULL; + } + unlink(recdb->db_path); + + tdb_flags = TDB_NOLOCK | TDB_INCOMPATIBLE_HASH | TDB_DISALLOW_NESTING; + recdb->db = tdb_wrap_open(mem_ctx, recdb->db_path, hash_size, + tdb_flags, O_RDWR|O_CREAT|O_EXCL, 0600); + if (recdb->db == NULL) { + talloc_free(recdb); + LOG("failed to create recovery db %s\n", recdb->db_path); + } + + recdb->persistent = persistent; + + return recdb; +} + +static const char *recdb_name(struct recdb_context *recdb) +{ + return recdb->db_name; +} + +struct recdb_add_traverse_state { + struct recdb_context *recdb; + int mypnn; +}; + +static int recdb_add_traverse(uint32_t reqid, struct ctdb_ltdb_header *header, + TDB_DATA key, TDB_DATA data, + void *private_data) +{ + struct recdb_add_traverse_state *state = + (struct recdb_add_traverse_state *)private_data; + struct ctdb_ltdb_header *hdr; + TDB_DATA prev_data; + int ret; + + /* header is not marshalled separately in the pulldb control */ + if (data.dsize < sizeof(struct ctdb_ltdb_header)) { + return -1; + } + + hdr = (struct ctdb_ltdb_header *)data.dptr; + + /* fetch the existing record, if any */ + prev_data = tdb_fetch(state->recdb->db->tdb, key); + + if (prev_data.dptr != NULL) { + struct ctdb_ltdb_header prev_hdr; + + prev_hdr = *(struct ctdb_ltdb_header *)prev_data.dptr; + free(prev_data.dptr); + if (hdr->rsn < prev_hdr.rsn || + (hdr->rsn == prev_hdr.rsn && + prev_hdr.dmaster != state->mypnn)) { + return 0; + } + } + + ret = tdb_store(state->recdb->db->tdb, key, data, TDB_REPLACE); + if (ret != 0) { + return -1; + } + return 0; +} + +static bool recdb_add(struct recdb_context *recdb, int mypnn, + struct ctdb_rec_buffer *recbuf) +{ + struct recdb_add_traverse_state state; + int ret; + + state.recdb = recdb; + state.mypnn = mypnn; + + ret = ctdb_rec_buffer_traverse(recbuf, recdb_add_traverse, &state); + if (ret != 0) { + return false; + } + + return true; +} + +struct recdb_traverse_state { + struct ctdb_rec_buffer *recbuf; + uint32_t pnn; + uint32_t reqid; + bool persistent; + bool failed; +}; + +static int recdb_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, + void *private_data) +{ + struct recdb_traverse_state *state = + (struct recdb_traverse_state *)private_data; + struct ctdb_ltdb_header *header; + int ret; + + /* + * skip empty records - but NOT for persistent databases: + * + * The record-by-record mode of recovery deletes empty records. + * For persistent databases, this can lead to data corruption + * by deleting records that should be there: + * + * - Assume the cluster has been running for a while. + * + * - A record R in a persistent database has been created and + * deleted a couple of times, the last operation being deletion, + * leaving an empty record with a high RSN, say 10. + * + * - Now a node N is turned off. + * + * - This leaves the local database copy of D on N with the empty + * copy of R and RSN 10. On all other nodes, the recovery has deleted + * the copy of record R. + * + * - Now the record is created again while node N is turned off. + * This creates R with RSN = 1 on all nodes except for N. + * + * - Now node N is turned on again. The following recovery will chose + * the older empty copy of R due to RSN 10 > RSN 1. + * + * ==> Hence the record is gone after the recovery. + * + * On databases like Samba's registry, this can damage the higher-level + * data structures built from the various tdb-level records. + */ + if (!state->persistent && + data.dsize <= sizeof(struct ctdb_ltdb_header)) { + return 0; + } + + /* update the dmaster field to point to us */ + header = (struct ctdb_ltdb_header *)data.dptr; + if (!state->persistent) { + header->dmaster = state->pnn; + header->flags |= CTDB_REC_FLAG_MIGRATED_WITH_DATA; + } + + ret = ctdb_rec_buffer_add(state->recbuf, state->recbuf, state->reqid, + NULL, key, data); + if (ret != 0) { + state->failed = true; + return ret; + } + + return 0; +} + +static struct ctdb_rec_buffer *recdb_records(struct recdb_context *recdb, + TALLOC_CTX *mem_ctx, uint32_t pnn) +{ + struct recdb_traverse_state state; + int ret; + + state.recbuf = ctdb_rec_buffer_init(mem_ctx, recdb->db_id); + if (state.recbuf == NULL) { + return NULL; + } + state.pnn = pnn; + state.reqid = 0; + state.persistent = recdb->persistent; + state.failed = false; + + ret = tdb_traverse_read(recdb->db->tdb, recdb_traverse, &state); + if (ret == -1 || state.failed) { + TALLOC_FREE(state.recbuf); + return NULL; + } + + return state.recbuf; +} + +/* + * Collect databases using highest sequence number + */ + +struct collect_highseqnum_db_state { + struct tevent_context *ev; + struct ctdb_client_context *client; + uint32_t *pnn_list; + int count; + uint32_t db_id; + struct recdb_context *recdb; + uint32_t max_pnn; +}; + +static void collect_highseqnum_db_seqnum_done(struct tevent_req *subreq); +static void collect_highseqnum_db_pulldb_done(struct tevent_req *subreq); + +static struct tevent_req *collect_highseqnum_db_send( + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + uint32_t *pnn_list, int count, + uint32_t db_id, struct recdb_context *recdb) +{ + struct tevent_req *req, *subreq; + struct collect_highseqnum_db_state *state; + struct ctdb_req_control request; + + req = tevent_req_create(mem_ctx, &state, + struct collect_highseqnum_db_state); + if (req == NULL) { + return NULL; + } + + state->ev = ev; + state->client = client; + state->pnn_list = pnn_list; + state->count = count; + state->db_id = db_id; + state->recdb = recdb; + + ctdb_req_control_get_db_seqnum(&request, db_id); + subreq = ctdb_client_control_multi_send(mem_ctx, ev, client, + state->pnn_list, state->count, + TIMEOUT(), &request); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, collect_highseqnum_db_seqnum_done, + req); + + return req; +} + +static void collect_highseqnum_db_seqnum_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct collect_highseqnum_db_state *state = tevent_req_data( + req, struct collect_highseqnum_db_state); + struct ctdb_reply_control **reply; + struct ctdb_req_control request; + struct ctdb_pulldb pulldb; + int *err_list; + bool status; + int ret, i; + uint64_t seqnum, max_seqnum; + + status = ctdb_client_control_multi_recv(subreq, &ret, state, + &err_list, &reply); + TALLOC_FREE(subreq); + if (! status) { + int ret2; + uint32_t pnn; + + ret2 = ctdb_client_control_multi_error(state->pnn_list, + state->count, err_list, + &pnn); + if (ret2 != 0) { + LOG("control GET_DB_SEQNUM failed for %s on node %u," + " ret=%d\n", recdb_name(state->recdb), pnn, ret2); + } else { + LOG("control GET_DB_SEQNUM failed for %s, ret=%d\n", + recdb_name(state->recdb), ret); + } + tevent_req_error(req, ret); + return; + } + + max_seqnum = 0; + state->max_pnn = state->pnn_list[0]; + for (i=0; icount; i++) { + ret = ctdb_reply_control_get_db_seqnum(reply[i], &seqnum); + if (ret != 0) { + tevent_req_error(req, EPROTO); + return; + } + + if (max_seqnum < seqnum) { + max_seqnum = seqnum; + state->max_pnn = state->pnn_list[i]; + } + } + + talloc_free(reply); + + LOG("Pull persistent db %s from node %d with seqnum 0x%"PRIx64"\n", + recdb_name(state->recdb), state->max_pnn, max_seqnum); + + pulldb.db_id = state->db_id; + pulldb.lmaster = CTDB_LMASTER_ANY; + + ctdb_req_control_pull_db(&request, &pulldb); + subreq = ctdb_client_control_send(state, state->ev, state->client, + state->max_pnn, TIMEOUT(), &request); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, collect_highseqnum_db_pulldb_done, + req); +} + +static void collect_highseqnum_db_pulldb_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct collect_highseqnum_db_state *state = tevent_req_data( + req, struct collect_highseqnum_db_state); + struct ctdb_reply_control *reply; + struct ctdb_rec_buffer *recbuf; + int ret; + bool status; + + status = ctdb_client_control_recv(subreq, &ret, state, &reply); + TALLOC_FREE(subreq); + if (! status) { + LOG("control PULL_DB failed for %s on node %u, ret=%d\n", + recdb_name(state->recdb), state->max_pnn, ret); + tevent_req_error(req, ret); + return; + } + + ret = ctdb_reply_control_pull_db(reply, state, &recbuf); + if (ret != 0) { + tevent_req_error(req, EPROTO); + return; + } + + talloc_free(reply); + + ret = recdb_add(state->recdb, ctdb_client_pnn(state->client), recbuf); + talloc_free(recbuf); + if (! ret) { + tevent_req_error(req, EIO); + return; + } + + tevent_req_done(req); +} + +static bool collect_highseqnum_db_recv(struct tevent_req *req, int *perr) +{ + int err; + + if (tevent_req_is_unix_error(req, &err)) { + if (perr != NULL) { + *perr = err; + } + return false; + } + + return true; +} + +/* + * Collect all databases + */ + +struct collect_all_db_state { + struct tevent_context *ev; + struct ctdb_client_context *client; + uint32_t *pnn_list; + int count; + uint32_t db_id; + struct recdb_context *recdb; + struct ctdb_pulldb pulldb; + int index; +}; + +static void collect_all_db_pulldb_done(struct tevent_req *subreq); + +static struct tevent_req *collect_all_db_send( + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + uint32_t *pnn_list, int count, + uint32_t db_id, struct recdb_context *recdb) +{ + struct tevent_req *req, *subreq; + struct collect_all_db_state *state; + struct ctdb_req_control request; + + req = tevent_req_create(mem_ctx, &state, + struct collect_all_db_state); + if (req == NULL) { + return NULL; + } + + state->ev = ev; + state->client = client; + state->pnn_list = pnn_list; + state->count = count; + state->db_id = db_id; + state->recdb = recdb; + + state->pulldb.db_id = db_id; + state->pulldb.lmaster = CTDB_LMASTER_ANY; + + state->index = 0; + + ctdb_req_control_pull_db(&request, &state->pulldb); + subreq = ctdb_client_control_send(state, ev, client, + state->pnn_list[state->index], + TIMEOUT(), &request); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, collect_all_db_pulldb_done, req); + + return req; +} + +static void collect_all_db_pulldb_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct collect_all_db_state *state = tevent_req_data( + req, struct collect_all_db_state); + struct ctdb_reply_control *reply; + struct ctdb_req_control request; + struct ctdb_rec_buffer *recbuf; + int ret; + bool status; + + status = ctdb_client_control_recv(subreq, &ret, state, &reply); + TALLOC_FREE(subreq); + if (! status) { + LOG("control PULL_DB failed for %s from node %u, ret=%d\n", + recdb_name(state->recdb), state->pnn_list[state->index], + ret); + tevent_req_error(req, ret); + return; + } + + ret = ctdb_reply_control_pull_db(reply, state, &recbuf); + if (ret != 0) { + LOG("control PULL_DB failed for %s, ret=%d\n", + recdb_name(state->recdb), ret); + tevent_req_error(req, EPROTO); + return; + } + + talloc_free(reply); + + status = recdb_add(state->recdb, ctdb_client_pnn(state->client), recbuf); + talloc_free(recbuf); + if (! status) { + tevent_req_error(req, EIO); + return; + } + + state->index += 1; + if (state->index == state->count) { + tevent_req_done(req); + return; + } + + ctdb_req_control_pull_db(&request, &state->pulldb); + subreq = ctdb_client_control_send(state, state->ev, state->client, + state->pnn_list[state->index], + TIMEOUT(), &request); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, collect_all_db_pulldb_done, req); +} + +static bool collect_all_db_recv(struct tevent_req *req, int *perr) +{ + int err; + + if (tevent_req_is_unix_error(req, &err)) { + if (perr != NULL) { + *perr = err; + } + return false; + } + + return true; +} + + +/** + * For each database do the following: + * - Get DB name + * - Get DB path + * - Freeze database on all nodes + * - Start transaction on all nodes + * - Collect database from all nodes + * - Wipe database on all nodes + * - Push database to all nodes + * - Commit transaction on all nodes + * - Thaw database on all nodes + */ + +struct recover_db_state { + struct tevent_context *ev; + struct ctdb_client_context *client; + struct ctdb_tunable_list *tun_list; + uint32_t *pnn_list; + int count; + uint32_t db_id; + bool persistent; + + uint32_t destnode; + struct ctdb_transdb transdb; + + const char *db_name, *db_path; + struct recdb_context *recdb; + struct ctdb_rec_buffer *recbuf; + +}; + +static void recover_db_name_done(struct tevent_req *subreq); +static void recover_db_path_done(struct tevent_req *subreq); +static void recover_db_freeze_done(struct tevent_req *subreq); +static void recover_db_transaction_started(struct tevent_req *subreq); +static void recover_db_collect_done(struct tevent_req *subreq); +static void recover_db_wipedb_done(struct tevent_req *subreq); +static void recover_db_pushdb_done(struct tevent_req *subreq); +static void recover_db_transaction_committed(struct tevent_req *subreq); +static void recover_db_thaw_done(struct tevent_req *subreq); + +static struct tevent_req *recover_db_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + struct ctdb_tunable_list *tun_list, + uint32_t *pnn_list, int count, + uint32_t generation, + uint32_t db_id, bool persistent) +{ + struct tevent_req *req, *subreq; + struct recover_db_state *state; + struct ctdb_req_control request; + + req = tevent_req_create(mem_ctx, &state, struct recover_db_state); + if (req == NULL) { + return NULL; + } + + state->ev = ev; + state->client = client; + state->tun_list = tun_list; + state->pnn_list = pnn_list; + state->count = count; + state->db_id = db_id; + state->persistent = persistent; + + state->destnode = ctdb_client_pnn(client); + state->transdb.db_id = db_id; + state->transdb.tid = generation; + + ctdb_req_control_get_dbname(&request, db_id); + subreq = ctdb_client_control_send(state, ev, client, state->destnode, + TIMEOUT(), &request); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, recover_db_name_done, req); + + return req; +} + +static void recover_db_name_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct recover_db_state *state = tevent_req_data( + req, struct recover_db_state); + struct ctdb_reply_control *reply; + struct ctdb_req_control request; + int ret; + bool status; + + status = ctdb_client_control_recv(subreq, &ret, state, &reply); + TALLOC_FREE(subreq); + if (! status) { + LOG("control GET_DBNAME failed for db=0x%x\n, ret=%d", + state->db_id, ret); + tevent_req_error(req, ret); + return; + } + + ret = ctdb_reply_control_get_dbname(reply, state, &state->db_name); + if (ret != 0) { + LOG("control GET_DBNAME failed for db=0x%x\n, ret=%d\n", + state->db_id, ret); + tevent_req_error(req, EPROTO); + return; + } + + talloc_free(reply); + + ctdb_req_control_getdbpath(&request, state->db_id); + subreq = ctdb_client_control_send(state, state->ev, state->client, + state->destnode, TIMEOUT(), + &request); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, recover_db_path_done, req); +} + +static void recover_db_path_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct recover_db_state *state = tevent_req_data( + req, struct recover_db_state); + struct ctdb_reply_control *reply; + struct ctdb_req_control request; + int ret; + bool status; + + status = ctdb_client_control_recv(subreq, &ret, state, &reply); + TALLOC_FREE(subreq); + if (! status) { + LOG("control GETDBPATH failed for db %s, ret=%d\n", + state->db_name, ret); + tevent_req_error(req, ret); + return; + } + + ret = ctdb_reply_control_getdbpath(reply, state, &state->db_path); + if (ret != 0) { + LOG("control GETDBPATH failed for db %s, ret=%d\n", + state->db_name, ret); + tevent_req_error(req, EPROTO); + return; + } + + talloc_free(reply); + + ctdb_req_control_db_freeze(&request, state->db_id); + subreq = ctdb_client_control_multi_send(state, state->ev, + state->client, + state->pnn_list, state->count, + TIMEOUT(), &request); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, recover_db_freeze_done, req); +} + +static void recover_db_freeze_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct recover_db_state *state = tevent_req_data( + req, struct recover_db_state); + struct ctdb_req_control request; + int *err_list; + int ret; + bool status; + + status = ctdb_client_control_multi_recv(subreq, &ret, NULL, &err_list, + NULL); + TALLOC_FREE(subreq); + if (! status) { + int ret2; + uint32_t pnn; + + ret2 = ctdb_client_control_multi_error(state->pnn_list, + state->count, err_list, + &pnn); + if (ret2 != 0) { + LOG("control FREEZE_DB failed for db %s on node %u," + " ret=%d\n", state->db_name, pnn, ret2); + } else { + LOG("control FREEZE_DB failed for db %s, ret=%d\n", + state->db_name, ret); + } + tevent_req_error(req, ret); + return; + } + + ctdb_req_control_db_transaction_start(&request, &state->transdb); + subreq = ctdb_client_control_multi_send(state, state->ev, + state->client, + state->pnn_list, state->count, + TIMEOUT(), &request); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, recover_db_transaction_started, req); +} + +static void recover_db_transaction_started(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct recover_db_state *state = tevent_req_data( + req, struct recover_db_state); + int *err_list; + int ret; + bool status; + + status = ctdb_client_control_multi_recv(subreq, &ret, NULL, &err_list, + NULL); + TALLOC_FREE(subreq); + if (! status) { + int ret2; + uint32_t pnn; + + ret2 = ctdb_client_control_multi_error(state->pnn_list, + state->count, + err_list, &pnn); + if (ret2 != 0) { + LOG("control TRANSACTION_DB failed for db=%s," + " ret=%d\n", state->db_name, pnn, ret2); + } else { + LOG("control TRANSACTION_DB failed for db=%s," + " ret=%d\n", state->db_name, ret); + } + tevent_req_error(req, ret); + return; + } + + state->recdb = recdb_create(state, state->db_id, state->db_name, + state->db_path, + state->tun_list->database_hash_size, + state->persistent); + if (tevent_req_nomem(state->recdb, req)) { + return; + } + + if (state->persistent && state->tun_list->recover_pdb_by_seqnum != 0) { + subreq = collect_highseqnum_db_send( + state, state->ev, state->client, + state->pnn_list, state->count, + state->db_id, state->recdb); + } else { + subreq = collect_all_db_send( + state, state->ev, state->client, + state->pnn_list, state->count, + state->db_id, state->recdb); + } + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, recover_db_collect_done, req); +} + +static void recover_db_collect_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct recover_db_state *state = tevent_req_data( + req, struct recover_db_state); + struct ctdb_req_control request; + int ret; + bool status; + + if (state->persistent && state->tun_list->recover_pdb_by_seqnum != 0) { + status = collect_highseqnum_db_recv(subreq, &ret); + } else { + status = collect_all_db_recv(subreq, &ret); + } + TALLOC_FREE(subreq); + if (! status) { + tevent_req_error(req, ret); + return; + } + + ctdb_req_control_wipe_database(&request, &state->transdb); + subreq = ctdb_client_control_multi_send(state, state->ev, + state->client, + state->pnn_list, state->count, + TIMEOUT(), &request); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, recover_db_wipedb_done, req); +} + +static void recover_db_wipedb_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct recover_db_state *state = tevent_req_data( + req, struct recover_db_state); + struct ctdb_req_control request; + int *err_list; + int ret; + bool status; + + status = ctdb_client_control_multi_recv(subreq, &ret, NULL, &err_list, + NULL); + TALLOC_FREE(subreq); + if (! status) { + int ret2; + uint32_t pnn; + + ret2 = ctdb_client_control_multi_error(state->pnn_list, + state->count, + err_list, &pnn); + if (ret2 != 0) { + LOG("control WIPEDB failed for db %s on node %u," + " ret=%d\n", state->db_name, pnn, ret2); + } else { + LOG("control WIPEDB failed for db %s, ret=%d\n", + state->db_name, pnn, ret); + } + tevent_req_error(req, ret); + return; + } + + state->recbuf = recdb_records(state->recdb, state, state->destnode); + if (tevent_req_nomem(state->recbuf, req)) { + return; + } + + TALLOC_FREE(state->recdb); + + ctdb_req_control_push_db(&request, state->recbuf); + subreq = ctdb_client_control_multi_send(state, state->ev, + state->client, + state->pnn_list, state->count, + TIMEOUT(), &request); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, recover_db_pushdb_done, req); +} + +static void recover_db_pushdb_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct recover_db_state *state = tevent_req_data( + req, struct recover_db_state); + struct ctdb_req_control request; + int *err_list; + int ret; + bool status; + + status = ctdb_client_control_multi_recv(subreq, &ret, NULL, &err_list, + NULL); + TALLOC_FREE(subreq); + if (! status) { + int ret2; + uint32_t pnn; + + ret2 = ctdb_client_control_multi_error(state->pnn_list, + state->count, + err_list, &pnn); + if (ret2 != 0) { + LOG("control PUSHDB failed for db %s on node %u," + " ret=%d\n", state->db_name, pnn, ret2); + } else { + LOG("control PUSHDB failed for db %s, ret=%d\n", + state->db_name, ret); + } + tevent_req_error(req, ret); + return; + } + + TALLOC_FREE(state->recbuf); + + ctdb_req_control_db_transaction_commit(&request, &state->transdb); + subreq = ctdb_client_control_multi_send(state, state->ev, + state->client, + state->pnn_list, state->count, + TIMEOUT(), &request); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, recover_db_transaction_committed, req); +} + +static void recover_db_transaction_committed(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct recover_db_state *state = tevent_req_data( + req, struct recover_db_state); + struct ctdb_req_control request; + int *err_list; + int ret; + bool status; + + status = ctdb_client_control_multi_recv(subreq, &ret, NULL, &err_list, + NULL); + TALLOC_FREE(subreq); + if (! status) { + int ret2; + uint32_t pnn; + + ret2 = ctdb_client_control_multi_error(state->pnn_list, + state->count, + err_list, &pnn); + if (ret2 != 0) { + LOG("control DB_TRANSACTION_COMMIT failed for db %s" + " on node %u, ret=%d", state->db_name, pnn, ret2); + } else { + LOG("control DB_TRANSACTION_COMMIT failed for db %s\n," + " ret=%d", state->db_name, ret); + } + tevent_req_error(req, ret); + return; + } + + ctdb_req_control_db_thaw(&request, state->db_id); + subreq = ctdb_client_control_multi_send(state, state->ev, + state->client, + state->pnn_list, state->count, + TIMEOUT(), &request); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, recover_db_thaw_done, req); +} + +static void recover_db_thaw_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct recover_db_state *state = tevent_req_data( + req, struct recover_db_state); + int *err_list; + int ret; + bool status; + + status = ctdb_client_control_multi_recv(subreq, &ret, NULL, &err_list, + NULL); + TALLOC_FREE(subreq); + if (! status) { + int ret2; + uint32_t pnn; + + ret2 = ctdb_client_control_multi_error(state->pnn_list, + state->count, + err_list, &pnn); + if (ret2 != 0) { + LOG("control DB_THAW failed for db %s on node %u," + " ret=%d\n", state->db_name, pnn, ret2); + } else { + LOG("control DB_THAW failed for db %s, ret=%d\n", + state->db_name, ret); + } + tevent_req_error(req, ret); + return; + } + + tevent_req_done(req); +} + +static bool recover_db_recv(struct tevent_req *req) +{ + int err; + + if (tevent_req_is_unix_error(req, &err)) { + return false; + } + + return true; +} + + +/* + * Start database recovery for each database + * + * Try to recover each database 5 times before failing recovery. + */ + +struct db_recovery_state { + struct tevent_context *ev; + struct ctdb_dbid_map *dbmap; + int num_replies; + int num_failed; +}; + +struct db_recovery_one_state { + struct tevent_req *req; + struct ctdb_client_context *client; + struct ctdb_dbid_map *dbmap; + struct ctdb_tunable_list *tun_list; + uint32_t *pnn_list; + int count; + uint32_t generation; + uint32_t db_id; + bool persistent; + int num_fails; +}; + +static void db_recovery_one_done(struct tevent_req *subreq); + +static struct tevent_req *db_recovery_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + struct ctdb_dbid_map *dbmap, + struct ctdb_tunable_list *tun_list, + uint32_t *pnn_list, int count, + uint32_t generation) +{ + struct tevent_req *req, *subreq; + struct db_recovery_state *state; + int i; + + req = tevent_req_create(mem_ctx, &state, struct db_recovery_state); + if (req == NULL) { + return NULL; + } + + state->ev = ev; + state->dbmap = dbmap; + state->num_replies = 0; + state->num_failed = 0; + + if (dbmap->num == 0) { + tevent_req_done(req); + return tevent_req_post(req, ev); + } + + for (i=0; inum; i++) { + struct db_recovery_one_state *substate; + + substate = talloc_zero(state, struct db_recovery_one_state); + if (tevent_req_nomem(substate, req)) { + return tevent_req_post(req, ev); + } + + substate->req = req; + substate->client = client; + substate->dbmap = dbmap; + substate->tun_list = tun_list; + substate->pnn_list = pnn_list; + substate->count = count; + substate->generation = generation; + substate->db_id = dbmap->dbs[i].db_id; + substate->persistent = dbmap->dbs[i].flags & + CTDB_DB_FLAGS_PERSISTENT; + + subreq = recover_db_send(state, ev, client, tun_list, + pnn_list, count, generation, + substate->db_id, + substate->persistent); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, db_recovery_one_done, + substate); + LOG("recover database 0x%08x\n", substate->db_id); + } + + return req; +} + +static void db_recovery_one_done(struct tevent_req *subreq) +{ + struct db_recovery_one_state *substate = tevent_req_callback_data( + subreq, struct db_recovery_one_state); + struct tevent_req *req = substate->req; + struct db_recovery_state *state = tevent_req_data( + req, struct db_recovery_state); + bool status; + + status = recover_db_recv(subreq); + TALLOC_FREE(subreq); + + if (status) { + talloc_free(substate); + goto done; + } + + substate->num_fails += 1; + if (substate->num_fails < 5) { + subreq = recover_db_send(state, state->ev, substate->client, + substate->tun_list, + substate->pnn_list, substate->count, + substate->generation, substate->db_id, + substate->persistent); + if (tevent_req_nomem(subreq, req)) { + goto failed; + } + tevent_req_set_callback(subreq, db_recovery_one_done, substate); + LOG("recover database 0x%08x, attempt %d\n", substate->db_id, + substate->num_fails+1); + return; + } + +failed: + state->num_failed += 1; + +done: + state->num_replies += 1; + + if (state->num_replies == state->dbmap->num) { + tevent_req_done(req); + } +} + +static bool db_recovery_recv(struct tevent_req *req, int *count) +{ + struct db_recovery_state *state = tevent_req_data( + req, struct db_recovery_state); + int err; + + if (tevent_req_is_unix_error(req, &err)) { + *count = 0; + return false; + } + + *count = state->num_replies - state->num_failed; + + if (state->num_failed > 0) { + return false; + } + + return true; +} + + +/* + * Run the parallel database recovery + * + * - Get nodemap + * - Get vnnmap + * - Get capabilities from all nodes + * - Get tunables from all nodes + * - Get dbmap + * - Set RECOVERY_ACTIVE + * - Send START_RECOVERY + * - Run database recovery + * - Send END_RECOVERY + * - Update vnnmap on all nodes + * - Set RECOVERY_NORMAL + */ + +struct recovery_state { + struct tevent_context *ev; + struct ctdb_client_context *client; + uint32_t generation; + uint32_t *pnn_list; + int count; + uint32_t destnode; + struct ctdb_node_map *nodemap; + uint32_t *caps; + struct ctdb_tunable_list *tun_list; + struct ctdb_vnn_map *vnnmap; + struct ctdb_dbid_map *dbmap; +}; + +static void recovery_nodemap_done(struct tevent_req *subreq); +static void recovery_vnnmap_done(struct tevent_req *subreq); +static void recovery_capabilities_done(struct tevent_req *subreq); +static void recovery_tunables_done(struct tevent_req *subreq); +static void recovery_dbmap_done(struct tevent_req *subreq); +static void recovery_active_done(struct tevent_req *subreq); +static void recovery_start_recovery_done(struct tevent_req *subreq); +static void recovery_db_recovery_done(struct tevent_req *subreq); +static void recovery_vnnmap_update_done(struct tevent_req *subreq); +static void recovery_normal_done(struct tevent_req *subreq); +static void recovery_end_recovery_done(struct tevent_req *subreq); + +static struct tevent_req *recovery_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + uint32_t generation) +{ + struct tevent_req *req, *subreq; + struct recovery_state *state; + struct ctdb_req_control request; + + req = tevent_req_create(mem_ctx, &state, struct recovery_state); + if (req == NULL) { + return NULL; + } + + state->ev = ev; + state->client = client; + state->generation = generation; + state->destnode = ctdb_client_pnn(client); + + ctdb_req_control_get_nodemap(&request); + subreq = ctdb_client_control_send(mem_ctx, ev, client, state->destnode, + TIMEOUT(), &request); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, recovery_nodemap_done, req); + + return req; +} + +static void recovery_nodemap_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct recovery_state *state = tevent_req_data( + req, struct recovery_state); + struct ctdb_reply_control *reply; + struct ctdb_req_control request; + bool status; + int ret; + + status = ctdb_client_control_recv(subreq, &ret, state, &reply); + TALLOC_FREE(subreq); + if (! status) { + LOG("control GET_NODEMAP failed to node %u, ret=%d\n", + state->destnode, ret); + tevent_req_error(req, ret); + return; + } + + ret = ctdb_reply_control_get_nodemap(reply, state, &state->nodemap); + if (ret != 0) { + LOG("control GET_NODEMAP failed, ret=%d\n", ret); + tevent_req_error(req, ret); + return; + } + + state->count = list_of_active_nodes(state->nodemap, CTDB_UNKNOWN_PNN, + state, &state->pnn_list); + if (state->count <= 0) { + tevent_req_error(req, ENOMEM); + return; + } + + ctdb_req_control_getvnnmap(&request); + subreq = ctdb_client_control_send(state, state->ev, state->client, + state->destnode, TIMEOUT(), + &request); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, recovery_vnnmap_done, req); +} + +static void recovery_vnnmap_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct recovery_state *state = tevent_req_data( + req, struct recovery_state); + struct ctdb_reply_control *reply; + struct ctdb_req_control request; + bool status; + int ret; + + status = ctdb_client_control_recv(subreq, &ret, state, &reply); + TALLOC_FREE(subreq); + if (! status) { + LOG("control GETVNNMAP failed to node %u, ret=%d\n", + state->destnode, ret); + tevent_req_error(req, ret); + return; + } + + ret = ctdb_reply_control_getvnnmap(reply, state, &state->vnnmap); + if (ret != 0) { + LOG("control GETVNNMAP failed, ret=%d\n", ret); + tevent_req_error(req, ret); + return; + } + + ctdb_req_control_get_capabilities(&request); + subreq = ctdb_client_control_multi_send(state, state->ev, + state->client, + state->pnn_list, state->count, + TIMEOUT(), &request); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, recovery_capabilities_done, req); +} + +static void recovery_capabilities_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct recovery_state *state = tevent_req_data( + req, struct recovery_state); + struct ctdb_reply_control **reply; + struct ctdb_req_control request; + int *err_list; + int ret, i; + bool status; + + status = ctdb_client_control_multi_recv(subreq, &ret, state, &err_list, + &reply); + TALLOC_FREE(subreq); + if (! status) { + int ret2; + uint32_t pnn; + + ret2 = ctdb_client_control_multi_error(state->pnn_list, + state->count, + err_list, &pnn); + if (ret2 != 0) { + LOG("control GET_CAPABILITIES failed on node %u," + " ret=%d\n", pnn, ret2); + } else { + LOG("control GET_CAPABILITIES failed, ret=%d\n", ret); + } + tevent_req_error(req, ret); + return; + } + + /* Make the array size same as nodemap */ + state->caps = talloc_zero_array(state, uint32_t, + state->nodemap->num); + if (tevent_req_nomem(state->caps, req)) { + return; + } + + for (i=0; icount; i++) { + uint32_t pnn; + + pnn = state->pnn_list[i]; + ret = ctdb_reply_control_get_capabilities(reply[i], + &state->caps[pnn]); + if (ret != 0) { + LOG("control GET_CAPABILITIES failed on node %u\n", pnn); + tevent_req_error(req, EPROTO); + return; + } + } + + talloc_free(reply); + + ctdb_req_control_get_all_tunables(&request); + subreq = ctdb_client_control_send(state, state->ev, state->client, + state->destnode, TIMEOUT(), + &request); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, recovery_tunables_done, req); +} + +static void recovery_tunables_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct recovery_state *state = tevent_req_data( + req, struct recovery_state); + struct ctdb_reply_control *reply; + struct ctdb_req_control request; + int ret; + bool status; + + status = ctdb_client_control_recv(subreq, &ret, state, &reply); + TALLOC_FREE(subreq); + if (! status) { + LOG("control GET_ALL_TUNABLES failed, ret=%d\n", ret); + tevent_req_error(req, ret); + return; + } + + ret = ctdb_reply_control_get_all_tunables(reply, state, + &state->tun_list); + if (ret != 0) { + LOG("control GET_ALL_TUNABLES failed, ret=%d\n", ret); + tevent_req_error(req, EPROTO); + return; + } + + talloc_free(reply); + + ctdb_req_control_get_dbmap(&request); + subreq = ctdb_client_control_send(state, state->ev, state->client, + state->destnode, TIMEOUT(), + &request); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, recovery_dbmap_done, req); +} + +static void recovery_dbmap_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct recovery_state *state = tevent_req_data( + req, struct recovery_state); + struct ctdb_reply_control *reply; + struct ctdb_req_control request; + int ret; + bool status; + + status = ctdb_client_control_recv(subreq, &ret, state, &reply); + TALLOC_FREE(subreq); + if (! status) { + LOG("control GET_DBMAP failed to node %u, ret=%d\n", + state->destnode, ret); + tevent_req_error(req, ret); + return; + } + + ret = ctdb_reply_control_get_dbmap(reply, state, &state->dbmap); + if (ret != 0) { + LOG("control GET_DBMAP failed, ret=%d\n", ret); + tevent_req_error(req, ret); + return; + } + + ctdb_req_control_set_recmode(&request, CTDB_RECOVERY_ACTIVE); + subreq = ctdb_client_control_multi_send(state, state->ev, + state->client, + state->pnn_list, state->count, + TIMEOUT(), &request); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, recovery_active_done, req); +} + +static void recovery_active_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct recovery_state *state = tevent_req_data( + req, struct recovery_state); + struct ctdb_req_control request; + struct ctdb_vnn_map *vnnmap; + int *err_list; + int ret, count, i; + bool status; + + status = ctdb_client_control_multi_recv(subreq, &ret, NULL, &err_list, + NULL); + TALLOC_FREE(subreq); + if (! status) { + int ret2; + uint32_t pnn; + + ret2 = ctdb_client_control_multi_error(state->pnn_list, + state->count, + err_list, &pnn); + if (ret2 != 0) { + LOG("failed to set recovery mode to ACTIVE on node %u," + " ret=%d\n", pnn, ret2); + } else { + LOG("failed to set recovery mode to ACTIVE, ret=%d\n", + ret); + } + tevent_req_error(req, ret); + return; + } + + LOG("set recovery mode to ACTIVE\n"); + + /* Calculate new VNNMAP */ + count = 0; + for (i=0; inodemap->num; i++) { + if (state->nodemap->node[i].flags & NODE_FLAGS_INACTIVE) { + continue; + } + if (!(state->caps[i] & CTDB_CAP_LMASTER)) { + continue; + } + count += 1; + } + + if (count == 0) { + LOG("no active lmasters found. Adding recmaster anyway\n"); + } + + vnnmap = talloc_zero(state, struct ctdb_vnn_map); + if (tevent_req_nomem(vnnmap, req)) { + return; + } + + vnnmap->size = (count == 0 ? 1 : count); + vnnmap->map = talloc_array(vnnmap, uint32_t, vnnmap->size); + if (tevent_req_nomem(vnnmap->map, req)) { + return; + } + + if (count == 0) { + vnnmap->map[0] = state->destnode; + } else { + count = 0; + for (i=0; inodemap->num; i++) { + if (state->nodemap->node[i].flags & + NODE_FLAGS_INACTIVE) { + continue; + } + if (!(state->caps[i] & CTDB_CAP_LMASTER)) { + continue; + } + + vnnmap->map[count] = state->nodemap->node[i].pnn; + count += 1; + } + } + + vnnmap->generation = state->generation; + + talloc_free(state->vnnmap); + state->vnnmap = vnnmap; + + ctdb_req_control_start_recovery(&request); + subreq = ctdb_client_control_multi_send(state, state->ev, + state->client, + state->pnn_list, state->count, + TIMEOUT(), &request); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, recovery_start_recovery_done, req); +} + +static void recovery_start_recovery_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct recovery_state *state = tevent_req_data( + req, struct recovery_state); + int *err_list; + int ret; + bool status; + + status = ctdb_client_control_multi_recv(subreq, &ret, NULL, &err_list, + NULL); + TALLOC_FREE(subreq); + if (! status) { + int ret2; + uint32_t pnn; + + ret2 = ctdb_client_control_multi_error(state->pnn_list, + state->count, + err_list, &pnn); + if (ret2 != 0) { + LOG("failed to run start_recovery event on node %u," + " ret=%d\n", pnn, ret2); + } else { + LOG("failed to run start_recovery event, ret=%d\n", + ret); + } + tevent_req_error(req, ret); + return; + } + + LOG("start_recovery event finished\n"); + + subreq = db_recovery_send(state, state->ev, state->client, + state->dbmap, state->tun_list, + state->pnn_list, state->count, + state->vnnmap->generation); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, recovery_db_recovery_done, req); +} + +static void recovery_db_recovery_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct recovery_state *state = tevent_req_data( + req, struct recovery_state); + struct ctdb_req_control request; + bool status; + int count; + + status = db_recovery_recv(subreq, &count); + TALLOC_FREE(subreq); + + LOG("%d databases recovered\n", count); + + if (! status) { + tevent_req_error(req, EIO); + return; + } + + ctdb_req_control_setvnnmap(&request, state->vnnmap); + subreq = ctdb_client_control_multi_send(state, state->ev, + state->client, + state->pnn_list, state->count, + TIMEOUT(), &request); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, recovery_vnnmap_update_done, req); +} + +static void recovery_vnnmap_update_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct recovery_state *state = tevent_req_data( + req, struct recovery_state); + struct ctdb_req_control request; + int *err_list; + int ret; + bool status; + + status = ctdb_client_control_multi_recv(subreq, &ret, NULL, &err_list, + NULL); + TALLOC_FREE(subreq); + if (! status) { + int ret2; + uint32_t pnn; + + ret2 = ctdb_client_control_multi_error(state->pnn_list, + state->count, + err_list, &pnn); + if (ret2 != 0) { + LOG("failed to update VNNMAP on node %u, ret=%d\n", + pnn, ret2); + } else { + LOG("failed to update VNNMAP, ret=%d\n", ret); + } + tevent_req_error(req, ret); + return; + } + + LOG("updated VNNMAP\n"); + + ctdb_req_control_set_recmode(&request, CTDB_RECOVERY_NORMAL); + subreq = ctdb_client_control_multi_send(state, state->ev, + state->client, + state->pnn_list, state->count, + TIMEOUT(), &request); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, recovery_normal_done, req); +} + +static void recovery_normal_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct recovery_state *state = tevent_req_data( + req, struct recovery_state); + struct ctdb_req_control request; + int *err_list; + int ret; + bool status; + + status = ctdb_client_control_multi_recv(subreq, &ret, state, &err_list, + NULL); + TALLOC_FREE(subreq); + if (! status) { + int ret2; + uint32_t pnn; + + ret2 = ctdb_client_control_multi_error(state->pnn_list, + state->count, + err_list, &pnn); + if (ret2 != 0) { + LOG("failed to set recovery mode to NORMAL on node %u," + " ret=%d\n", pnn, ret2); + } else { + LOG("failed to set recovery mode to NORMAL, ret=%d\n", + ret); + } + tevent_req_error(req, ret); + return; + } + + LOG("set recovery mode to NORMAL\n"); + + ctdb_req_control_end_recovery(&request); + subreq = ctdb_client_control_multi_send(state, state->ev, + state->client, + state->pnn_list, state->count, + TIMEOUT(), &request); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, recovery_end_recovery_done, req); +} + +static void recovery_end_recovery_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct recovery_state *state = tevent_req_data( + req, struct recovery_state); + int *err_list; + int ret; + bool status; + + status = ctdb_client_control_multi_recv(subreq, &ret, state, &err_list, + NULL); + TALLOC_FREE(subreq); + if (! status) { + int ret2; + uint32_t pnn; + + ret2 = ctdb_client_control_multi_error(state->pnn_list, + state->count, + err_list, &pnn); + if (ret2 != 0) { + LOG("failed to run recovered event on node %u," + " ret=%d\n", pnn, ret2); + } else { + LOG("failed to run recovered event, ret=%d\n", ret); + } + tevent_req_error(req, ret); + return; + } + + LOG("recovered event finished\n"); + + tevent_req_done(req); +} + +static void recovery_recv(struct tevent_req *req, int *perr) +{ + int err; + + if (tevent_req_is_unix_error(req, &err)) { + if (perr != NULL) { + *perr = err; + } + return; + } +} + +static void usage(const char *progname) +{ + fprintf(stderr, "\nUsage: %s \n", + progname); +} + + +/* + * Arguments - log fd, write fd, socket path, generation + */ +int main(int argc, char *argv[]) +{ + int log_fd, write_fd; + const char *sockpath; + TALLOC_CTX *mem_ctx; + struct tevent_context *ev; + struct ctdb_client_context *client; + int ret; + struct tevent_req *req; + uint32_t generation; + + if (argc != 5) { + usage(argv[0]); + exit(1); + } + + log_fd = atoi(argv[1]); + if (log_fd != STDOUT_FILENO && log_fd != STDERR_FILENO) { + close(STDOUT_FILENO); + close(STDERR_FILENO); + dup2(log_fd, STDOUT_FILENO); + dup2(log_fd, STDERR_FILENO); + } + close(log_fd); + + write_fd = atoi(argv[2]); + sockpath = argv[3]; + generation = (uint32_t)strtoul(argv[4], NULL, 0); + + mem_ctx = talloc_new(NULL); + if (mem_ctx == NULL) { + LOG("talloc_new() failed\n"); + goto failed; + } + + ev = tevent_context_init(mem_ctx); + if (ev == NULL) { + LOG("tevent_context_init() failed\n"); + goto failed; + } + + ret = ctdb_client_init(mem_ctx, ev, sockpath, &client); + if (ret != 0) { + LOG("ctdb_client_init() failed, ret=%d\n", ret); + goto failed; + } + + req = recovery_send(mem_ctx, ev, client, generation); + if (req == NULL) { + LOG("database_recover_send() failed\n"); + goto failed; + } + + if (! tevent_req_poll(req, ev)) { + LOG("tevent_req_poll() failed\n"); + goto failed; + } + + recovery_recv(req, &ret); + TALLOC_FREE(req); + if (ret != 0) { + LOG("database recovery failed, ret=%d\n", ret); + goto failed; + } + + sys_write(write_fd, &ret, sizeof(ret)); + return 0; + +failed: + talloc_free(mem_ctx); + return 1; +} diff --git a/ctdb/wscript b/ctdb/wscript index fcdb7c0..fcc30c1 100755 --- a/ctdb/wscript +++ b/ctdb/wscript @@ -425,6 +425,12 @@ def build(bld): deps='samba-util ctdb-common-util replace tdb', install_path='${BINDIR}') + bld.SAMBA_BINARY('ctdb_recovery_helper', + source='server/ctdb_recovery_helper.c', + deps='''ctdb-client2 ctdb-protocol ctdb-util + samba-util replace tdb''', + install_path='${BINDIR}') + bld.SAMBA_GENERATOR('ctdb-smnotify-h', source='utils/smnotify/smnotify.x', target='utils/smnotify/smnotify.h', From 14cacd2925a77a1f45b42ad102ce1eb9448e4d7c Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Thu, 17 Sep 2015 16:00:47 +1000 Subject: [PATCH 067/136] ctdb-recovery: Factor out existing database recovery code Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/server/ctdb_recoverd.c | 250 +++++++++++++++++++++++--------------------- 1 file changed, 132 insertions(+), 118 deletions(-) diff --git a/ctdb/server/ctdb_recoverd.c b/ctdb/server/ctdb_recoverd.c index ac920d5..4527e01 100644 --- a/ctdb/server/ctdb_recoverd.c +++ b/ctdb/server/ctdb_recoverd.c @@ -1799,129 +1799,29 @@ static bool do_takeover_run(struct ctdb_recoverd *rec, return ok; } - -/* - we are the recmaster, and recovery is needed - start a recovery run - */ -static int do_recovery(struct ctdb_recoverd *rec, - TALLOC_CTX *mem_ctx, uint32_t pnn, - struct ctdb_node_map *nodemap, struct ctdb_vnn_map *vnnmap) +static int db_recovery_serial(struct ctdb_recoverd *rec, TALLOC_CTX *mem_ctx, + uint32_t pnn, struct ctdb_node_map *nodemap, + struct ctdb_vnn_map *vnnmap, + struct ctdb_dbid_map *dbmap) { struct ctdb_context *ctdb = rec->ctdb; - int i, j, ret; uint32_t generation; - struct ctdb_dbid_map *dbmap; TDB_DATA data; uint32_t *nodes; - struct timeval start_time; - uint32_t culprit = (uint32_t)-1; - bool self_ban; - - DEBUG(DEBUG_NOTICE, (__location__ " Starting do_recovery\n")); - - /* if recovery fails, force it again */ - rec->need_recovery = true; - - if (!ctdb_op_begin(rec->recovery)) { - return -1; - } - - if (rec->election_timeout) { - /* an election is in progress */ - DEBUG(DEBUG_ERR, ("do_recovery called while election in progress - try again later\n")); - goto fail; - } - - ban_misbehaving_nodes(rec, &self_ban); - if (self_ban) { - DEBUG(DEBUG_NOTICE, ("This node was banned, aborting recovery\n")); - goto fail; - } - - if (ctdb->recovery_lock_file != NULL) { - if (ctdb_recovery_have_lock(ctdb)) { - DEBUG(DEBUG_NOTICE, ("Already holding recovery lock\n")); - } else { - start_time = timeval_current(); - DEBUG(DEBUG_NOTICE, ("Attempting to take recovery lock (%s)\n", - ctdb->recovery_lock_file)); - if (!ctdb_recovery_lock(ctdb)) { - if (ctdb->runstate == CTDB_RUNSTATE_FIRST_RECOVERY) { - /* If ctdb is trying first recovery, it's - * possible that current node does not know - * yet who the recmaster is. - */ - DEBUG(DEBUG_ERR, ("Unable to get recovery lock" - " - retrying recovery\n")); - goto fail; - } - - DEBUG(DEBUG_ERR,("Unable to get recovery lock - aborting recovery " - "and ban ourself for %u seconds\n", - ctdb->tunable.recovery_ban_period)); - ctdb_ban_node(rec, pnn, ctdb->tunable.recovery_ban_period); - goto fail; - } - ctdb_ctrl_report_recd_lock_latency(ctdb, - CONTROL_TIMEOUT(), - timeval_elapsed(&start_time)); - DEBUG(DEBUG_NOTICE, - ("Recovery lock taken successfully by recovery daemon\n")); - } - } - - DEBUG(DEBUG_NOTICE, (__location__ " Recovery initiated due to problem with node %u\n", rec->last_culprit_node)); - - /* get a list of all databases */ - ret = ctdb_ctrl_getdbmap(ctdb, CONTROL_TIMEOUT(), pnn, mem_ctx, &dbmap); - if (ret != 0) { - DEBUG(DEBUG_ERR, (__location__ " Unable to get dbids from node :%u\n", pnn)); - goto fail; - } - - /* we do the db creation before we set the recovery mode, so the freeze happens - on all databases we will be dealing with. */ - - /* verify that we have all the databases any other node has */ - ret = create_missing_local_databases(ctdb, nodemap, pnn, &dbmap, mem_ctx); - if (ret != 0) { - DEBUG(DEBUG_ERR, (__location__ " Unable to create missing local databases\n")); - goto fail; - } - - /* verify that all other nodes have all our databases */ - ret = create_missing_remote_databases(ctdb, nodemap, pnn, dbmap, mem_ctx); - if (ret != 0) { - DEBUG(DEBUG_ERR, (__location__ " Unable to create missing remote databases\n")); - goto fail; - } - DEBUG(DEBUG_NOTICE, (__location__ " Recovery - created remote databases\n")); - - /* update the database priority for all remote databases */ - ret = update_db_priority_on_remote_nodes(ctdb, nodemap, pnn, dbmap, mem_ctx); - if (ret != 0) { - DEBUG(DEBUG_ERR, (__location__ " Unable to set db priority on remote nodes\n")); - } - DEBUG(DEBUG_NOTICE, (__location__ " Recovery - updated db priority for all databases\n")); - - - /* update all other nodes to use the same setting for reclock files - as the local recovery master. - */ - sync_recovery_lock_file_across_cluster(rec); + int ret, i, j; /* set recovery mode to active on all nodes */ ret = set_recovery_mode(ctdb, rec, nodemap, CTDB_RECOVERY_ACTIVE); if (ret != 0) { DEBUG(DEBUG_ERR, (__location__ " Unable to set recovery mode to active on cluster\n")); - goto fail; + return -1; } /* execute the "startrecovery" event script on all nodes */ ret = run_startrecovery_eventscript(rec, nodemap); if (ret!=0) { DEBUG(DEBUG_ERR, (__location__ " Unable to run the 'startrecovery' event on cluster\n")); - goto fail; + return -1; } /* @@ -1938,7 +1838,7 @@ static int do_recovery(struct ctdb_recoverd *rec, DEBUG(DEBUG_WARNING, (__location__ "Unable to update flags on inactive node %d\n", i)); } else { DEBUG(DEBUG_ERR, (__location__ " Unable to update flags on all nodes for node %d\n", i)); - goto fail; + return -1; } } } @@ -1962,7 +1862,7 @@ static int do_recovery(struct ctdb_recoverd *rec, ret = ctdb_ctrl_setvnnmap(ctdb, CONTROL_TIMEOUT(), pnn, mem_ctx, vnnmap); if (ret != 0) { DEBUG(DEBUG_ERR, (__location__ " Unable to set vnnmap for node %u\n", pnn)); - goto fail; + return -1; } /* Database generations are updated when the transaction is commited to @@ -1990,7 +1890,7 @@ static int do_recovery(struct ctdb_recoverd *rec, NULL) != 0) { DEBUG(DEBUG_ERR,("Failed to cancel recovery transaction\n")); } - goto fail; + return -1; } DEBUG(DEBUG_NOTICE,(__location__ " started transactions on all nodes\n")); @@ -2002,7 +1902,7 @@ static int do_recovery(struct ctdb_recoverd *rec, pnn, nodemap, generation); if (ret != 0) { DEBUG(DEBUG_ERR, (__location__ " Failed to recover database 0x%x\n", dbmap->dbs[i].dbid)); - goto fail; + return -1; } } @@ -2015,17 +1915,16 @@ static int do_recovery(struct ctdb_recoverd *rec, NULL, NULL, NULL) != 0) { DEBUG(DEBUG_ERR, (__location__ " Unable to commit recovery changes. Recovery failed.\n")); - goto fail; + return -1; } DEBUG(DEBUG_NOTICE, (__location__ " Recovery - committed databases\n")); - /* update the capabilities for all nodes */ ret = update_capabilities(rec, nodemap); if (ret!=0) { DEBUG(DEBUG_ERR, (__location__ " Unable to update node capabilities.\n")); - goto fail; + return -1; } /* build a new vnn map with all the currently active and @@ -2060,13 +1959,13 @@ static int do_recovery(struct ctdb_recoverd *rec, vnnmap->map = talloc_realloc(vnnmap, vnnmap->map, uint32_t, vnnmap->size); CTDB_NO_MEMORY(ctdb, vnnmap->map); vnnmap->map[0] = pnn; - } + } /* update to the new vnnmap on all nodes */ ret = update_vnnmap_on_all_nodes(ctdb, nodemap, pnn, vnnmap, mem_ctx); if (ret != 0) { DEBUG(DEBUG_ERR, (__location__ " Unable to update vnnmap on all nodes\n")); - goto fail; + return -1; } DEBUG(DEBUG_NOTICE, (__location__ " Recovery - updated vnnmap\n")); @@ -2075,7 +1974,7 @@ static int do_recovery(struct ctdb_recoverd *rec, ret = set_recovery_master(ctdb, nodemap, pnn); if (ret!=0) { DEBUG(DEBUG_ERR, (__location__ " Unable to set recovery master\n")); - goto fail; + return -1; } DEBUG(DEBUG_NOTICE, (__location__ " Recovery - updated recmaster\n")); @@ -2084,11 +1983,126 @@ static int do_recovery(struct ctdb_recoverd *rec, ret = set_recovery_mode(ctdb, rec, nodemap, CTDB_RECOVERY_NORMAL); if (ret != 0) { DEBUG(DEBUG_ERR, (__location__ " Unable to set recovery mode to normal on cluster\n")); - goto fail; + return -1; } DEBUG(DEBUG_NOTICE, (__location__ " Recovery - disabled recovery mode\n")); + return 0; +} + +/* + we are the recmaster, and recovery is needed - start a recovery run + */ +static int do_recovery(struct ctdb_recoverd *rec, + TALLOC_CTX *mem_ctx, uint32_t pnn, + struct ctdb_node_map *nodemap, struct ctdb_vnn_map *vnnmap) +{ + struct ctdb_context *ctdb = rec->ctdb; + int i, ret; + struct ctdb_dbid_map *dbmap; + struct timeval start_time; + uint32_t culprit = (uint32_t)-1; + bool self_ban; + + DEBUG(DEBUG_NOTICE, (__location__ " Starting do_recovery\n")); + + /* if recovery fails, force it again */ + rec->need_recovery = true; + + if (!ctdb_op_begin(rec->recovery)) { + return -1; + } + + if (rec->election_timeout) { + /* an election is in progress */ + DEBUG(DEBUG_ERR, ("do_recovery called while election in progress - try again later\n")); + goto fail; + } + + ban_misbehaving_nodes(rec, &self_ban); + if (self_ban) { + DEBUG(DEBUG_NOTICE, ("This node was banned, aborting recovery\n")); + goto fail; + } + + if (ctdb->recovery_lock_file != NULL) { + if (ctdb_recovery_have_lock(ctdb)) { + DEBUG(DEBUG_NOTICE, ("Already holding recovery lock\n")); + } else { + start_time = timeval_current(); + DEBUG(DEBUG_NOTICE, ("Attempting to take recovery lock (%s)\n", + ctdb->recovery_lock_file)); + if (!ctdb_recovery_lock(ctdb)) { + if (ctdb->runstate == CTDB_RUNSTATE_FIRST_RECOVERY) { + /* If ctdb is trying first recovery, it's + * possible that current node does not know + * yet who the recmaster is. + */ + DEBUG(DEBUG_ERR, ("Unable to get recovery lock" + " - retrying recovery\n")); + goto fail; + } + + DEBUG(DEBUG_ERR,("Unable to get recovery lock - aborting recovery " + "and ban ourself for %u seconds\n", + ctdb->tunable.recovery_ban_period)); + ctdb_ban_node(rec, pnn, ctdb->tunable.recovery_ban_period); + goto fail; + } + ctdb_ctrl_report_recd_lock_latency(ctdb, + CONTROL_TIMEOUT(), + timeval_elapsed(&start_time)); + DEBUG(DEBUG_NOTICE, + ("Recovery lock taken successfully by recovery daemon\n")); + } + } + + DEBUG(DEBUG_NOTICE, (__location__ " Recovery initiated due to problem with node %u\n", rec->last_culprit_node)); + + /* get a list of all databases */ + ret = ctdb_ctrl_getdbmap(ctdb, CONTROL_TIMEOUT(), pnn, mem_ctx, &dbmap); + if (ret != 0) { + DEBUG(DEBUG_ERR, (__location__ " Unable to get dbids from node :%u\n", pnn)); + goto fail; + } + + /* we do the db creation before we set the recovery mode, so the freeze happens + on all databases we will be dealing with. */ + + /* verify that we have all the databases any other node has */ + ret = create_missing_local_databases(ctdb, nodemap, pnn, &dbmap, mem_ctx); + if (ret != 0) { + DEBUG(DEBUG_ERR, (__location__ " Unable to create missing local databases\n")); + goto fail; + } + + /* verify that all other nodes have all our databases */ + ret = create_missing_remote_databases(ctdb, nodemap, pnn, dbmap, mem_ctx); + if (ret != 0) { + DEBUG(DEBUG_ERR, (__location__ " Unable to create missing remote databases\n")); + goto fail; + } + DEBUG(DEBUG_NOTICE, (__location__ " Recovery - created remote databases\n")); + + /* update the database priority for all remote databases */ + ret = update_db_priority_on_remote_nodes(ctdb, nodemap, pnn, dbmap, mem_ctx); + if (ret != 0) { + DEBUG(DEBUG_ERR, (__location__ " Unable to set db priority on remote nodes\n")); + } + DEBUG(DEBUG_NOTICE, (__location__ " Recovery - updated db priority for all databases\n")); + + + /* update all other nodes to use the same setting for reclock files + as the local recovery master. + */ + sync_recovery_lock_file_across_cluster(rec); + + ret = db_recovery_serial(rec, mem_ctx, pnn, nodemap, vnnmap, dbmap); + if (ret != 0) { + goto fail; + } + /* Fetch known/available public IPs from each active node */ ret = ctdb_reload_remote_public_ips(ctdb, rec, nodemap, &culprit); if (ret != 0) { From 9843363629972f162f923e759c6060a712fac2d2 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Thu, 17 Sep 2015 16:07:37 +1000 Subject: [PATCH 068/136] ctdb-recoverd: Update capabilities before the database recovery Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/server/ctdb_recoverd.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ctdb/server/ctdb_recoverd.c b/ctdb/server/ctdb_recoverd.c index 4527e01..5ae8870 100644 --- a/ctdb/server/ctdb_recoverd.c +++ b/ctdb/server/ctdb_recoverd.c @@ -1920,13 +1920,6 @@ static int db_recovery_serial(struct ctdb_recoverd *rec, TALLOC_CTX *mem_ctx, DEBUG(DEBUG_NOTICE, (__location__ " Recovery - committed databases\n")); - /* update the capabilities for all nodes */ - ret = update_capabilities(rec, nodemap); - if (ret!=0) { - DEBUG(DEBUG_ERR, (__location__ " Unable to update node capabilities.\n")); - return -1; - } - /* build a new vnn map with all the currently active and unbanned nodes */ vnnmap = talloc(mem_ctx, struct ctdb_vnn_map); @@ -2098,6 +2091,13 @@ static int do_recovery(struct ctdb_recoverd *rec, */ sync_recovery_lock_file_across_cluster(rec); + /* update the capabilities for all nodes */ + ret = update_capabilities(rec, nodemap); + if (ret!=0) { + DEBUG(DEBUG_ERR, (__location__ " Unable to update node capabilities.\n")); + return -1; + } + ret = db_recovery_serial(rec, mem_ctx, pnn, nodemap, vnnmap, dbmap); if (ret != 0) { goto fail; From 4b39a7706f910c2830e4869b5e6363c45fbb7804 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Thu, 17 Sep 2015 17:10:15 +1000 Subject: [PATCH 069/136] ctdb-recoverd: Update flags on all nodes before database recovery Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/server/ctdb_recoverd.c | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/ctdb/server/ctdb_recoverd.c b/ctdb/server/ctdb_recoverd.c index 5ae8870..d85967a 100644 --- a/ctdb/server/ctdb_recoverd.c +++ b/ctdb/server/ctdb_recoverd.c @@ -1824,27 +1824,6 @@ static int db_recovery_serial(struct ctdb_recoverd *rec, TALLOC_CTX *mem_ctx, return -1; } - /* - update all nodes to have the same flags that we have - */ - for (i=0;inum;i++) { - if (nodemap->nodes[i].flags & NODE_FLAGS_DISCONNECTED) { - continue; - } - - ret = update_flags_on_all_nodes(ctdb, nodemap, i, nodemap->nodes[i].flags); - if (ret != 0) { - if (nodemap->nodes[i].flags & NODE_FLAGS_INACTIVE) { - DEBUG(DEBUG_WARNING, (__location__ "Unable to update flags on inactive node %d\n", i)); - } else { - DEBUG(DEBUG_ERR, (__location__ " Unable to update flags on all nodes for node %d\n", i)); - return -1; - } - } - } - - DEBUG(DEBUG_NOTICE, (__location__ " Recovery - updated flags\n")); - /* pick a new generation number */ generation = new_generation(); @@ -2098,6 +2077,27 @@ static int do_recovery(struct ctdb_recoverd *rec, return -1; } + /* + update all nodes to have the same flags that we have + */ + for (i=0;inum;i++) { + if (nodemap->nodes[i].flags & NODE_FLAGS_DISCONNECTED) { + continue; + } + + ret = update_flags_on_all_nodes(ctdb, nodemap, i, nodemap->nodes[i].flags); + if (ret != 0) { + if (nodemap->nodes[i].flags & NODE_FLAGS_INACTIVE) { + DEBUG(DEBUG_WARNING, (__location__ "Unable to update flags on inactive node %d\n", i)); + } else { + DEBUG(DEBUG_ERR, (__location__ " Unable to update flags on all nodes for node %d\n", i)); + return -1; + } + } + } + + DEBUG(DEBUG_NOTICE, (__location__ " Recovery - updated flags\n")); + ret = db_recovery_serial(rec, mem_ctx, pnn, nodemap, vnnmap, dbmap); if (ret != 0) { goto fail; From f0613ac4f7b3d3721750b7ee187a40a8a185a74e Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Thu, 17 Sep 2015 16:13:55 +1000 Subject: [PATCH 070/136] ctdb-daemon: Use a define for default capabilities Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/include/ctdb_protocol.h | 2 ++ ctdb/protocol/protocol.h | 2 ++ ctdb/server/ctdbd.c | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ctdb/include/ctdb_protocol.h b/ctdb/include/ctdb_protocol.h index e195e57..893e4c6 100644 --- a/ctdb/include/ctdb_protocol.h +++ b/ctdb/include/ctdb_protocol.h @@ -589,6 +589,8 @@ struct ctdb_node_map { /* This capability is set if NATGW is enabled */ #define CTDB_CAP_NATGW 0x00000008 +#define CTDB_CAP_DEFAULT (0) + struct ctdb_public_ip { uint32_t pnn; diff --git a/ctdb/protocol/protocol.h b/ctdb/protocol/protocol.h index f740587..cb372a8 100644 --- a/ctdb/protocol/protocol.h +++ b/ctdb/protocol/protocol.h @@ -698,6 +698,8 @@ struct ctdb_public_ip_list { /* This capability is set if NATGW is enabled */ #define CTDB_CAP_NATGW 0x00000008 +#define CTDB_CAP_DEFAULT (0) + struct ctdb_node_and_flags { uint32_t pnn; uint32_t flags; diff --git a/ctdb/server/ctdbd.c b/ctdb/server/ctdbd.c index d057ed6..ff9ad6a 100644 --- a/ctdb/server/ctdbd.c +++ b/ctdb/server/ctdbd.c @@ -218,7 +218,7 @@ int main(int argc, const char *argv[]) } /* set ctdbd capabilities */ - ctdb->capabilities = 0; + ctdb->capabilities = CTDB_CAP_DEFAULT; if (options.no_lmaster == 0) { ctdb->capabilities |= CTDB_CAP_LMASTER; } From cbfabd8104f56599d0b1f0a2f17d5154144a9341 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Thu, 17 Sep 2015 16:14:51 +1000 Subject: [PATCH 071/136] ctdb-daemon: Add parallel database recovery capability Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/include/ctdb_protocol.h | 7 ++++++- ctdb/protocol/protocol.h | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/ctdb/include/ctdb_protocol.h b/ctdb/include/ctdb_protocol.h index 893e4c6..80c6860 100644 --- a/ctdb/include/ctdb_protocol.h +++ b/ctdb/include/ctdb_protocol.h @@ -589,7 +589,12 @@ struct ctdb_node_map { /* This capability is set if NATGW is enabled */ #define CTDB_CAP_NATGW 0x00000008 -#define CTDB_CAP_DEFAULT (0) +/* + * Node features + */ +#define CTDB_CAP_PARALLEL_RECOVERY 0x00010000 + +#define CTDB_CAP_DEFAULT (CTDB_CAP_PARALLEL_RECOVERY) struct ctdb_public_ip { diff --git a/ctdb/protocol/protocol.h b/ctdb/protocol/protocol.h index cb372a8..054bab3 100644 --- a/ctdb/protocol/protocol.h +++ b/ctdb/protocol/protocol.h @@ -698,7 +698,12 @@ struct ctdb_public_ip_list { /* This capability is set if NATGW is enabled */ #define CTDB_CAP_NATGW 0x00000008 -#define CTDB_CAP_DEFAULT (0) +/* + * Node features + */ +#define CTDB_CAP_PARALLEL_RECOVERY 0x00010000 + +#define CTDB_CAP_DEFAULT (CTDB_CAP_PARALLEL_RECOVERY) struct ctdb_node_and_flags { uint32_t pnn; From e6ff36506c820523ab23b3749227bf6df6218d76 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Thu, 17 Sep 2015 16:22:38 +1000 Subject: [PATCH 072/136] ctdb-recoverd: Add code for parallel database recovery Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/server/ctdb_recoverd.c | 143 ++++++++++++++++++++++++++- ctdb/tests/simple/scripts/local_daemons.bash | 1 + 2 files changed, 143 insertions(+), 1 deletion(-) diff --git a/ctdb/server/ctdb_recoverd.c b/ctdb/server/ctdb_recoverd.c index d85967a..a7ba649 100644 --- a/ctdb/server/ctdb_recoverd.c +++ b/ctdb/server/ctdb_recoverd.c @@ -1799,6 +1799,126 @@ static bool do_takeover_run(struct ctdb_recoverd *rec, return ok; } +struct recovery_helper_state { + int fd[2]; + pid_t pid; + int result; + bool done; +}; + +static void ctdb_recovery_handler(struct tevent_context *ev, + struct tevent_fd *fde, + uint16_t flags, void *private_data) +{ + struct recovery_helper_state *state = talloc_get_type_abort( + private_data, struct recovery_helper_state); + int ret; + + ret = sys_read(state->fd[0], &state->result, sizeof(state->result)); + if (ret != sizeof(state->result)) { + state->result = EPIPE; + } + + state->done = true; +} + + +static int db_recovery_parallel(struct ctdb_recoverd *rec, TALLOC_CTX *mem_ctx) +{ + static char prog[PATH_MAX+1] = ""; + const char **args; + struct recovery_helper_state *state; + struct tevent_fd *fde; + int nargs, ret; + + if (!ctdb_set_helper("recovery_helper", prog, sizeof(prog), + "CTDB_RECOVERY_HELPER", CTDB_HELPER_BINDIR, + "ctdb_recovery_helper")) { + ctdb_die(rec->ctdb, "Unable to set recovery helper\n"); + } + + state = talloc_zero(mem_ctx, struct recovery_helper_state); + if (state == NULL) { + DEBUG(DEBUG_ERR, (__location__ " memory error\n")); + return -1; + } + + state->pid = -1; + + ret = pipe(state->fd); + if (ret != 0) { + DEBUG(DEBUG_ERR, + ("Failed to create pipe for recovery helper\n")); + goto fail; + } + + set_close_on_exec(state->fd[0]); + + nargs = 4; + args = talloc_array(state, const char *, nargs); + if (args == NULL) { + DEBUG(DEBUG_ERR, (__location__ " memory error\n")); + goto fail; + } + + args[0] = talloc_asprintf(args, "%d", state->fd[1]); + args[1] = rec->ctdb->daemon.name; + args[2] = talloc_asprintf(args, "%u", new_generation()); + args[3] = NULL; + + if (args[0] == NULL || args[2] == NULL) { + DEBUG(DEBUG_ERR, (__location__ " memory error\n")); + goto fail; + } + + if (!ctdb_vfork_with_logging(state, rec->ctdb, "recovery", prog, nargs, + args, NULL, NULL, &state->pid)) { + DEBUG(DEBUG_ERR, + ("Failed to create child for recovery helper\n")); + goto fail; + } + + close(state->fd[1]); + state->fd[1] = -1; + + state->done = false; + + fde = tevent_add_fd(rec->ctdb->ev, rec->ctdb, state->fd[0], + TEVENT_FD_READ, ctdb_recovery_handler, state); + if (fde == NULL) { + goto fail; + } + tevent_fd_set_auto_close(fde); + + while (!state->done) { + tevent_loop_once(rec->ctdb->ev); + } + + close(state->fd[0]); + state->fd[0] = -1; + + if (state->result != 0) { + goto fail; + } + + ctdb_kill(rec->ctdb, state->pid, SIGKILL); + talloc_free(state); + return 0; + +fail: + if (state->fd[0] != -1) { + close(state->fd[0]); + } + if (state->fd[1] != -1) { + close(state->fd[1]); + } + if (state->pid != -1) { + ctdb_kill(rec->ctdb, state->pid, SIGKILL); + } + talloc_free(state); + return -1; +} + static int db_recovery_serial(struct ctdb_recoverd *rec, TALLOC_CTX *mem_ctx, uint32_t pnn, struct ctdb_node_map *nodemap, struct ctdb_vnn_map *vnnmap, @@ -1976,6 +2096,7 @@ static int do_recovery(struct ctdb_recoverd *rec, struct timeval start_time; uint32_t culprit = (uint32_t)-1; bool self_ban; + bool par_recovery; DEBUG(DEBUG_NOTICE, (__location__ " Starting do_recovery\n")); @@ -2098,7 +2219,27 @@ static int do_recovery(struct ctdb_recoverd *rec, DEBUG(DEBUG_NOTICE, (__location__ " Recovery - updated flags\n")); - ret = db_recovery_serial(rec, mem_ctx, pnn, nodemap, vnnmap, dbmap); + /* Check if all participating nodes have parallel recovery capability */ + par_recovery = true; + for (i=0; inum; i++) { + if (nodemap->nodes[i].flags & NODE_FLAGS_INACTIVE) { + continue; + } + + if (!(rec->caps[i].capabilities & + CTDB_CAP_PARALLEL_RECOVERY)) { + par_recovery = false; + break; + } + } + + if (par_recovery) { + ret = db_recovery_parallel(rec, mem_ctx); + } else { + ret = db_recovery_serial(rec, mem_ctx, pnn, nodemap, vnnmap, + dbmap); + } + if (ret != 0) { goto fail; } diff --git a/ctdb/tests/simple/scripts/local_daemons.bash b/ctdb/tests/simple/scripts/local_daemons.bash index 6015dd5..5071b1e 100644 --- a/ctdb/tests/simple/scripts/local_daemons.bash +++ b/ctdb/tests/simple/scripts/local_daemons.bash @@ -12,6 +12,7 @@ if [ -n "$ctdb_dir" -a -d "${ctdb_dir}/bin" ] ; then PATH="${ctdb_dir}/bin:${PATH}" export CTDB_LOCK_HELPER="${ctdb_dir}/bin/ctdb_lock_helper" export CTDB_EVENT_HELPER="${ctdb_dir}/bin/ctdb_event_helper" + export CTDB_RECOVERY_HELPER="${ctdb_dir}/bin/ctdb_recovery_helper" fi export CTDB_NODES="${TEST_VAR_DIR}/nodes.txt" From ffff66b011131c16c369b397d6fcdd5b75a6db4e Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Mon, 21 Sep 2015 17:12:25 +1000 Subject: [PATCH 073/136] ctdb-call: Improve a log message Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/server/ctdb_call.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ctdb/server/ctdb_call.c b/ctdb/server/ctdb_call.c index a591ae5..e767bf7 100644 --- a/ctdb/server/ctdb_call.c +++ b/ctdb/server/ctdb_call.c @@ -1375,7 +1375,8 @@ static void ctdb_call_resend(struct ctdb_call_state *state) state->c->hdr.destnode = ctdb->pnn; ctdb_queue_packet(ctdb, &state->c->hdr); - DEBUG(DEBUG_NOTICE,("resent ctdb_call\n")); + DEBUG(DEBUG_NOTICE,("resent ctdb_call for db %s reqid %u generation %u\n", + state->ctdb_db->db_name, state->reqid, state->generation)); } /* From fbd9c9fd2f9a4e3e4cf03af574b322752670d632 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Tue, 6 Oct 2015 11:52:06 +1100 Subject: [PATCH 074/136] ctdb-recoverd: Do not freeze databases for election If election occurs during SMB activity, then trying to freeze all the databases can cause samba/ctdb deadlock which parallel database recovery is trying to avoid. Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/server/ctdb_recoverd.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/ctdb/server/ctdb_recoverd.c b/ctdb/server/ctdb_recoverd.c index a7ba649..d5f0fd6 100644 --- a/ctdb/server/ctdb_recoverd.c +++ b/ctdb/server/ctdb_recoverd.c @@ -463,7 +463,10 @@ static void transaction_start_fail_callback(struct ctdb_context *ctdb, uint32_t /* change recovery mode on all nodes */ -static int set_recovery_mode(struct ctdb_context *ctdb, struct ctdb_recoverd *rec, struct ctdb_node_map *nodemap, uint32_t rec_mode) +static int set_recovery_mode(struct ctdb_context *ctdb, + struct ctdb_recoverd *rec, + struct ctdb_node_map *nodemap, + uint32_t rec_mode, bool freeze) { TDB_DATA data; uint32_t *nodes; @@ -489,7 +492,7 @@ static int set_recovery_mode(struct ctdb_context *ctdb, struct ctdb_recoverd *re } /* freeze all nodes */ - if (rec_mode == CTDB_RECOVERY_ACTIVE) { + if (freeze && rec_mode == CTDB_RECOVERY_ACTIVE) { int i; for (i=1; i<=NUM_DB_PRIORITIES; i++) { @@ -1931,7 +1934,7 @@ static int db_recovery_serial(struct ctdb_recoverd *rec, TALLOC_CTX *mem_ctx, int ret, i, j; /* set recovery mode to active on all nodes */ - ret = set_recovery_mode(ctdb, rec, nodemap, CTDB_RECOVERY_ACTIVE); + ret = set_recovery_mode(ctdb, rec, nodemap, CTDB_RECOVERY_ACTIVE, true); if (ret != 0) { DEBUG(DEBUG_ERR, (__location__ " Unable to set recovery mode to active on cluster\n")); return -1; @@ -2072,7 +2075,7 @@ static int db_recovery_serial(struct ctdb_recoverd *rec, TALLOC_CTX *mem_ctx, DEBUG(DEBUG_NOTICE, (__location__ " Recovery - updated recmaster\n")); /* disable recovery mode */ - ret = set_recovery_mode(ctdb, rec, nodemap, CTDB_RECOVERY_NORMAL); + ret = set_recovery_mode(ctdb, rec, nodemap, CTDB_RECOVERY_NORMAL, false); if (ret != 0) { DEBUG(DEBUG_ERR, (__location__ " Unable to set recovery mode to normal on cluster\n")); return -1; @@ -2876,7 +2879,7 @@ static void force_election(struct ctdb_recoverd *rec, uint32_t pnn, DEBUG(DEBUG_INFO,(__location__ " Force an election\n")); /* set all nodes to recovery mode to stop all internode traffic */ - ret = set_recovery_mode(ctdb, rec, nodemap, CTDB_RECOVERY_ACTIVE); + ret = set_recovery_mode(ctdb, rec, nodemap, CTDB_RECOVERY_ACTIVE, false); if (ret != 0) { DEBUG(DEBUG_ERR, (__location__ " Unable to set recovery mode to active on cluster\n")); return; From 3cf93d91361191a7accdf0ddf5e811212e0a5ca2 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Tue, 6 Oct 2015 14:46:48 +1100 Subject: [PATCH 075/136] ctdb-recoverd: Get rid of connected-ness comparison in election The reason for favouring more connected node is to create a larger cluster in case of a split brain. In split brain condition, the nodes are not communicating across partitions and each partition will run its own election. Among all the partitions, the node which holds the recovery lock will eventually "win". All the other nodes which won election but could not grab recovery lock will end up banning themselves. This also prevents the recovery master role from bouncing between nodes during startup when the entire cluster is restarted. Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/server/ctdb_recoverd.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/ctdb/server/ctdb_recoverd.c b/ctdb/server/ctdb_recoverd.c index d5f0fd6..3c7f7f4 100644 --- a/ctdb/server/ctdb_recoverd.c +++ b/ctdb/server/ctdb_recoverd.c @@ -2400,11 +2400,6 @@ static bool ctdb_election_win(struct ctdb_recoverd *rec, struct election_message return true; } - /* try to use the most connected node */ - if (cmp == 0) { - cmp = (int)myem.num_connected - (int)em->num_connected; - } - /* then the longest running node */ if (cmp == 0) { cmp = timeval_compare(&em->priority_time, &myem.priority_time); From 01017482876defa74137295fa08ed7f27fc12f61 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Tue, 6 Oct 2015 17:31:41 +1100 Subject: [PATCH 076/136] ctdb-recoverd: Always check for recmaster before doing recovery Recovery daemon checks if it is the recovery master before performing certain checks. During those checks it's possible that re-election can change the recmaster. In such a case, the recovery daemon should never do a database recovery. This is not complete fix since the recovery master can still change while the recovery is going on. The correct fix is to abort recovery if the recovery master changes. Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke Autobuild-User(master): Amitay Isaacs Autobuild-Date(master): Wed Oct 7 17:55:05 CEST 2015 on sn-devel-104 --- ctdb/server/ctdb_recoverd.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/ctdb/server/ctdb_recoverd.c b/ctdb/server/ctdb_recoverd.c index 3c7f7f4..1165318 100644 --- a/ctdb/server/ctdb_recoverd.c +++ b/ctdb/server/ctdb_recoverd.c @@ -2103,6 +2103,24 @@ static int do_recovery(struct ctdb_recoverd *rec, DEBUG(DEBUG_NOTICE, (__location__ " Starting do_recovery\n")); + /* Check if the current node is still the recmaster. It's possible that + * re-election has changed the recmaster, but we have not yet updated + * that information. + */ + ret = ctdb_ctrl_getrecmaster(ctdb, mem_ctx, CONTROL_TIMEOUT(), + pnn, &ctdb->recovery_master); + if (ret != 0) { + DEBUG(DEBUG_ERR, (__location__ " Unable to get recmaster\n")); + return -1; + } + + if (pnn != ctdb->recovery_master) { + DEBUG(DEBUG_NOTICE, + ("Recovery master changed to %u, aborting recovery\n", + ctdb->recovery_master)); + return -1; + } + /* if recovery fails, force it again */ rec->need_recovery = true; From 7b9016ac6723438ed1930d144eb109e3eb88677a Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 2 Oct 2015 19:51:01 -0700 Subject: [PATCH 077/136] lib: Fix error talloc leaks in ctdb_read_packet() Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- source3/lib/ctdbd_conn.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c index c743356..44f70f5 100644 --- a/source3/lib/ctdbd_conn.c +++ b/source3/lib/ctdbd_conn.c @@ -337,9 +337,11 @@ static int ctdb_read_packet(int fd, int timeout, TALLOC_CTX *mem_ctx, nread = read_data(fd, ((char *)req) + sizeof(msglen), msglen - sizeof(msglen)); if (nread == -1) { + TALLOC_FREE(req); return errno; } if (nread == 0) { + TALLOC_FREE(req); return EIO; } From 858af0b4473d02e24be76e4baf51dec03ed99045 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 2 Oct 2015 19:54:31 -0700 Subject: [PATCH 078/136] lib: Add ctdbd_control_unix Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- source3/lib/ctdbd_conn.c | 42 ++++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c index 44f70f5..ee93799 100644 --- a/source3/lib/ctdbd_conn.c +++ b/source3/lib/ctdbd_conn.c @@ -68,6 +68,12 @@ static NTSTATUS ctdbd_control(struct ctdbd_connection *conn, uint64_t srvid, uint32_t flags, TDB_DATA data, TALLOC_CTX *mem_ctx, TDB_DATA *outdata, int *cstatus); +static int ctdbd_control_unix(struct ctdbd_connection *conn, + uint32_t vnn, uint32_t opcode, + uint64_t srvid, uint32_t flags, + TDB_DATA data, + TALLOC_CTX *mem_ctx, TDB_DATA *outdata, + int *cstatus); /* * exit on fatal communications errors with the ctdbd daemon @@ -639,7 +645,7 @@ NTSTATUS ctdbd_messaging_send_iov(struct ctdbd_connection *conn, /* * send/recv a generic ctdb control message */ -static NTSTATUS ctdbd_control(struct ctdbd_connection *conn, +static int ctdbd_control_unix(struct ctdbd_connection *conn, uint32_t vnn, uint32_t opcode, uint64_t srvid, uint32_t flags, TDB_DATA data, @@ -651,7 +657,6 @@ static NTSTATUS ctdbd_control(struct ctdbd_connection *conn, struct ctdb_reply_control *reply = NULL; struct iovec iov[2]; ssize_t nwritten; - NTSTATUS status; int ret; ZERO_STRUCT(req); @@ -684,20 +689,19 @@ static NTSTATUS ctdbd_control(struct ctdbd_connection *conn, if (cstatus) { *cstatus = 0; } - return NT_STATUS_OK; + return 0; } ret = ctdb_read_req(conn, req.hdr.reqid, NULL, &hdr); if (ret != 0) { DEBUG(10, ("ctdb_read_req failed: %s\n", strerror(ret))); - status = map_nt_error_from_unix(ret); - goto fail; + return ret; } if (hdr->operation != CTDB_REPLY_CONTROL) { DEBUG(0, ("received invalid reply\n")); - status = NT_STATUS_INVALID_NETWORK_RESPONSE; - goto fail; + TALLOC_FREE(hdr); + return EIO; } reply = (struct ctdb_reply_control *)hdr; @@ -705,7 +709,7 @@ static NTSTATUS ctdbd_control(struct ctdbd_connection *conn, if (!(outdata->dptr = (uint8_t *)talloc_memdup( mem_ctx, reply->data, reply->datalen))) { TALLOC_FREE(reply); - return NT_STATUS_NO_MEMORY; + return ENOMEM; } outdata->dsize = reply->datalen; } @@ -713,11 +717,25 @@ static NTSTATUS ctdbd_control(struct ctdbd_connection *conn, (*cstatus) = reply->status; } - status = NT_STATUS_OK; - - fail: TALLOC_FREE(reply); - return status; + return ret; +} + +static NTSTATUS ctdbd_control(struct ctdbd_connection *conn, + uint32_t vnn, uint32_t opcode, + uint64_t srvid, uint32_t flags, + TDB_DATA data, + TALLOC_CTX *mem_ctx, TDB_DATA *outdata, + int *cstatus) +{ + int ret; + + ret = ctdbd_control_unix(conn, vnn, opcode, srvid, flags, data, + mem_ctx, outdata, cstatus); + if (ret != 0) { + return map_nt_error_from_unix(ret); + } + return NT_STATUS_OK; } /* From a5438e09af4148abb71d5de70f7e220f0cfbbbdf Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 2 Oct 2015 20:00:32 -0700 Subject: [PATCH 079/136] lib: Use ctdbd_control_unix in register_with_ctdbd Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- source3/lib/ctdbd_conn.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c index ee93799..e307faf 100644 --- a/source3/lib/ctdbd_conn.c +++ b/source3/lib/ctdbd_conn.c @@ -113,16 +113,15 @@ NTSTATUS register_with_ctdbd(struct ctdbd_connection *conn, uint64_t srvid, void *private_data) { - NTSTATUS status; - int cstatus; + int ret, cstatus; size_t num_callbacks; struct ctdbd_srvid_cb *tmp; - status = ctdbd_control(conn, CTDB_CURRENT_NODE, - CTDB_CONTROL_REGISTER_SRVID, srvid, 0, - tdb_null, NULL, NULL, &cstatus); - if (!NT_STATUS_IS_OK(status)) { - return status; + ret = ctdbd_control_unix(conn, CTDB_CURRENT_NODE, + CTDB_CONTROL_REGISTER_SRVID, srvid, 0, + tdb_null, NULL, NULL, &cstatus); + if (ret != 0) { + return map_nt_error_from_unix(ret); } num_callbacks = talloc_array_length(conn->callbacks); From a8c035fb6dfd88abd5eebb4d79c9e927b51b5a0d Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 2 Oct 2015 20:00:32 -0700 Subject: [PATCH 080/136] lib: Use ctdbd_control_unix in get_cluster_vnn Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- source3/lib/ctdbd_conn.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c index e307faf..c684174 100644 --- a/source3/lib/ctdbd_conn.c +++ b/source3/lib/ctdbd_conn.c @@ -185,16 +185,16 @@ static int ctdbd_msg_call_back(struct ctdbd_connection *conn, static NTSTATUS get_cluster_vnn(struct ctdbd_connection *conn, uint32_t *vnn) { int32_t cstatus=-1; - NTSTATUS status; - status = ctdbd_control(conn, - CTDB_CURRENT_NODE, CTDB_CONTROL_GET_PNN, 0, 0, - tdb_null, NULL, NULL, &cstatus); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("ctdbd_control failed: %s\n", nt_errstr(status))); - return status; + int ret; + ret = ctdbd_control_unix(conn, + CTDB_CURRENT_NODE, CTDB_CONTROL_GET_PNN, 0, 0, + tdb_null, NULL, NULL, &cstatus); + if (ret != 0) { + DEBUG(1, ("ctdbd_control failed: %s\n", strerror(ret))); + return map_nt_error_from_unix(ret); } *vnn = (uint32_t)cstatus; - return status; + return NT_STATUS_OK; } /* From 4d43101500fb9339fc49e3f95bc5e1a23eff1b42 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 2 Oct 2015 20:05:15 -0700 Subject: [PATCH 081/136] lib: Rename a variable We'll have "int ret" in the next commit Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- source3/lib/ctdbd_conn.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c index c684174..30654cb 100644 --- a/source3/lib/ctdbd_conn.c +++ b/source3/lib/ctdbd_conn.c @@ -207,7 +207,7 @@ static bool ctdbd_working(struct ctdbd_connection *conn, uint32_t vnn) TDB_DATA outdata; struct ctdb_node_map *m; uint32_t failure_flags; - bool ret = false; + bool ok = false; int i; status = ctdbd_control(conn, CTDB_CURRENT_NODE, @@ -245,10 +245,10 @@ static bool ctdbd_working(struct ctdbd_connection *conn, uint32_t vnn) goto fail; } - ret = true; + ok = true; fail: TALLOC_FREE(outdata.dptr); - return ret; + return ok; } uint32_t ctdbd_vnn(const struct ctdbd_connection *conn) From ab79b952de8b0887a3e19e0f5e467e40ae4e793f Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 2 Oct 2015 20:06:59 -0700 Subject: [PATCH 082/136] lib: Use ctdbd_control_unix in ctdbd_working Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- source3/lib/ctdbd_conn.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c index 30654cb..eb585d1 100644 --- a/source3/lib/ctdbd_conn.c +++ b/source3/lib/ctdbd_conn.c @@ -203,18 +203,17 @@ static NTSTATUS get_cluster_vnn(struct ctdbd_connection *conn, uint32_t *vnn) static bool ctdbd_working(struct ctdbd_connection *conn, uint32_t vnn) { int32_t cstatus=-1; - NTSTATUS status; TDB_DATA outdata; struct ctdb_node_map *m; uint32_t failure_flags; bool ok = false; - int i; + int i, ret; - status = ctdbd_control(conn, CTDB_CURRENT_NODE, - CTDB_CONTROL_GET_NODEMAP, 0, 0, - tdb_null, talloc_tos(), &outdata, &cstatus); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("ctdbd_control failed: %s\n", nt_errstr(status))); + ret = ctdbd_control_unix(conn, CTDB_CURRENT_NODE, + CTDB_CONTROL_GET_NODEMAP, 0, 0, + tdb_null, talloc_tos(), &outdata, &cstatus); + if (ret != 0) { + DEBUG(1, ("ctdbd_control failed: %s\n", strerror(ret))); return false; } if ((cstatus != 0) || (outdata.dptr == NULL)) { From 24d0add465e90183a244272fe8220c85e2f9409b Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 2 Oct 2015 20:08:53 -0700 Subject: [PATCH 083/136] lib: Use ctdbd_control_unix in ctdbd_dbpath Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- source3/lib/ctdbd_conn.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c index eb585d1..ccdd76b 100644 --- a/source3/lib/ctdbd_conn.c +++ b/source3/lib/ctdbd_conn.c @@ -869,7 +869,7 @@ bool ctdb_processes_exist(struct ctdbd_connection *conn, char *ctdbd_dbpath(struct ctdbd_connection *conn, TALLOC_CTX *mem_ctx, uint32_t db_id) { - NTSTATUS status; + int ret; TDB_DATA data; TDB_DATA rdata = {0}; int32_t cstatus = 0; @@ -877,11 +877,12 @@ char *ctdbd_dbpath(struct ctdbd_connection *conn, data.dptr = (uint8_t*)&db_id; data.dsize = sizeof(db_id); - status = ctdbd_control(conn, CTDB_CURRENT_NODE, - CTDB_CONTROL_GETDBPATH, 0, 0, data, - mem_ctx, &rdata, &cstatus); - if (!NT_STATUS_IS_OK(status) || cstatus != 0) { - DEBUG(0,(__location__ " ctdb_control for getdbpath failed\n")); + ret = ctdbd_control_unix(conn, CTDB_CURRENT_NODE, + CTDB_CONTROL_GETDBPATH, 0, 0, data, + mem_ctx, &rdata, &cstatus); + if ((ret != 0) || cstatus != 0) { + DEBUG(0, (__location__ " ctdb_control for getdbpath failed: %s\n", + strerror(ret))); return NULL; } From a44894506e904a6f0076eed54969bd5cfcc55b7a Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 2 Oct 2015 20:08:53 -0700 Subject: [PATCH 084/136] lib: Use ctdbd_control_unix in ctdbd_db_attach Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- source3/lib/ctdbd_conn.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c index ccdd76b..7bb1e35 100644 --- a/source3/lib/ctdbd_conn.c +++ b/source3/lib/ctdbd_conn.c @@ -895,22 +895,22 @@ char *ctdbd_dbpath(struct ctdbd_connection *conn, NTSTATUS ctdbd_db_attach(struct ctdbd_connection *conn, const char *name, uint32_t *db_id, int tdb_flags) { - NTSTATUS status; + int ret; TDB_DATA data; int32_t cstatus; bool persistent = (tdb_flags & TDB_CLEAR_IF_FIRST) == 0; data = string_term_tdb_data(name); - status = ctdbd_control(conn, CTDB_CURRENT_NODE, - persistent - ? CTDB_CONTROL_DB_ATTACH_PERSISTENT - : CTDB_CONTROL_DB_ATTACH, - tdb_flags, 0, data, NULL, &data, &cstatus); - if (!NT_STATUS_IS_OK(status)) { + ret = ctdbd_control_unix(conn, CTDB_CURRENT_NODE, + persistent + ? CTDB_CONTROL_DB_ATTACH_PERSISTENT + : CTDB_CONTROL_DB_ATTACH, + tdb_flags, 0, data, NULL, &data, &cstatus); + if (ret != 0) { DEBUG(0, (__location__ " ctdb_control for db_attach " - "failed: %s\n", nt_errstr(status))); - return status; + "failed: %s\n", strerror(ret))); + return map_nt_error_from_unix(ret); } if (cstatus != 0 || data.dsize != sizeof(uint32_t)) { @@ -928,14 +928,14 @@ NTSTATUS ctdbd_db_attach(struct ctdbd_connection *conn, data.dptr = (uint8_t *)db_id; data.dsize = sizeof(*db_id); - status = ctdbd_control(conn, CTDB_CURRENT_NODE, - CTDB_CONTROL_ENABLE_SEQNUM, 0, 0, data, - NULL, NULL, &cstatus); - if (!NT_STATUS_IS_OK(status) || cstatus != 0) { - DEBUG(0,(__location__ " ctdb_control for enable seqnum " - "failed\n")); - return NT_STATUS_IS_OK(status) ? NT_STATUS_INTERNAL_ERROR : - status; + ret = ctdbd_control_unix(conn, CTDB_CURRENT_NODE, + CTDB_CONTROL_ENABLE_SEQNUM, 0, 0, data, + NULL, NULL, &cstatus); + if ((ret != 0) || cstatus != 0) { + DEBUG(0, (__location__ " ctdb_control for enable seqnum " + "failed: %s\n", strerror(ret))); + return (ret == 0) ? NT_STATUS_INTERNAL_ERROR : + map_nt_error_from_unix(ret); } return NT_STATUS_OK; From dae02e9adb4099a37501d9f234a351f34aadaa93 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 2 Oct 2015 20:08:53 -0700 Subject: [PATCH 085/136] lib: Use ctdbd_control_unix in ctdbd_db_attach Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- source3/lib/ctdbd_conn.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c index 7bb1e35..525aab7 100644 --- a/source3/lib/ctdbd_conn.c +++ b/source3/lib/ctdbd_conn.c @@ -1087,7 +1087,7 @@ NTSTATUS ctdbd_traverse(struct ctdbd_connection *master, uint32_t db_id, { struct ctdbd_connection *conn; NTSTATUS status; - + int ret; TDB_DATA key, data; struct ctdb_traverse_start t; int cstatus; @@ -1109,13 +1109,14 @@ NTSTATUS ctdbd_traverse(struct ctdbd_connection *master, uint32_t db_id, data.dptr = (uint8_t *)&t; data.dsize = sizeof(t); - status = ctdbd_control(conn, CTDB_CURRENT_NODE, - CTDB_CONTROL_TRAVERSE_START, conn->rand_srvid, 0, - data, NULL, NULL, &cstatus); + ret = ctdbd_control_unix(conn, CTDB_CURRENT_NODE, + CTDB_CONTROL_TRAVERSE_START, conn->rand_srvid, + 0, data, NULL, NULL, &cstatus); - if (!NT_STATUS_IS_OK(status) || (cstatus != 0)) { + if ((ret != 0) || (cstatus != 0)) { + status = map_nt_error_from_unix(ret); - DEBUG(0,("ctdbd_control failed: %s, %d\n", nt_errstr(status), + DEBUG(0,("ctdbd_control failed: %s, %d\n", strerror(ret), cstatus)); if (NT_STATUS_IS_OK(status)) { @@ -1132,7 +1133,6 @@ NTSTATUS ctdbd_traverse(struct ctdbd_connection *master, uint32_t db_id, struct ctdb_req_header *hdr = NULL; struct ctdb_req_message *m; struct ctdb_rec_data *d; - int ret; ret = ctdb_read_packet(conn->fd, conn->timeout, conn, &hdr); if (ret != 0) { From 108b6270f7bf702b13344386b8838fd645c13929 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 2 Oct 2015 20:08:53 -0700 Subject: [PATCH 086/136] lib: Use ctdbd_control_unix in ctdbd_register_ips Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- source3/lib/ctdbd_conn.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c index 525aab7..5840627 100644 --- a/source3/lib/ctdbd_conn.c +++ b/source3/lib/ctdbd_conn.c @@ -1227,6 +1227,7 @@ NTSTATUS ctdbd_register_ips(struct ctdbd_connection *conn, struct ctdb_control_tcp_addr p; TDB_DATA data = { .dptr = (uint8_t *)&p, .dsize = sizeof(p) }; NTSTATUS status; + int ret; struct sockaddr_storage client; struct sockaddr_storage server; @@ -1265,9 +1266,14 @@ NTSTATUS ctdbd_register_ips(struct ctdbd_connection *conn, * can send an extra ack to trigger a reset for our client, so it * immediately reconnects */ - return ctdbd_control(conn, CTDB_CURRENT_NODE, - CTDB_CONTROL_TCP_CLIENT, 0, - CTDB_CTRL_FLAG_NOREPLY, data, NULL, NULL, NULL); + ret = ctdbd_control_unix(conn, CTDB_CURRENT_NODE, + CTDB_CONTROL_TCP_CLIENT, 0, + CTDB_CTRL_FLAG_NOREPLY, data, NULL, NULL, + NULL); + if (ret != 0) { + return map_nt_error_from_unix(ret); + } + return NT_STATUS_OK; } /* From fd6293c987f1d8c97be4bddd08301bc78a754a60 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 2 Oct 2015 20:29:56 -0700 Subject: [PATCH 087/136] lib: Remove ctdbd_control Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- source3/lib/ctdbd_conn.c | 31 ++++++++----------------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c index 5840627..04fbe9c 100644 --- a/source3/lib/ctdbd_conn.c +++ b/source3/lib/ctdbd_conn.c @@ -63,11 +63,6 @@ static uint32_t ctdbd_next_reqid(struct ctdbd_connection *conn) return conn->reqid; } -static NTSTATUS ctdbd_control(struct ctdbd_connection *conn, - uint32_t vnn, uint32_t opcode, - uint64_t srvid, uint32_t flags, TDB_DATA data, - TALLOC_CTX *mem_ctx, TDB_DATA *outdata, - int *cstatus); static int ctdbd_control_unix(struct ctdbd_connection *conn, uint32_t vnn, uint32_t opcode, uint64_t srvid, uint32_t flags, @@ -719,23 +714,6 @@ static int ctdbd_control_unix(struct ctdbd_connection *conn, return ret; } -static NTSTATUS ctdbd_control(struct ctdbd_connection *conn, - uint32_t vnn, uint32_t opcode, - uint64_t srvid, uint32_t flags, - TDB_DATA data, - TALLOC_CTX *mem_ctx, TDB_DATA *outdata, - int *cstatus) -{ - int ret; - - ret = ctdbd_control_unix(conn, vnn, opcode, srvid, flags, data, - mem_ctx, outdata, cstatus); - if (ret != 0) { - return map_nt_error_from_unix(ret); - } - return NT_STATUS_OK; -} - /* * see if a remote process exists */ @@ -1284,7 +1262,14 @@ NTSTATUS ctdbd_control_local(struct ctdbd_connection *conn, uint32_t opcode, TALLOC_CTX *mem_ctx, TDB_DATA *outdata, int *cstatus) { - return ctdbd_control(conn, CTDB_CURRENT_NODE, opcode, srvid, flags, data, mem_ctx, outdata, cstatus); + int ret; + + ret = ctdbd_control_unix(conn, CTDB_CURRENT_NODE, opcode, srvid, flags, data, + mem_ctx, outdata, cstatus); + if (ret != 0) { + return map_nt_error_from_unix(ret); + } + return NT_STATUS_OK; } NTSTATUS ctdb_watch_us(struct ctdbd_connection *conn) From 7b8853fc42b929e9f14bf249998a6111c10aad66 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 2 Oct 2015 20:31:52 -0700 Subject: [PATCH 088/136] lib: Rename ctdbd_control_unix to ctdbd_control Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- source3/lib/ctdbd_conn.c | 82 ++++++++++++++++++++++++------------------------ 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c index 04fbe9c..bdb6746 100644 --- a/source3/lib/ctdbd_conn.c +++ b/source3/lib/ctdbd_conn.c @@ -63,12 +63,12 @@ static uint32_t ctdbd_next_reqid(struct ctdbd_connection *conn) return conn->reqid; } -static int ctdbd_control_unix(struct ctdbd_connection *conn, - uint32_t vnn, uint32_t opcode, - uint64_t srvid, uint32_t flags, - TDB_DATA data, - TALLOC_CTX *mem_ctx, TDB_DATA *outdata, - int *cstatus); +static int ctdbd_control(struct ctdbd_connection *conn, + uint32_t vnn, uint32_t opcode, + uint64_t srvid, uint32_t flags, + TDB_DATA data, + TALLOC_CTX *mem_ctx, TDB_DATA *outdata, + int *cstatus); /* * exit on fatal communications errors with the ctdbd daemon @@ -112,9 +112,9 @@ NTSTATUS register_with_ctdbd(struct ctdbd_connection *conn, uint64_t srvid, size_t num_callbacks; struct ctdbd_srvid_cb *tmp; - ret = ctdbd_control_unix(conn, CTDB_CURRENT_NODE, - CTDB_CONTROL_REGISTER_SRVID, srvid, 0, - tdb_null, NULL, NULL, &cstatus); + ret = ctdbd_control(conn, CTDB_CURRENT_NODE, + CTDB_CONTROL_REGISTER_SRVID, srvid, 0, + tdb_null, NULL, NULL, &cstatus); if (ret != 0) { return map_nt_error_from_unix(ret); } @@ -181,9 +181,9 @@ static NTSTATUS get_cluster_vnn(struct ctdbd_connection *conn, uint32_t *vnn) { int32_t cstatus=-1; int ret; - ret = ctdbd_control_unix(conn, - CTDB_CURRENT_NODE, CTDB_CONTROL_GET_PNN, 0, 0, - tdb_null, NULL, NULL, &cstatus); + ret = ctdbd_control(conn, + CTDB_CURRENT_NODE, CTDB_CONTROL_GET_PNN, 0, 0, + tdb_null, NULL, NULL, &cstatus); if (ret != 0) { DEBUG(1, ("ctdbd_control failed: %s\n", strerror(ret))); return map_nt_error_from_unix(ret); @@ -204,9 +204,9 @@ static bool ctdbd_working(struct ctdbd_connection *conn, uint32_t vnn) bool ok = false; int i, ret; - ret = ctdbd_control_unix(conn, CTDB_CURRENT_NODE, - CTDB_CONTROL_GET_NODEMAP, 0, 0, - tdb_null, talloc_tos(), &outdata, &cstatus); + ret = ctdbd_control(conn, CTDB_CURRENT_NODE, + CTDB_CONTROL_GET_NODEMAP, 0, 0, + tdb_null, talloc_tos(), &outdata, &cstatus); if (ret != 0) { DEBUG(1, ("ctdbd_control failed: %s\n", strerror(ret))); return false; @@ -638,12 +638,12 @@ NTSTATUS ctdbd_messaging_send_iov(struct ctdbd_connection *conn, /* * send/recv a generic ctdb control message */ -static int ctdbd_control_unix(struct ctdbd_connection *conn, - uint32_t vnn, uint32_t opcode, - uint64_t srvid, uint32_t flags, - TDB_DATA data, - TALLOC_CTX *mem_ctx, TDB_DATA *outdata, - int *cstatus) +static int ctdbd_control(struct ctdbd_connection *conn, + uint32_t vnn, uint32_t opcode, + uint64_t srvid, uint32_t flags, + TDB_DATA data, + TALLOC_CTX *mem_ctx, TDB_DATA *outdata, + int *cstatus) { struct ctdb_req_control req; struct ctdb_req_header *hdr; @@ -855,9 +855,9 @@ char *ctdbd_dbpath(struct ctdbd_connection *conn, data.dptr = (uint8_t*)&db_id; data.dsize = sizeof(db_id); - ret = ctdbd_control_unix(conn, CTDB_CURRENT_NODE, - CTDB_CONTROL_GETDBPATH, 0, 0, data, - mem_ctx, &rdata, &cstatus); + ret = ctdbd_control(conn, CTDB_CURRENT_NODE, + CTDB_CONTROL_GETDBPATH, 0, 0, data, + mem_ctx, &rdata, &cstatus); if ((ret != 0) || cstatus != 0) { DEBUG(0, (__location__ " ctdb_control for getdbpath failed: %s\n", strerror(ret))); @@ -880,11 +880,11 @@ NTSTATUS ctdbd_db_attach(struct ctdbd_connection *conn, data = string_term_tdb_data(name); - ret = ctdbd_control_unix(conn, CTDB_CURRENT_NODE, - persistent - ? CTDB_CONTROL_DB_ATTACH_PERSISTENT - : CTDB_CONTROL_DB_ATTACH, - tdb_flags, 0, data, NULL, &data, &cstatus); + ret = ctdbd_control(conn, CTDB_CURRENT_NODE, + persistent + ? CTDB_CONTROL_DB_ATTACH_PERSISTENT + : CTDB_CONTROL_DB_ATTACH, + tdb_flags, 0, data, NULL, &data, &cstatus); if (ret != 0) { DEBUG(0, (__location__ " ctdb_control for db_attach " "failed: %s\n", strerror(ret))); @@ -906,9 +906,9 @@ NTSTATUS ctdbd_db_attach(struct ctdbd_connection *conn, data.dptr = (uint8_t *)db_id; data.dsize = sizeof(*db_id); - ret = ctdbd_control_unix(conn, CTDB_CURRENT_NODE, - CTDB_CONTROL_ENABLE_SEQNUM, 0, 0, data, - NULL, NULL, &cstatus); + ret = ctdbd_control(conn, CTDB_CURRENT_NODE, + CTDB_CONTROL_ENABLE_SEQNUM, 0, 0, data, + NULL, NULL, &cstatus); if ((ret != 0) || cstatus != 0) { DEBUG(0, (__location__ " ctdb_control for enable seqnum " "failed: %s\n", strerror(ret))); @@ -1087,9 +1087,9 @@ NTSTATUS ctdbd_traverse(struct ctdbd_connection *master, uint32_t db_id, data.dptr = (uint8_t *)&t; data.dsize = sizeof(t); - ret = ctdbd_control_unix(conn, CTDB_CURRENT_NODE, - CTDB_CONTROL_TRAVERSE_START, conn->rand_srvid, - 0, data, NULL, NULL, &cstatus); + ret = ctdbd_control(conn, CTDB_CURRENT_NODE, + CTDB_CONTROL_TRAVERSE_START, conn->rand_srvid, + 0, data, NULL, NULL, &cstatus); if ((ret != 0) || (cstatus != 0)) { status = map_nt_error_from_unix(ret); @@ -1244,10 +1244,10 @@ NTSTATUS ctdbd_register_ips(struct ctdbd_connection *conn, * can send an extra ack to trigger a reset for our client, so it * immediately reconnects */ - ret = ctdbd_control_unix(conn, CTDB_CURRENT_NODE, - CTDB_CONTROL_TCP_CLIENT, 0, - CTDB_CTRL_FLAG_NOREPLY, data, NULL, NULL, - NULL); + ret = ctdbd_control(conn, CTDB_CURRENT_NODE, + CTDB_CONTROL_TCP_CLIENT, 0, + CTDB_CTRL_FLAG_NOREPLY, data, NULL, NULL, + NULL); if (ret != 0) { return map_nt_error_from_unix(ret); } @@ -1264,8 +1264,8 @@ NTSTATUS ctdbd_control_local(struct ctdbd_connection *conn, uint32_t opcode, { int ret; - ret = ctdbd_control_unix(conn, CTDB_CURRENT_NODE, opcode, srvid, flags, data, - mem_ctx, outdata, cstatus); + ret = ctdbd_control(conn, CTDB_CURRENT_NODE, opcode, srvid, flags, data, + mem_ctx, outdata, cstatus); if (ret != 0) { return map_nt_error_from_unix(ret); } From 84ad1a13721da44cf55650e04780a64cefe5f8e0 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 2 Oct 2015 20:42:05 -0700 Subject: [PATCH 089/136] lib: Make register_with_ctdbd return 0/errno Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- source3/include/ctdbd_conn.h | 12 ++++++------ source3/lib/ctdb_dummy.c | 14 +++++++------- source3/lib/ctdbd_conn.c | 40 +++++++++++++++++++++------------------- source3/lib/messages_ctdbd.c | 11 +++++++++-- source3/smbd/notifyd/notifyd.c | 9 ++++----- 5 files changed, 47 insertions(+), 39 deletions(-) diff --git a/source3/include/ctdbd_conn.h b/source3/include/ctdbd_conn.h index 6c46cdb..1db0c0a 100644 --- a/source3/include/ctdbd_conn.h +++ b/source3/include/ctdbd_conn.h @@ -86,12 +86,12 @@ NTSTATUS ctdb_unwatch(struct ctdbd_connection *conn); struct ctdb_req_message; -NTSTATUS register_with_ctdbd(struct ctdbd_connection *conn, uint64_t srvid, - int (*cb)(uint32_t src_vnn, uint32_t dst_vnn, - uint64_t dst_srvid, - const uint8_t *msg, size_t msglen, - void *private_data), - void *private_data); +int register_with_ctdbd(struct ctdbd_connection *conn, uint64_t srvid, + int (*cb)(uint32_t src_vnn, uint32_t dst_vnn, + uint64_t dst_srvid, + const uint8_t *msg, size_t msglen, + void *private_data), + void *private_data); NTSTATUS ctdbd_probe(const char *sockname, int timeout); #endif /* _CTDBD_CONN_H */ diff --git a/source3/lib/ctdb_dummy.c b/source3/lib/ctdb_dummy.c index d8658cf..dea1db6 100644 --- a/source3/lib/ctdb_dummy.c +++ b/source3/lib/ctdb_dummy.c @@ -36,14 +36,14 @@ NTSTATUS ctdbd_messaging_send_iov(struct ctdbd_connection *conn, return NT_STATUS_NOT_IMPLEMENTED; } -NTSTATUS register_with_ctdbd(struct ctdbd_connection *conn, uint64_t srvid, - int (*cb)(uint32_t src_vnn, uint32_t dst_vnn, - uint64_t dst_srvid, - const uint8_t *msg, size_t msglen, - void *private_data), - void *private_data) +int register_with_ctdbd(struct ctdbd_connection *conn, uint64_t srvid, + int (*cb)(uint32_t src_vnn, uint32_t dst_vnn, + uint64_t dst_srvid, + const uint8_t *msg, size_t msglen, + void *private_data), + void *private_data) { - return NT_STATUS_NOT_IMPLEMENTED; + return ENOSYS; } NTSTATUS ctdbd_register_ips(struct ctdbd_connection *conn, diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c index bdb6746..347606c 100644 --- a/source3/lib/ctdbd_conn.c +++ b/source3/lib/ctdbd_conn.c @@ -100,12 +100,12 @@ static void ctdb_packet_dump(struct ctdb_req_header *hdr) /* * Register a srvid with ctdbd */ -NTSTATUS register_with_ctdbd(struct ctdbd_connection *conn, uint64_t srvid, - int (*cb)(uint32_t src_vnn, uint32_t dst_vnn, - uint64_t dst_srvid, - const uint8_t *msg, size_t msglen, - void *private_data), - void *private_data) +int register_with_ctdbd(struct ctdbd_connection *conn, uint64_t srvid, + int (*cb)(uint32_t src_vnn, uint32_t dst_vnn, + uint64_t dst_srvid, + const uint8_t *msg, size_t msglen, + void *private_data), + void *private_data) { int ret, cstatus; @@ -116,7 +116,7 @@ NTSTATUS register_with_ctdbd(struct ctdbd_connection *conn, uint64_t srvid, CTDB_CONTROL_REGISTER_SRVID, srvid, 0, tdb_null, NULL, NULL, &cstatus); if (ret != 0) { - return map_nt_error_from_unix(ret); + return ret; } num_callbacks = talloc_array_length(conn->callbacks); @@ -124,7 +124,7 @@ NTSTATUS register_with_ctdbd(struct ctdbd_connection *conn, uint64_t srvid, tmp = talloc_realloc(conn, conn->callbacks, struct ctdbd_srvid_cb, num_callbacks + 1); if (tmp == NULL) { - return NT_STATUS_NO_MEMORY; + return ENOMEM; } conn->callbacks = tmp; @@ -132,7 +132,7 @@ NTSTATUS register_with_ctdbd(struct ctdbd_connection *conn, uint64_t srvid, .srvid = srvid, .cb = cb, .private_data = private_data }; - return NT_STATUS_OK; + return 0; } static int ctdbd_msg_call_back(struct ctdbd_connection *conn, @@ -467,11 +467,12 @@ static NTSTATUS ctdbd_init_connection(TALLOC_CTX *mem_ctx, generate_random_buffer((unsigned char *)&conn->rand_srvid, sizeof(conn->rand_srvid)); - status = register_with_ctdbd(conn, conn->rand_srvid, NULL, NULL); + ret = register_with_ctdbd(conn, conn->rand_srvid, NULL, NULL); - if (!NT_STATUS_IS_OK(status)) { + if (ret != 0) { DEBUG(5, ("Could not register random srvid: %s\n", - nt_errstr(status))); + strerror(ret))); + status = map_nt_error_from_unix(ret); goto fail; } @@ -493,6 +494,7 @@ NTSTATUS ctdbd_messaging_connection(TALLOC_CTX *mem_ctx, { struct ctdbd_connection *conn; NTSTATUS status; + int ret; status = ctdbd_init_connection(mem_ctx, sockname, timeout, &conn); @@ -500,8 +502,9 @@ NTSTATUS ctdbd_messaging_connection(TALLOC_CTX *mem_ctx, return status; } - status = register_with_ctdbd(conn, MSG_SRVID_SAMBA, NULL, NULL); - if (!NT_STATUS_IS_OK(status)) { + ret = register_with_ctdbd(conn, MSG_SRVID_SAMBA, NULL, NULL); + if (ret != 0) { + status = map_nt_error_from_unix(ret); goto fail; } @@ -1204,7 +1207,6 @@ NTSTATUS ctdbd_register_ips(struct ctdbd_connection *conn, { struct ctdb_control_tcp_addr p; TDB_DATA data = { .dptr = (uint8_t *)&p, .dsize = sizeof(p) }; - NTSTATUS status; int ret; struct sockaddr_storage client; struct sockaddr_storage server; @@ -1233,10 +1235,10 @@ NTSTATUS ctdbd_register_ips(struct ctdbd_connection *conn, * We want to be told about IP releases */ - status = register_with_ctdbd(conn, CTDB_SRVID_RELEASE_IP, - cb, private_data); - if (!NT_STATUS_IS_OK(status)) { - return status; + ret = register_with_ctdbd(conn, CTDB_SRVID_RELEASE_IP, + cb, private_data); + if (ret != 0) { + return map_nt_error_from_unix(ret); } /* diff --git a/source3/lib/messages_ctdbd.c b/source3/lib/messages_ctdbd.c index 4d8b574..e6724a8 100644 --- a/source3/lib/messages_ctdbd.c +++ b/source3/lib/messages_ctdbd.c @@ -171,6 +171,7 @@ NTSTATUS messaging_ctdbd_init(struct messaging_context *msg_ctx, struct messaging_backend *result; struct messaging_ctdbd_context *ctx; NTSTATUS status; + int ret; if (!(result = talloc(mem_ctx, struct messaging_backend))) { DEBUG(0, ("talloc failed\n")); @@ -202,8 +203,14 @@ NTSTATUS messaging_ctdbd_init(struct messaging_context *msg_ctx, return status; } - status = register_with_ctdbd(ctx->conn, getpid(), - messaging_ctdb_recv, msg_ctx); + ret = register_with_ctdbd(ctx->conn, getpid(), + messaging_ctdb_recv, msg_ctx); + if (ret != 0) { + DEBUG(10, ("register_with_ctdbd failed: %s\n", + strerror(ret))); + TALLOC_FREE(result); + return map_nt_error_from_unix(ret); + } global_ctdb_connection_pid = getpid(); global_ctdbd_connection = ctx->conn; diff --git a/source3/smbd/notifyd/notifyd.c b/source3/smbd/notifyd/notifyd.c index 3a9bc75..5554273 100644 --- a/source3/smbd/notifyd/notifyd.c +++ b/source3/smbd/notifyd/notifyd.c @@ -181,7 +181,6 @@ struct tevent_req *notifyd_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct tevent_req *req, *subreq; struct notifyd_state *state; struct server_id_db *names_db; - NTSTATUS status; int ret; req = tevent_req_create(mem_ctx, &state, struct notifyd_state); @@ -275,10 +274,10 @@ struct tevent_req *notifyd_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, tevent_req_set_callback(subreq, notifyd_clean_peers_finished, req); - status = register_with_ctdbd(ctdbd_conn, CTDB_SRVID_SAMBA_NOTIFY_PROXY, - notifyd_snoop_broadcast, state); - if (!NT_STATUS_IS_OK(status)) { - tevent_req_error(req, map_errno_from_nt_status(status)); + ret = register_with_ctdbd(ctdbd_conn, CTDB_SRVID_SAMBA_NOTIFY_PROXY, + notifyd_snoop_broadcast, state); + if (ret != 0) { + tevent_req_error(req, ret); return tevent_req_post(req, ev); } From f3c88bd6c2190cbb32501d2721d04bfc81ef4d22 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 2 Oct 2015 20:42:05 -0700 Subject: [PATCH 090/136] lib: Make get_cluster_vnn return 0/errno Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- source3/lib/ctdbd_conn.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c index 347606c..30c0936 100644 --- a/source3/lib/ctdbd_conn.c +++ b/source3/lib/ctdbd_conn.c @@ -177,7 +177,7 @@ static int ctdbd_msg_call_back(struct ctdbd_connection *conn, /* * get our vnn from the cluster */ -static NTSTATUS get_cluster_vnn(struct ctdbd_connection *conn, uint32_t *vnn) +static int get_cluster_vnn(struct ctdbd_connection *conn, uint32_t *vnn) { int32_t cstatus=-1; int ret; @@ -186,10 +186,10 @@ static NTSTATUS get_cluster_vnn(struct ctdbd_connection *conn, uint32_t *vnn) tdb_null, NULL, NULL, &cstatus); if (ret != 0) { DEBUG(1, ("ctdbd_control failed: %s\n", strerror(ret))); - return map_nt_error_from_unix(ret); + return ret; } *vnn = (uint32_t)cstatus; - return NT_STATUS_OK; + return ret; } /* @@ -451,10 +451,11 @@ static NTSTATUS ctdbd_init_connection(TALLOC_CTX *mem_ctx, } talloc_set_destructor(conn, ctdbd_connection_destructor); - status = get_cluster_vnn(conn, &conn->our_vnn); + ret = get_cluster_vnn(conn, &conn->our_vnn); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(10, ("get_cluster_vnn failed: %s\n", nt_errstr(status))); + if (ret != 0) { + DEBUG(10, ("get_cluster_vnn failed: %s\n", strerror(ret))); + status = map_nt_error_from_unix(ret); goto fail; } From 03fd13f01a6f5b4fbb3f9ab846d3326e81fb561b Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 2 Oct 2015 20:42:05 -0700 Subject: [PATCH 091/136] lib: Make ctdbd_register_msg_ctx return 0/errno Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- source3/include/ctdbd_conn.h | 4 ++-- source3/lib/ctdbd_conn.c | 8 ++++---- source3/lib/messages_ctdbd.c | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/source3/include/ctdbd_conn.h b/source3/include/ctdbd_conn.h index 1db0c0a..40c2d89 100644 --- a/source3/include/ctdbd_conn.h +++ b/source3/include/ctdbd_conn.h @@ -32,8 +32,8 @@ NTSTATUS ctdbd_messaging_connection(TALLOC_CTX *mem_ctx, uint32_t ctdbd_vnn(const struct ctdbd_connection *conn); -NTSTATUS ctdbd_register_msg_ctx(struct ctdbd_connection *conn, - struct messaging_context *msg_ctx); +int ctdbd_register_msg_ctx(struct ctdbd_connection *conn, + struct messaging_context *msg_ctx); struct messaging_context *ctdb_conn_msg_ctx(struct ctdbd_connection *conn); int ctdbd_conn_get_fd(struct ctdbd_connection *conn); diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c index 30c0936..deb3e4e 100644 --- a/source3/lib/ctdbd_conn.c +++ b/source3/lib/ctdbd_conn.c @@ -582,8 +582,8 @@ static void ctdbd_socket_handler(struct tevent_context *event_ctx, * Prepare a ctdbd connection to receive messages */ -NTSTATUS ctdbd_register_msg_ctx(struct ctdbd_connection *conn, - struct messaging_context *msg_ctx) +int ctdbd_register_msg_ctx(struct ctdbd_connection *conn, + struct messaging_context *msg_ctx) { SMB_ASSERT(conn->msg_ctx == NULL); SMB_ASSERT(conn->fde == NULL); @@ -595,12 +595,12 @@ NTSTATUS ctdbd_register_msg_ctx(struct ctdbd_connection *conn, ctdbd_socket_handler, conn))) { DEBUG(0, ("event_add_fd failed\n")); - return NT_STATUS_NO_MEMORY; + return ENOMEM; } conn->msg_ctx = msg_ctx; - return NT_STATUS_OK; + return 0; } NTSTATUS ctdbd_messaging_send_iov(struct ctdbd_connection *conn, diff --git a/source3/lib/messages_ctdbd.c b/source3/lib/messages_ctdbd.c index e6724a8..599a9bd 100644 --- a/source3/lib/messages_ctdbd.c +++ b/source3/lib/messages_ctdbd.c @@ -194,13 +194,13 @@ NTSTATUS messaging_ctdbd_init(struct messaging_context *msg_ctx, return status; } - status = ctdbd_register_msg_ctx(ctx->conn, msg_ctx); + ret = ctdbd_register_msg_ctx(ctx->conn, msg_ctx); - if (!NT_STATUS_IS_OK(status)) { + if (ret != 0) { DEBUG(10, ("ctdbd_register_msg_ctx failed: %s\n", - nt_errstr(status))); + strerror(ret))); TALLOC_FREE(result); - return status; + return map_nt_error_from_unix(ret); } ret = register_with_ctdbd(ctx->conn, getpid(), From 9da6cce5c064338ce63f394d9c3a64c449f41b66 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 2 Oct 2015 20:42:05 -0700 Subject: [PATCH 092/136] lib: Make ctdbd_init_connection return 0/errno Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- source3/lib/ctdbd_conn.c | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c index deb3e4e..efedfd4 100644 --- a/source3/lib/ctdbd_conn.c +++ b/source3/lib/ctdbd_conn.c @@ -417,23 +417,22 @@ static int ctdbd_connection_destructor(struct ctdbd_connection *c) * Get us a ctdbd connection */ -static NTSTATUS ctdbd_init_connection(TALLOC_CTX *mem_ctx, - const char *sockname, int timeout, - struct ctdbd_connection **pconn) +static int ctdbd_init_connection(TALLOC_CTX *mem_ctx, + const char *sockname, int timeout, + struct ctdbd_connection **pconn) { struct ctdbd_connection *conn; int ret; - NTSTATUS status; if (!(conn = talloc_zero(mem_ctx, struct ctdbd_connection))) { DEBUG(0, ("talloc failed\n")); - return NT_STATUS_NO_MEMORY; + return ENOMEM; } conn->sockname = talloc_strdup(conn, sockname); if (conn->sockname == NULL) { DBG_ERR("%s: talloc failed\n", __func__); - status = NT_STATUS_NO_MEMORY; + ret = ENOMEM; goto fail; } @@ -445,7 +444,6 @@ static NTSTATUS ctdbd_init_connection(TALLOC_CTX *mem_ctx, ret = ctdbd_connect(conn->sockname, &conn->fd); if (ret != 0) { - status = map_nt_error_from_unix(ret); DEBUG(1, ("ctdbd_connect failed: %s\n", strerror(ret))); goto fail; } @@ -455,13 +453,12 @@ static NTSTATUS ctdbd_init_connection(TALLOC_CTX *mem_ctx, if (ret != 0) { DEBUG(10, ("get_cluster_vnn failed: %s\n", strerror(ret))); - status = map_nt_error_from_unix(ret); goto fail; } if (!ctdbd_working(conn, conn->our_vnn)) { DEBUG(2, ("Node is not working, can not connect\n")); - status = NT_STATUS_INTERNAL_DB_ERROR; + ret = EIO; goto fail; } @@ -473,16 +470,15 @@ static NTSTATUS ctdbd_init_connection(TALLOC_CTX *mem_ctx, if (ret != 0) { DEBUG(5, ("Could not register random srvid: %s\n", strerror(ret))); - status = map_nt_error_from_unix(ret); goto fail; } *pconn = conn; - return NT_STATUS_OK; + return 0; fail: TALLOC_FREE(conn); - return status; + return ret; } /* @@ -497,10 +493,10 @@ NTSTATUS ctdbd_messaging_connection(TALLOC_CTX *mem_ctx, NTSTATUS status; int ret; - status = ctdbd_init_connection(mem_ctx, sockname, timeout, &conn); + ret = ctdbd_init_connection(mem_ctx, sockname, timeout, &conn); - if (!NT_STATUS_IS_OK(status)) { - return status; + if (ret != 0) { + return map_nt_error_from_unix(ret); } ret = register_with_ctdbd(conn, MSG_SRVID_SAMBA, NULL, NULL); @@ -1075,13 +1071,13 @@ NTSTATUS ctdbd_traverse(struct ctdbd_connection *master, uint32_t db_id, int cstatus; become_root(); - status = ctdbd_init_connection(NULL, master->sockname, master->timeout, - &conn); + ret = ctdbd_init_connection(NULL, master->sockname, master->timeout, + &conn); unbecome_root(); - if (!NT_STATUS_IS_OK(status)) { + if (ret != 0) { DEBUG(0, ("ctdbd_init_connection failed: %s\n", - nt_errstr(status))); - return status; + strerror(ret))); + return map_nt_error_from_unix(ret); } t.db_id = db_id; From 546d8b4129cb782c38337ed37a80420c3e846306 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 2 Oct 2015 20:42:05 -0700 Subject: [PATCH 093/136] lib: Make ctdbd_messaging_connection return 0/errno Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- source3/include/ctdbd_conn.h | 6 +++--- source3/lib/ctdbd_conn.c | 22 ++++++++++------------ source3/lib/messages_ctdbd.c | 11 +++++------ 3 files changed, 18 insertions(+), 21 deletions(-) diff --git a/source3/include/ctdbd_conn.h b/source3/include/ctdbd_conn.h index 40c2d89..9d71927 100644 --- a/source3/include/ctdbd_conn.h +++ b/source3/include/ctdbd_conn.h @@ -26,9 +26,9 @@ struct ctdbd_connection; struct messaging_context; struct messaging_rec; -NTSTATUS ctdbd_messaging_connection(TALLOC_CTX *mem_ctx, - const char *sockname, int timeout, - struct ctdbd_connection **pconn); +int ctdbd_messaging_connection(TALLOC_CTX *mem_ctx, + const char *sockname, int timeout, + struct ctdbd_connection **pconn); uint32_t ctdbd_vnn(const struct ctdbd_connection *conn); diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c index efedfd4..5b19299 100644 --- a/source3/lib/ctdbd_conn.c +++ b/source3/lib/ctdbd_conn.c @@ -485,32 +485,30 @@ static int ctdbd_init_connection(TALLOC_CTX *mem_ctx, * Get us a ctdbd connection and register us as a process */ -NTSTATUS ctdbd_messaging_connection(TALLOC_CTX *mem_ctx, - const char *sockname, int timeout, - struct ctdbd_connection **pconn) +int ctdbd_messaging_connection(TALLOC_CTX *mem_ctx, + const char *sockname, int timeout, + struct ctdbd_connection **pconn) { struct ctdbd_connection *conn; - NTSTATUS status; int ret; ret = ctdbd_init_connection(mem_ctx, sockname, timeout, &conn); if (ret != 0) { - return map_nt_error_from_unix(ret); + return ret; } ret = register_with_ctdbd(conn, MSG_SRVID_SAMBA, NULL, NULL); if (ret != 0) { - status = map_nt_error_from_unix(ret); goto fail; } *pconn = conn; - return NT_STATUS_OK; + return 0; fail: TALLOC_FREE(conn); - return status; + return ret; } struct messaging_context *ctdb_conn_msg_ctx(struct ctdbd_connection *conn) @@ -1322,15 +1320,15 @@ NTSTATUS ctdbd_probe(const char *sockname, int timeout) * later */ struct ctdbd_connection *conn = NULL; - NTSTATUS status; + int ret; - status = ctdbd_messaging_connection(talloc_tos(), sockname, timeout, - &conn); + ret = ctdbd_messaging_connection(talloc_tos(), sockname, timeout, + &conn); /* * We only care if we can connect. */ TALLOC_FREE(conn); - return status; + return map_nt_error_from_unix(ret); } diff --git a/source3/lib/messages_ctdbd.c b/source3/lib/messages_ctdbd.c index 599a9bd..a9ec04f 100644 --- a/source3/lib/messages_ctdbd.c +++ b/source3/lib/messages_ctdbd.c @@ -170,7 +170,6 @@ NTSTATUS messaging_ctdbd_init(struct messaging_context *msg_ctx, { struct messaging_backend *result; struct messaging_ctdbd_context *ctx; - NTSTATUS status; int ret; if (!(result = talloc(mem_ctx, struct messaging_backend))) { @@ -184,14 +183,14 @@ NTSTATUS messaging_ctdbd_init(struct messaging_context *msg_ctx, return NT_STATUS_NO_MEMORY; } - status = ctdbd_messaging_connection(ctx, lp_ctdbd_socket(), - lp_ctdb_timeout(), &ctx->conn); + ret = ctdbd_messaging_connection(ctx, lp_ctdbd_socket(), + lp_ctdb_timeout(), &ctx->conn); - if (!NT_STATUS_IS_OK(status)) { + if (ret != 0) { DEBUG(10, ("ctdbd_messaging_connection failed: %s\n", - nt_errstr(status))); + strerror(ret))); TALLOC_FREE(result); - return status; + return map_nt_error_from_unix(ret); } ret = ctdbd_register_msg_ctx(ctx->conn, msg_ctx); From fdfc7299a67b5c7d0eac2d084a6e9ac490f083f5 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 2 Oct 2015 20:42:05 -0700 Subject: [PATCH 094/136] lib: Make ctdbd_messaging_send_iov return 0/errno Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- source3/include/ctdbd_conn.h | 6 +++--- source3/lib/ctdb_dummy.c | 8 ++++---- source3/lib/ctdbd_conn.c | 8 ++++---- source3/lib/messages_ctdbd.c | 9 ++------- source3/smbd/notifyd/notifyd.c | 8 ++++---- 5 files changed, 17 insertions(+), 22 deletions(-) diff --git a/source3/include/ctdbd_conn.h b/source3/include/ctdbd_conn.h index 9d71927..7a3b07b 100644 --- a/source3/include/ctdbd_conn.h +++ b/source3/include/ctdbd_conn.h @@ -38,9 +38,9 @@ struct messaging_context *ctdb_conn_msg_ctx(struct ctdbd_connection *conn); int ctdbd_conn_get_fd(struct ctdbd_connection *conn); -NTSTATUS ctdbd_messaging_send_iov(struct ctdbd_connection *conn, - uint32_t dst_vnn, uint64_t dst_srvid, - const struct iovec *iov, int iovlen); +int ctdbd_messaging_send_iov(struct ctdbd_connection *conn, + uint32_t dst_vnn, uint64_t dst_srvid, + const struct iovec *iov, int iovlen); bool ctdbd_process_exists(struct ctdbd_connection *conn, uint32_t vnn, pid_t pid); diff --git a/source3/lib/ctdb_dummy.c b/source3/lib/ctdb_dummy.c index dea1db6..838b24d 100644 --- a/source3/lib/ctdb_dummy.c +++ b/source3/lib/ctdb_dummy.c @@ -29,11 +29,11 @@ NTSTATUS ctdbd_probe(const char *sockname, int timeout) return NT_STATUS_NOT_IMPLEMENTED; } -NTSTATUS ctdbd_messaging_send_iov(struct ctdbd_connection *conn, - uint32_t dst_vnn, uint64_t dst_srvid, - const struct iovec *iov, int iovlen) +int ctdbd_messaging_send_iov(struct ctdbd_connection *conn, + uint32_t dst_vnn, uint64_t dst_srvid, + const struct iovec *iov, int iovlen) { - return NT_STATUS_NOT_IMPLEMENTED; + return ENOSYS; } int register_with_ctdbd(struct ctdbd_connection *conn, uint64_t srvid, diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c index 5b19299..e41b0d4 100644 --- a/source3/lib/ctdbd_conn.c +++ b/source3/lib/ctdbd_conn.c @@ -597,9 +597,9 @@ int ctdbd_register_msg_ctx(struct ctdbd_connection *conn, return 0; } -NTSTATUS ctdbd_messaging_send_iov(struct ctdbd_connection *conn, - uint32_t dst_vnn, uint64_t dst_srvid, - const struct iovec *iov, int iovlen) +int ctdbd_messaging_send_iov(struct ctdbd_connection *conn, + uint32_t dst_vnn, uint64_t dst_srvid, + const struct iovec *iov, int iovlen) { struct ctdb_req_message r; struct iovec iov2[iovlen+1]; @@ -630,7 +630,7 @@ NTSTATUS ctdbd_messaging_send_iov(struct ctdbd_connection *conn, cluster_fatal("cluster dispatch daemon msg write error\n"); } - return NT_STATUS_OK; + return 0; } /* diff --git a/source3/lib/messages_ctdbd.c b/source3/lib/messages_ctdbd.c index a9ec04f..a0c8d90 100644 --- a/source3/lib/messages_ctdbd.c +++ b/source3/lib/messages_ctdbd.c @@ -82,7 +82,6 @@ static int messaging_ctdb_send(struct server_id src, backend->private_data, struct messaging_ctdbd_context); uint8_t hdr[MESSAGE_HDR_LENGTH]; struct iovec iov2[iovlen+1]; - NTSTATUS status; if (num_fds > 0) { return ENOSYS; @@ -92,12 +91,8 @@ static int messaging_ctdb_send(struct server_id src, iov2[0] = (struct iovec){ .iov_base = hdr, .iov_len = sizeof(hdr) }; memcpy(&iov2[1], iov, iovlen * sizeof(*iov)); - status = ctdbd_messaging_send_iov(ctx->conn, pid.vnn, pid.pid, - iov2, iovlen+1); - if (NT_STATUS_IS_OK(status)) { - return 0; - } - return map_errno_from_nt_status(status); + return ctdbd_messaging_send_iov(ctx->conn, pid.vnn, pid.pid, + iov2, iovlen+1); } static int messaging_ctdbd_destructor(struct messaging_ctdbd_context *ctx) diff --git a/source3/smbd/notifyd/notifyd.c b/source3/smbd/notifyd/notifyd.c index 5554273..06f48cf 100644 --- a/source3/smbd/notifyd/notifyd.c +++ b/source3/smbd/notifyd/notifyd.c @@ -942,11 +942,11 @@ static void notifyd_broadcast_reclog(struct ctdbd_connection *ctdbd_conn, struct server_id src, struct messaging_reclog *log) { - NTSTATUS status; enum ndr_err_code ndr_err; uint8_t msghdr[MESSAGE_HDR_LENGTH]; DATA_BLOB blob; struct iovec iov[2]; + int ret; if (log == NULL) { return; @@ -971,13 +971,13 @@ static void notifyd_broadcast_reclog(struct ctdbd_connection *ctdbd_conn, iov[1] = (struct iovec) { .iov_base = blob.data, .iov_len = blob.length }; - status = ctdbd_messaging_send_iov( + ret = ctdbd_messaging_send_iov( ctdbd_conn, CTDB_BROADCAST_VNNMAP, CTDB_SRVID_SAMBA_NOTIFY_PROXY, iov, ARRAY_SIZE(iov)); TALLOC_FREE(blob.data); - if (!NT_STATUS_IS_OK(status)) { + if (ret != 0) { DEBUG(1, ("%s: ctdbd_messaging_send failed: %s\n", - __func__, nt_errstr(status))); + __func__, strerror(ret))); goto done; } From 210e1fb265e4c1dde6a67aecfb72951703df3cc0 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 2 Oct 2015 20:42:05 -0700 Subject: [PATCH 095/136] lib: Make ctdbd_db_attach return 0/errno Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- source3/include/ctdbd_conn.h | 4 ++-- source3/lib/ctdbd_conn.c | 15 +++++++-------- source3/lib/dbwrap/dbwrap_ctdb.c | 7 +++++-- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/source3/include/ctdbd_conn.h b/source3/include/ctdbd_conn.h index 7a3b07b..7e56a4c 100644 --- a/source3/include/ctdbd_conn.h +++ b/source3/include/ctdbd_conn.h @@ -51,8 +51,8 @@ bool ctdb_processes_exist(struct ctdbd_connection *conn, char *ctdbd_dbpath(struct ctdbd_connection *conn, TALLOC_CTX *mem_ctx, uint32_t db_id); -NTSTATUS ctdbd_db_attach(struct ctdbd_connection *conn, const char *name, - uint32_t *db_id, int tdb_flags); +int ctdbd_db_attach(struct ctdbd_connection *conn, const char *name, + uint32_t *db_id, int tdb_flags); NTSTATUS ctdbd_migrate(struct ctdbd_connection *conn, uint32_t db_id, TDB_DATA key); diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c index e41b0d4..d759be6 100644 --- a/source3/lib/ctdbd_conn.c +++ b/source3/lib/ctdbd_conn.c @@ -868,8 +868,8 @@ char *ctdbd_dbpath(struct ctdbd_connection *conn, /* * attach to a ctdb database */ -NTSTATUS ctdbd_db_attach(struct ctdbd_connection *conn, - const char *name, uint32_t *db_id, int tdb_flags) +int ctdbd_db_attach(struct ctdbd_connection *conn, + const char *name, uint32_t *db_id, int tdb_flags) { int ret; TDB_DATA data; @@ -886,19 +886,19 @@ NTSTATUS ctdbd_db_attach(struct ctdbd_connection *conn, if (ret != 0) { DEBUG(0, (__location__ " ctdb_control for db_attach " "failed: %s\n", strerror(ret))); - return map_nt_error_from_unix(ret); + return ret; } if (cstatus != 0 || data.dsize != sizeof(uint32_t)) { DEBUG(0,(__location__ " ctdb_control for db_attach failed\n")); - return NT_STATUS_INTERNAL_ERROR; + return EIO; } *db_id = *(uint32_t *)data.dptr; talloc_free(data.dptr); if (!(tdb_flags & TDB_SEQNUM)) { - return NT_STATUS_OK; + return 0; } data.dptr = (uint8_t *)db_id; @@ -910,11 +910,10 @@ NTSTATUS ctdbd_db_attach(struct ctdbd_connection *conn, if ((ret != 0) || cstatus != 0) { DEBUG(0, (__location__ " ctdb_control for enable seqnum " "failed: %s\n", strerror(ret))); - return (ret == 0) ? NT_STATUS_INTERNAL_ERROR : - map_nt_error_from_unix(ret); + return (ret == 0) ? EIO : ret; } - return NT_STATUS_OK; + return 0; } /* diff --git a/source3/lib/dbwrap/dbwrap_ctdb.c b/source3/lib/dbwrap/dbwrap_ctdb.c index 9402bdd..c495c5c 100644 --- a/source3/lib/dbwrap/dbwrap_ctdb.c +++ b/source3/lib/dbwrap/dbwrap_ctdb.c @@ -1547,6 +1547,7 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx, struct ctdb_db_priority prio; NTSTATUS status; int cstatus; + int ret; if (!lp_clustering()) { DEBUG(10, ("Clustering disabled -- no ctdb\n")); @@ -1582,8 +1583,10 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx, return NULL; } - if (!NT_STATUS_IS_OK(ctdbd_db_attach(conn, name, &db_ctdb->db_id, tdb_flags))) { - DEBUG(0, ("ctdbd_db_attach failed for %s\n", name)); + ret = ctdbd_db_attach(conn, name, &db_ctdb->db_id, tdb_flags); + if (ret != 0) { + DEBUG(0, ("ctdbd_db_attach failed for %s: %s\n", name, + strerror(ret))); TALLOC_FREE(result); return NULL; } From 4636912985e47f0562524b33ba457e5e4d33a0b9 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 2 Oct 2015 20:42:05 -0700 Subject: [PATCH 096/136] lib: Make ctdbd_migrate return 0/errno Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- source3/include/ctdbd_conn.h | 3 +-- source3/lib/ctdbd_conn.c | 9 ++------- source3/lib/dbwrap/dbwrap_ctdb.c | 9 +++++---- 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/source3/include/ctdbd_conn.h b/source3/include/ctdbd_conn.h index 7e56a4c..6ebd451 100644 --- a/source3/include/ctdbd_conn.h +++ b/source3/include/ctdbd_conn.h @@ -54,8 +54,7 @@ char *ctdbd_dbpath(struct ctdbd_connection *conn, int ctdbd_db_attach(struct ctdbd_connection *conn, const char *name, uint32_t *db_id, int tdb_flags); -NTSTATUS ctdbd_migrate(struct ctdbd_connection *conn, uint32_t db_id, - TDB_DATA key); +int ctdbd_migrate(struct ctdbd_connection *conn, uint32_t db_id, TDB_DATA key); NTSTATUS ctdbd_parse(struct ctdbd_connection *conn, uint32_t db_id, TDB_DATA key, bool local_copy, diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c index d759be6..899d616 100644 --- a/source3/lib/ctdbd_conn.c +++ b/source3/lib/ctdbd_conn.c @@ -919,14 +919,12 @@ int ctdbd_db_attach(struct ctdbd_connection *conn, /* * force the migration of a record to this node */ -NTSTATUS ctdbd_migrate(struct ctdbd_connection *conn, uint32_t db_id, - TDB_DATA key) +int ctdbd_migrate(struct ctdbd_connection *conn, uint32_t db_id, TDB_DATA key) { struct ctdb_req_call req; struct ctdb_req_header *hdr; struct iovec iov[2]; ssize_t nwritten; - NTSTATUS status; int ret; ZERO_STRUCT(req); @@ -958,21 +956,18 @@ NTSTATUS ctdbd_migrate(struct ctdbd_connection *conn, uint32_t db_id, ret = ctdb_read_req(conn, req.hdr.reqid, NULL, &hdr); if (ret != 0) { DEBUG(10, ("ctdb_read_req failed: %s\n", strerror(ret))); - status = map_nt_error_from_unix(ret); goto fail; } if (hdr->operation != CTDB_REPLY_CALL) { DEBUG(0, ("received invalid reply\n")); - status = NT_STATUS_INTERNAL_ERROR; goto fail; } - status = NT_STATUS_OK; fail: TALLOC_FREE(hdr); - return status; + return ret; } /* diff --git a/source3/lib/dbwrap/dbwrap_ctdb.c b/source3/lib/dbwrap/dbwrap_ctdb.c index c495c5c..57afc85 100644 --- a/source3/lib/dbwrap/dbwrap_ctdb.c +++ b/source3/lib/dbwrap/dbwrap_ctdb.c @@ -1019,6 +1019,7 @@ static struct db_record *fetch_locked_internal(struct db_ctdb_ctx *ctx, double ctdb_time = 0; int duration_msecs; int lockret; + int ret; if (!(result = talloc(mem_ctx, struct db_record))) { DEBUG(0, ("talloc failed\n")); @@ -1105,13 +1106,13 @@ static struct db_record *fetch_locked_internal(struct db_ctdb_ctx *ctx, ((struct ctdb_ltdb_header *)ctdb_data.dptr)->flags : 0)); GetTimeOfDay(&ctdb_start_time); - status = ctdbd_migrate(messaging_ctdbd_connection(), ctx->db_id, - key); + ret = ctdbd_migrate(messaging_ctdbd_connection(), ctx->db_id, + key); ctdb_time += timeval_elapsed(&ctdb_start_time); - if (!NT_STATUS_IS_OK(status)) { + if (ret != 0) { DEBUG(5, ("ctdb_migrate failed: %s\n", - nt_errstr(status))); + strerror(ret))); TALLOC_FREE(result); return NULL; } From b78c282a91779fe53caaefca2c5a610d77694891 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 2 Oct 2015 20:42:05 -0700 Subject: [PATCH 097/136] lib: Make ctdbd_parse return 0/errno Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- source3/include/ctdbd_conn.h | 10 +++++----- source3/lib/ctdbd_conn.c | 19 +++++++++---------- source3/lib/dbwrap/dbwrap_ctdb.c | 10 +++++++--- 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/source3/include/ctdbd_conn.h b/source3/include/ctdbd_conn.h index 6ebd451..c2a6939 100644 --- a/source3/include/ctdbd_conn.h +++ b/source3/include/ctdbd_conn.h @@ -56,11 +56,11 @@ int ctdbd_db_attach(struct ctdbd_connection *conn, const char *name, int ctdbd_migrate(struct ctdbd_connection *conn, uint32_t db_id, TDB_DATA key); -NTSTATUS ctdbd_parse(struct ctdbd_connection *conn, uint32_t db_id, - TDB_DATA key, bool local_copy, - void (*parser)(TDB_DATA key, TDB_DATA data, - void *private_data), - void *private_data); +int ctdbd_parse(struct ctdbd_connection *conn, uint32_t db_id, + TDB_DATA key, bool local_copy, + void (*parser)(TDB_DATA key, TDB_DATA data, + void *private_data), + void *private_data); NTSTATUS ctdbd_traverse(struct ctdbd_connection *master, uint32_t db_id, void (*fn)(TDB_DATA key, TDB_DATA data, diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c index 899d616..ac2c56d 100644 --- a/source3/lib/ctdbd_conn.c +++ b/source3/lib/ctdbd_conn.c @@ -973,18 +973,17 @@ int ctdbd_migrate(struct ctdbd_connection *conn, uint32_t db_id, TDB_DATA key) /* * Fetch a record and parse it */ -NTSTATUS ctdbd_parse(struct ctdbd_connection *conn, uint32_t db_id, - TDB_DATA key, bool local_copy, - void (*parser)(TDB_DATA key, TDB_DATA data, - void *private_data), - void *private_data) +int ctdbd_parse(struct ctdbd_connection *conn, uint32_t db_id, + TDB_DATA key, bool local_copy, + void (*parser)(TDB_DATA key, TDB_DATA data, + void *private_data), + void *private_data) { struct ctdb_req_call req; struct ctdb_req_header *hdr = NULL; struct ctdb_reply_call *reply; struct iovec iov[2]; ssize_t nwritten; - NTSTATUS status; uint32_t flags; int ret; @@ -1022,7 +1021,7 @@ NTSTATUS ctdbd_parse(struct ctdbd_connection *conn, uint32_t db_id, if ((hdr == NULL) || (hdr->operation != CTDB_REPLY_CALL)) { DEBUG(0, ("received invalid reply\n")); - status = NT_STATUS_INTERNAL_ERROR; + ret = EIO; goto fail; } reply = (struct ctdb_reply_call *)hdr; @@ -1031,17 +1030,17 @@ NTSTATUS ctdbd_parse(struct ctdbd_connection *conn, uint32_t db_id, /* * Treat an empty record as non-existing */ - status = NT_STATUS_NOT_FOUND; + ret = ENOENT; goto fail; } parser(key, make_tdb_data(&reply->data[0], reply->datalen), private_data); - status = NT_STATUS_OK; + ret = 0; fail: TALLOC_FREE(hdr); - return status; + return ret; } /* diff --git a/source3/lib/dbwrap/dbwrap_ctdb.c b/source3/lib/dbwrap/dbwrap_ctdb.c index 57afc85..c90e59b 100644 --- a/source3/lib/dbwrap/dbwrap_ctdb.c +++ b/source3/lib/dbwrap/dbwrap_ctdb.c @@ -1009,7 +1009,6 @@ static struct db_record *fetch_locked_internal(struct db_ctdb_ctx *ctx, { struct db_record *result; struct db_ctdb_rec *crec; - NTSTATUS status; TDB_DATA ctdb_data; int migrate_attempts; struct timeval migrate_start; @@ -1256,6 +1255,7 @@ static NTSTATUS db_ctdb_parse_record(struct db_context *db, TDB_DATA key, db->private_data, struct db_ctdb_ctx); struct db_ctdb_parse_record_state state; NTSTATUS status; + int ret; state.parser = parser; state.private_data = private_data; @@ -1293,8 +1293,12 @@ static NTSTATUS db_ctdb_parse_record(struct db_context *db, TDB_DATA key, return NT_STATUS_OK; } - return ctdbd_parse(messaging_ctdbd_connection(), ctx->db_id, key, - state.ask_for_readonly_copy, parser, private_data); + ret = ctdbd_parse(messaging_ctdbd_connection(), ctx->db_id, key, + state.ask_for_readonly_copy, parser, private_data); + if (ret != 0) { + return map_nt_error_from_unix(ret); + } + return NT_STATUS_OK; } struct traverse_state { From 4caf48ecb35ca6f7b07f8b67ea94284445911e49 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 2 Oct 2015 20:42:05 -0700 Subject: [PATCH 098/136] lib: Make ctdbd_traverse return 0/errno Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- source3/include/ctdbd_conn.h | 8 ++++---- source3/lib/ctdbd_conn.c | 24 ++++++++++-------------- source3/lib/dbwrap/dbwrap_ctdb.c | 20 ++++++++++---------- 3 files changed, 24 insertions(+), 28 deletions(-) diff --git a/source3/include/ctdbd_conn.h b/source3/include/ctdbd_conn.h index c2a6939..de3ab46 100644 --- a/source3/include/ctdbd_conn.h +++ b/source3/include/ctdbd_conn.h @@ -62,10 +62,10 @@ int ctdbd_parse(struct ctdbd_connection *conn, uint32_t db_id, void *private_data), void *private_data); -NTSTATUS ctdbd_traverse(struct ctdbd_connection *master, uint32_t db_id, - void (*fn)(TDB_DATA key, TDB_DATA data, - void *private_data), - void *private_data); +int ctdbd_traverse(struct ctdbd_connection *master, uint32_t db_id, + void (*fn)(TDB_DATA key, TDB_DATA data, + void *private_data), + void *private_data); NTSTATUS ctdbd_register_ips(struct ctdbd_connection *conn, const struct sockaddr_storage *server, diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c index ac2c56d..fb812a3 100644 --- a/source3/lib/ctdbd_conn.c +++ b/source3/lib/ctdbd_conn.c @@ -1015,7 +1015,6 @@ int ctdbd_parse(struct ctdbd_connection *conn, uint32_t db_id, ret = ctdb_read_req(conn, req.hdr.reqid, NULL, &hdr); if (ret != 0) { DEBUG(10, ("ctdb_read_req failed: %s\n", strerror(ret))); - status = map_nt_error_from_unix(ret); goto fail; } @@ -1049,13 +1048,12 @@ int ctdbd_parse(struct ctdbd_connection *conn, uint32_t db_id, everything in-line. */ -NTSTATUS ctdbd_traverse(struct ctdbd_connection *master, uint32_t db_id, +int ctdbd_traverse(struct ctdbd_connection *master, uint32_t db_id, void (*fn)(TDB_DATA key, TDB_DATA data, void *private_data), void *private_data) { struct ctdbd_connection *conn; - NTSTATUS status; int ret; TDB_DATA key, data; struct ctdb_traverse_start t; @@ -1068,7 +1066,7 @@ NTSTATUS ctdbd_traverse(struct ctdbd_connection *master, uint32_t db_id, if (ret != 0) { DEBUG(0, ("ctdbd_init_connection failed: %s\n", strerror(ret))); - return map_nt_error_from_unix(ret); + return ret; } t.db_id = db_id; @@ -1083,19 +1081,17 @@ NTSTATUS ctdbd_traverse(struct ctdbd_connection *master, uint32_t db_id, 0, data, NULL, NULL, &cstatus); if ((ret != 0) || (cstatus != 0)) { - status = map_nt_error_from_unix(ret); - DEBUG(0,("ctdbd_control failed: %s, %d\n", strerror(ret), cstatus)); - if (NT_STATUS_IS_OK(status)) { + if (ret == 0) { /* * We need a mapping here */ - status = NT_STATUS_UNSUCCESSFUL; + ret = EIO; } TALLOC_FREE(conn); - return status; + return ret; } while (True) { @@ -1114,7 +1110,7 @@ NTSTATUS ctdbd_traverse(struct ctdbd_connection *master, uint32_t db_id, DEBUG(0, ("Got operation %u, expected a message\n", (unsigned)hdr->operation)); TALLOC_FREE(conn); - return NT_STATUS_UNEXPECTED_IO_ERROR; + return EIO; } m = (struct ctdb_req_message *)hdr; @@ -1123,7 +1119,7 @@ NTSTATUS ctdbd_traverse(struct ctdbd_connection *master, uint32_t db_id, DEBUG(0, ("Got invalid traverse data of length %d\n", (int)m->datalen)); TALLOC_FREE(conn); - return NT_STATUS_UNEXPECTED_IO_ERROR; + return EIO; } key.dsize = d->keylen; @@ -1134,14 +1130,14 @@ NTSTATUS ctdbd_traverse(struct ctdbd_connection *master, uint32_t db_id, if (key.dsize == 0 && data.dsize == 0) { /* end of traverse */ TALLOC_FREE(conn); - return NT_STATUS_OK; + return 0; } if (data.dsize < sizeof(struct ctdb_ltdb_header)) { DEBUG(0, ("Got invalid ltdb header length %d\n", (int)data.dsize)); TALLOC_FREE(conn); - return NT_STATUS_UNEXPECTED_IO_ERROR; + return EIO; } data.dsize -= sizeof(struct ctdb_ltdb_header); data.dptr += sizeof(struct ctdb_ltdb_header); @@ -1150,7 +1146,7 @@ NTSTATUS ctdbd_traverse(struct ctdbd_connection *master, uint32_t db_id, fn(key, data, private_data); } } - return NT_STATUS_OK; + return 0; } /* diff --git a/source3/lib/dbwrap/dbwrap_ctdb.c b/source3/lib/dbwrap/dbwrap_ctdb.c index c90e59b..914ca4f 100644 --- a/source3/lib/dbwrap/dbwrap_ctdb.c +++ b/source3/lib/dbwrap/dbwrap_ctdb.c @@ -1362,7 +1362,7 @@ static int db_ctdb_traverse(struct db_context *db, void *private_data), void *private_data) { - NTSTATUS status; + int ret; struct db_ctdb_ctx *ctx = talloc_get_type_abort(db->private_data, struct db_ctdb_ctx); struct traverse_state state; @@ -1374,7 +1374,6 @@ static int db_ctdb_traverse(struct db_context *db, if (db->persistent) { struct tdb_context *ltdb = ctx->wtdb->tdb; - int ret; /* for persistent databases we don't need to do a ctdb traverse, we can do a faster local traverse */ @@ -1392,6 +1391,7 @@ static int db_ctdb_traverse(struct db_context *db, struct ctdb_rec_data *rec=NULL; int i; int count = 0; + NTSTATUS status; if (newkeys == NULL) { return -1; @@ -1420,9 +1420,9 @@ static int db_ctdb_traverse(struct db_context *db, return ret; } - status = ctdbd_traverse(messaging_ctdbd_connection(), ctx->db_id, - traverse_callback, &state); - if (!NT_STATUS_IS_OK(status)) { + ret = ctdbd_traverse(messaging_ctdbd_connection(), ctx->db_id, + traverse_callback, &state); + if (ret != 0) { return -1; } return state.count; @@ -1494,7 +1494,7 @@ static int db_ctdb_traverse_read(struct db_context *db, void *private_data), void *private_data) { - NTSTATUS status; + int ret; struct db_ctdb_ctx *ctx = talloc_get_type_abort(db->private_data, struct db_ctdb_ctx); struct traverse_state state; @@ -1510,9 +1510,9 @@ static int db_ctdb_traverse_read(struct db_context *db, return tdb_traverse_read(ctx->wtdb->tdb, traverse_persistent_callback_read, &state); } - status = ctdbd_traverse(messaging_ctdbd_connection(), ctx->db_id, - traverse_read_callback, &state); - if (!NT_STATUS_IS_OK(status)) { + ret = ctdbd_traverse(messaging_ctdbd_connection(), ctx->db_id, + traverse_read_callback, &state); + if (ret != 0) { return -1; } return state.count; @@ -1658,7 +1658,7 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx, /* honor permissions if user has specified O_CREAT */ if (open_flags & O_CREAT) { - int fd, ret; + int fd; fd = tdb_fd(db_ctdb->wtdb->tdb); ret = fchmod(fd, mode); if (ret == -1) { From a039463d823ad4e7fbff5a3f8e4416c184e40f36 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 2 Oct 2015 20:42:05 -0700 Subject: [PATCH 099/136] lib: Make ctdbd_register_ips return 0/errno Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- source3/include/ctdbd_conn.h | 16 ++++++++-------- source3/lib/ctdb_dummy.c | 18 +++++++++--------- source3/lib/ctdbd_conn.c | 24 ++++++++++++------------ source3/smbd/process.c | 7 ++++++- 4 files changed, 35 insertions(+), 30 deletions(-) diff --git a/source3/include/ctdbd_conn.h b/source3/include/ctdbd_conn.h index de3ab46..ff1bc95 100644 --- a/source3/include/ctdbd_conn.h +++ b/source3/include/ctdbd_conn.h @@ -67,14 +67,14 @@ int ctdbd_traverse(struct ctdbd_connection *master, uint32_t db_id, void *private_data), void *private_data); -NTSTATUS ctdbd_register_ips(struct ctdbd_connection *conn, - const struct sockaddr_storage *server, - const struct sockaddr_storage *client, - int (*cb)(uint32_t src_vnn, uint32_t dst_vnn, - uint64_t dst_srvid, - const uint8_t *msg, size_t msglen, - void *private_data), - void *private_data); +int ctdbd_register_ips(struct ctdbd_connection *conn, + const struct sockaddr_storage *server, + const struct sockaddr_storage *client, + int (*cb)(uint32_t src_vnn, uint32_t dst_vnn, + uint64_t dst_srvid, + const uint8_t *msg, size_t msglen, + void *private_data), + void *private_data); NTSTATUS ctdbd_control_local(struct ctdbd_connection *conn, uint32_t opcode, uint64_t srvid, uint32_t flags, TDB_DATA data, diff --git a/source3/lib/ctdb_dummy.c b/source3/lib/ctdb_dummy.c index 838b24d..7afb6b3 100644 --- a/source3/lib/ctdb_dummy.c +++ b/source3/lib/ctdb_dummy.c @@ -46,16 +46,16 @@ int register_with_ctdbd(struct ctdbd_connection *conn, uint64_t srvid, return ENOSYS; } -NTSTATUS ctdbd_register_ips(struct ctdbd_connection *conn, - const struct sockaddr_storage *_server, - const struct sockaddr_storage *_client, - int (*cb)(uint32_t src_vnn, uint32_t dst_vnn, - uint64_t dst_srvid, - const uint8_t *msg, size_t msglen, - void *private_data), - void *private_data) +int ctdbd_register_ips(struct ctdbd_connection *conn, + const struct sockaddr_storage *_server, + const struct sockaddr_storage *_client, + int (*cb)(uint32_t src_vnn, uint32_t dst_vnn, + uint64_t dst_srvid, + const uint8_t *msg, size_t msglen, + void *private_data), + void *private_data) { - return NT_STATUS_NOT_IMPLEMENTED; + return ENOSYS; } bool ctdb_processes_exist(struct ctdbd_connection *conn, diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c index fb812a3..0ba0d75 100644 --- a/source3/lib/ctdbd_conn.c +++ b/source3/lib/ctdbd_conn.c @@ -1180,14 +1180,14 @@ static void smbd_ctdb_canonicalize_ip(const struct sockaddr_storage *in, * Register us as a server for a particular tcp connection */ -NTSTATUS ctdbd_register_ips(struct ctdbd_connection *conn, - const struct sockaddr_storage *_server, - const struct sockaddr_storage *_client, - int (*cb)(uint32_t src_vnn, uint32_t dst_vnn, - uint64_t dst_srvid, - const uint8_t *msg, size_t msglen, - void *private_data), - void *private_data) +int ctdbd_register_ips(struct ctdbd_connection *conn, + const struct sockaddr_storage *_server, + const struct sockaddr_storage *_client, + int (*cb)(uint32_t src_vnn, uint32_t dst_vnn, + uint64_t dst_srvid, + const uint8_t *msg, size_t msglen, + void *private_data), + void *private_data) { struct ctdb_control_tcp_addr p; TDB_DATA data = { .dptr = (uint8_t *)&p, .dsize = sizeof(p) }; @@ -1212,7 +1212,7 @@ NTSTATUS ctdbd_register_ips(struct ctdbd_connection *conn, memcpy(&p.src.ip6, &client, sizeof(p.src.ip6)); break; default: - return NT_STATUS_INTERNAL_ERROR; + return EIO; } /* @@ -1222,7 +1222,7 @@ NTSTATUS ctdbd_register_ips(struct ctdbd_connection *conn, ret = register_with_ctdbd(conn, CTDB_SRVID_RELEASE_IP, cb, private_data); if (ret != 0) { - return map_nt_error_from_unix(ret); + return ret; } /* @@ -1235,9 +1235,9 @@ NTSTATUS ctdbd_register_ips(struct ctdbd_connection *conn, CTDB_CTRL_FLAG_NOREPLY, data, NULL, NULL, NULL); if (ret != 0) { - return map_nt_error_from_unix(ret); + return ret; } - return NT_STATUS_OK; + return 0; } /* diff --git a/source3/smbd/process.c b/source3/smbd/process.c index 8d9275c..b491b31 100644 --- a/source3/smbd/process.c +++ b/source3/smbd/process.c @@ -2693,6 +2693,7 @@ static NTSTATUS smbd_register_ips(struct smbXsrv_connection *xconn, { struct smbd_release_ip_state *state; struct ctdbd_connection *cconn; + int ret; cconn = messaging_ctdbd_connection(); if (cconn == NULL) { @@ -2712,7 +2713,11 @@ static NTSTATUS smbd_register_ips(struct smbXsrv_connection *xconn, return NT_STATUS_NO_MEMORY; } - return ctdbd_register_ips(cconn, srv, clnt, release_ip, state); + ret = ctdbd_register_ips(cconn, srv, clnt, release_ip, state); + if (ret != 0) { + return map_nt_error_from_unix(ret); + } + return NT_STATUS_OK; } static void msg_kill_client_ip(struct messaging_context *msg_ctx, From 2d00fcda69152688427e59d63425f0969a95f971 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 2 Oct 2015 20:42:05 -0700 Subject: [PATCH 100/136] lib: Make ctdbd_control_local return 0/errno Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- source3/include/ctdbd_conn.h | 8 +++---- source3/lib/ctdbd_conn.c | 40 +++++++++++++++------------------ source3/lib/dbwrap/dbwrap_ctdb.c | 48 ++++++++++++++++++++-------------------- 3 files changed, 46 insertions(+), 50 deletions(-) diff --git a/source3/include/ctdbd_conn.h b/source3/include/ctdbd_conn.h index ff1bc95..7073c0c 100644 --- a/source3/include/ctdbd_conn.h +++ b/source3/include/ctdbd_conn.h @@ -76,10 +76,10 @@ int ctdbd_register_ips(struct ctdbd_connection *conn, void *private_data), void *private_data); -NTSTATUS ctdbd_control_local(struct ctdbd_connection *conn, uint32_t opcode, - uint64_t srvid, uint32_t flags, TDB_DATA data, - TALLOC_CTX *mem_ctx, TDB_DATA *outdata, - int *cstatus); +int ctdbd_control_local(struct ctdbd_connection *conn, uint32_t opcode, + uint64_t srvid, uint32_t flags, TDB_DATA data, + TALLOC_CTX *mem_ctx, TDB_DATA *outdata, + int *cstatus); NTSTATUS ctdb_watch_us(struct ctdbd_connection *conn); NTSTATUS ctdb_unwatch(struct ctdbd_connection *conn); diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c index 0ba0d75..3d9f8f0 100644 --- a/source3/lib/ctdbd_conn.c +++ b/source3/lib/ctdbd_conn.c @@ -1243,26 +1243,20 @@ int ctdbd_register_ips(struct ctdbd_connection *conn, /* call a control on the local node */ -NTSTATUS ctdbd_control_local(struct ctdbd_connection *conn, uint32_t opcode, - uint64_t srvid, uint32_t flags, TDB_DATA data, - TALLOC_CTX *mem_ctx, TDB_DATA *outdata, - int *cstatus) +int ctdbd_control_local(struct ctdbd_connection *conn, uint32_t opcode, + uint64_t srvid, uint32_t flags, TDB_DATA data, + TALLOC_CTX *mem_ctx, TDB_DATA *outdata, + int *cstatus) { - int ret; - - ret = ctdbd_control(conn, CTDB_CURRENT_NODE, opcode, srvid, flags, data, - mem_ctx, outdata, cstatus); - if (ret != 0) { - return map_nt_error_from_unix(ret); - } - return NT_STATUS_OK; + return ctdbd_control(conn, CTDB_CURRENT_NODE, opcode, srvid, flags, data, + mem_ctx, outdata, cstatus); } NTSTATUS ctdb_watch_us(struct ctdbd_connection *conn) { struct ctdb_client_notify_register reg_data; size_t struct_len; - NTSTATUS status; + int ret; int cstatus; reg_data.srvid = CTDB_SRVID_SAMBA_NOTIFY; @@ -1272,34 +1266,36 @@ NTSTATUS ctdb_watch_us(struct ctdbd_connection *conn) struct_len = offsetof(struct ctdb_client_notify_register, notify_data) + reg_data.len; - status = ctdbd_control_local( + ret = ctdbd_control_local( conn, CTDB_CONTROL_REGISTER_NOTIFY, conn->rand_srvid, 0, make_tdb_data((uint8_t *)®_data, struct_len), NULL, NULL, &cstatus); - if (!NT_STATUS_IS_OK(status)) { + if (ret != 0) { DEBUG(1, ("ctdbd_control_local failed: %s\n", - nt_errstr(status))); + strerror(ret))); + return map_nt_error_from_unix(ret); } - return status; + return NT_STATUS_OK; } NTSTATUS ctdb_unwatch(struct ctdbd_connection *conn) { struct ctdb_client_notify_deregister dereg_data; - NTSTATUS status; + int ret; int cstatus; dereg_data.srvid = CTDB_SRVID_SAMBA_NOTIFY; - status = ctdbd_control_local( + ret = ctdbd_control_local( conn, CTDB_CONTROL_DEREGISTER_NOTIFY, conn->rand_srvid, 0, make_tdb_data((uint8_t *)&dereg_data, sizeof(dereg_data)), NULL, NULL, &cstatus); - if (!NT_STATUS_IS_OK(status)) { + if (ret != 0) { DEBUG(1, ("ctdbd_control_local failed: %s\n", - nt_errstr(status))); + strerror(ret))); + return map_nt_error_from_unix(ret); } - return status; + return NT_STATUS_OK; } NTSTATUS ctdbd_probe(const char *sockname, int timeout) diff --git a/source3/lib/dbwrap/dbwrap_ctdb.c b/source3/lib/dbwrap/dbwrap_ctdb.c index 914ca4f..e024fe5 100644 --- a/source3/lib/dbwrap/dbwrap_ctdb.c +++ b/source3/lib/dbwrap/dbwrap_ctdb.c @@ -761,12 +761,12 @@ static int db_ctdb_transaction_commit(struct db_context *db) again: /* tell ctdbd to commit to the other nodes */ - rets = ctdbd_control_local(messaging_ctdbd_connection(), - CTDB_CONTROL_TRANS3_COMMIT, - h->ctx->db_id, 0, - db_ctdb_marshall_finish(h->m_write), - NULL, NULL, &status); - if (!NT_STATUS_IS_OK(rets) || status != 0) { + ret = ctdbd_control_local(messaging_ctdbd_connection(), + CTDB_CONTROL_TRANS3_COMMIT, + h->ctx->db_id, 0, + db_ctdb_marshall_finish(h->m_write), + NULL, NULL, &status); + if ((ret != 0) || status != 0) { /* * The TRANS3_COMMIT control should only possibly fail when a * recovery has been running concurrently. In any case, the db @@ -853,6 +853,7 @@ static NTSTATUS db_ctdb_store(struct db_record *rec, TDB_DATA data, int flag) static NTSTATUS db_ctdb_send_schedule_for_deletion(struct db_record *rec) { NTSTATUS status; + int ret; struct ctdb_control_schedule_for_deletion *dd; TDB_DATA indata; int cstatus; @@ -872,21 +873,21 @@ static NTSTATUS db_ctdb_send_schedule_for_deletion(struct db_record *rec) dd->keylen = rec->key.dsize; memcpy(dd->key, rec->key.dptr, rec->key.dsize); - status = ctdbd_control_local(messaging_ctdbd_connection(), - CTDB_CONTROL_SCHEDULE_FOR_DELETION, - crec->ctdb_ctx->db_id, - CTDB_CTRL_FLAG_NOREPLY, /* flags */ - indata, - NULL, /* outdata */ - NULL, /* errmsg */ - &cstatus); + ret = ctdbd_control_local(messaging_ctdbd_connection(), + CTDB_CONTROL_SCHEDULE_FOR_DELETION, + crec->ctdb_ctx->db_id, + CTDB_CTRL_FLAG_NOREPLY, /* flags */ + indata, + NULL, /* outdata */ + NULL, /* errmsg */ + &cstatus); talloc_free(indata.dptr); - if (!NT_STATUS_IS_OK(status) || cstatus != 0) { + if ((ret != 0) || cstatus != 0) { DEBUG(1, (__location__ " Error sending local control " "SCHEDULE_FOR_DELETION: %s, cstatus = %d\n", - nt_errstr(status), cstatus)); - if (NT_STATUS_IS_OK(status)) { + strerror(ret), cstatus)); + if (ret != 0) { status = NT_STATUS_UNSUCCESSFUL; } } @@ -1550,7 +1551,6 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx, struct ctdbd_connection *conn; struct loadparm_context *lp_ctx; struct ctdb_db_priority prio; - NTSTATUS status; int cstatus; int ret; @@ -1608,14 +1608,14 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx, prio.db_id = db_ctdb->db_id; prio.priority = lock_order; - status = ctdbd_control_local( + ret = ctdbd_control_local( conn, CTDB_CONTROL_SET_DB_PRIORITY, 0, 0, make_tdb_data((uint8_t *)&prio, sizeof(prio)), NULL, NULL, &cstatus); - if (!NT_STATUS_IS_OK(status) || (cstatus != 0)) { + if ((ret != 0) || (cstatus != 0)) { DEBUG(1, ("CTDB_CONTROL_SET_DB_PRIORITY failed: %s, %d\n", - nt_errstr(status), cstatus)); + strerror(ret), cstatus)); TALLOC_FREE(result); return NULL; } @@ -1628,12 +1628,12 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx, indata = make_tdb_data((uint8_t *)&db_ctdb->db_id, sizeof(db_ctdb->db_id)); - status = ctdbd_control_local( + ret = ctdbd_control_local( conn, CTDB_CONTROL_SET_DB_READONLY, 0, 0, indata, NULL, NULL, &cstatus); - if (!NT_STATUS_IS_OK(status) || (cstatus != 0)) { + if ((ret != 0) || (cstatus != 0)) { DEBUG(1, ("CTDB_CONTROL_SET_DB_READONLY failed: " - "%s, %d\n", nt_errstr(status), cstatus)); + "%s, %d\n", strerror(ret), cstatus)); TALLOC_FREE(result); return NULL; } From b02fd997d26d20c207052707cda96581d6a97edb Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 2 Oct 2015 20:42:05 -0700 Subject: [PATCH 101/136] lib: Make ctdb_watch_us return 0/errno Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- source3/include/ctdbd_conn.h | 2 +- source3/lib/ctdbd_conn.c | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/source3/include/ctdbd_conn.h b/source3/include/ctdbd_conn.h index 7073c0c..1fb77fd 100644 --- a/source3/include/ctdbd_conn.h +++ b/source3/include/ctdbd_conn.h @@ -80,7 +80,7 @@ int ctdbd_control_local(struct ctdbd_connection *conn, uint32_t opcode, uint64_t srvid, uint32_t flags, TDB_DATA data, TALLOC_CTX *mem_ctx, TDB_DATA *outdata, int *cstatus); -NTSTATUS ctdb_watch_us(struct ctdbd_connection *conn); +int ctdb_watch_us(struct ctdbd_connection *conn); NTSTATUS ctdb_unwatch(struct ctdbd_connection *conn); struct ctdb_req_message; diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c index 3d9f8f0..ee598c6 100644 --- a/source3/lib/ctdbd_conn.c +++ b/source3/lib/ctdbd_conn.c @@ -1252,7 +1252,7 @@ int ctdbd_control_local(struct ctdbd_connection *conn, uint32_t opcode, mem_ctx, outdata, cstatus); } -NTSTATUS ctdb_watch_us(struct ctdbd_connection *conn) +int ctdb_watch_us(struct ctdbd_connection *conn) { struct ctdb_client_notify_register reg_data; size_t struct_len; @@ -1273,9 +1273,8 @@ NTSTATUS ctdb_watch_us(struct ctdbd_connection *conn) if (ret != 0) { DEBUG(1, ("ctdbd_control_local failed: %s\n", strerror(ret))); - return map_nt_error_from_unix(ret); } - return NT_STATUS_OK; + return ret; } NTSTATUS ctdb_unwatch(struct ctdbd_connection *conn) From a6ddb991331ae07e18b9d8d12cabd25f2d82965a Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 2 Oct 2015 20:42:05 -0700 Subject: [PATCH 102/136] lib: Make ctdb_unwatch return 0/errno Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- source3/include/ctdbd_conn.h | 2 +- source3/lib/ctdbd_conn.c | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/source3/include/ctdbd_conn.h b/source3/include/ctdbd_conn.h index 1fb77fd..a42deae 100644 --- a/source3/include/ctdbd_conn.h +++ b/source3/include/ctdbd_conn.h @@ -81,7 +81,7 @@ int ctdbd_control_local(struct ctdbd_connection *conn, uint32_t opcode, TALLOC_CTX *mem_ctx, TDB_DATA *outdata, int *cstatus); int ctdb_watch_us(struct ctdbd_connection *conn); -NTSTATUS ctdb_unwatch(struct ctdbd_connection *conn); +int ctdb_unwatch(struct ctdbd_connection *conn); struct ctdb_req_message; diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c index ee598c6..0f5b41e 100644 --- a/source3/lib/ctdbd_conn.c +++ b/source3/lib/ctdbd_conn.c @@ -1277,7 +1277,7 @@ int ctdb_watch_us(struct ctdbd_connection *conn) return ret; } -NTSTATUS ctdb_unwatch(struct ctdbd_connection *conn) +int ctdb_unwatch(struct ctdbd_connection *conn) { struct ctdb_client_notify_deregister dereg_data; int ret; @@ -1292,9 +1292,8 @@ NTSTATUS ctdb_unwatch(struct ctdbd_connection *conn) if (ret != 0) { DEBUG(1, ("ctdbd_control_local failed: %s\n", strerror(ret))); - return map_nt_error_from_unix(ret); } - return NT_STATUS_OK; + return ret; } NTSTATUS ctdbd_probe(const char *sockname, int timeout) From 6cc1e660eeb730b30cbd7bc323648444144db904 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 2 Oct 2015 20:42:05 -0700 Subject: [PATCH 103/136] lib: Make ctdbd_probe return 0/errno Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- source3/include/ctdbd_conn.h | 2 +- source3/lib/ctdb_dummy.c | 4 ++-- source3/lib/ctdbd_conn.c | 4 ++-- source3/lib/util_cluster.c | 8 ++++---- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/source3/include/ctdbd_conn.h b/source3/include/ctdbd_conn.h index a42deae..1381569 100644 --- a/source3/include/ctdbd_conn.h +++ b/source3/include/ctdbd_conn.h @@ -91,6 +91,6 @@ int register_with_ctdbd(struct ctdbd_connection *conn, uint64_t srvid, const uint8_t *msg, size_t msglen, void *private_data), void *private_data); -NTSTATUS ctdbd_probe(const char *sockname, int timeout); +int ctdbd_probe(const char *sockname, int timeout); #endif /* _CTDBD_CONN_H */ diff --git a/source3/lib/ctdb_dummy.c b/source3/lib/ctdb_dummy.c index 7afb6b3..c2783ee 100644 --- a/source3/lib/ctdb_dummy.c +++ b/source3/lib/ctdb_dummy.c @@ -24,9 +24,9 @@ #include "lib/dbwrap/dbwrap_ctdb.h" #include "torture/proto.h" -NTSTATUS ctdbd_probe(const char *sockname, int timeout) +int ctdbd_probe(const char *sockname, int timeout) { - return NT_STATUS_NOT_IMPLEMENTED; + return ENOSYS; } int ctdbd_messaging_send_iov(struct ctdbd_connection *conn, diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c index 0f5b41e..f091da7 100644 --- a/source3/lib/ctdbd_conn.c +++ b/source3/lib/ctdbd_conn.c @@ -1296,7 +1296,7 @@ int ctdb_unwatch(struct ctdbd_connection *conn) return ret; } -NTSTATUS ctdbd_probe(const char *sockname, int timeout) +int ctdbd_probe(const char *sockname, int timeout) { /* * Do a very early check if ctdbd is around to avoid an abort and core @@ -1313,5 +1313,5 @@ NTSTATUS ctdbd_probe(const char *sockname, int timeout) */ TALLOC_FREE(conn); - return map_nt_error_from_unix(ret); + return ret; } diff --git a/source3/lib/util_cluster.c b/source3/lib/util_cluster.c index 85f006c..bfa1154 100644 --- a/source3/lib/util_cluster.c +++ b/source3/lib/util_cluster.c @@ -26,12 +26,12 @@ bool cluster_probe_ok(void) { if (lp_clustering()) { - NTSTATUS status; + int ret; - status = ctdbd_probe(lp_ctdbd_socket(), lp_ctdb_timeout()); - if (!NT_STATUS_IS_OK(status)) { + ret = ctdbd_probe(lp_ctdbd_socket(), lp_ctdb_timeout()); + if (ret != 0) { DEBUG(0, ("clustering=yes but ctdbd connect failed: " - "%s\n", nt_errstr(status))); + "%s\n", strerror(ret))); return false; } } From a599b96f2928e5c5ec801a8e26b08ef0c082831a Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 2 Oct 2015 22:30:35 -0700 Subject: [PATCH 104/136] lib: Remove messaging_tevent_context() dependency from ctdbd_conn.c Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- source3/include/ctdbd_conn.h | 3 ++- source3/lib/ctdbd_conn.c | 12 +++++------- source3/lib/messages_ctdbd.c | 3 ++- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/source3/include/ctdbd_conn.h b/source3/include/ctdbd_conn.h index 1381569..9342ddc 100644 --- a/source3/include/ctdbd_conn.h +++ b/source3/include/ctdbd_conn.h @@ -33,7 +33,8 @@ int ctdbd_messaging_connection(TALLOC_CTX *mem_ctx, uint32_t ctdbd_vnn(const struct ctdbd_connection *conn); int ctdbd_register_msg_ctx(struct ctdbd_connection *conn, - struct messaging_context *msg_ctx); + struct messaging_context *msg_ctx, + struct tevent_context *ev); struct messaging_context *ctdb_conn_msg_ctx(struct ctdbd_connection *conn); int ctdbd_conn_get_fd(struct ctdbd_connection *conn); diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c index f091da7..990819e 100644 --- a/source3/lib/ctdbd_conn.c +++ b/source3/lib/ctdbd_conn.c @@ -577,17 +577,15 @@ static void ctdbd_socket_handler(struct tevent_context *event_ctx, */ int ctdbd_register_msg_ctx(struct ctdbd_connection *conn, - struct messaging_context *msg_ctx) + struct messaging_context *msg_ctx, + struct tevent_context *ev) { SMB_ASSERT(conn->msg_ctx == NULL); SMB_ASSERT(conn->fde == NULL); - if (!(conn->fde = tevent_add_fd(messaging_tevent_context(msg_ctx), - conn, - conn->fd, - TEVENT_FD_READ, - ctdbd_socket_handler, - conn))) { + conn->fde = tevent_add_fd(ev, conn, conn->fd, TEVENT_FD_READ, + ctdbd_socket_handler, conn); + if (conn->fde == NULL) { DEBUG(0, ("event_add_fd failed\n")); return ENOMEM; } diff --git a/source3/lib/messages_ctdbd.c b/source3/lib/messages_ctdbd.c index a0c8d90..5acd468 100644 --- a/source3/lib/messages_ctdbd.c +++ b/source3/lib/messages_ctdbd.c @@ -188,7 +188,8 @@ NTSTATUS messaging_ctdbd_init(struct messaging_context *msg_ctx, return map_nt_error_from_unix(ret); } - ret = ctdbd_register_msg_ctx(ctx->conn, msg_ctx); + ret = ctdbd_register_msg_ctx(ctx->conn, msg_ctx, + messaging_tevent_context(msg_ctx)); if (ret != 0) { DEBUG(10, ("ctdbd_register_msg_ctx failed: %s\n", From 7ae694372ca0037f38b82b5069a54edaeeedbd90 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 2 Oct 2015 22:33:12 -0700 Subject: [PATCH 105/136] lib: Use poll_intr_one_fd in ctdb_read_packet This is an actual bug fix if someone sets "ctdb timeout" to something != 0 Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- source3/lib/ctdbd_conn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c index 990819e..9e598ac 100644 --- a/source3/lib/ctdbd_conn.c +++ b/source3/lib/ctdbd_conn.c @@ -301,7 +301,7 @@ static int ctdb_read_packet(int fd, int timeout, TALLOC_CTX *mem_ctx, ssize_t nread; if (timeout != -1) { - ret = poll_one_fd(fd, POLLIN, timeout, &revents); + ret = poll_intr_one_fd(fd, POLLIN, timeout, &revents); if (ret == -1) { return errno; } From 678ad954e8734fce52d283e95c0b7c5c9d0d1318 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 2 Oct 2015 20:42:05 -0700 Subject: [PATCH 106/136] lib: Make messaging_ctdbd_init return 0/errno Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- source3/include/messages.h | 6 +++--- source3/lib/ctdb_dummy.c | 6 +++--- source3/lib/messages.c | 18 ++++++++---------- source3/lib/messages_ctdbd.c | 18 +++++++++--------- 4 files changed, 23 insertions(+), 25 deletions(-) diff --git a/source3/include/messages.h b/source3/include/messages.h index c620f92..5ad155b 100644 --- a/source3/include/messages.h +++ b/source3/include/messages.h @@ -74,9 +74,9 @@ struct messaging_backend { void *private_data; }; -NTSTATUS messaging_ctdbd_init(struct messaging_context *msg_ctx, - TALLOC_CTX *mem_ctx, - struct messaging_backend **presult); +int messaging_ctdbd_init(struct messaging_context *msg_ctx, + TALLOC_CTX *mem_ctx, + struct messaging_backend **presult); struct ctdbd_connection *messaging_ctdbd_connection(void); bool message_send_all(struct messaging_context *msg_ctx, diff --git a/source3/lib/ctdb_dummy.c b/source3/lib/ctdb_dummy.c index c2783ee..5162242 100644 --- a/source3/lib/ctdb_dummy.c +++ b/source3/lib/ctdb_dummy.c @@ -81,11 +81,11 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx, return NULL; } -NTSTATUS messaging_ctdbd_init(struct messaging_context *msg_ctx, - TALLOC_CTX *mem_ctx, +int messaging_ctdbd_init(struct messaging_context *msg_ctx, + TALLOC_CTX *mem_ctx, struct messaging_backend **presult) { - return NT_STATUS_NOT_IMPLEMENTED; + return ENOSYS; } struct ctdbd_connection *messaging_ctdbd_connection(void) diff --git a/source3/lib/messages.c b/source3/lib/messages.c index 07d1c83..717cd4c 100644 --- a/source3/lib/messages.c +++ b/source3/lib/messages.c @@ -291,7 +291,6 @@ struct messaging_context *messaging_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev) { struct messaging_context *ctx; - NTSTATUS status; int ret; const char *lck_path; const char *priv_path; @@ -349,11 +348,11 @@ struct messaging_context *messaging_init(TALLOC_CTX *mem_ctx, talloc_set_destructor(ctx, messaging_context_destructor); if (lp_clustering()) { - status = messaging_ctdbd_init(ctx, ctx, &ctx->remote); + ret = messaging_ctdbd_init(ctx, ctx, &ctx->remote); - if (!NT_STATUS_IS_OK(status)) { + if (ret != 0) { DEBUG(2, ("messaging_ctdbd_init failed: %s\n", - nt_errstr(status))); + strerror(ret))); TALLOC_FREE(ctx); return NULL; } @@ -390,7 +389,6 @@ struct server_id messaging_server_id(const struct messaging_context *msg_ctx) */ NTSTATUS messaging_reinit(struct messaging_context *msg_ctx) { - NTSTATUS status; int ret; TALLOC_FREE(msg_ctx->msg_dgm_ref); @@ -410,13 +408,13 @@ NTSTATUS messaging_reinit(struct messaging_context *msg_ctx) TALLOC_FREE(msg_ctx->remote); if (lp_clustering()) { - status = messaging_ctdbd_init(msg_ctx, msg_ctx, - &msg_ctx->remote); + ret = messaging_ctdbd_init(msg_ctx, msg_ctx, + &msg_ctx->remote); - if (!NT_STATUS_IS_OK(status)) { + if (ret != 0) { DEBUG(1, ("messaging_ctdbd_init failed: %s\n", - nt_errstr(status))); - return status; + strerror(ret))); + return map_nt_error_from_unix(ret); } } diff --git a/source3/lib/messages_ctdbd.c b/source3/lib/messages_ctdbd.c index 5acd468..90bae76 100644 --- a/source3/lib/messages_ctdbd.c +++ b/source3/lib/messages_ctdbd.c @@ -159,9 +159,9 @@ static int messaging_ctdb_recv( return 0; } -NTSTATUS messaging_ctdbd_init(struct messaging_context *msg_ctx, - TALLOC_CTX *mem_ctx, - struct messaging_backend **presult) +int messaging_ctdbd_init(struct messaging_context *msg_ctx, + TALLOC_CTX *mem_ctx, + struct messaging_backend **presult) { struct messaging_backend *result; struct messaging_ctdbd_context *ctx; @@ -169,13 +169,13 @@ NTSTATUS messaging_ctdbd_init(struct messaging_context *msg_ctx, if (!(result = talloc(mem_ctx, struct messaging_backend))) { DEBUG(0, ("talloc failed\n")); - return NT_STATUS_NO_MEMORY; + return ENOMEM; } if (!(ctx = talloc(result, struct messaging_ctdbd_context))) { DEBUG(0, ("talloc failed\n")); TALLOC_FREE(result); - return NT_STATUS_NO_MEMORY; + return ENOMEM; } ret = ctdbd_messaging_connection(ctx, lp_ctdbd_socket(), @@ -185,7 +185,7 @@ NTSTATUS messaging_ctdbd_init(struct messaging_context *msg_ctx, DEBUG(10, ("ctdbd_messaging_connection failed: %s\n", strerror(ret))); TALLOC_FREE(result); - return map_nt_error_from_unix(ret); + return ret; } ret = ctdbd_register_msg_ctx(ctx->conn, msg_ctx, @@ -195,7 +195,7 @@ NTSTATUS messaging_ctdbd_init(struct messaging_context *msg_ctx, DEBUG(10, ("ctdbd_register_msg_ctx failed: %s\n", strerror(ret))); TALLOC_FREE(result); - return map_nt_error_from_unix(ret); + return ret; } ret = register_with_ctdbd(ctx->conn, getpid(), @@ -204,7 +204,7 @@ NTSTATUS messaging_ctdbd_init(struct messaging_context *msg_ctx, DEBUG(10, ("register_with_ctdbd failed: %s\n", strerror(ret))); TALLOC_FREE(result); - return map_nt_error_from_unix(ret); + return ret; } global_ctdb_connection_pid = getpid(); @@ -217,5 +217,5 @@ NTSTATUS messaging_ctdbd_init(struct messaging_context *msg_ctx, result->private_data = (void *)ctx; *presult = result; - return NT_STATUS_OK; + return 0; } From 2bc55c5321a44e439a2e00309e979c0188c3fc75 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 2 Oct 2015 20:42:05 -0700 Subject: [PATCH 107/136] lib: Make messaging_send_iov_from return 0/errno Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- source3/include/messages.h | 10 +++++----- source3/lib/messages.c | 36 ++++++++++++++++++------------------ source3/lib/messages_ctdbd.c | 10 +++++----- source3/smbd/notifyd/notifyd.c | 8 ++++---- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/source3/include/messages.h b/source3/include/messages.h index 5ad155b..9a3ea25 100644 --- a/source3/include/messages.h +++ b/source3/include/messages.h @@ -123,11 +123,11 @@ NTSTATUS messaging_send(struct messaging_context *msg_ctx, NTSTATUS messaging_send_buf(struct messaging_context *msg_ctx, struct server_id server, uint32_t msg_type, const uint8_t *buf, size_t len); -NTSTATUS messaging_send_iov_from(struct messaging_context *msg_ctx, - struct server_id src, struct server_id dst, - uint32_t msg_type, - const struct iovec *iov, int iovlen, - const int *fds, size_t num_fds); +int messaging_send_iov_from(struct messaging_context *msg_ctx, + struct server_id src, struct server_id dst, + uint32_t msg_type, + const struct iovec *iov, int iovlen, + const int *fds, size_t num_fds); NTSTATUS messaging_send_iov(struct messaging_context *msg_ctx, struct server_id server, uint32_t msg_type, const struct iovec *iov, int iovlen, diff --git a/source3/lib/messages.c b/source3/lib/messages.c index 717cd4c..03e6097 100644 --- a/source3/lib/messages.c +++ b/source3/lib/messages.c @@ -518,37 +518,34 @@ NTSTATUS messaging_send_buf(struct messaging_context *msg_ctx, return messaging_send(msg_ctx, server, msg_type, &blob); } -NTSTATUS messaging_send_iov_from(struct messaging_context *msg_ctx, - struct server_id src, struct server_id dst, - uint32_t msg_type, - const struct iovec *iov, int iovlen, - const int *fds, size_t num_fds) +int messaging_send_iov_from(struct messaging_context *msg_ctx, + struct server_id src, struct server_id dst, + uint32_t msg_type, + const struct iovec *iov, int iovlen, + const int *fds, size_t num_fds) { int ret; uint8_t hdr[MESSAGE_HDR_LENGTH]; struct iovec iov2[iovlen+1]; if (server_id_is_disconnected(&dst)) { - return NT_STATUS_INVALID_PARAMETER_MIX; + return EINVAL; } if (num_fds > INT8_MAX) { - return NT_STATUS_INVALID_PARAMETER_MIX; + return EINVAL; } if (!procid_is_local(&dst)) { if (num_fds > 0) { - return NT_STATUS_NOT_SUPPORTED; + return ENOSYS; } ret = msg_ctx->remote->send_fn(src, dst, msg_type, iov, iovlen, NULL, 0, msg_ctx->remote); - if (ret != 0) { - return map_nt_error_from_unix(ret); - } - return NT_STATUS_OK; + return ret; } message_hdr_put(hdr, msg_type, src, dst); @@ -559,10 +556,7 @@ NTSTATUS messaging_send_iov_from(struct messaging_context *msg_ctx, ret = messaging_dgm_send(dst.pid, iov2, iovlen+1, fds, num_fds); unbecome_root(); - if (ret != 0) { - return map_nt_error_from_unix(ret); - } - return NT_STATUS_OK; + return ret; } NTSTATUS messaging_send_iov(struct messaging_context *msg_ctx, @@ -570,8 +564,14 @@ NTSTATUS messaging_send_iov(struct messaging_context *msg_ctx, const struct iovec *iov, int iovlen, const int *fds, size_t num_fds) { - return messaging_send_iov_from(msg_ctx, msg_ctx->id, dst, msg_type, - iov, iovlen, fds, num_fds); + int ret; + + ret = messaging_send_iov_from(msg_ctx, msg_ctx->id, dst, msg_type, + iov, iovlen, fds, num_fds); + if (ret != 0) { + return map_nt_error_from_unix(ret); + } + return NT_STATUS_OK; } static struct messaging_rec *messaging_rec_dup(TALLOC_CTX *mem_ctx, diff --git a/source3/lib/messages_ctdbd.c b/source3/lib/messages_ctdbd.c index 90bae76..48563a8 100644 --- a/source3/lib/messages_ctdbd.c +++ b/source3/lib/messages_ctdbd.c @@ -112,7 +112,7 @@ static int messaging_ctdb_recv( struct messaging_context *msg_ctx = talloc_get_type_abort( private_data, struct messaging_context); struct server_id me = messaging_server_id(msg_ctx); - NTSTATUS status; + int ret; struct iovec iov; struct server_id src, dst; enum messaging_type msg_type; @@ -148,12 +148,12 @@ static int messaging_ctdb_recv( * Go through the event loop */ - status = messaging_send_iov_from(msg_ctx, src, dst, msg_type, - &iov, 1, NULL, 0); + ret = messaging_send_iov_from(msg_ctx, src, dst, msg_type, + &iov, 1, NULL, 0); - if (!NT_STATUS_IS_OK(status)) { + if (ret != 0) { DEBUG(10, ("%s: messaging_send_iov_from failed: %s\n", - __func__, nt_errstr(status))); + __func__, strerror(ret))); } return 0; diff --git a/source3/smbd/notifyd/notifyd.c b/source3/smbd/notifyd/notifyd.c index 06f48cf..141556d 100644 --- a/source3/smbd/notifyd/notifyd.c +++ b/source3/smbd/notifyd/notifyd.c @@ -791,7 +791,7 @@ static void notifyd_send_delete(struct messaging_context *msg_ctx, }; uint8_t nul = 0; struct iovec iov[3]; - NTSTATUS status; + int ret; /* * Send a rec_change to ourselves to delete a dead entry @@ -803,13 +803,13 @@ static void notifyd_send_delete(struct messaging_context *msg_ctx, iov[1] = (struct iovec) { .iov_base = key.dptr, .iov_len = key.dsize }; iov[2] = (struct iovec) { .iov_base = &nul, .iov_len = sizeof(nul) }; - status = messaging_send_iov_from( + ret = messaging_send_iov_from( msg_ctx, instance->client, messaging_server_id(msg_ctx), MSG_SMB_NOTIFY_REC_CHANGE, iov, ARRAY_SIZE(iov), NULL, 0); - if (!NT_STATUS_IS_OK(status)) { + if (ret != 0) { DEBUG(10, ("%s: messaging_send_iov_from returned %s\n", - __func__, nt_errstr(status))); + __func__, strerror(ret))); } } From 5709dece4860f205e31309e31ec4e3e938d9f6a5 Mon Sep 17 00:00:00 2001 From: Uri Simchoni Date: Wed, 7 Oct 2015 22:44:11 +0300 Subject: [PATCH 108/136] vfs_commit: set the fd on open before calling SMB_VFS_FSTAT BUG: https://bugzilla.samba.org/show_bug.cgi?id=11547 Signed-off-by: Uri Simchoni Reviewed-by: Jeremy Allison Autobuild-User(master): Jeremy Allison Autobuild-Date(master): Thu Oct 8 02:56:41 CEST 2015 on sn-devel-104 --- source3/modules/vfs_commit.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/source3/modules/vfs_commit.c b/source3/modules/vfs_commit.c index a6bc2a4..f1e2743 100644 --- a/source3/modules/vfs_commit.c +++ b/source3/modules/vfs_commit.c @@ -230,7 +230,16 @@ static int commit_open( /* EOF commit modes require us to know the initial file size. */ if (c && (c->on_eof != EOF_NONE)) { SMB_STRUCT_STAT st; - if (SMB_VFS_FSTAT(fsp, &st) == -1) { + /* + * Setting the fd of the FSP is a hack + * but also practiced elsewhere - + * needed for calling the VFS. + */ + fsp->fh->fd = fd; + if (SMB_VFS_FSTAT(fsp, &st) == -1) { + int saved_errno = errno; + SMB_VFS_CLOSE(fsp); + errno = saved_errno; return -1; } c->eof = st.st_ex_size; From f25a5c9e84e802bc7005d6bd400cbf784fb30fdf Mon Sep 17 00:00:00 2001 From: Richard Sharpe Date: Wed, 7 Oct 2015 17:19:38 -0700 Subject: [PATCH 109/136] Fix a few small spelling mistakes in DEBUG messages to reduce confusion for those trying to debug stuff. Signed-off-by: Richard Sharpe Reviewed-by: Ira Cooper Autobuild-User(master): Richard Sharpe Autobuild-Date(master): Thu Oct 8 08:48:06 CEST 2015 on sn-devel-104 --- source3/smbd/server.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source3/smbd/server.c b/source3/smbd/server.c index 7b2b055..ca9fb9e 100644 --- a/source3/smbd/server.c +++ b/source3/smbd/server.c @@ -705,7 +705,7 @@ static bool smbd_open_one_socket(struct smbd_parent_context *parent, ifss, true); if (s->fd == -1) { - DEBUG(0,("smbd_open_once_socket: open_socket_in: " + DEBUG(0,("smbd_open_one_socket: open_socket_in: " "%s\n", strerror(errno))); TALLOC_FREE(s); /* @@ -723,7 +723,7 @@ static bool smbd_open_one_socket(struct smbd_parent_context *parent, set_blocking(s->fd, False); if (listen(s->fd, SMBD_LISTEN_BACKLOG) == -1) { - DEBUG(0,("open_sockets_smbd: listen: " + DEBUG(0,("smbd_open_one_socket: listen: " "%s\n", strerror(errno))); close(s->fd); TALLOC_FREE(s); @@ -736,7 +736,7 @@ static bool smbd_open_one_socket(struct smbd_parent_context *parent, smbd_accept_connection, s); if (!s->fde) { - DEBUG(0,("open_sockets_smbd: " + DEBUG(0,("smbd_open_one_socket: " "tevent_add_fd: %s\n", strerror(errno))); close(s->fd); From 1dc05386f20481596ee7360d6f4e628a16675d3f Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 24 Feb 2015 13:26:29 +1300 Subject: [PATCH 110/136] build: Move __attribute__ ((destructor)) and ((constructor)) tests to wafsamba This allows us to use them in talloc as well. Signed-off-by: Andrew Bartlett Signed-off-by: Adrian Cochrane Reviewed-by: Jeremy Allison --- buildtools/wafsamba/wscript | 34 ++++++++++++++++++++++++++++++++++ lib/uid_wrapper/wscript | 34 ---------------------------------- nsswitch/wb_common.c | 2 +- source3/wscript | 6 ------ 4 files changed, 35 insertions(+), 41 deletions(-) diff --git a/buildtools/wafsamba/wscript b/buildtools/wafsamba/wscript index d6bb688..422b742 100755 --- a/buildtools/wafsamba/wscript +++ b/buildtools/wafsamba/wscript @@ -361,6 +361,40 @@ def configure(conf): cflags=conf.env.VISIBILITY_CFLAGS, define='HAVE_VISIBILITY_ATTR', addmain=False) + # check HAVE_CONSTRUCTOR_ATTRIBUTE + conf.CHECK_CODE(''' + void test_constructor_attribute(void) __attribute__ ((constructor)); + + void test_constructor_attribute(void) + { + return; + } + + int main(void) { + return 0; + } + ''', + 'HAVE_CONSTRUCTOR_ATTRIBUTE', + addmain=False, + msg='Checking for library constructor support') + + # check HAVE_DESTRUCTOR_ATTRIBUTE + conf.CHECK_CODE(''' + void test_destructor_attribute(void) __attribute__ ((destructor)); + + void test_destructor_attribute(void) + { + return; + } + + int main(void) { + return 0; + } + ''', + 'HAVE_DESTRUCTOR_ATTRIBUTE', + addmain=False, + msg='Checking for library destructor support') + if sys.platform.startswith('aix'): conf.DEFINE('_ALL_SOURCE', 1, add_to_cflags=True) # Might not be needed if ALL_SOURCE is defined diff --git a/lib/uid_wrapper/wscript b/lib/uid_wrapper/wscript index 016b33a..8e3950f 100644 --- a/lib/uid_wrapper/wscript +++ b/lib/uid_wrapper/wscript @@ -35,40 +35,6 @@ def configure(conf): addmain=False, msg='Checking for thread local storage') - # check HAVE_CONSTRUCTOR_ATTRIBUTE - conf.CHECK_CODE(''' - void test_constructor_attribute(void) __attribute__ ((constructor)); - - void test_constructor_attribute(void) - { - return; - } - - int main(void) { - return 0; - } - ''', - 'HAVE_CONSTRUCTOR_ATTRIBUTE', - addmain=False, - msg='Checking for library constructor support') - - # check HAVE_DESTRUCTOR_ATTRIBUTE - conf.CHECK_CODE(''' - void test_destructor_attribute(void) __attribute__ ((destructor)); - - void test_destructor_attribute(void) - { - return; - } - - int main(void) { - return 0; - } - ''', - 'HAVE_DESTRUCTOR_ATTRIBUTE', - addmain=False, - msg='Checking for library destructor support') - if Options.options.address_sanitizer: # check HAVE_ADDRESS_SANITIZER_ATTRIBUTE conf.CHECK_CODE(''' diff --git a/nsswitch/wb_common.c b/nsswitch/wb_common.c index 139f010..da1a844 100644 --- a/nsswitch/wb_common.c +++ b/nsswitch/wb_common.c @@ -88,7 +88,7 @@ static void winbind_close_sock(struct winbindd_context *ctx) /* Destructor for global context to ensure fd is closed */ -#if HAVE_FUNCTION_ATTRIBUTE_DESTRUCTOR +#if HAVE_DESTRUCTOR_ATTRIBUTE __attribute__((destructor)) #endif static void winbind_destructor(void) diff --git a/source3/wscript b/source3/wscript index 9ff9c20..3118f59 100644 --- a/source3/wscript +++ b/source3/wscript @@ -1492,12 +1492,6 @@ main() { conf.env['CTDB_INCLUDE'] = conf.srcdir + '/ctdb/include' conf.env.with_ctdb = True - conf.CHECK_CODE('__attribute__((destructor)) static void cleanup(void) { }', - 'HAVE_FUNCTION_ATTRIBUTE_DESTRUCTOR', - addmain=False, - link=False, - msg='Checking whether we can compile with __attribute__((destructor))') - conf.CHECK_CODE('void seekdir(DIR *d, long loc) { return; }', 'SEEKDIR_RETURNS_VOID', headers='sys/types.h dirent.h', From 30ea897194c68c149d4986b22a5d964454bec258 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Thu, 17 Oct 2013 10:30:23 +1300 Subject: [PATCH 111/136] lib/talloc: Disrupt buffer overflow attacks on Samba by using random magic By setting the talloc magic to a random value, we make it much harder to overwrite a talloc_chunk in a valid way with a simple buffer overflow. The flags are placed before more senstive variables so they have to be overwritten first. Inspired by the exploit in: http://blog.csnc.ch/wp-content/uploads/2012/07/sambaexploit_v1.0.pdf Andrew Bartlett Signed-off-by: Andrew Bartlett Signed-off-by: Adrian Cochrane Reviewed-by: Jeremy Allison --- lib/talloc/talloc.c | 69 +++++++++++++++++++++++++++++++++++++++-------------- lib/talloc/wscript | 3 +++ 2 files changed, 54 insertions(+), 18 deletions(-) diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c index c10fd53..37a6522 100644 --- a/lib/talloc/talloc.c +++ b/lib/talloc/talloc.c @@ -33,6 +33,10 @@ #include "replace.h" #include "talloc.h" +#ifdef HAVE_SYS_AUXV_H +#include +#endif + #ifdef TALLOC_BUILD_VERSION_MAJOR #if (TALLOC_VERSION_MAJOR != TALLOC_BUILD_VERSION_MAJOR) #error "TALLOC_VERSION_MAJOR != TALLOC_BUILD_VERSION_MAJOR" @@ -60,20 +64,26 @@ #define MAX_TALLOC_SIZE 0x10000000 -#define TALLOC_MAGIC_BASE 0xe814ec70 -#define TALLOC_MAGIC ( \ - TALLOC_MAGIC_BASE + \ - (TALLOC_VERSION_MAJOR << 12) + \ - (TALLOC_VERSION_MINOR << 4) \ -) #define TALLOC_FLAG_FREE 0x01 #define TALLOC_FLAG_LOOP 0x02 #define TALLOC_FLAG_POOL 0x04 /* This is a talloc pool */ #define TALLOC_FLAG_POOLMEM 0x08 /* This is allocated in a pool */ +/* + * Bits above this are random, used to make it harder to fake talloc + * headers during an attack. Try not to change this without good reason. + */ +#define TALLOC_FLAG_MASK 0x0F + #define TALLOC_MAGIC_REFERENCE ((const char *)1) +#define TALLOC_MAGIC_BASE 0xe814ec70 +static unsigned int talloc_magic = ( + TALLOC_MAGIC_BASE + + (TALLOC_VERSION_MAJOR << 12) + + (TALLOC_VERSION_MINOR << 4)); + /* by default we abort when given a bad pointer (such as when talloc_free() is called on a pointer that came from malloc() */ #ifndef TALLOC_ABORT @@ -249,13 +259,13 @@ typedef int (*talloc_destructor_t)(void *); struct talloc_pool_hdr; struct talloc_chunk { + unsigned flags; struct talloc_chunk *next, *prev; struct talloc_chunk *parent, *child; struct talloc_reference_handle *refs; talloc_destructor_t destructor; const char *name; size_t size; - unsigned flags; /* * limit semantics: @@ -297,6 +307,35 @@ _PUBLIC_ void talloc_set_log_fn(void (*log_fn)(const char *message)) talloc_log_fn = log_fn; } +#ifdef HAVE_CONSTRUCTOR_ATTRIBUTE +void talloc_lib_init(void) __attribute__((constructor)); +void talloc_lib_init(void) +{ + uint32_t random_value; +#if defined(HAVE_GETAUXVAL) && defined(AT_RANDOM) + uint8_t *p; + /* + * Use the kernel-provided random values used for + * ASLR. This won't change per-exec, which is ideal for us + */ + p = (uint8_t *) getauxval(AT_RANDOM); + if (p) { + memcpy(&random_value, p, sizeof(random_value)); + } else +#endif + { + /* + * Otherwise, hope the location we are loaded in + * memory is randomised by someone else + */ + random_value = ((uintptr_t)talloc_lib_init & 0xFFFFFFFF); + } + talloc_magic = random_value & ~TALLOC_FLAG_MASK; +} +#else +#warning "No __attribute__((constructor)) support found on this platform, additional talloc security measures not available" +#endif + static void talloc_log(const char *fmt, ...) PRINTF_ATTRIBUTE(1,2); static void talloc_log(const char *fmt, ...) { @@ -345,12 +384,6 @@ static void talloc_abort(const char *reason) static void talloc_abort_magic(unsigned magic) { - unsigned striped = magic - TALLOC_MAGIC_BASE; - unsigned major = (striped & 0xFFFFF000) >> 12; - unsigned minor = (striped & 0x00000FF0) >> 4; - talloc_log("Bad talloc magic[0x%08X/%u/%u] expected[0x%08X/%u/%u]\n", - magic, major, minor, - TALLOC_MAGIC, TALLOC_VERSION_MAJOR, TALLOC_VERSION_MINOR); talloc_abort("Bad talloc magic value - wrong talloc version used/mixed"); } @@ -369,9 +402,9 @@ static inline struct talloc_chunk *talloc_chunk_from_ptr(const void *ptr) { const char *pp = (const char *)ptr; struct talloc_chunk *tc = discard_const_p(struct talloc_chunk, pp - TC_HDR_SIZE); - if (unlikely((tc->flags & (TALLOC_FLAG_FREE | ~0xF)) != TALLOC_MAGIC)) { - if ((tc->flags & (~0xFFF)) == TALLOC_MAGIC_BASE) { - talloc_abort_magic(tc->flags & (~0xF)); + if (unlikely((tc->flags & (TALLOC_FLAG_FREE | ~TALLOC_FLAG_MASK)) != talloc_magic)) { + if ((tc->flags & (~0xF)) == talloc_magic) { + talloc_abort_magic(tc->flags & (~TALLOC_FLAG_MASK)); return NULL; } @@ -561,7 +594,7 @@ static inline struct talloc_chunk *talloc_alloc_pool(struct talloc_chunk *parent pool_hdr->end = (void *)((char *)pool_hdr->end + chunk_size); - result->flags = TALLOC_MAGIC | TALLOC_FLAG_POOLMEM; + result->flags = talloc_magic | TALLOC_FLAG_POOLMEM; result->pool = pool_hdr; pool_hdr->object_count++; @@ -617,7 +650,7 @@ static inline void *__talloc_with_prefix(const void *context, size_t size, return NULL; } tc = (struct talloc_chunk *)(ptr + prefix_len); - tc->flags = TALLOC_MAGIC; + tc->flags = talloc_magic; tc->pool = NULL; talloc_memlimit_grow(limit, total_len); diff --git a/lib/talloc/wscript b/lib/talloc/wscript index bbe0cb1..d4f389f 100644 --- a/lib/talloc/wscript +++ b/lib/talloc/wscript @@ -66,6 +66,9 @@ def configure(conf): Logs.warn('Disabling pytalloc-util as python devel libs not found') conf.env.disable_python = True + conf.CHECK_HEADERS('sys/auxv.h') + conf.CHECK_FUNCS('getauxval') + conf.SAMBA_CONFIG_H() conf.SAMBA_CHECK_UNDEFINED_SYMBOL_FLAGS() From 4a4664a80e20544097cdd075ca5d1423e6a9b364 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 24 Feb 2015 13:43:54 +1300 Subject: [PATCH 112/136] lib/talloc: Provide multiple-loading detection for libtalloc via rand() The use of rand() is strongly discrouanged, but here is it ideal, as we just want to select a different set of random bytes if we are called again within the same process. Signed-off-by: Andrew Bartlett Signed-off-by: Adrian Cochrane Reviewed-by: Jeremy Allison --- lib/talloc/talloc.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c index 37a6522..b35e1c2 100644 --- a/lib/talloc/talloc.c +++ b/lib/talloc/talloc.c @@ -320,7 +320,22 @@ void talloc_lib_init(void) */ p = (uint8_t *) getauxval(AT_RANDOM); if (p) { - memcpy(&random_value, p, sizeof(random_value)); + /* + * We get 16 bytes from getauxval. By calling rand(), + * a totally insecure PRNG, but one that will + * deterministically have a different value when called + * twice, we ensure that if two talloc-like libraries + * are somehow loaded in the same address space, that + * because we choose different bytes, we will keep the + * protection against collision of multiple talloc + * libs. + * + * This protection is important because the effects of + * passing a talloc pointer from one to the other may + * be very hard to determine. + */ + int offset = rand() % (16 - sizeof(random_value)); + memcpy(&random_value, p + offset, sizeof(random_value)); } else #endif { From f5135bda942ff13f0baf2c629147d0755eb96090 Mon Sep 17 00:00:00 2001 From: Adrian Cochrane Date: Wed, 2 Sep 2015 13:30:31 +1200 Subject: [PATCH 113/136] talloc: Test magic protection measures. Signed-off-by: Adrian Cochrane Reviewed-by: Andrew Bartlett Reviewed-by: Jeremy Allison --- lib/talloc/testsuite.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/lib/talloc/testsuite.c b/lib/talloc/testsuite.c index c67cfb9..9f83039 100644 --- a/lib/talloc/testsuite.c +++ b/lib/talloc/testsuite.c @@ -31,6 +31,9 @@ #include #endif +#include +#include + #include "talloc_testsuite.h" static struct timeval timeval_current(void) @@ -1852,6 +1855,67 @@ static bool test_pthread_talloc_passing(void) } #endif +static void test_magic_protection_abort(const char *reason) +{ + /* exit with errcode 42 to communicate successful test to the parent process */ + if (strcmp(reason, "Bad talloc magic value - unknown value") == 0) { + _exit(42); + } else { + printf("talloc aborted for an unexpected reason\n"); + } +} + +static bool test_magic_protection(void) +{ + void *pool = talloc_pool(NULL, 1024); + int *p1, *p2; + pid_t pid; + int exit_status; + + printf("test: magic_protection\n"); + p1 = talloc(pool, int); + p2 = talloc(pool, int); + + /* To avoid complaints from the compiler assign values to the p1 & p2. */ + *p1 = 6; + *p2 = 9; + + pid = fork(); + if (pid == 0) { + talloc_set_abort_fn(test_magic_protection_abort); + + /* + * Simulate a security attack + * by triggering a buffer overflow in memset to overwrite the + * constructor in the next pool chunk. + * + * Real attacks would attempt to set a real destructor. + */ + memset(p1, '\0', 32); + + /* Then the attack takes effect when the memory's freed. */ + talloc_free(pool); + } else { + while (wait(&exit_status) != pid); + } + + if (!WIFEXITED(exit_status)) { + printf("Child exited through unexpected abnormal means\n"); + return false; + } + if (WEXITSTATUS(exit_status) != 42) { + printf("Child exited with wrong exit status\n"); + return false; + } + if (WIFSIGNALED(exit_status)) { + printf("Child recieved unexpected signal\n"); + return false; + } + + printf("success: magic_protection\n"); + return true; +} + static void test_reset(void) { talloc_set_log_fn(test_log_stdout); @@ -1934,6 +1998,8 @@ bool torture_local_talloc(struct torture_context *tctx) } test_reset(); ret &= test_autofree(); + test_reset(); + ret &= test_magic_protection(); test_reset(); talloc_disable_null_tracking(); From 906a26a2abc70f824b654f71678314648b28d058 Mon Sep 17 00:00:00 2001 From: Adrian Cochrane Date: Fri, 4 Sep 2015 12:03:33 +1200 Subject: [PATCH 114/136] talloc: Provide tests access to talloc_magic Signed-off-by: Adrian Cochrane Reviewed-by: Andrew Bartlett Reviewed-by: Jeremy Allison --- lib/talloc/talloc.c | 5 +++++ lib/talloc/talloc.h | 2 ++ 2 files changed, 7 insertions(+) diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c index b35e1c2..90b9d96 100644 --- a/lib/talloc/talloc.c +++ b/lib/talloc/talloc.c @@ -300,6 +300,11 @@ _PUBLIC_ int talloc_version_minor(void) return TALLOC_VERSION_MINOR; } +_PUBLIC_ int talloc_test_get_magic(void) +{ + return talloc_magic; +} + static void (*talloc_log_fn)(const char *message); _PUBLIC_ void talloc_set_log_fn(void (*log_fn)(const char *message)) diff --git a/lib/talloc/talloc.h b/lib/talloc/talloc.h index 5ece54d..b7408b9 100644 --- a/lib/talloc/talloc.h +++ b/lib/talloc/talloc.h @@ -47,6 +47,8 @@ extern "C" { int talloc_version_major(void); int talloc_version_minor(void); +/* This is mostly useful only for testing */ +int talloc_test_get_magic(void); /** * @brief Define a talloc parent type From 2b9bfab36d9ae0f7fa2a989195129a1a6b62393b Mon Sep 17 00:00:00 2001 From: Adrian Cochrane Date: Fri, 9 Oct 2015 13:32:55 +1300 Subject: [PATCH 115/136] talloc: Increment minor version due to added talloc_test_get_magic. Signed-off-by: Adrian Cochrane Reviewed-by: Andrew Bartlett Reviewed-by: Jeremy Allison --- lib/talloc/ABI/pytalloc-util-2.1.4.sigs | 6 +++ lib/talloc/ABI/talloc-2.1.4.sigs | 65 +++++++++++++++++++++++++++++++++ lib/talloc/wscript | 2 +- 3 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 lib/talloc/ABI/pytalloc-util-2.1.4.sigs create mode 100644 lib/talloc/ABI/talloc-2.1.4.sigs diff --git a/lib/talloc/ABI/pytalloc-util-2.1.4.sigs b/lib/talloc/ABI/pytalloc-util-2.1.4.sigs new file mode 100644 index 0000000..961c1a8 --- /dev/null +++ b/lib/talloc/ABI/pytalloc-util-2.1.4.sigs @@ -0,0 +1,6 @@ +pytalloc_CObject_FromTallocPtr: PyObject *(void *) +pytalloc_Check: int (PyObject *) +pytalloc_GetObjectType: PyTypeObject *(void) +pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) +pytalloc_steal: PyObject *(PyTypeObject *, void *) +pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) diff --git a/lib/talloc/ABI/talloc-2.1.4.sigs b/lib/talloc/ABI/talloc-2.1.4.sigs new file mode 100644 index 0000000..9969ce3 --- /dev/null +++ b/lib/talloc/ABI/talloc-2.1.4.sigs @@ -0,0 +1,65 @@ +_talloc: void *(const void *, size_t) +_talloc_array: void *(const void *, size_t, unsigned int, const char *) +_talloc_free: int (void *, const char *) +_talloc_get_type_abort: void *(const void *, const char *, const char *) +_talloc_memdup: void *(const void *, const void *, size_t, const char *) +_talloc_move: void *(const void *, const void *) +_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t) +_talloc_realloc: void *(const void *, void *, size_t, const char *) +_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *) +_talloc_reference_loc: void *(const void *, const void *, const char *) +_talloc_set_destructor: void (const void *, int (*)(void *)) +_talloc_steal_loc: void *(const void *, const void *, const char *) +_talloc_zero: void *(const void *, size_t, const char *) +_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *) +talloc_asprintf: char *(const void *, const char *, ...) +talloc_asprintf_append: char *(char *, const char *, ...) +talloc_asprintf_append_buffer: char *(char *, const char *, ...) +talloc_autofree_context: void *(void) +talloc_check_name: void *(const void *, const char *) +talloc_disable_null_tracking: void (void) +talloc_enable_leak_report: void (void) +talloc_enable_leak_report_full: void (void) +talloc_enable_null_tracking: void (void) +talloc_enable_null_tracking_no_autofree: void (void) +talloc_find_parent_byname: void *(const void *, const char *) +talloc_free_children: void (void *) +talloc_get_name: const char *(const void *) +talloc_get_size: size_t (const void *) +talloc_increase_ref_count: int (const void *) +talloc_init: void *(const char *, ...) +talloc_is_parent: int (const void *, const void *) +talloc_named: void *(const void *, size_t, const char *, ...) +talloc_named_const: void *(const void *, size_t, const char *) +talloc_parent: void *(const void *) +talloc_parent_name: const char *(const void *) +talloc_pool: void *(const void *, size_t) +talloc_realloc_fn: void *(const void *, void *, size_t) +talloc_reference_count: size_t (const void *) +talloc_reparent: void *(const void *, const void *, const void *) +talloc_report: void (const void *, FILE *) +talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *) +talloc_report_depth_file: void (const void *, int, int, FILE *) +talloc_report_full: void (const void *, FILE *) +talloc_set_abort_fn: void (void (*)(const char *)) +talloc_set_log_fn: void (void (*)(const char *)) +talloc_set_log_stderr: void (void) +talloc_set_memlimit: int (const void *, size_t) +talloc_set_name: const char *(const void *, const char *, ...) +talloc_set_name_const: void (const void *, const char *) +talloc_show_parents: void (const void *, FILE *) +talloc_strdup: char *(const void *, const char *) +talloc_strdup_append: char *(char *, const char *) +talloc_strdup_append_buffer: char *(char *, const char *) +talloc_strndup: char *(const void *, const char *, size_t) +talloc_strndup_append: char *(char *, const char *, size_t) +talloc_strndup_append_buffer: char *(char *, const char *, size_t) +talloc_test_get_magic: int (void) +talloc_total_blocks: size_t (const void *) +talloc_total_size: size_t (const void *) +talloc_unlink: int (const void *, void *) +talloc_vasprintf: char *(const void *, const char *, va_list) +talloc_vasprintf_append: char *(char *, const char *, va_list) +talloc_vasprintf_append_buffer: char *(char *, const char *, va_list) +talloc_version_major: int (void) +talloc_version_minor: int (void) diff --git a/lib/talloc/wscript b/lib/talloc/wscript index d4f389f..19294d9 100644 --- a/lib/talloc/wscript +++ b/lib/talloc/wscript @@ -1,7 +1,7 @@ #!/usr/bin/env python APPNAME = 'talloc' -VERSION = '2.1.3' +VERSION = '2.1.4' blddir = 'bin' From 7b6d1a2a5d5561e641d9001901b9e43a64117681 Mon Sep 17 00:00:00 2001 From: Adrian Cochrane Date: Fri, 4 Sep 2015 12:59:57 +1200 Subject: [PATCH 116/136] talloc: Test that talloc magic differs between processes. Signed-off-by: Adrian Cochrane Reviewed-by: Andrew Bartlett Reviewed-by: Jeremy Allison Autobuild-User(master): Jeremy Allison Autobuild-Date(master): Fri Oct 9 23:15:06 CEST 2015 on sn-devel-104 --- lib/talloc/test_magic_differs.sh | 14 ++++++++++++++ lib/talloc/test_magic_differs_helper.c | 12 ++++++++++++ lib/talloc/wscript | 11 ++++++++++- 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100755 lib/talloc/test_magic_differs.sh create mode 100644 lib/talloc/test_magic_differs_helper.c diff --git a/lib/talloc/test_magic_differs.sh b/lib/talloc/test_magic_differs.sh new file mode 100755 index 0000000..0f765f0 --- /dev/null +++ b/lib/talloc/test_magic_differs.sh @@ -0,0 +1,14 @@ +#!/bin/sh +# This test ensures that two different talloc processes do not use the same +# magic value to lessen the opportunity for transferrable attacks. + +echo "test: magic differs" + +if [ + "`./talloc_test_magic_differs_helper`" != "`./talloc_test_magic_differs_helper`" +]; then + echo "failure: magic remained the same between executions" + exit 1 +fi + +echo "success: magic differs" diff --git a/lib/talloc/test_magic_differs_helper.c b/lib/talloc/test_magic_differs_helper.c new file mode 100644 index 0000000..6798827 --- /dev/null +++ b/lib/talloc/test_magic_differs_helper.c @@ -0,0 +1,12 @@ +#include +#include "talloc.h" + +/* + * This program is called by a testing shell script in order to ensure that + * if the library is loaded into different processes it uses different magic + * values in order to thwart security attacks. + */ +int main(int argc, char *argv[]) { + printf("%i\n", talloc_test_get_magic()); + return 0; +} diff --git a/lib/talloc/wscript b/lib/talloc/wscript index 19294d9..9cedbbf 100644 --- a/lib/talloc/wscript +++ b/lib/talloc/wscript @@ -100,6 +100,10 @@ def build(bld): testsuite_deps, install=False) + bld.SAMBA_BINARY('talloc_test_magic_differs_helper', + 'test_magic_differs_helper.c', + 'talloc', install=False) + else: private_library = True @@ -154,9 +158,14 @@ def test(ctx): cmd = os.path.join(Utils.g_module.blddir, 'talloc_testsuite') ret = samba_utils.RUN_COMMAND(cmd) print("testsuite returned %d" % ret) + magic_cmd = os.path.join(srcdir, 'lib', 'talloc', + 'test_magic_differs.sh') + + magic_ret = samba_utils.RUN_COMMAND(magic_cmd) + print("magic differs test returned %d" % magic_ret) pyret = samba_utils.RUN_PYTHON_TESTS(['test_pytalloc.py']) print("python testsuite returned %d" % pyret) - sys.exit(ret or pyret) + sys.exit(ret or magic_ret or pyret) def dist(): '''makes a tarball for distribution''' From b95b2be8451e7804704dc2046b6c3eb35f79220e Mon Sep 17 00:00:00 2001 From: Richard Sharpe Date: Sat, 10 Oct 2015 17:58:59 -0700 Subject: [PATCH 117/136] A small improvement to the DEBUG message when pass-through authentication fails with ACCESS_DENIED. Increased it to log level 1 so it will print out and pointed to Restrict NTLM as the setting so people know what to look for. Signed-off-by: Richard Sharpe Reviewed-by: Uri Simchoni Autobuild-User(master): Richard Sharpe Autobuild-Date(master): Sun Oct 11 06:28:05 CEST 2015 on sn-devel-104 --- source3/winbindd/winbindd_pam.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c index 329db62..0ea146b 100644 --- a/source3/winbindd/winbindd_pam.c +++ b/source3/winbindd/winbindd_pam.c @@ -1428,8 +1428,9 @@ static NTSTATUS winbind_samlogon_retry_loop(struct winbindd_domain *domain, rpc changetrustpw' */ if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) { - DEBUG(3,("winbind_samlogon_retry_loop: sam_logon returned " - "ACCESS_DENIED. Maybe the trust account " + DEBUG(1,("winbind_samlogon_retry_loop: sam_logon returned " + "ACCESS_DENIED. Maybe the DC has Restrict " + "NTLM set or the trust account " "password was changed and we didn't know it. " "Killing connections to domain %s\n", domainname)); From 2f7bee43d8bcb8cc5205b159862e57954e4fc26c Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 9 Oct 2015 12:18:53 +0200 Subject: [PATCH 118/136] wbinfo: make --verbose --pam-logon print sids MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Volker Lendecke Reviewed-by: Günther Deschner Autobuild-User(master): Volker Lendecke Autobuild-Date(master): Mon Oct 12 14:01:50 CEST 2015 on sn-devel-104 --- nsswitch/wbinfo.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/nsswitch/wbinfo.c b/nsswitch/wbinfo.c index f45d7b5..330fa91 100644 --- a/nsswitch/wbinfo.c +++ b/nsswitch/wbinfo.c @@ -1831,6 +1831,7 @@ static bool wbinfo_pam_logon(char *username, bool verbose) if (verbose && (info != NULL)) { struct wbcAuthUserInfo *i = info->info; + uint32_t j; if (i->account_name != NULL) { d_printf("account_name: %s\n", i->account_name); @@ -1863,6 +1864,15 @@ static bool wbinfo_pam_logon(char *username, bool verbose) d_printf("home_drive: %s\n", i->home_drive); } + d_printf("sids:"); + + for (j=0; jnum_sids; j++) { + char buf[WBC_SID_STRING_BUFLEN]; + wbcSidToStringBuf(&i->sids[j].sid, buf, sizeof(buf)); + d_printf(" %s", buf); + } + d_printf("\n"); + wbcFreeMemory(info); info = NULL; } From b5cf80a7b58095fd711968ef03f84740d0119553 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Mon, 12 Oct 2015 12:06:50 +0200 Subject: [PATCH 119/136] talloc: Fix the O3 developer build Compilers can't see that the child exits. Thus "exit_status" is used uninitialized in the child. Signed-off-by: Volker Lendecke Reviewed-by: Ralph Boehme --- lib/talloc/testsuite.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/talloc/testsuite.c b/lib/talloc/testsuite.c index 9f83039..34410b8 100644 --- a/lib/talloc/testsuite.c +++ b/lib/talloc/testsuite.c @@ -1895,10 +1895,13 @@ static bool test_magic_protection(void) /* Then the attack takes effect when the memory's freed. */ talloc_free(pool); - } else { - while (wait(&exit_status) != pid); + + /* Never reached. Make compilers happy */ + return true; } + while (wait(&exit_status) != pid); + if (!WIFEXITED(exit_status)) { printf("Child exited through unexpected abnormal means\n"); return false; From 8807ad18c2cc1a0cdc4f47c294d44123d2a53ec8 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Mon, 12 Oct 2015 12:17:56 +0200 Subject: [PATCH 120/136] dynconfig: Fix deps, no talloc required MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Volker Lendecke Reviewed-by: Ralph Boehme Autobuild-User(master): Ralph Böhme Autobuild-Date(master): Mon Oct 12 17:06:04 CEST 2015 on sn-devel-104 --- dynconfig/wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dynconfig/wscript b/dynconfig/wscript index 6410c38..606fbad 100755 --- a/dynconfig/wscript +++ b/dynconfig/wscript @@ -412,7 +412,7 @@ def build(bld): version_header = 'version.h' bld.SAMBA_SUBSYSTEM('DYNCONFIG', 'dynconfig.c', - deps='replace talloc', + deps='replace', public_headers=os_path_relpath(os.path.join(Options.launch_dir, version_header), bld.curdir), header_path='samba', cflags=cflags) From 3c00e8d76a2ef6194a8ce522c15853e5b8e9262b Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Sat, 10 Oct 2015 08:45:41 +1300 Subject: [PATCH 121/136] pam_smbpass: REMOVE this PAM module This pam module causes GPLv3, thread-unsafe Samba code to be directly loaded into the address space of many system services. The code in question was not expected to run in this context, and while using the Samba, rather than the system password file is a admirable goal, this needs to be done over inter-process communication, such as is done by pam_winbind. pam_winbind is not a total replacement, as the migrate functionality used to keep the Samba password up to date with the system password is not present, but otherwise can provide essentially the same services. Andrew Bartlett Signed-off-by: Andrew Bartlett Reviewed-by: Jeremy Allison --- source3/pam_smbpass/CHANGELOG | 31 -- source3/pam_smbpass/INSTALL | 64 --- source3/pam_smbpass/README | 68 --- source3/pam_smbpass/TODO | 7 - source3/pam_smbpass/general.h | 134 ----- source3/pam_smbpass/pam_smb_acct.c | 150 ------ source3/pam_smbpass/pam_smb_auth.c | 264 ---------- source3/pam_smbpass/pam_smb_passwd.c | 365 ------------- source3/pam_smbpass/samples/README | 3 - source3/pam_smbpass/samples/kdc-pdc | 15 - source3/pam_smbpass/samples/password-mature | 14 - source3/pam_smbpass/samples/password-migration | 18 - source3/pam_smbpass/samples/password-sync | 15 - source3/pam_smbpass/support.c | 698 ------------------------- source3/pam_smbpass/support.h | 57 -- source3/pam_smbpass/wscript_build | 16 - source3/wscript_build | 1 - 17 files changed, 1920 deletions(-) delete mode 100644 source3/pam_smbpass/CHANGELOG delete mode 100644 source3/pam_smbpass/INSTALL delete mode 100644 source3/pam_smbpass/README delete mode 100644 source3/pam_smbpass/TODO delete mode 100644 source3/pam_smbpass/general.h delete mode 100644 source3/pam_smbpass/pam_smb_acct.c delete mode 100644 source3/pam_smbpass/pam_smb_auth.c delete mode 100644 source3/pam_smbpass/pam_smb_passwd.c delete mode 100644 source3/pam_smbpass/samples/README delete mode 100644 source3/pam_smbpass/samples/kdc-pdc delete mode 100644 source3/pam_smbpass/samples/password-mature delete mode 100644 source3/pam_smbpass/samples/password-migration delete mode 100644 source3/pam_smbpass/samples/password-sync delete mode 100644 source3/pam_smbpass/support.c delete mode 100644 source3/pam_smbpass/support.h delete mode 100644 source3/pam_smbpass/wscript_build diff --git a/source3/pam_smbpass/CHANGELOG b/source3/pam_smbpass/CHANGELOG deleted file mode 100644 index 96ef784..0000000 --- a/source3/pam_smbpass/CHANGELOG +++ /dev/null @@ -1,31 +0,0 @@ -version 0.7.5 25 Mar 2001 - - Use Samba 2.2.0 (alpha) as the target codebase, since it doesn't look - like Samba will be offering shared libraries in the near future. - - added a Makefile and support scripts to make the build process easier. - - imported some Solaris fixes that I've been sitting on. - -version 0.7.4 20 Jan 2000 - - added a 'migrate' option to the authentication code which makes no - effort to authenticate the user, or even to ask for a password, but - it can be useful for filling in an SMB password db. - -version 0.7.3 19 Jan 2000 - - updated to use the SAMBA_TNG Samba branch, allowing us to dynamically - link against Luke's new shared libs (libsamba, libsmb). - -version 0.7.2 20 Jul 1999 - - miscellaneous bugfixes. Cleanup of legacy pam_pwdb code. - - fixed return value of pam_sm_setcred function. - - fix to autoconf support - - clarified some of the messages being logged - -version 0.6, 15 Jul 1999 - - updated to use the new Samba (2.0) password database API. - - added autoconf support. May now theoretically compile on more - platforms than PAM itself does. - - added support for account management functions (i.e., disabled - accounts) - -version 0.5, 4 Apr 1998 - - added support for hashed passwords as input. Now capable of serving - as an authentication agent for encrypted network transactions. diff --git a/source3/pam_smbpass/INSTALL b/source3/pam_smbpass/INSTALL deleted file mode 100644 index ae2ba02..0000000 --- a/source3/pam_smbpass/INSTALL +++ /dev/null @@ -1,64 +0,0 @@ - -Because pam_smbpass is derived from the Samba smbpasswd utility, recent -versions of pam_smbpass require a copy of the Samba source code to be -available on the build system. Version 0.7.5 has been tested against -Samba 2.2.0-alpha3, and this is the recommended version of Samba to use -for building pam_smbpass. This only affects /building/ pam_smbpass; you -can still run any version of the Samba server that you want, although -clearly it saves some disk space to have only one copy of the source -code on your system (Samba 2.2.0-alpha3 takes roughly 32MB of disk space -to build pam_smbpass). - -Version 0.7.5 features a new build system to make it easier to build -pam_smbpass. - - -Using the new build system -========================== - -If you don't have a copy of the Samba source code on your machine, and you -don't have a preferred Samba version (or mirror site), you can build -pam_smbpass by just typing 'make'. - -If you want to use a version other than 2.2.0-alpha3, or you want to -download the source code from a faster Samba mirror (see - for a list of mirror sites), please download -the source code and unpack it before running make. The build scripts will -attempt to autodetect your Samba source directory, and if it can't be -found automatically, you will be given the opportunity to specify an -alternate directory for the Samba sources. - -Feedback is welcome if you try (or succeed!) to build pam_smbpass with -other versions of Samba. - - -Options to 'make' -================= - -By default, pam_smbpass will configure the Samba build tree with the -options - - --with-fhs --with-privatedir=/etc --with-configdir=/etc - -This will configure pam_smbpass to look for the smbpasswd file as -/etc/smbpasswd (or /etc/smbpasswd.tdb), and the smb.conf file as -/etc/smb.conf. You can override these options by setting CONFIGOPTS when -calling make. E.g., if you have your smb.conf file in /usr/etc and your -smbpasswd file in /usr/etc/private, you might run - - make CONFIGOPTS="--with-privatedir=/usr/etc/private --with-configdir=/usr/etc" - -For a complete list of available configuration options, see -'./samba/configure --help' - - -Installing the module -===================== - -If all goes well in the build process, the file pam_smbpass.so will be -created in the current directory. Simply install the module into your -system's PAM module directory: - - install -m 755 -s bin/pam_smbpass.so /lib/security - -and you're all set. diff --git a/source3/pam_smbpass/README b/source3/pam_smbpass/README deleted file mode 100644 index a5bde25..0000000 --- a/source3/pam_smbpass/README +++ /dev/null @@ -1,68 +0,0 @@ -23 Jan 2015 - -=== WARNING === - -This PAM module is deprecated and will be removed from the Samba source code -with the release of Samba 4.3. If you are still using this module please -migrate to pam_winbind or another suiteable solution. - -25 Mar 2001 - -pam_smbpass is a PAM module which can be used on conforming systems to -keep the smbpasswd (Samba password) database in sync with the unix -password file. PAM (Pluggable Authentication Modules) is an API supported -under some Unices, such as Solaris, HPUX and Linux, that provides a -generic interface to authentication mechanisms. - -For more information on PAM, see http://ftp.kernel.org/pub/linux/libs/pam/ - -This module authenticates a local smbpasswd user database. If you require -support for authenticating against a remote SMB server, or if you're -concerned about the presence of suid root binaries on your system, it is -recommended that you use pam_winbind instead. - -Options recognized by this module are as follows: - - debug - log more debugging info - audit - like debug, but also logs unknown usernames - use_first_pass - don't prompt the user for passwords; - take them from PAM_ items instead - try_first_pass - try to get the password from a previous - PAM module, fall back to prompting the user - use_authtok - like try_first_pass, but *fail* if the new - PAM_AUTHTOK has not been previously set. - (intended for stacking password modules only) - not_set_pass - don't make passwords used by this module - available to other modules. - nodelay - don't insert ~1 second delays on authentication - failure. - nullok - null passwords are allowed. - nonull - null passwords are not allowed. Used to - override the Samba configuration. - migrate - only meaningful in an "auth" context; - used to update smbpasswd file with a - password used for successful authentication. - smbconf= - specify an alternate path to the smb.conf - file. - -See the samples/ directory for example PAM configurations using this -module. - -Thanks go to the following people: - -* Andrew Morgan , for providing the Linux-PAM -framework, without which none of this would have happened - -* Christian Gafton and Andrew Morgan again, for the -pam_pwdb module upon which pam_smbpass was originally based - -* Luke Leighton for being receptive to the idea, -and for the occasional good-natured complaint about the project's status -that keep me working on it :) - -* and of course, all the other members of the Samba team -, for creating a great product -and for giving this project a purpose - ---------------------- -Stephen Langasek diff --git a/source3/pam_smbpass/TODO b/source3/pam_smbpass/TODO deleted file mode 100644 index 20cf4fb..0000000 --- a/source3/pam_smbpass/TODO +++ /dev/null @@ -1,7 +0,0 @@ -This is a tentative TODO file which will probably get much longer before -it gets much shorter. - -- Recognizing (and overriding) debug options in the smb.conf file -- Support for 'name=value' parameters in the PAM config -- Compliant handling of unrecognized PAM parameters (i.e., fail on error) -- diff --git a/source3/pam_smbpass/general.h b/source3/pam_smbpass/general.h deleted file mode 100644 index c3e4b8b..0000000 --- a/source3/pam_smbpass/general.h +++ /dev/null @@ -1,134 +0,0 @@ -#include "../librpc/gen_ndr/samr.h" -#include "../libcli/auth/pam_errors.h" -#include "passdb.h" - -#ifndef LINUX -/* This is only needed by modules in the Sun implementation. */ -#if defined(HAVE_SECURITY_PAM_APPL_H) -#include -#elif defined(HAVE_PAM_PAM_APPL_H) -#include -#endif -#endif /* LINUX */ - -#if defined(HAVE_SECURITY_PAM_MODULES_H) -#include -#elif defined(HAVE_PAM_PAM_MODULES_H) -#include -#endif - -#ifndef PAM_AUTHTOK_RECOVER_ERR -#define PAM_AUTHTOK_RECOVER_ERR PAM_AUTHTOK_RECOVERY_ERR -#endif - -#include "replace.h" -#include "system/filesys.h" -#include "system/wait.h" -#include "system/syslog.h" - -/* - * here is the string to inform the user that the new passwords they - * typed were not the same. - */ - -#define MISTYPED_PASS "Sorry, passwords do not match" - -/* type definition for the control options */ - -typedef struct { - const char *token; - unsigned int mask; /* shall assume 32 bits of flags */ - unsigned int flag; -} SMB_Ctrls; - -#ifndef False -#define False (0) -#endif - -#ifndef True -#define True (1) -#endif - -/* macro to determine if a given flag is on */ -#define on(x,ctrl) (smb_args[x].flag & ctrl) - -/* macro to determine that a given flag is NOT on */ -#define off(x,ctrl) (!on(x,ctrl)) - -/* macro to turn on/off a ctrl flag manually */ -#define set(x,ctrl) (ctrl = ((ctrl)&smb_args[x].mask)|smb_args[x].flag) -#define unset(x,ctrl) (ctrl &= ~(smb_args[x].flag)) - -/* the generic mask */ -#define _ALL_ON_ (~0U) - -/* end of macro definitions definitions for the control flags */ - -/* - * These are the options supported by the smb password module, very - * similar to the pwdb options - */ - -#define SMB__OLD_PASSWD 0 /* internal */ -#define SMB__VERIFY_PASSWD 1 /* internal */ - -#define SMB_AUDIT 2 /* print more things than debug.. - some information may be sensitive */ -#define SMB_USE_FIRST_PASS 3 -#define SMB_TRY_FIRST_PASS 4 -#define SMB_NOT_SET_PASS 5 /* don't set the AUTHTOK items */ - -#define SMB__NONULL 6 /* internal */ -#define SMB__QUIET 7 /* internal */ -#define SMB_USE_AUTHTOK 8 /* insist on reading PAM_AUTHTOK */ -#define SMB__NULLOK 9 /* Null token ok */ -#define SMB_DEBUG 10 /* send more info to syslog(3) */ -#define SMB_NODELAY 11 /* admin does not want a fail-delay */ -#define SMB_MIGRATE 12 /* Does no authentication, just - updates the smb database. */ -#define SMB_CONF_FILE 13 /* Alternate location of smb.conf */ - -#define SMB_CTRLS_ 14 /* number of ctrl arguments defined */ - -static const SMB_Ctrls smb_args[SMB_CTRLS_] = { -/* symbol token name ctrl mask ctrl * - * ------------------ ------------------ -------------- ---------- */ - -/* SMB__OLD_PASSWD */ { NULL, _ALL_ON_, 01 }, -/* SMB__VERIFY_PASSWD */ { NULL, _ALL_ON_, 02 }, -/* SMB_AUDIT */ { "audit", _ALL_ON_, 04 }, -/* SMB_USE_FIRST_PASS */ { "use_first_pass", _ALL_ON_^(030), 010 }, -/* SMB_TRY_FIRST_PASS */ { "try_first_pass", _ALL_ON_^(030), 020 }, -/* SMB_NOT_SET_PASS */ { "not_set_pass", _ALL_ON_, 040 }, -/* SMB__NONULL */ { "nonull", _ALL_ON_, 0100 }, -/* SMB__QUIET */ { NULL, _ALL_ON_, 0200 }, -/* SMB_USE_AUTHTOK */ { "use_authtok", _ALL_ON_, 0400 }, -/* SMB__NULLOK */ { "nullok", _ALL_ON_^(0100), 0 }, -/* SMB_DEBUG */ { "debug", _ALL_ON_, 01000 }, -/* SMB_NODELAY */ { "nodelay", _ALL_ON_, 02000 }, -/* SMB_MIGRATE */ { "migrate", _ALL_ON_^(0100), 04000 }, -/* SMB_CONF_FILE */ { "smbconf=", _ALL_ON_, 0 }, -}; - -#define SMB_DEFAULTS (smb_args[SMB__NONULL].flag) - -/* - * the following is used to keep track of the number of times a user fails - * to authenticate themself. - */ - -#define SMB_MAX_RETRIES 3 - -struct _pam_failed_auth { - char *user; /* user that's failed to be authenticated */ - uid_t id; /* uid of requested user */ - char *agent; /* attempt from user with name */ - int count; /* number of failures so far */ -}; - -/* - * General use functions go here - */ - -/* from support.c */ -int make_remark(pam_handle_t *, unsigned int, int, const char *); diff --git a/source3/pam_smbpass/pam_smb_acct.c b/source3/pam_smbpass/pam_smb_acct.c deleted file mode 100644 index 8dbbf3a..0000000 --- a/source3/pam_smbpass/pam_smb_acct.c +++ /dev/null @@ -1,150 +0,0 @@ -/* Unix NT password database implementation, version 0.7.5. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, see . -*/ - -/* indicate the following groups are defined */ -#define PAM_SM_ACCT - -#include "includes.h" - -#ifndef LINUX - -/* This is only used in the Sun implementation. */ -#if defined(HAVE_SECURITY_PAM_APPL_H) -#include -#elif defined(HAVE_PAM_PAM_APPL_H) -#include -#endif - -#endif /* LINUX */ - -#if defined(HAVE_SECURITY_PAM_MODULES_H) -#include -#elif defined(HAVE_PAM_PAM_MODULES_H) -#include -#endif - -#include "general.h" - -#include "support.h" - - -/* - * pam_sm_acct_mgmt() verifies whether or not the account is disabled. - * - */ - -int pam_sm_acct_mgmt( pam_handle_t *pamh, int flags, - int argc, const char **argv ) -{ - unsigned int ctrl; - int retval; - - const char *name; - struct samu *sampass = NULL; - void (*oldsig_handler)(int); - TALLOC_CTX *frame = talloc_stackframe(); - - /* Samba initialization. */ - - ctrl = set_ctrl(pamh, flags, argc, argv ); - - /* get the username */ - - retval = pam_get_user( pamh, &name, "Username: " ); - if (retval != PAM_SUCCESS) { - if (on( SMB_DEBUG, ctrl )) { - _log_err(pamh, LOG_DEBUG, "acct: could not identify user" ); - } - TALLOC_FREE(frame); - return retval; - } - if (on( SMB_DEBUG, ctrl )) { - _log_err(pamh, LOG_DEBUG, "acct: username [%s] obtained", name ); - } - - if (geteuid() != 0) { - _log_err(pamh, LOG_DEBUG, "Cannot access samba password database, not running as root."); - TALLOC_FREE(frame); - return PAM_AUTHINFO_UNAVAIL; - } - - /* Getting into places that might use LDAP -- protect the app - from a SIGPIPE it's not expecting */ - oldsig_handler = CatchSignal(SIGPIPE, SIG_IGN); - if (!initialize_password_db(True, NULL)) { - _log_err(pamh, LOG_ALERT, "Cannot access samba password database" ); - CatchSignal(SIGPIPE, oldsig_handler); - TALLOC_FREE(frame); - return PAM_AUTHINFO_UNAVAIL; - } - - /* Get the user's record. */ - - if (!(sampass = samu_new( NULL ))) { - CatchSignal(SIGPIPE, oldsig_handler); - /* malloc fail. */ - TALLOC_FREE(frame); - return nt_status_to_pam(NT_STATUS_NO_MEMORY); - } - - if (!pdb_getsampwnam(sampass, name )) { - _log_err(pamh, LOG_DEBUG, "acct: could not identify user"); - CatchSignal(SIGPIPE, oldsig_handler); - TALLOC_FREE(frame); - return PAM_USER_UNKNOWN; - } - - /* check for lookup failure */ - if (!strlen(pdb_get_username(sampass)) ) { - CatchSignal(SIGPIPE, oldsig_handler); - TALLOC_FREE(frame); - return PAM_USER_UNKNOWN; - } - - if (pdb_get_acct_ctrl(sampass) & ACB_DISABLED) { - if (on( SMB_DEBUG, ctrl )) { - _log_err(pamh, LOG_DEBUG, - "acct: account %s is administratively disabled", name); - } - make_remark( pamh, ctrl, PAM_ERROR_MSG - , "Your account has been disabled; " - "please see your system administrator." ); - - CatchSignal(SIGPIPE, oldsig_handler); - TALLOC_FREE(frame); - return PAM_ACCT_EXPIRED; - } - - /* TODO: support for expired passwords. */ - - CatchSignal(SIGPIPE, oldsig_handler); - TALLOC_FREE(frame); - return PAM_SUCCESS; -} - -/* static module data */ -#ifdef PAM_STATIC -struct pam_module _pam_smbpass_acct_modstruct = { - "pam_smbpass", - NULL, - NULL, - pam_sm_acct_mgmt, - NULL, - NULL, - NULL -}; -#endif - diff --git a/source3/pam_smbpass/pam_smb_auth.c b/source3/pam_smbpass/pam_smb_auth.c deleted file mode 100644 index 06ab845..0000000 --- a/source3/pam_smbpass/pam_smb_auth.c +++ /dev/null @@ -1,264 +0,0 @@ -/* Unix NT password database implementation, version 0.7.5. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, see . -*/ - -/* indicate the following groups are defined */ -#define PAM_SM_AUTH - -#include "includes.h" -#include "lib/util/debug.h" - -#ifndef LINUX - -/* This is only used in the Sun implementation. */ -#if defined(HAVE_SECURITY_PAM_APPL_H) -#include -#elif defined(HAVE_PAM_PAM_APPL_H) -#include -#endif - -#endif /* LINUX */ - -#if defined(HAVE_SECURITY_PAM_MODULES_H) -#include -#elif defined(HAVE_PAM_PAM_MODULES_H) -#include -#endif - -#include "general.h" - -#include "support.h" - -static void ret_data_cleanup(pam_handle_t *pamh, void *data, int error_status) -{ - free(data); -} - -#define AUTH_RETURN \ -do { \ - /* Restore application signal handler */ \ - CatchSignal(SIGPIPE, oldsig_handler); \ - if(ret_data) { \ - *ret_data = retval; \ - pam_set_data(pamh, \ - "smb_setcred_return", \ - (void *)ret_data, \ - ret_data_cleanup); \ - } \ - TALLOC_FREE(frame); \ - return retval; \ -} while (0) - -static int _smb_add_user(pam_handle_t *pamh, unsigned int ctrl, - const char *name, struct samu *sampass, bool exist); - - -/* - * pam_sm_authenticate() authenticates users against the samba password file. - * - * First, obtain the password from the user. Then use a - * routine in 'support.c' to authenticate the user. - */ - -#define _SMB_AUTHTOK "-SMB-PASS" - -int pam_sm_authenticate(pam_handle_t *pamh, int flags, - int argc, const char **argv) -{ - unsigned int ctrl; - int retval, *ret_data = NULL; - struct samu *sampass = NULL; - const char *name; - void (*oldsig_handler)(int) = NULL; - bool found; - TALLOC_CTX *frame = talloc_stackframe(); - - /* Points to memory managed by the PAM library. Do not free. */ - char *p = NULL; - - /* Samba initialization. */ - - ctrl = set_ctrl(pamh, flags, argc, argv); - - /* Get a few bytes so we can pass our return value to - pam_sm_setcred(). */ - ret_data = SMB_MALLOC_P(int); - - /* we need to do this before we call AUTH_RETURN */ - /* Getting into places that might use LDAP -- protect the app - from a SIGPIPE it's not expecting */ - oldsig_handler = CatchSignal(SIGPIPE, SIG_IGN); - - /* get the username */ - retval = pam_get_user( pamh, &name, "Username: " ); - if ( retval != PAM_SUCCESS ) { - if (on( SMB_DEBUG, ctrl )) { - _log_err(pamh, LOG_DEBUG, "auth: could not identify user"); - } - AUTH_RETURN; - } - if (on( SMB_DEBUG, ctrl )) { - _log_err(pamh, LOG_DEBUG, "username [%s] obtained", name ); - } - - if (geteuid() != 0) { - _log_err(pamh, LOG_DEBUG, "Cannot access samba password database, not running as root."); - retval = PAM_AUTHINFO_UNAVAIL; - AUTH_RETURN; - } - - if (!initialize_password_db(True, NULL)) { - _log_err(pamh, LOG_ALERT, "Cannot access samba password database" ); - retval = PAM_AUTHINFO_UNAVAIL; - AUTH_RETURN; - } - - sampass = samu_new( NULL ); - if (!sampass) { - _log_err(pamh, LOG_ALERT, "Cannot talloc a samu struct" ); - retval = nt_status_to_pam(NT_STATUS_NO_MEMORY); - AUTH_RETURN; - } - - found = pdb_getsampwnam( sampass, name ); - - if (on( SMB_MIGRATE, ctrl )) { - retval = _smb_add_user(pamh, ctrl, name, sampass, found); - TALLOC_FREE(sampass); - AUTH_RETURN; - } - - if (!found) { - _log_err(pamh, LOG_ALERT, "Failed to find entry for user %s.", name); - retval = PAM_USER_UNKNOWN; - TALLOC_FREE(sampass); - sampass = NULL; - AUTH_RETURN; - } - - /* if this user does not have a password... */ - - if (_smb_blankpasswd( ctrl, sampass )) { - TALLOC_FREE(sampass); - retval = PAM_SUCCESS; - AUTH_RETURN; - } - - /* get this user's authentication token */ - - retval = _smb_read_password(pamh, ctrl, NULL, "Password: ", NULL, _SMB_AUTHTOK, &p); - if (retval != PAM_SUCCESS ) { - _log_err(pamh,LOG_CRIT, "auth: no password provided for [%s]", name); - TALLOC_FREE(sampass); - AUTH_RETURN; - } - - /* verify the password of this user */ - - retval = _smb_verify_password( pamh, sampass, p, ctrl ); - TALLOC_FREE(sampass); - p = NULL; - AUTH_RETURN; -} - -/* - * This function is for setting samba credentials. If anyone comes up - * with any credentials they think should be set, let me know. - */ - -int pam_sm_setcred(pam_handle_t *pamh, int flags, - int argc, const char **argv) -{ - int retval, *pretval = NULL; - - retval = PAM_SUCCESS; - - _pam_get_data(pamh, "smb_setcred_return", &pretval); - if(pretval) { - retval = *pretval; - SAFE_FREE(pretval); - } - pam_set_data(pamh, "smb_setcred_return", NULL, NULL); - - return retval; -} - -/* Helper function for adding a user to the db. */ -static int _smb_add_user(pam_handle_t *pamh, unsigned int ctrl, - const char *name, struct samu *sampass, bool exist) -{ - char *err_str = NULL; - char *msg_str = NULL; - const char *pass = NULL; - int retval; - TALLOC_CTX *frame = talloc_stackframe(); - - /* Get the authtok; if we don't have one, silently fail. */ - retval = _pam_get_item( pamh, PAM_AUTHTOK, &pass ); - - if (retval != PAM_SUCCESS) { - _log_err(pamh, LOG_ALERT - , "pam_get_item returned error to pam_sm_authenticate" ); - TALLOC_FREE(frame); - return PAM_AUTHTOK_RECOVER_ERR; - } - - /* Add the user to the db if they aren't already there. */ - if (!exist) { - retval = NT_STATUS_IS_OK(local_password_change(name, LOCAL_ADD_USER|LOCAL_SET_PASSWORD, - pass, &err_str, &msg_str)); - if (!retval && err_str) { - make_remark(pamh, ctrl, PAM_ERROR_MSG, err_str ); - } else if (msg_str) { - make_remark(pamh, ctrl, PAM_TEXT_INFO, msg_str ); - } - pass = NULL; - - SAFE_FREE(err_str); - SAFE_FREE(msg_str); - TALLOC_FREE(frame); - return PAM_IGNORE; - } else { - /* mimick 'update encrypted' as long as the 'no pw req' flag is not set */ - if ( pdb_get_acct_ctrl(sampass) & ~ACB_PWNOTREQ ) { - retval = NT_STATUS_IS_OK(local_password_change(name, LOCAL_SET_PASSWORD, - pass, &err_str, &msg_str)); - if (!retval && err_str) { - make_remark(pamh, ctrl, PAM_ERROR_MSG, err_str ); - } else if (msg_str) { - make_remark(pamh, ctrl, PAM_TEXT_INFO, msg_str ); - } - } - } - - SAFE_FREE(err_str); - SAFE_FREE(msg_str); - pass = NULL; - TALLOC_FREE(frame); - return PAM_IGNORE; -} - -/* static module data */ -#ifdef PAM_STATIC -struct pam_module _pam_smbpass_auth_modstruct = { - "pam_smbpass", - pam_sm_authenticate, - pam_sm_setcred, - NULL, - NULL, - NULL, - NULL -}; -#endif diff --git a/source3/pam_smbpass/pam_smb_passwd.c b/source3/pam_smbpass/pam_smb_passwd.c deleted file mode 100644 index 1adebe2..0000000 --- a/source3/pam_smbpass/pam_smb_passwd.c +++ /dev/null @@ -1,365 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Use PAM to update user passwords in the local SAM - Copyright (C) Steve Langasek 1998-2003 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -*/ - -/* indicate the following groups are defined */ -#define PAM_SM_PASSWORD - -#include "includes.h" - -/* This is only used in the Sun implementation. FIXME: we really - want a define here that distinguishes between the Solaris PAM - and others (including FreeBSD). */ - -#ifndef LINUX -#if defined(HAVE_SECURITY_PAM_APPL_H) -#include -#elif defined(HAVE_PAM_PAM_APPL_H) -#include -#endif -#endif - -#if defined(HAVE_SECURITY_PAM_MODULES_H) -#include -#elif defined(HAVE_PAM_PAM_MODULES_H) -#include -#endif - -#include "general.h" - -#include "support.h" - -static int smb_update_db( pam_handle_t *pamh, int ctrl, const char *user, const char *pass_new ) -{ - int retval; - char *err_str = NULL; - char *msg_str = NULL; - - retval = NT_STATUS_IS_OK(local_password_change(user, LOCAL_SET_PASSWORD, pass_new, - &err_str, - &msg_str)); - - if (!retval) { - if (err_str) { - make_remark(pamh, ctrl, PAM_ERROR_MSG, err_str ); - } - - /* FIXME: what value is appropriate here? */ - retval = PAM_AUTHTOK_ERR; - } else { - if (msg_str) { - make_remark(pamh, ctrl, PAM_TEXT_INFO, msg_str ); - } - retval = PAM_SUCCESS; - } - - SAFE_FREE(err_str); - SAFE_FREE(msg_str); - return retval; -} - - -/* data tokens */ - -#define _SMB_OLD_AUTHTOK "-SMB-OLD-PASS" -#define _SMB_NEW_AUTHTOK "-SMB-NEW-PASS" - -/* - * FUNCTION: pam_sm_chauthtok() - * - * This function is called twice by the PAM library, once with - * PAM_PRELIM_CHECK set, and then again with PAM_UPDATE_AUTHTOK set. With - * Linux-PAM, these two passes generally involve first checking the old - * token and then changing the token. This is what we do here. - * - * Having obtained a new password. The function updates the - * SMB_PASSWD_FILE file (normally, $(LIBDIR)/smbpasswd). - */ - -int pam_sm_chauthtok(pam_handle_t *pamh, int flags, - int argc, const char **argv) -{ - unsigned int ctrl; - int retval; - - struct samu *sampass = NULL; - void (*oldsig_handler)(int); - const char *user; - char *pass_old = NULL; - char *pass_new = NULL; - TALLOC_CTX *frame = talloc_stackframe(); - - /* Samba initialization. */ - - ctrl = set_ctrl(pamh, flags, argc, argv); - - /* - * First get the name of a user. No need to do anything if we can't - * determine this. - */ - - retval = pam_get_user( pamh, &user, "Username: " ); - if (retval != PAM_SUCCESS) { - if (on( SMB_DEBUG, ctrl )) { - _log_err(pamh, LOG_DEBUG, "password: could not identify user"); - } - TALLOC_FREE(frame); - return retval; - } - if (on( SMB_DEBUG, ctrl )) { - _log_err(pamh, LOG_DEBUG, "username [%s] obtained", user); - } - - if (geteuid() != 0) { - _log_err(pamh, LOG_DEBUG, "Cannot access samba password database, not running as root."); - TALLOC_FREE(frame); - return PAM_AUTHINFO_UNAVAIL; - } - - /* Getting into places that might use LDAP -- protect the app - from a SIGPIPE it's not expecting */ - oldsig_handler = CatchSignal(SIGPIPE, SIG_IGN); - - if (!initialize_password_db(False, NULL)) { - _log_err(pamh, LOG_ALERT, "Cannot access samba password database" ); - CatchSignal(SIGPIPE, oldsig_handler); - TALLOC_FREE(frame); - return PAM_AUTHINFO_UNAVAIL; - } - - /* obtain user record */ - if ( !(sampass = samu_new( NULL )) ) { - CatchSignal(SIGPIPE, oldsig_handler); - TALLOC_FREE(frame); - return nt_status_to_pam(NT_STATUS_NO_MEMORY); - } - - if (!pdb_getsampwnam(sampass,user)) { - _log_err(pamh, LOG_ALERT, "Failed to find entry for user %s.", user); - CatchSignal(SIGPIPE, oldsig_handler); - TALLOC_FREE(frame); - return PAM_USER_UNKNOWN; - } - if (on( SMB_DEBUG, ctrl )) { - _log_err(pamh, LOG_DEBUG, "Located account for %s", user); - } - - if (flags & PAM_PRELIM_CHECK) { - /* - * obtain and verify the current password (OLDAUTHTOK) for - * the user. - */ - - char *Announce; - - if (_smb_blankpasswd( ctrl, sampass )) { - - TALLOC_FREE(sampass); - CatchSignal(SIGPIPE, oldsig_handler); - TALLOC_FREE(frame); - return PAM_SUCCESS; - } - - /* Password change by root, or for an expired token, doesn't - require authentication. Is this a good choice? */ - if (getuid() != 0 && !(flags & PAM_CHANGE_EXPIRED_AUTHTOK)) { - - /* tell user what is happening */ - if (asprintf(&Announce, "Changing password for %s", user) == -1) { - _log_err(pamh, LOG_CRIT, "password: out of memory"); - TALLOC_FREE(sampass); - CatchSignal(SIGPIPE, oldsig_handler); - TALLOC_FREE(frame); - return PAM_BUF_ERR; - } - - set( SMB__OLD_PASSWD, ctrl ); - retval = _smb_read_password( pamh, ctrl, Announce, "Current SMB password: ", - NULL, _SMB_OLD_AUTHTOK, &pass_old ); - SAFE_FREE( Announce ); - - if (retval != PAM_SUCCESS) { - _log_err(pamh, LOG_NOTICE, - "password - (old) token not obtained"); - TALLOC_FREE(sampass); - CatchSignal(SIGPIPE, oldsig_handler); - TALLOC_FREE(frame); - return retval; - } - - /* verify that this is the password for this user */ - - retval = _smb_verify_password( pamh, sampass, pass_old, ctrl ); - - } else { - pass_old = NULL; - retval = PAM_SUCCESS; /* root doesn't have to */ - } - - pass_old = NULL; - TALLOC_FREE(sampass); - CatchSignal(SIGPIPE, oldsig_handler); - TALLOC_FREE(frame); - return retval; - - } else if (flags & PAM_UPDATE_AUTHTOK) { - - /* - * obtain the proposed password - */ - - /* - * get the old token back. NULL was ok only if root [at this - * point we assume that this has already been enforced on a - * previous call to this function]. - */ - - if (off( SMB_NOT_SET_PASS, ctrl )) { - retval = _pam_get_item( pamh, PAM_OLDAUTHTOK, - &pass_old ); - } else { - retval = _pam_get_data( pamh, _SMB_OLD_AUTHTOK, - &pass_old ); - if (retval == PAM_NO_MODULE_DATA) { - pass_old = NULL; - retval = PAM_SUCCESS; - } - } - - if (retval != PAM_SUCCESS) { - _log_err(pamh, LOG_NOTICE, "password: user not authenticated"); - TALLOC_FREE(sampass); - CatchSignal(SIGPIPE, oldsig_handler); - TALLOC_FREE(frame); - return retval; - } - - /* - * use_authtok is to force the use of a previously entered - * password -- needed for pluggable password strength checking - * or other module stacking - */ - - if (on( SMB_USE_AUTHTOK, ctrl )) { - set( SMB_USE_FIRST_PASS, ctrl ); - } - - retval = _smb_read_password( pamh, ctrl - , NULL - , "Enter new SMB password: " - , "Retype new SMB password: " - , _SMB_NEW_AUTHTOK - , &pass_new ); - - if (retval != PAM_SUCCESS) { - if (on( SMB_DEBUG, ctrl )) { - _log_err(pamh, LOG_ALERT, - "password: new password not obtained"); - } - pass_old = NULL; /* tidy up */ - TALLOC_FREE(sampass); - CatchSignal(SIGPIPE, oldsig_handler); - TALLOC_FREE(frame); - return retval; - } - - /* - * At this point we know who the user is and what they - * propose as their new password. Verify that the new - * password is acceptable. - */ - - if (pass_new[0] == '\0') { /* "\0" password = NULL */ - pass_new = NULL; - } - - retval = _pam_smb_approve_pass(pamh, ctrl, pass_old, pass_new); - - if (retval != PAM_SUCCESS) { - _log_err(pamh, LOG_NOTICE, "new password not acceptable"); - pass_new = pass_old = NULL; /* tidy up */ - TALLOC_FREE(sampass); - CatchSignal(SIGPIPE, oldsig_handler); - TALLOC_FREE(frame); - return retval; - } - - /* - * By reaching here we have approved the passwords and must now - * rebuild the smb password file. - */ - - /* update the password database */ - - retval = smb_update_db(pamh, ctrl, user, pass_new); - if (retval == PAM_SUCCESS) { - uid_t uid; - - /* password updated */ - if (!sid_to_uid(pdb_get_user_sid(sampass), &uid)) { - _log_err(pamh, LOG_NOTICE, - "Unable to get uid for user %s", - pdb_get_username(sampass)); - _log_err(pamh, LOG_NOTICE, "password for (%s) changed by (%s/%d)", - user, uidtoname(getuid()), getuid()); - } else { - _log_err(pamh, LOG_NOTICE, "password for (%s/%d) changed by (%s/%d)", - user, uid, uidtoname(getuid()), getuid()); - } - } else { - _log_err(pamh, LOG_ERR, "password change failed for user %s", user); - } - - pass_old = pass_new = NULL; - if (sampass) { - TALLOC_FREE(sampass); - sampass = NULL; - } - - } else { /* something has broken with the library */ - - _log_err(pamh, LOG_ALERT, "password received unknown request"); - retval = PAM_ABORT; - - } - - if (sampass) { - TALLOC_FREE(sampass); - sampass = NULL; - } - - TALLOC_FREE(sampass); - CatchSignal(SIGPIPE, oldsig_handler); - TALLOC_FREE(frame); - return retval; -} - -/* static module data */ -#ifdef PAM_STATIC -struct pam_module _pam_smbpass_passwd_modstruct = { - "pam_smbpass", - NULL, - NULL, - NULL, - NULL, - NULL, - pam_sm_chauthtok -}; -#endif - diff --git a/source3/pam_smbpass/samples/README b/source3/pam_smbpass/samples/README deleted file mode 100644 index d776033..0000000 --- a/source3/pam_smbpass/samples/README +++ /dev/null @@ -1,3 +0,0 @@ -This directory contains example configurations demonstrating various uses -of pam_smbpass. These examples use Linux-style /etc/pam.d syntax, and -must be modified for use on Solaris systems. diff --git a/source3/pam_smbpass/samples/kdc-pdc b/source3/pam_smbpass/samples/kdc-pdc deleted file mode 100644 index 70f1998..0000000 --- a/source3/pam_smbpass/samples/kdc-pdc +++ /dev/null @@ -1,15 +0,0 @@ -#%PAM-1.0 -# kdc-pdc -# -# A sample PAM configuration that shows pam_smbpass used together with -# pam_krb5. This could be useful on a Samba PDC that is also a member of -# a Kerberos realm. - -auth requisite pam_nologin.so -auth requisite pam_krb5.so -auth optional pam_smbpass.so migrate -account required pam_krb5.so -password requisite pam_cracklib.so retry=3 -password optional pam_smbpass.so nullok use_authtok try_first_pass -password required pam_krb5.so use_authtok try_first_pass -session required pam_krb5.so diff --git a/source3/pam_smbpass/samples/password-mature b/source3/pam_smbpass/samples/password-mature deleted file mode 100644 index 6d73e09..0000000 --- a/source3/pam_smbpass/samples/password-mature +++ /dev/null @@ -1,14 +0,0 @@ -#%PAM-1.0 -# password-mature -# -# A sample PAM configuration for a 'mature' smbpasswd installation. -# private/smbpasswd is fully populated, and we consider it an error if -# the smbpasswd doesn't exist or doesn't match the Unix password. - -auth requisite pam_nologin.so -auth required pam_unix.so -account required pam_unix.so -password requisite pam_cracklib.so retry=3 -password requisite pam_unix.so shadow md5 use_authtok try_first_pass -password required pam_smbpass.so use_authtok use_first_pass -session required pam_unix.so diff --git a/source3/pam_smbpass/samples/password-migration b/source3/pam_smbpass/samples/password-migration deleted file mode 100644 index 305cb53..0000000 --- a/source3/pam_smbpass/samples/password-migration +++ /dev/null @@ -1,18 +0,0 @@ -#%PAM-1.0 -# password-migration -# -# A sample PAM configuration that shows the use of pam_smbpass to migrate -# from plaintext to encrypted passwords for Samba. Unlike other methods, -# this can be used for users who have never connected to Samba shares: -# password migration takes place when users ftp in, login using ssh, pop -# their mail, etc. - -auth requisite pam_nologin.so -# pam_smbpass is called IFF pam_unix succeeds. -auth requisite pam_unix.so -auth optional pam_smbpass.so migrate -account required pam_unix.so -password requisite pam_cracklib.so retry=3 -password requisite pam_unix.so shadow md5 use_authtok try_first_pass -password optional pam_smbpass.so nullok use_authtok try_first_pass -session required pam_unix.so diff --git a/source3/pam_smbpass/samples/password-sync b/source3/pam_smbpass/samples/password-sync deleted file mode 100644 index 0a950dd..0000000 --- a/source3/pam_smbpass/samples/password-sync +++ /dev/null @@ -1,15 +0,0 @@ -#%PAM-1.0 -# password-sync -# -# A sample PAM configuration that shows the use of pam_smbpass to make -# sure private/smbpasswd is kept in sync when /etc/passwd (/etc/shadow) -# is changed. Useful when an expired password might be changed by an -# application (such as ssh). - -auth requisite pam_nologin.so -auth required pam_unix.so -account required pam_unix.so -password requisite pam_cracklib.so retry=3 -password requisite pam_unix.so shadow md5 use_authtok try_first_pass -password required pam_smbpass.so nullok use_authtok try_first_pass -session required pam_unix.so diff --git a/source3/pam_smbpass/support.c b/source3/pam_smbpass/support.c deleted file mode 100644 index c49c2c5..0000000 --- a/source3/pam_smbpass/support.c +++ /dev/null @@ -1,698 +0,0 @@ -/* Unix NT password database implementation, version 0.6. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, see . - */ - -#include "config.h" -#include "includes.h" -#include "general.h" - -#include "support.h" -#include "secrets.h" - -#include "../libcli/auth/libcli_auth.h" -#if defined(HAVE_SECURITY_PAM_EXT_H) -#include -#elif defined(HAVE_PAM_PAM_EXT_H) -#include -#endif - -#if defined(HAVE_SECURITY__PAM_MACROS_H) -#include -#elif defined(HAVE_PAM__PAM_MACROS_H) -#include -#endif - -#ifdef HAVE_SYSLOG_H -#include -#endif - -#define _pam_overwrite(x) \ -do { \ - register char *__xx__; \ - if ((__xx__=(x))) \ - while (*__xx__) \ - *__xx__++ = '\0'; \ -} while (0) - -/* - * Don't just free it, forget it too. - */ - -#define _pam_drop(X) \ -do { \ - if (X) { \ - free(X); \ - X=NULL; \ - } \ -} while (0) - -#define _pam_drop_reply(/* struct pam_response * */ reply, /* int */ replies) \ -do { \ - int reply_i; \ - \ - for (reply_i=0; reply_iconv(nargs, (const struct pam_message **) message - ,response, conv->appdata_ptr); - - if (retval != PAM_SUCCESS && on(SMB_DEBUG, ctrl)) { - _log_err(pamh, LOG_DEBUG, "conversation failure [%s]" - ,pam_strerror(pamh, retval)); - } - } else { - _log_err(pamh, LOG_ERR, "couldn't obtain coversation function [%s]" - ,pam_strerror(pamh, retval)); - } - - return retval; /* propagate error status */ -} - -int make_remark( pam_handle_t * pamh, unsigned int ctrl - , int type, const char *text ) -{ - if (off(SMB__QUIET, ctrl)) { - struct pam_message *pmsg[1], msg[1]; - struct pam_response *resp; - - pmsg[0] = &msg[0]; - msg[0].msg = discard_const_p(char, text); - msg[0].msg_style = type; - resp = NULL; - - return converse(pamh, ctrl, 1, pmsg, &resp); - } - return PAM_SUCCESS; -} - - -/* set the control flags for the SMB module. */ - -unsigned int set_ctrl(pam_handle_t *pamh, - int flags, - int argc, - const char **argv) -{ - int i = 0; - const char *service_file = NULL; - unsigned int ctrl; - bool ok; - - ctrl = SMB_DEFAULTS; /* the default selection of options */ - - /* set some flags manually */ - - /* A good, sane default (matches Samba's behavior). */ - set( SMB__NONULL, ctrl ); - - /* initialize service file location */ - service_file=get_dyn_CONFIGFILE(); - - if (flags & PAM_SILENT) { - set( SMB__QUIET, ctrl ); - } - - /* Run through the arguments once, looking for an alternate smb config - file location */ - while (i < argc) { - int j; - - for (j = 0; j < SMB_CTRLS_; ++j) { - if (smb_args[j].token - && !strncmp(argv[i], smb_args[j].token, strlen(smb_args[j].token))) - { - break; - } - } - - if (j == SMB_CONF_FILE) { - service_file = argv[i] + 8; - } - i++; - } - - /* Read some options from the Samba config. Can be overridden by - the PAM config. */ - if(lp_load_client(service_file) == false) { - _log_err(pamh, LOG_ERR, "Error loading service file %s", service_file); - } - - ok = secrets_init(); - if (!ok) { - _log_err(pamh, LOG_ERR, "Error loading secrets database"); - } - - if (lp_null_passwords()) { - set( SMB__NULLOK, ctrl ); - } - - /* now parse the rest of the arguments to this module */ - - while (argc-- > 0) { - int j; - - for (j = 0; j < SMB_CTRLS_; ++j) { - if (smb_args[j].token - && !strncmp(*argv, smb_args[j].token, strlen(smb_args[j].token))) - { - break; - } - } - - if (j >= SMB_CTRLS_) { - _log_err(pamh, LOG_ERR, "unrecognized option [%s]", *argv); - } else { - ctrl &= smb_args[j].mask; /* for turning things off */ - ctrl |= smb_args[j].flag; /* for turning things on */ - } - - ++argv; /* step to next argument */ - } - - /* auditing is a more sensitive version of debug */ - - if (on( SMB_AUDIT, ctrl )) { - set( SMB_DEBUG, ctrl ); - } - /* return the set of flags */ - - return ctrl; -} - -/* use this to free strings. ESPECIALLY password strings */ - -char * _pam_delete( register char *xx ) -{ - _pam_overwrite( xx ); - _pam_drop( xx ); - return NULL; -} - -void _cleanup( pam_handle_t * pamh, void *x, int error_status ) -{ - x = _pam_delete( (char *) x ); -} - -/* JHT - * - * Safe duplication of character strings. "Paranoid"; don't leave - * evidence of old token around for later stack analysis. - * - */ -char * smbpXstrDup( pam_handle_t *pamh, const char *x ) -{ - register char *newstr = NULL; - - if (x != NULL) { - register int i; - - for (i = 0; x[i]; ++i); /* length of string */ - if ((newstr = SMB_MALLOC_ARRAY(char, ++i)) == NULL) { - i = 0; - _log_err(pamh, LOG_CRIT, "out of memory in smbpXstrDup"); - } else { - while (i-- > 0) { - newstr[i] = x[i]; - } - } - x = NULL; - } - return newstr; /* return the duplicate or NULL on error */ -} - -/* ************************************************************** * - * Useful non-trivial functions * - * ************************************************************** */ - -void _cleanup_failures( pam_handle_t * pamh, void *fl, int err ) -{ - int quiet; - const char *service = NULL; - struct _pam_failed_auth *failure; - -#ifdef PAM_DATA_SILENT - quiet = err & PAM_DATA_SILENT; /* should we log something? */ -#else - quiet = 0; -#endif -#ifdef PAM_DATA_REPLACE - err &= PAM_DATA_REPLACE; /* are we just replacing data? */ -#endif - failure = (struct _pam_failed_auth *) fl; - - if (failure != NULL) { - -#ifdef PAM_DATA_SILENT - if (!quiet && !err) { /* under advisement from Sun,may go away */ -#else - if (!quiet) { /* under advisement from Sun,may go away */ -#endif - - /* log the number of authentication failures */ - if (failure->count != 0) { - _pam_get_item( pamh, PAM_SERVICE, &service ); - _log_err(pamh, LOG_NOTICE - , "%d authentication %s " - "from %s for service %s as %s(%d)" - , failure->count - , failure->count == 1 ? "failure" : "failures" - , failure->agent - , service == NULL ? "**unknown**" : service - , failure->user, failure->id ); - if (failure->count > SMB_MAX_RETRIES) { - _log_err(pamh, LOG_ALERT - , "service(%s) ignoring max retries; %d > %d" - , service == NULL ? "**unknown**" : service - , failure->count - , SMB_MAX_RETRIES ); - } - } - } - _pam_delete( failure->agent ); /* tidy up */ - _pam_delete( failure->user ); /* tidy up */ - SAFE_FREE( failure ); - } -} - -int _smb_verify_password( pam_handle_t * pamh, struct samu *sampass, - const char *p, unsigned int ctrl ) -{ - uchar lm_pw[16]; - uchar nt_pw[16]; - int retval = PAM_AUTH_ERR; - char *data_name; - const char *name; - - if (!sampass) - return PAM_ABORT; - - name = pdb_get_username(sampass); - -#ifdef HAVE_PAM_FAIL_DELAY - if (off( SMB_NODELAY, ctrl )) { - (void) pam_fail_delay( pamh, 1000000 ); /* 1 sec delay for on failure */ - } -#endif - - if (!pdb_get_nt_passwd(sampass)) - { - _log_err(pamh, LOG_DEBUG, "user %s has null SMB password", name); - - if (off( SMB__NONULL, ctrl ) - && (pdb_get_acct_ctrl(sampass) & ACB_PWNOTREQ)) - { /* this means we've succeeded */ - return PAM_SUCCESS; - } else { - const char *service = NULL; - - _pam_get_item( pamh, PAM_SERVICE, &service ); - _log_err(pamh, LOG_NOTICE, "failed auth request by %s for service %s as %s", - uidtoname(getuid()), service ? service : "**unknown**", name); - return PAM_AUTH_ERR; - } - } - - if (asprintf(&data_name, "-SMB-FAIL- %s", name) == -1) { - _log_err(pamh, LOG_CRIT, "no memory for data-name" ); - return PAM_AUTH_ERR; - } - - /* - * The password we were given wasn't an encrypted password, or it - * didn't match the one we have. We encrypt the password now and try - * again. - */ - - nt_lm_owf_gen(p, nt_pw, lm_pw); - - /* the moment of truth -- do we agree with the password? */ - - if (!memcmp( nt_pw, pdb_get_nt_passwd(sampass), 16 )) { - - retval = PAM_SUCCESS; - if (data_name) { /* reset failures */ - pam_set_data(pamh, data_name, NULL, _cleanup_failures); - } - } else { - - const char *service = NULL; - - retval = PAM_AUTH_ERR; - - _pam_get_item( pamh, PAM_SERVICE, &service ); - - if (data_name != NULL) { - struct _pam_failed_auth *newauth = NULL; - const struct _pam_failed_auth *old = NULL; - - /* get a failure recorder */ - - newauth = SMB_MALLOC_P( struct _pam_failed_auth ); - - if (newauth != NULL) { - - /* any previous failures for this user ? */ - _pam_get_data(pamh, data_name, &old); - - if (old != NULL) { - newauth->count = old->count + 1; - if (newauth->count >= SMB_MAX_RETRIES) { - retval = PAM_MAXTRIES; - } - } else { - _log_err(pamh, LOG_NOTICE, - "failed auth request by %s for service %s as %s", - uidtoname(getuid()), - service ? service : "**unknown**", name); - newauth->count = 1; - } - if (!sid_to_uid(pdb_get_user_sid(sampass), &(newauth->id))) { - _log_err(pamh, LOG_NOTICE, - "failed auth request by %s for service %s as %s", - uidtoname(getuid()), - service ? service : "**unknown**", name); - } - newauth->user = smbpXstrDup( pamh, name ); - newauth->agent = smbpXstrDup( pamh, uidtoname( getuid() ) ); - pam_set_data( pamh, data_name, newauth, _cleanup_failures ); - - } else { - _log_err(pamh, LOG_CRIT, "no memory for failure recorder" ); - _log_err(pamh, LOG_NOTICE, - "failed auth request by %s for service %s as %s(%d)", - uidtoname(getuid()), - service ? service : "**unknown**", name); - } - } - _log_err(pamh, LOG_NOTICE, - "failed auth request by %s for service %s as %s(%d)", - uidtoname(getuid()), - service ? service : "**unknown**", name); - } - - _pam_delete( data_name ); - - return retval; -} - - -/* - * _smb_blankpasswd() is a quick check for a blank password - * - * returns TRUE if user does not have a password - * - to avoid prompting for one in such cases (CG) - */ - -int _smb_blankpasswd( unsigned int ctrl, struct samu *sampass ) -{ - int retval; - - /* - * This function does not have to be too smart if something goes - * wrong, return FALSE and let this case to be treated somewhere - * else (CG) - */ - - if (on( SMB__NONULL, ctrl )) - return 0; /* will fail but don't let on yet */ - - if (!(pdb_get_acct_ctrl(sampass) & ACB_PWNOTREQ)) - return 0; - - if (pdb_get_nt_passwd(sampass) == NULL) - retval = 1; - else - retval = 0; - - return retval; -} - -/* - * obtain a password from the user - */ - -int _smb_read_password( pam_handle_t * pamh, unsigned int ctrl, - const char *comment, const char *prompt1, - const char *prompt2, const char *data_name, char **pass ) -{ - int authtok_flag; - int retval; - char *item = NULL; - char *token; - - struct pam_message msg[3], *pmsg[3]; - struct pam_response *resp; - int i, expect; - - - /* make sure nothing inappropriate gets returned */ - - *pass = token = NULL; - - /* which authentication token are we getting? */ - - authtok_flag = on(SMB__OLD_PASSWD, ctrl) ? PAM_OLDAUTHTOK : PAM_AUTHTOK; - - /* should we obtain the password from a PAM item ? */ - - if (on(SMB_TRY_FIRST_PASS, ctrl) || on(SMB_USE_FIRST_PASS, ctrl)) { - retval = _pam_get_item( pamh, authtok_flag, &item ); - if (retval != PAM_SUCCESS) { - /* very strange. */ - _log_err(pamh, LOG_ALERT, - "pam_get_item returned error to smb_read_password"); - return retval; - } else if (item != NULL) { /* we have a password! */ - *pass = item; - item = NULL; - return PAM_SUCCESS; - } else if (on( SMB_USE_FIRST_PASS, ctrl )) { - return PAM_AUTHTOK_RECOVER_ERR; /* didn't work */ - } else if (on( SMB_USE_AUTHTOK, ctrl ) - && off( SMB__OLD_PASSWD, ctrl )) - { - return PAM_AUTHTOK_RECOVER_ERR; - } - } - - /* - * getting here implies we will have to get the password from the - * user directly. - */ - - /* prepare to converse */ - if (comment != NULL && off(SMB__QUIET, ctrl)) { - pmsg[0] = &msg[0]; - msg[0].msg_style = PAM_TEXT_INFO; - msg[0].msg = discard_const_p(char, comment); - i = 1; - } else { - i = 0; - } - - pmsg[i] = &msg[i]; - msg[i].msg_style = PAM_PROMPT_ECHO_OFF; - msg[i++].msg = discard_const_p(char, prompt1); - - if (prompt2 != NULL) { - pmsg[i] = &msg[i]; - msg[i].msg_style = PAM_PROMPT_ECHO_OFF; - msg[i++].msg = discard_const_p(char, prompt2); - expect = 2; - } else - expect = 1; - - resp = NULL; - - retval = converse( pamh, ctrl, i, pmsg, &resp ); - - if (resp != NULL) { - int j = comment ? 1 : 0; - /* interpret the response */ - - if (retval == PAM_SUCCESS) { /* a good conversation */ - - token = smbpXstrDup(pamh, resp[j++].resp); - if (token != NULL) { - if (expect == 2) { - /* verify that password entered correctly */ - if (!resp[j].resp || strcmp( token, resp[j].resp )) { - _pam_delete( token ); - retval = PAM_AUTHTOK_RECOVER_ERR; - make_remark( pamh, ctrl, PAM_ERROR_MSG - , MISTYPED_PASS ); - } - } - } else { - _log_err(pamh, LOG_NOTICE, - "could not recover authentication token"); - } - } - - /* tidy up */ - _pam_drop_reply( resp, expect ); - - } else { - retval = (retval == PAM_SUCCESS) ? PAM_AUTHTOK_RECOVER_ERR : retval; - } - - if (retval != PAM_SUCCESS) { - if (on( SMB_DEBUG, ctrl )) - _log_err(pamh, LOG_DEBUG, "unable to obtain a password"); - return retval; - } - /* 'token' is the entered password */ - - if (off( SMB_NOT_SET_PASS, ctrl )) { - - /* we store this password as an item */ - - retval = pam_set_item( pamh, authtok_flag, (const void *)token ); - _pam_delete( token ); /* clean it up */ - if (retval != PAM_SUCCESS - || (retval = _pam_get_item( pamh, authtok_flag - ,&item )) != PAM_SUCCESS) - { - _log_err(pamh, LOG_CRIT, "error manipulating password"); - return retval; - } - } else { - /* - * then store it as data specific to this module. pam_end() - * will arrange to clean it up. - */ - - retval = pam_set_data( pamh, data_name, (void *) token, _cleanup ); - if (retval != PAM_SUCCESS - || (retval = _pam_get_data( pamh, data_name, &item )) - != PAM_SUCCESS) - { - _log_err(pamh, LOG_CRIT, "error manipulating password data [%s]", - pam_strerror( pamh, retval )); - _pam_delete( token ); - item = NULL; - return retval; - } - token = NULL; /* break link to password */ - } - - *pass = item; - item = NULL; /* break link to password */ - - return PAM_SUCCESS; -} - -int _pam_smb_approve_pass(pam_handle_t * pamh, - unsigned int ctrl, - const char *pass_old, - const char *pass_new ) -{ - - /* Further checks should be handled through module stacking. -SRL */ - if (pass_new == NULL || (pass_old && !strcmp( pass_old, pass_new ))) - { - if (on(SMB_DEBUG, ctrl)) { - _log_err(pamh, LOG_DEBUG, - "passwd: bad authentication token (null or unchanged)"); - } - make_remark( pamh, ctrl, PAM_ERROR_MSG, pass_new == NULL ? - "No password supplied" : "Password unchanged" ); - return PAM_AUTHTOK_ERR; - } - - return PAM_SUCCESS; -} - -/* - * Work around the pam API that has functions with void ** as parameters - * These lead to strict aliasing warnings with gcc. - */ -int _pam_get_item(const pam_handle_t *pamh, - int item_type, - const void *_item) -{ - const void **item = (const void **)_item; - return pam_get_item(pamh, item_type, item); -} - -int _pam_get_data(const pam_handle_t *pamh, - const char *module_data_name, - const void *_data) -{ - const void **data = (const void **)_data; - return pam_get_data(pamh, module_data_name, data); -} diff --git a/source3/pam_smbpass/support.h b/source3/pam_smbpass/support.h deleted file mode 100644 index 832247d..0000000 --- a/source3/pam_smbpass/support.h +++ /dev/null @@ -1,57 +0,0 @@ -/* syslogging function for errors and other information */ -extern void _log_err(pam_handle_t *, int, const char *, ...); - -/* set the control flags for the UNIX module. */ -extern unsigned int set_ctrl(pam_handle_t *, int, int, const char **); - -/* generic function for freeing pam data segments */ -extern void _cleanup(pam_handle_t *, void *, int); - -/* - * Safe duplication of character strings. "Paranoid"; don't leave - * evidence of old token around for later stack analysis. - */ - -extern char *smbpXstrDup(pam_handle_t *,const char *); - -/* ************************************************************** * - * Useful non-trivial functions * - * ************************************************************** */ - -extern void _cleanup_failures(pam_handle_t *, void *, int); - -/* compare 2 strings */ -extern bool strequal(const char *, const char *); - -extern struct smb_passwd * -_my_get_smbpwnam(FILE *, const char *, bool *, bool *, long *); - -extern int _smb_verify_password( pam_handle_t *pamh , struct samu *sampass, - const char *p, unsigned int ctrl ); - -/* - * this function obtains the name of the current user and ensures - * that the PAM_USER item is set to this value - */ - -extern int _smb_get_user(pam_handle_t *, unsigned int, - const char *, const char **); - -/* _smb_blankpasswd() is a quick check for a blank password */ - -extern int _smb_blankpasswd(unsigned int, struct samu *); - - -/* obtain a password from the user */ -extern int _smb_read_password( pam_handle_t *, unsigned int, const char*, - const char *, const char *, const char *, char **); - -extern int _pam_smb_approve_pass(pam_handle_t *, unsigned int, const char *, - const char *); - -int _pam_get_item(const pam_handle_t *pamh, - int item_type, - const void *_item); -int _pam_get_data(const pam_handle_t *pamh, - const char *module_data_name, - const void *_data); diff --git a/source3/pam_smbpass/wscript_build b/source3/pam_smbpass/wscript_build deleted file mode 100644 index a4eaa6c..0000000 --- a/source3/pam_smbpass/wscript_build +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env python - -if bld.CONFIG_SET('WITH_PAM_MODULES'): - bld.SAMBA3_LIBRARY('pamsmbpass', - source='''pam_smb_auth.c - pam_smb_passwd.c - pam_smb_acct.c - support.c''', - allow_warnings=True, - deps='''tdb talloc pam PAM_ERRORS wbclient cap asn1util param pdb - LIBNTLMSSP LIBTSOCKET''', - cflags='-DLOCALEDIR=\"%s/locale\"' % bld.env.DATADIR, - realname='pam_smbpass.so', - install_path='${PAMMODULESDIR}', - enabled=bld.env.with_pam_smbpass - ) diff --git a/source3/wscript_build b/source3/wscript_build index 48fb144..b08ac3e 100755 --- a/source3/wscript_build +++ b/source3/wscript_build @@ -1527,7 +1527,6 @@ bld.RECURSE('librpc') bld.RECURSE('librpc/idl') bld.RECURSE('libsmb') bld.RECURSE('modules') -bld.RECURSE('pam_smbpass') bld.RECURSE('param') bld.RECURSE('passdb') bld.RECURSE('rpc_server') From d643aafe59738890cb8b71e2e865c56ea1fe6539 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Wed, 7 Oct 2015 14:28:32 +0200 Subject: [PATCH 122/136] s3:smbd: remove unused arg oplock_request The use of oplock_request in calculate_open_access_flags() was removed in 196da5925. Signed-off-by: Ralph Boehme Reviewed-by: Jeremy Allison --- source3/smbd/open.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 162e834..ef1505d 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -2354,7 +2354,6 @@ static int disposition_to_open_flags(uint32_t create_disposition) } static int calculate_open_access_flags(uint32_t access_mask, - int oplock_request, uint32_t private_flags) { bool need_write, need_read; @@ -2641,8 +2640,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, * mean the same thing under DOS and Unix. */ - flags = calculate_open_access_flags(access_mask, oplock_request, - private_flags); + flags = calculate_open_access_flags(access_mask, private_flags); /* * Currently we only look at FILE_WRITE_THROUGH for create options. From cd0c2a5eca43cea76491ae0d820414287c234c1a Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Sun, 11 Oct 2015 09:38:18 +0200 Subject: [PATCH 123/136] s3:smbstatus: add stream name to share_entry_forall() Add stream name argument to share_entry_forall machinery so smbstatus can print the stream name of a file. Bug: https://bugzilla.samba.org/show_bug.cgi?id=11550 Signed-off-by: Ralph Boehme Reviewed-by: Jeremy Allison --- source3/locking/proto.h | 3 ++- source3/locking/share_mode_lock.c | 11 ++++++++--- source3/rpc_server/srvsvc/srv_srvsvc_nt.c | 21 +++++++++++++++------ source3/utils/status.c | 6 +++++- 4 files changed, 30 insertions(+), 11 deletions(-) diff --git a/source3/locking/proto.h b/source3/locking/proto.h index 652ec2a..8ff1c7c 100644 --- a/source3/locking/proto.h +++ b/source3/locking/proto.h @@ -202,7 +202,8 @@ int share_mode_forall(int (*fn)(struct file_id fid, const struct share_mode_data *data, void *private_data), void *private_data); -int share_entry_forall(int (*fn)(const struct share_mode_entry *, const char *, +int share_entry_forall(int (*fn)(const struct share_mode_entry *, + const char *, const char *, const char *, void *), void *private_data); bool share_mode_cleanup_disconnected(struct file_id id, diff --git a/source3/locking/share_mode_lock.c b/source3/locking/share_mode_lock.c index 5eedcc5..6273aec 100644 --- a/source3/locking/share_mode_lock.c +++ b/source3/locking/share_mode_lock.c @@ -728,7 +728,9 @@ int share_mode_forall(int (*fn)(struct file_id fid, struct share_entry_forall_state { int (*fn)(const struct share_mode_entry *e, - const char *service_path, const char *base_name, + const char *service_path, + const char *base_name, + const char *stream_name, void *private_data); void *private_data; }; @@ -744,7 +746,9 @@ static int share_entry_traverse_fn(struct file_id fid, int ret; ret = state->fn(&data->share_modes[i], - data->servicepath, data->base_name, + data->servicepath, + data->base_name, + data->stream_name, state->private_data); if (ret != 0) { return ret; @@ -760,7 +764,8 @@ static int share_entry_traverse_fn(struct file_id fid, ********************************************************************/ int share_entry_forall(int (*fn)(const struct share_mode_entry *, - const char *, const char *, void *), + const char *, const char *, + const char *, void *), void *private_data) { struct share_entry_forall_state state = { diff --git a/source3/rpc_server/srvsvc/srv_srvsvc_nt.c b/source3/rpc_server/srvsvc/srv_srvsvc_nt.c index be79e6a..96c022b 100644 --- a/source3/rpc_server/srvsvc/srv_srvsvc_nt.c +++ b/source3/rpc_server/srvsvc/srv_srvsvc_nt.c @@ -80,7 +80,9 @@ struct share_conn_stat { ********************************************************************/ static int enum_file_fn(const struct share_mode_entry *e, - const char *sharepath, const char *fname, + const char *sharepath, + const char *fname, + const char *sname, void *private_data) { struct file_enum_count *fenum = @@ -129,8 +131,9 @@ static int enum_file_fn(const struct share_mode_entry *e, if ( strcmp( fname, "." ) == 0 ) { fullpath = talloc_asprintf(fenum->ctx, "C:%s", sharepath ); } else { - fullpath = talloc_asprintf(fenum->ctx, "C:%s/%s", - sharepath, fname ); + fullpath = talloc_asprintf(fenum->ctx, "C:%s/%s%s", + sharepath, fname, + sname ? sname : ""); } if (!fullpath) { return 0; @@ -829,7 +832,9 @@ static WERROR init_srv_sess_info_0(struct pipes_struct *p, **********************************************************************/ static int count_sess_files_fn(const struct share_mode_entry *e, - const char *sharepath, const char *fname, + const char *sharepath, + const char *fname, + const char *sname, void *data) { struct sess_file_info *info = data; @@ -954,7 +959,9 @@ static WERROR init_srv_sess_info_1(struct pipes_struct *p, ********************************************************************/ static int share_file_fn(const struct share_mode_entry *e, - const char *sharepath, const char *fname, + const char *sharepath, + const char *fname, + const char *sname, void *data) { struct share_file_stat *sfs = data; @@ -2692,7 +2699,9 @@ struct enum_file_close_state { }; static int enum_file_close_fn(const struct share_mode_entry *e, - const char *sharepath, const char *fname, + const char *sharepath, + const char *fname, + const char *sname, void *private_data) { char msg[MSG_SMB_SHARE_MODE_ENTRY_SIZE]; diff --git a/source3/utils/status.c b/source3/utils/status.c index a22d05b..f81ab5f 100644 --- a/source3/utils/status.c +++ b/source3/utils/status.c @@ -117,6 +117,7 @@ static bool Ucrit_addPid( struct server_id pid ) static int print_share_mode(const struct share_mode_entry *e, const char *sharepath, const char *fname, + const char *sname, void *dummy) { static int count; @@ -190,7 +191,10 @@ static int print_share_mode(const struct share_mode_entry *e, d_printf("NONE "); } - d_printf(" %s %s %s",sharepath, fname, time_to_asc((time_t)e->time.tv_sec)); + d_printf(" %s %s%s %s", + sharepath, fname, + sname ? sname : "", + time_to_asc((time_t)e->time.tv_sec)); } return 0; From 0ef9c67b56a0b493ed06f9a64ac2bc2233041aee Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Mon, 12 Oct 2015 12:28:04 +0200 Subject: [PATCH 124/136] s3:locking: initialize lease pointer in share_mode_traverse_fn() Initialize lease pointer to point to the share_mode_data leases array entry at index lease_idx. This fixes a bug in smbstatus where the lease info is not printed. Bug: https://bugzilla.samba.org/show_bug.cgi?id=11549 Signed-off-by: Ralph Boehme Reviewed-by: Jeremy Allison Autobuild-User(master): Jeremy Allison Autobuild-Date(master): Tue Oct 13 01:14:09 CEST 2015 on sn-devel-104 --- source3/locking/share_mode_lock.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/source3/locking/share_mode_lock.c b/source3/locking/share_mode_lock.c index 6273aec..fe105e3 100644 --- a/source3/locking/share_mode_lock.c +++ b/source3/locking/share_mode_lock.c @@ -687,13 +687,17 @@ static int share_mode_traverse_fn(struct db_record *rec, void *_state) DEBUG(1, ("ndr_pull_share_mode_lock failed\n")); return 0; } + + for (i=0; inum_share_modes; i++) { + struct share_mode_entry *entry = &d->share_modes[i]; + entry->stale = false; /* [skip] in idl */ + entry->lease = &d->leases[entry->lease_idx]; + } + if (DEBUGLEVEL > 10) { DEBUG(11, ("parse_share_modes:\n")); NDR_PRINT_DEBUG(share_mode_data, d); } - for (i=0; inum_share_modes; i++) { - d->share_modes[i].stale = false; /* [skip] in idl */ - } ret = state->fn(fid, d, state->private_data); From 258ce91f3175196610b9db98c409749d33123038 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Mon, 12 Oct 2015 15:57:34 +0200 Subject: [PATCH 125/136] lib: Move sys_rw* to lib/util genrand.c will require it soon Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- lib/util/sys_rw.c | 101 +++++++++++++++++++++++ lib/util/sys_rw.h | 36 +++++++++ lib/util/sys_rw_data.c | 117 +++++++++++++++++++++++++++ lib/util/sys_rw_data.h | 34 ++++++++ lib/util/wscript_build | 6 ++ source3/lib/ctdbd_conn.c | 2 +- source3/lib/recvfile.c | 2 +- source3/lib/sys_rw.c | 101 ----------------------- source3/lib/sys_rw.h | 36 --------- source3/lib/sys_rw_data.c | 117 --------------------------- source3/lib/sys_rw_data.h | 34 -------- source3/lib/util.c | 4 +- source3/lib/util_file.c | 2 +- source3/lib/util_sock.c | 4 +- source3/lib/util_transfer_file.c | 2 +- source3/libsmb/unexpected.c | 2 +- source3/modules/vfs_aio_fork.c | 4 +- source3/modules/vfs_aio_linux.c | 2 +- source3/modules/vfs_aio_posix.c | 2 +- source3/modules/vfs_cacheprime.c | 2 +- source3/modules/vfs_default.c | 2 +- source3/modules/vfs_fruit.c | 2 +- source3/modules/vfs_glusterfs.c | 2 +- source3/modules/vfs_preopen.c | 2 +- source3/modules/vfs_smb_traffic_analyzer.c | 2 +- source3/nmbd/asyncdns.c | 2 +- source3/printing/print_cups.c | 2 +- source3/printing/printing.c | 2 +- source3/rpc_server/samr/srv_samr_chgpasswd.c | 2 +- source3/smbd/notify_inotify.c | 2 +- source3/smbd/process.c | 2 +- source3/smbd/reply.c | 2 +- source3/smbd/scavenger.c | 2 +- source3/smbd/smb2_read.c | 2 +- source3/torture/torture.c | 2 +- source3/utils/smbfilter.c | 2 +- source3/winbindd/winbindd_dual.c | 4 +- source3/wscript_build | 5 -- 38 files changed, 326 insertions(+), 325 deletions(-) create mode 100644 lib/util/sys_rw.c create mode 100644 lib/util/sys_rw.h create mode 100644 lib/util/sys_rw_data.c create mode 100644 lib/util/sys_rw_data.h delete mode 100644 source3/lib/sys_rw.c delete mode 100644 source3/lib/sys_rw.h delete mode 100644 source3/lib/sys_rw_data.c delete mode 100644 source3/lib/sys_rw_data.h diff --git a/lib/util/sys_rw.c b/lib/util/sys_rw.c new file mode 100644 index 0000000..f625066 --- /dev/null +++ b/lib/util/sys_rw.c @@ -0,0 +1,101 @@ +/* + * Unix SMB/CIFS implementation. + * Samba system utilities + * Copyright (C) Andrew Tridgell 1992-1998 + * Copyright (C) Jeremy Allison 1998-2005 + * Copyright (C) Timur Bakeyev 2005 + * Copyright (C) Bjoern Jacke 2006-2007 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "replace.h" +#include "system/filesys.h" +#include "lib/util/sys_rw.h" + +/******************************************************************* +A read wrapper that will deal with EINTR/EWOULDBLOCK +********************************************************************/ + +ssize_t sys_read(int fd, void *buf, size_t count) +{ + ssize_t ret; + + do { + ret = read(fd, buf, count); + } while (ret == -1 && (errno == EINTR || errno == EAGAIN || + errno == EWOULDBLOCK)); + + return ret; +} + +/******************************************************************* +A write wrapper that will deal with EINTR/EWOULDBLOCK. +********************************************************************/ + +ssize_t sys_write(int fd, const void *buf, size_t count) +{ + ssize_t ret; + + do { + ret = write(fd, buf, count); + } while (ret == -1 && (errno == EINTR || errno == EAGAIN || + errno == EWOULDBLOCK)); + + return ret; +} + +/******************************************************************* +A writev wrapper that will deal with EINTR. +********************************************************************/ + +ssize_t sys_writev(int fd, const struct iovec *iov, int iovcnt) +{ + ssize_t ret; + + do { + ret = writev(fd, iov, iovcnt); + } while (ret == -1 && (errno == EINTR || errno == EAGAIN || + errno == EWOULDBLOCK)); + + return ret; +} + +/******************************************************************* +A pread wrapper that will deal with EINTR +********************************************************************/ + +ssize_t sys_pread(int fd, void *buf, size_t count, off_t off) +{ + ssize_t ret; + + do { + ret = pread(fd, buf, count, off); + } while (ret == -1 && errno == EINTR); + return ret; +} + +/******************************************************************* +A write wrapper that will deal with EINTR +********************************************************************/ + +ssize_t sys_pwrite(int fd, const void *buf, size_t count, off_t off) +{ + ssize_t ret; + + do { + ret = pwrite(fd, buf, count, off); + } while (ret == -1 && errno == EINTR); + return ret; +} diff --git a/lib/util/sys_rw.h b/lib/util/sys_rw.h new file mode 100644 index 0000000..ee1584e --- /dev/null +++ b/lib/util/sys_rw.h @@ -0,0 +1,36 @@ +/* + * Unix SMB/CIFS implementation. + * Samba system utilities + * Copyright (C) Andrew Tridgell 1992-1998 + * Copyright (C) Jeremy Allison 1998-2005 + * Copyright (C) Timur Bakeyev 2005 + * Copyright (C) Bjoern Jacke 2006-2007 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __LIB_SYS_RW_H__ +#define __LIB_SYS_RW_H__ + +#include + +struct iovec; + +ssize_t sys_read(int fd, void *buf, size_t count); +ssize_t sys_write(int fd, const void *buf, size_t count); +ssize_t sys_writev(int fd, const struct iovec *iov, int iovcnt); +ssize_t sys_pread(int fd, void *buf, size_t count, off_t off); +ssize_t sys_pwrite(int fd, const void *buf, size_t count, off_t off); + +#endif diff --git a/lib/util/sys_rw_data.c b/lib/util/sys_rw_data.c new file mode 100644 index 0000000..de71716 --- /dev/null +++ b/lib/util/sys_rw_data.c @@ -0,0 +1,117 @@ +/* + * Unix SMB/CIFS implementation. + * Samba system utilities + * Copyright (C) Andrew Tridgell 1992-1998 + * Copyright (C) Jeremy Allison 1998-2005 + * Copyright (C) Timur Bakeyev 2005 + * Copyright (C) Bjoern Jacke 2006-2007 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "replace.h" +#include "system/filesys.h" +#include "lib/util/sys_rw_data.h" +#include "lib/util/sys_rw.h" +#include "lib/util/iov_buf.h" + +/**************************************************************************** + Write all data from an iov array + NB. This can be called with a non-socket fd, don't add dependencies + on socket calls. +****************************************************************************/ + +ssize_t write_data_iov(int fd, const struct iovec *orig_iov, int iovcnt) +{ + ssize_t to_send; + ssize_t thistime; + size_t sent; + struct iovec iov_copy[iovcnt]; + struct iovec *iov; + + to_send = iov_buflen(orig_iov, iovcnt); + if (to_send == -1) { + errno = EINVAL; + return -1; + } + + thistime = sys_writev(fd, orig_iov, iovcnt); + if ((thistime <= 0) || (thistime == to_send)) { + return thistime; + } + sent = thistime; + + /* + * We could not send everything in one call. Make a copy of iov that + * we can mess with. + */ + + memcpy(iov_copy, orig_iov, sizeof(struct iovec) * iovcnt); + iov = iov_copy; + + while (sent < to_send) { + bool ok; + + ok = iov_advance(&iov, &iovcnt, thistime); + if (!ok) { + errno = EIO; + return -1; + } + + thistime = sys_writev(fd, iov, iovcnt); + if (thistime <= 0) { + break; + } + sent += thistime; + } + + return sent; +} + +/**************************************************************************** + Write data to a fd. + NB. This can be called with a non-socket fd, don't add dependencies + on socket calls. +****************************************************************************/ + +ssize_t write_data(int fd, const void *buffer, size_t n) +{ + struct iovec iov; + + iov.iov_base = discard_const_p(void, buffer); + iov.iov_len = n; + return write_data_iov(fd, &iov, 1); +} + +/* + * Blocking read n bytes from a fd + */ + +ssize_t read_data(int fd, void *buffer, size_t n) +{ + ssize_t nread; + + nread = 0; + + while (nread < n) { + ssize_t ret; + ret = sys_read(fd, ((char *)buffer) + nread, n - nread); + if (ret <= 0) { + return ret; + } + nread += ret; + } + + return nread; +} diff --git a/lib/util/sys_rw_data.h b/lib/util/sys_rw_data.h new file mode 100644 index 0000000..bda3795 --- /dev/null +++ b/lib/util/sys_rw_data.h @@ -0,0 +1,34 @@ +/* + * Unix SMB/CIFS implementation. + * Samba system utilities + * Copyright (C) Andrew Tridgell 1992-1998 + * Copyright (C) Jeremy Allison 1998-2005 + * Copyright (C) Timur Bakeyev 2005 + * Copyright (C) Bjoern Jacke 2006-2007 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __LIB_SYS_RW_DATA_H__ +#define __LIB_SYS_RW_DATA_H__ + +#include + +struct iovec; + +ssize_t write_data_iov(int fd, const struct iovec *iov, int iovcnt); +ssize_t write_data(int fd, const void *buffer, size_t n); +ssize_t read_data(int fd, void *buffer, size_t n); + +#endif diff --git a/lib/util/wscript_build b/lib/util/wscript_build index e3bf073..2b48685 100755 --- a/lib/util/wscript_build +++ b/lib/util/wscript_build @@ -181,3 +181,9 @@ if not bld.env.SAMBA_UTIL_CORE_ONLY: source='iov_buf.c', local_include=False, private_library=True) + + bld.SAMBA3_LIBRARY('sys_rw', + source='sys_rw.c sys_rw_data.c', + deps='replace iov_buf', + local_include=False, + private_library=True) diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c index 9e598ac..c7c6356 100644 --- a/source3/lib/ctdbd_conn.c +++ b/source3/lib/ctdbd_conn.c @@ -23,7 +23,7 @@ #include "serverid.h" #include "ctdbd_conn.h" #include "system/select.h" -#include "lib/sys_rw_data.h" +#include "lib/util/sys_rw_data.h" #include "lib/util/iov_buf.h" #include "messages.h" diff --git a/source3/lib/recvfile.c b/source3/lib/recvfile.c index 403d5e8..e1eb241 100644 --- a/source3/lib/recvfile.c +++ b/source3/lib/recvfile.c @@ -25,7 +25,7 @@ #include "includes.h" #include "system/filesys.h" -#include "lib/sys_rw.h" +#include "lib/util/sys_rw.h" /* Do this on our own in TRANSFER_BUF_SIZE chunks. * It's safe to make direct syscalls to lseek/write here diff --git a/source3/lib/sys_rw.c b/source3/lib/sys_rw.c deleted file mode 100644 index 6d8f149..0000000 --- a/source3/lib/sys_rw.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * Samba system utilities - * Copyright (C) Andrew Tridgell 1992-1998 - * Copyright (C) Jeremy Allison 1998-2005 - * Copyright (C) Timur Bakeyev 2005 - * Copyright (C) Bjoern Jacke 2006-2007 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "replace.h" -#include "system/filesys.h" -#include "lib/sys_rw.h" - -/******************************************************************* -A read wrapper that will deal with EINTR/EWOULDBLOCK -********************************************************************/ - -ssize_t sys_read(int fd, void *buf, size_t count) -{ - ssize_t ret; - - do { - ret = read(fd, buf, count); - } while (ret == -1 && (errno == EINTR || errno == EAGAIN || - errno == EWOULDBLOCK)); - - return ret; -} - -/******************************************************************* -A write wrapper that will deal with EINTR/EWOULDBLOCK. -********************************************************************/ - -ssize_t sys_write(int fd, const void *buf, size_t count) -{ - ssize_t ret; - - do { - ret = write(fd, buf, count); - } while (ret == -1 && (errno == EINTR || errno == EAGAIN || - errno == EWOULDBLOCK)); - - return ret; -} - -/******************************************************************* -A writev wrapper that will deal with EINTR. -********************************************************************/ - -ssize_t sys_writev(int fd, const struct iovec *iov, int iovcnt) -{ - ssize_t ret; - - do { - ret = writev(fd, iov, iovcnt); - } while (ret == -1 && (errno == EINTR || errno == EAGAIN || - errno == EWOULDBLOCK)); - - return ret; -} - -/******************************************************************* -A pread wrapper that will deal with EINTR -********************************************************************/ - -ssize_t sys_pread(int fd, void *buf, size_t count, off_t off) -{ - ssize_t ret; - - do { - ret = pread(fd, buf, count, off); - } while (ret == -1 && errno == EINTR); - return ret; -} - -/******************************************************************* -A write wrapper that will deal with EINTR -********************************************************************/ - -ssize_t sys_pwrite(int fd, const void *buf, size_t count, off_t off) -{ - ssize_t ret; - - do { - ret = pwrite(fd, buf, count, off); - } while (ret == -1 && errno == EINTR); - return ret; -} diff --git a/source3/lib/sys_rw.h b/source3/lib/sys_rw.h deleted file mode 100644 index ee1584e..0000000 --- a/source3/lib/sys_rw.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * Samba system utilities - * Copyright (C) Andrew Tridgell 1992-1998 - * Copyright (C) Jeremy Allison 1998-2005 - * Copyright (C) Timur Bakeyev 2005 - * Copyright (C) Bjoern Jacke 2006-2007 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef __LIB_SYS_RW_H__ -#define __LIB_SYS_RW_H__ - -#include - -struct iovec; - -ssize_t sys_read(int fd, void *buf, size_t count); -ssize_t sys_write(int fd, const void *buf, size_t count); -ssize_t sys_writev(int fd, const struct iovec *iov, int iovcnt); -ssize_t sys_pread(int fd, void *buf, size_t count, off_t off); -ssize_t sys_pwrite(int fd, const void *buf, size_t count, off_t off); - -#endif diff --git a/source3/lib/sys_rw_data.c b/source3/lib/sys_rw_data.c deleted file mode 100644 index e3f934d..0000000 --- a/source3/lib/sys_rw_data.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * Samba system utilities - * Copyright (C) Andrew Tridgell 1992-1998 - * Copyright (C) Jeremy Allison 1998-2005 - * Copyright (C) Timur Bakeyev 2005 - * Copyright (C) Bjoern Jacke 2006-2007 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "replace.h" -#include "system/filesys.h" -#include "lib/sys_rw_data.h" -#include "lib/sys_rw.h" -#include "lib/util/iov_buf.h" - -/**************************************************************************** - Write all data from an iov array - NB. This can be called with a non-socket fd, don't add dependencies - on socket calls. -****************************************************************************/ - -ssize_t write_data_iov(int fd, const struct iovec *orig_iov, int iovcnt) -{ - ssize_t to_send; - ssize_t thistime; - size_t sent; - struct iovec iov_copy[iovcnt]; - struct iovec *iov; - - to_send = iov_buflen(orig_iov, iovcnt); - if (to_send == -1) { - errno = EINVAL; - return -1; - } - - thistime = sys_writev(fd, orig_iov, iovcnt); - if ((thistime <= 0) || (thistime == to_send)) { - return thistime; - } - sent = thistime; - - /* - * We could not send everything in one call. Make a copy of iov that - * we can mess with. - */ - - memcpy(iov_copy, orig_iov, sizeof(struct iovec) * iovcnt); - iov = iov_copy; - - while (sent < to_send) { - bool ok; - - ok = iov_advance(&iov, &iovcnt, thistime); - if (!ok) { - errno = EIO; - return -1; - } - - thistime = sys_writev(fd, iov, iovcnt); - if (thistime <= 0) { - break; - } - sent += thistime; - } - - return sent; -} - -/**************************************************************************** - Write data to a fd. - NB. This can be called with a non-socket fd, don't add dependencies - on socket calls. -****************************************************************************/ - -ssize_t write_data(int fd, const void *buffer, size_t n) -{ - struct iovec iov; - - iov.iov_base = discard_const_p(void, buffer); - iov.iov_len = n; - return write_data_iov(fd, &iov, 1); -} - -/* - * Blocking read n bytes from a fd - */ - -ssize_t read_data(int fd, void *buffer, size_t n) -{ - ssize_t nread; - - nread = 0; - - while (nread < n) { - ssize_t ret; - ret = sys_read(fd, ((char *)buffer) + nread, n - nread); - if (ret <= 0) { - return ret; - } - nread += ret; - } - - return nread; -} diff --git a/source3/lib/sys_rw_data.h b/source3/lib/sys_rw_data.h deleted file mode 100644 index bda3795..0000000 --- a/source3/lib/sys_rw_data.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * Samba system utilities - * Copyright (C) Andrew Tridgell 1992-1998 - * Copyright (C) Jeremy Allison 1998-2005 - * Copyright (C) Timur Bakeyev 2005 - * Copyright (C) Bjoern Jacke 2006-2007 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef __LIB_SYS_RW_DATA_H__ -#define __LIB_SYS_RW_DATA_H__ - -#include - -struct iovec; - -ssize_t write_data_iov(int fd, const struct iovec *iov, int iovcnt); -ssize_t write_data(int fd, const void *buffer, size_t n); -ssize_t read_data(int fd, void *buffer, size_t n); - -#endif diff --git a/source3/lib/util.c b/source3/lib/util.c index 2ac4dbd..f633575 100644 --- a/source3/lib/util.c +++ b/source3/lib/util.c @@ -30,8 +30,8 @@ #include "messages.h" #include "libcli/security/security.h" #include "serverid.h" -#include "lib/sys_rw.h" -#include "lib/sys_rw_data.h" +#include "lib/util/sys_rw.h" +#include "lib/util/sys_rw_data.h" #include "lib/util/util_process.h" #ifdef HAVE_SYS_PRCTL_H diff --git a/source3/lib/util_file.c b/source3/lib/util_file.c index a603f01..5584d91 100644 --- a/source3/lib/util_file.c +++ b/source3/lib/util_file.c @@ -18,7 +18,7 @@ */ #include "includes.h" -#include "lib/sys_rw.h" +#include "lib/util/sys_rw.h" /** Load from a pipe into memory. diff --git a/source3/lib/util_sock.c b/source3/lib/util_sock.c index cb57f84..2939b4f 100644 --- a/source3/lib/util_sock.c +++ b/source3/lib/util_sock.c @@ -28,8 +28,8 @@ #include "../lib/util/tevent_unix.h" #include "../lib/util/tevent_ntstatus.h" #include "../lib/tsocket/tsocket.h" -#include "lib/sys_rw.h" -#include "lib/sys_rw_data.h" +#include "lib/util/sys_rw.h" +#include "lib/util/sys_rw_data.h" const char *client_addr(int fd, char *addr, size_t addrlen) { diff --git a/source3/lib/util_transfer_file.c b/source3/lib/util_transfer_file.c index 91f4f6f..5653906 100644 --- a/source3/lib/util_transfer_file.c +++ b/source3/lib/util_transfer_file.c @@ -22,7 +22,7 @@ #include #include "transfer_file.h" -#include "lib/sys_rw.h" +#include "lib/util/sys_rw.h" /**************************************************************************** Transfer some data between two fd's. diff --git a/source3/libsmb/unexpected.c b/source3/libsmb/unexpected.c index 013d798..27d21b6 100644 --- a/source3/libsmb/unexpected.c +++ b/source3/libsmb/unexpected.c @@ -22,7 +22,7 @@ #include "../lib/util/tevent_ntstatus.h" #include "lib/tsocket/tsocket.h" #include "libsmb/nmblib.h" -#include "lib/sys_rw.h" +#include "lib/util/sys_rw.h" static const char *nmbd_socket_dir(void) { diff --git a/source3/modules/vfs_aio_fork.c b/source3/modules/vfs_aio_fork.c index 5b398b2e..7fca3d1 100644 --- a/source3/modules/vfs_aio_fork.c +++ b/source3/modules/vfs_aio_fork.c @@ -26,8 +26,8 @@ #include "smbd/globals.h" #include "lib/async_req/async_sock.h" #include "lib/util/tevent_unix.h" -#include "lib/sys_rw.h" -#include "lib/sys_rw_data.h" +#include "lib/util/sys_rw.h" +#include "lib/util/sys_rw_data.h" #include "lib/msghdr.h" #if !defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL) && !defined(HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS) diff --git a/source3/modules/vfs_aio_linux.c b/source3/modules/vfs_aio_linux.c index db5f075..74ebb3c 100644 --- a/source3/modules/vfs_aio_linux.c +++ b/source3/modules/vfs_aio_linux.c @@ -24,7 +24,7 @@ #include "smbd/smbd.h" #include "smbd/globals.h" #include "lib/util/tevent_unix.h" -#include "lib/sys_rw.h" +#include "lib/util/sys_rw.h" #include #include diff --git a/source3/modules/vfs_aio_posix.c b/source3/modules/vfs_aio_posix.c index ef5f706..bca69b4 100644 --- a/source3/modules/vfs_aio_posix.c +++ b/source3/modules/vfs_aio_posix.c @@ -24,7 +24,7 @@ #include "smbd/smbd.h" #include "smbd/globals.h" #include "lib/util/tevent_unix.h" -#include "lib/sys_rw.h" +#include "lib/util/sys_rw.h" #include /* The signal we'll use to signify aio done. */ diff --git a/source3/modules/vfs_cacheprime.c b/source3/modules/vfs_cacheprime.c index e90e09a..cb8b328 100644 --- a/source3/modules/vfs_cacheprime.c +++ b/source3/modules/vfs_cacheprime.c @@ -17,7 +17,7 @@ #include "includes.h" #include "smbd/smbd.h" -#include "lib/sys_rw.h" +#include "lib/util/sys_rw.h" /* Cache priming module. * diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c index 9ea630a..bbe8cca 100644 --- a/source3/modules/vfs_default.c +++ b/source3/modules/vfs_default.c @@ -32,7 +32,7 @@ #include "lib/util/tevent_unix.h" #include "lib/asys/asys.h" #include "lib/util/tevent_ntstatus.h" -#include "lib/sys_rw.h" +#include "lib/util/sys_rw.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_VFS diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index 8393366..25a86c1 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -29,7 +29,7 @@ #include "messages.h" #include "libcli/security/security.h" #include "../libcli/smb/smb2_create_ctx.h" -#include "lib/sys_rw.h" +#include "lib/util/sys_rw.h" #include "lib/util/tevent_ntstatus.h" /* diff --git a/source3/modules/vfs_glusterfs.c b/source3/modules/vfs_glusterfs.c index a66887d..cf8066e 100644 --- a/source3/modules/vfs_glusterfs.c +++ b/source3/modules/vfs_glusterfs.c @@ -43,7 +43,7 @@ #include "lib/util/tevent_unix.h" #include "lib/tevent/tevent_internal.h" #include "smbd/globals.h" -#include "lib/sys_rw.h" +#include "lib/util/sys_rw.h" #define DEFAULT_VOLFILE_SERVER "localhost" diff --git a/source3/modules/vfs_preopen.c b/source3/modules/vfs_preopen.c index c83d312..b67aad8 100644 --- a/source3/modules/vfs_preopen.c +++ b/source3/modules/vfs_preopen.c @@ -21,7 +21,7 @@ #include "includes.h" #include "system/filesys.h" #include "smbd/smbd.h" -#include "lib/sys_rw_data.h" +#include "lib/util/sys_rw_data.h" struct preopen_state; diff --git a/source3/modules/vfs_smb_traffic_analyzer.c b/source3/modules/vfs_smb_traffic_analyzer.c index 0208cde..f5c39ad 100644 --- a/source3/modules/vfs_smb_traffic_analyzer.c +++ b/source3/modules/vfs_smb_traffic_analyzer.c @@ -29,7 +29,7 @@ #include "../librpc/gen_ndr/ndr_netlogon.h" #include "auth.h" #include "../lib/tsocket/tsocket.h" -#include "lib/sys_rw_data.h" +#include "lib/util/sys_rw_data.h" /* abstraction for the send_over_network function */ enum sock_type {INTERNET_SOCKET = 0, UNIX_DOMAIN_SOCKET}; diff --git a/source3/nmbd/asyncdns.c b/source3/nmbd/asyncdns.c index 66e3674..b4532fa 100644 --- a/source3/nmbd/asyncdns.c +++ b/source3/nmbd/asyncdns.c @@ -19,7 +19,7 @@ #include "includes.h" #include "nmbd/nmbd.h" -#include "lib/sys_rw_data.h" +#include "lib/util/sys_rw_data.h" /*************************************************************************** Add a DNS result to the name cache. diff --git a/source3/printing/print_cups.c b/source3/printing/print_cups.c index 110711c..756d67a 100644 --- a/source3/printing/print_cups.c +++ b/source3/printing/print_cups.c @@ -26,7 +26,7 @@ #include "printing.h" #include "printing/pcap.h" #include "librpc/gen_ndr/ndr_printcap.h" -#include "lib/sys_rw.h" +#include "lib/util/sys_rw.h" #ifdef HAVE_CUPS #include diff --git a/source3/printing/printing.c b/source3/printing/printing.c index 4a2ffd1..e7e6c6d 100644 --- a/source3/printing/printing.c +++ b/source3/printing/printing.c @@ -36,7 +36,7 @@ #include "messages.h" #include "util_tdb.h" #include "lib/param/loadparm.h" -#include "lib/sys_rw_data.h" +#include "lib/util/sys_rw_data.h" extern struct current_user current_user; extern userdom_struct current_user_info; diff --git a/source3/rpc_server/samr/srv_samr_chgpasswd.c b/source3/rpc_server/samr/srv_samr_chgpasswd.c index ad710bb..bfb7af6 100644 --- a/source3/rpc_server/samr/srv_samr_chgpasswd.c +++ b/source3/rpc_server/samr/srv_samr_chgpasswd.c @@ -54,7 +54,7 @@ #include "rpc_server/samr/srv_samr_util.h" #include "passdb.h" #include "auth.h" -#include "lib/sys_rw.h" +#include "lib/util/sys_rw.h" #ifndef ALLOW_CHANGE_PASSWORD #if (defined(HAVE_TERMIOS_H) && defined(HAVE_DUP2) && defined(HAVE_SETSID)) diff --git a/source3/smbd/notify_inotify.c b/source3/smbd/notify_inotify.c index 8f47124..78fb654 100644 --- a/source3/smbd/notify_inotify.c +++ b/source3/smbd/notify_inotify.c @@ -24,7 +24,7 @@ #include "includes.h" #include "../librpc/gen_ndr/notify.h" #include "smbd/smbd.h" -#include "lib/sys_rw_data.h" +#include "lib/util/sys_rw_data.h" #include diff --git a/source3/smbd/process.c b/source3/smbd/process.c index b491b31..c99c75e 100644 --- a/source3/smbd/process.c +++ b/source3/smbd/process.c @@ -39,7 +39,7 @@ #include "../libcli/security/dom_sid.h" #include "../libcli/security/security_token.h" #include "lib/id_cache.h" -#include "lib/sys_rw_data.h" +#include "lib/util/sys_rw_data.h" #include "serverid.h" #include "system/threads.h" diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index b1b91e1..bebb789 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -43,7 +43,7 @@ #include "../lib/tsocket/tsocket.h" #include "lib/tevent_wait.h" #include "libcli/smb/smb_signing.h" -#include "lib/sys_rw_data.h" +#include "lib/util/sys_rw_data.h" /**************************************************************************** Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext diff --git a/source3/smbd/scavenger.c b/source3/smbd/scavenger.c index baf71d8..ea0a894 100644 --- a/source3/smbd/scavenger.c +++ b/source3/smbd/scavenger.c @@ -26,7 +26,7 @@ #include "smbd/scavenger.h" #include "locking/proto.h" #include "lib/util/util_process.h" -#include "lib/sys_rw.h" +#include "lib/util/sys_rw.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_SCAVENGER diff --git a/source3/smbd/smb2_read.c b/source3/smbd/smb2_read.c index 03cd54b..89527f3 100644 --- a/source3/smbd/smb2_read.c +++ b/source3/smbd/smb2_read.c @@ -26,7 +26,7 @@ #include "libcli/security/security.h" #include "../lib/util/tevent_ntstatus.h" #include "rpc_server/srv_pipe_hnd.h" -#include "lib/sys_rw_data.h" +#include "lib/util/sys_rw_data.h" static struct tevent_req *smbd_smb2_read_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, diff --git a/source3/torture/torture.c b/source3/torture/torture.c index 914caf8..21d2dd2 100644 --- a/source3/torture/torture.c +++ b/source3/torture/torture.c @@ -41,7 +41,7 @@ #include "util_tdb.h" #include "../libcli/smb/read_smb.h" #include "../libcli/smb/smbXcli_base.h" -#include "lib/sys_rw_data.h" +#include "lib/util/sys_rw_data.h" extern char *optarg; extern int optind; diff --git a/source3/utils/smbfilter.c b/source3/utils/smbfilter.c index 9b871be..9068448 100644 --- a/source3/utils/smbfilter.c +++ b/source3/utils/smbfilter.c @@ -22,7 +22,7 @@ #include "system/select.h" #include "../lib/util/select.h" #include "libsmb/nmblib.h" -#include "lib/sys_rw_data.h" +#include "lib/util/sys_rw_data.h" #define SECURITY_MASK 0 #define SECURITY_SET 0 diff --git a/source3/winbindd/winbindd_dual.c b/source3/winbindd/winbindd_dual.c index 213462e..17a89a7 100644 --- a/source3/winbindd/winbindd_dual.c +++ b/source3/winbindd/winbindd_dual.c @@ -38,8 +38,8 @@ #include "messages.h" #include "../lib/util/tevent_unix.h" #include "lib/param/loadparm.h" -#include "lib/sys_rw.h" -#include "lib/sys_rw_data.h" +#include "lib/util/sys_rw.h" +#include "lib/util/sys_rw_data.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_WINBIND diff --git a/source3/wscript_build b/source3/wscript_build index b08ac3e..be0b7e6 100755 --- a/source3/wscript_build +++ b/source3/wscript_build @@ -247,11 +247,6 @@ bld.SAMBA3_SUBSYSTEM('KRBCLIENT', source='libads/kerberos.c libads/ads_status.c', public_deps='krb5samba k5crypto gssapi LIBTSOCKET CLDAP LIBNMB') -bld.SAMBA3_LIBRARY('sys_rw', - source='lib/sys_rw.c lib/sys_rw_data.c', - deps='replace iov_buf', - private_library=True) - bld.SAMBA3_SUBSYSTEM('samba3util', source='''lib/system.c lib/sendfile.c From 5380f7b63648e505d6da25dc75d2487658998fdb Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 3 Oct 2015 00:27:22 +0200 Subject: [PATCH 126/136] lib: Add a little tool to perftest generate_random_buffer() Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- lib/util/tests/genrandperf.c | 39 +++++++++++++++++++++++++++++++++++++++ lib/util/wscript_build | 6 ++++++ 2 files changed, 45 insertions(+) create mode 100644 lib/util/tests/genrandperf.c diff --git a/lib/util/tests/genrandperf.c b/lib/util/tests/genrandperf.c new file mode 100644 index 0000000..32d19ab --- /dev/null +++ b/lib/util/tests/genrandperf.c @@ -0,0 +1,39 @@ +/* + Unix SMB/CIFS implementation. + local testing of random data routines. + Copyright (C) Volker Lendecke 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "replace.h" +#include "lib/util/genrand.h" + +int main(int argc, const char *argv[]) +{ + int i, num; + uint64_t val; + + if (argc != 2) { + fprintf(stderr, "genrandperf \n"); + exit(1); + } + num = atoi(argv[1]); + + for(i=0; i Date: Fri, 2 Oct 2015 00:27:22 +0200 Subject: [PATCH 127/136] Rely on /dev/urandom This removes quite a bit of code. All reasonable systems have /dev/urandom these days. Linux, Solaris and the BSDs do. In case we find a system without /dev/urandom, we will have to go hunting in other libraries. The main reason for this is speed: On Ubuntu 14.04 doing direct reads from /dev/urandom is 2-3 times faster than our md4 based code. On virtualized FreeBSD 10 the difference is even larger. My first approach was to use fopen/fread. It was even faster, but less than twice as fast. So I thought we could save the additional complexity when having to deal with throwing away buffers when forking and the additional memory footprint per process. With this simple generate_random_buffer it will be easier to adapt new syscalls to get randomness. Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison Autobuild-User(master): Jeremy Allison Autobuild-Date(master): Tue Oct 13 04:25:39 CEST 2015 on sn-devel-104 --- lib/util/genrand.c | 259 +++------------------------------------- lib/util/genrand.h | 11 -- lib/util/tests/genrand.c | 12 -- lib/util/wscript_build | 2 +- source3/lib/util.c | 6 - source3/passdb/secrets.c | 29 ----- source4/param/secrets.c | 53 -------- source4/param/secrets.h | 8 -- source4/smbd/process_standard.c | 6 - source4/smbd/server.c | 6 - 10 files changed, 17 insertions(+), 375 deletions(-) diff --git a/lib/util/genrand.c b/lib/util/genrand.c index 4473433..a775535 100644 --- a/lib/util/genrand.c +++ b/lib/util/genrand.c @@ -21,268 +21,41 @@ #include "replace.h" #include "system/filesys.h" -#include "../lib/crypto/crypto.h" #include "lib/util/genrand.h" +#include "sys_rw_data.h" #include "lib/util/blocking.h" -#include "lib/util/time_basic.h" -#include "lib/util/byteorder.h" - -/** - * @file - * @brief Random number generation - */ - -static unsigned char hash[258]; -static uint32_t counter; - -static bool done_reseed = false; -static unsigned int bytes_since_reseed = 0; static int urand_fd = -1; -static void (*reseed_callback)(void *userdata, int *newseed); -static void *reseed_callback_userdata = NULL; - -/** - Copy any user given reseed data. -**/ - -_PUBLIC_ void set_rand_reseed_callback(void (*fn)(void *, int *), void *userdata) -{ - reseed_callback = fn; - reseed_callback_userdata = userdata; - set_need_random_reseed(); -} - -/** - * Tell the random number generator it needs to reseed. - */ -_PUBLIC_ void set_need_random_reseed(void) +static void open_urandom(void) { - done_reseed = false; - bytes_since_reseed = 0; -} - -static void get_rand_reseed_data(int *reseed_data) -{ - if (reseed_callback) { - reseed_callback(reseed_callback_userdata, reseed_data); - } else { - *reseed_data = 0; - } -} - -/**************************************************************** - Setup the seed. -*****************************************************************/ - -static void seed_random_stream(unsigned char *seedval, size_t seedlen) -{ - unsigned char j = 0; - size_t ind; - - for (ind = 0; ind < 256; ind++) - hash[ind] = (unsigned char)ind; - - for( ind = 0; ind < 256; ind++) { - unsigned char tc; - - j += (hash[ind] + seedval[ind%seedlen]); - - tc = hash[ind]; - hash[ind] = hash[j]; - hash[j] = tc; - } - - hash[256] = 0; - hash[257] = 0; -} - -/**************************************************************** - Get datasize bytes worth of random data. -*****************************************************************/ - -static void get_random_stream(unsigned char *data, size_t datasize) -{ - unsigned char index_i = hash[256]; - unsigned char index_j = hash[257]; - size_t ind; - - for( ind = 0; ind < datasize; ind++) { - unsigned char tc; - unsigned char t; - - index_i++; - index_j += hash[index_i]; - - tc = hash[index_i]; - hash[index_i] = hash[index_j]; - hash[index_j] = tc; - - t = hash[index_i] + hash[index_j]; - data[ind] = hash[t]; - } - - hash[256] = index_i; - hash[257] = index_j; -} - -/**************************************************************** - Get a 16 byte hash from the contents of a file. - - Note that the hash is initialised, because the extra entropy is not - worth the valgrind pain. -*****************************************************************/ - -static void do_filehash(const char *fname, unsigned char *the_hash) -{ - unsigned char buf[1011]; /* deliberate weird size */ - unsigned char tmp_md4[16]; - int fd, n; - - ZERO_STRUCT(tmp_md4); - - fd = open(fname,O_RDONLY,0); - if (fd == -1) + if (urand_fd != -1) { return; - - while ((n = read(fd, (char *)buf, sizeof(buf))) > 0) { - mdfour(tmp_md4, buf, n); - for (n=0;n<16;n++) - the_hash[n] ^= tmp_md4[n]; - } - close(fd); -} - -/************************************************************** - Try and get a good random number seed. Try a number of - different factors. Firstly, try /dev/urandom - use if exists. - - We use /dev/urandom as a read of /dev/random can block if - the entropy pool dries up. This leads clients to timeout - or be very slow on connect. - - If we can't use /dev/urandom then seed the stream random generator - above... -**************************************************************/ - -static int do_reseed(int fd) -{ - unsigned char seed_inbuf[40]; - uint32_t v1, v2; struct timeval tval; pid_t mypid; - int reseed_data = 0; - - if (fd == -1) { - fd = open( "/dev/urandom", O_RDONLY,0); - if (fd != -1) { - smb_set_close_on_exec(fd); - } - } - if (fd != -1 - && (read(fd, seed_inbuf, sizeof(seed_inbuf)) == sizeof(seed_inbuf))) { - seed_random_stream(seed_inbuf, sizeof(seed_inbuf)); - return fd; } - - /* Add in some secret file contents */ - - do_filehash("/etc/shadow", &seed_inbuf[0]); - - /* - * Add the counter, time of day, and pid. - */ - - GetTimeOfDay(&tval); - mypid = getpid(); - v1 = (counter++) + mypid + tval.tv_sec; - v2 = (counter++) * mypid + tval.tv_usec; - - SIVAL(seed_inbuf, 32, v1 ^ IVAL(seed_inbuf, 32)); - SIVAL(seed_inbuf, 36, v2 ^ IVAL(seed_inbuf, 36)); - - /* - * Add any user-given reseed data. - */ - - get_rand_reseed_data(&reseed_data); - if (reseed_data) { - size_t i; - for (i = 0; i < sizeof(seed_inbuf); i++) - seed_inbuf[i] ^= ((char *)(&reseed_data))[i % sizeof(reseed_data)]; + urand_fd = open( "/dev/urandom", O_RDONLY,0); + if (urand_fd == -1) { + abort(); } - - seed_random_stream(seed_inbuf, sizeof(seed_inbuf)); - - return -1; + smb_set_close_on_exec(urand_fd); } -/** - Interface to the (hopefully) good crypto random number generator. - Will use our internal PRNG if more than 40 bytes of random generation - has been requested, otherwise tries to read from /dev/random -**/ _PUBLIC_ void generate_random_buffer(uint8_t *out, int len) { - unsigned char md4_buf[64]; - unsigned char tmp_buf[16]; - unsigned char *p; - - if(!done_reseed) { - bytes_since_reseed += len; - - /* Magic constant to try and avoid reading 40 bytes - * and setting up the PRNG if the app only ever wants - * a few bytes */ - if (bytes_since_reseed < 40) { - if (urand_fd == -1) { - urand_fd = open( "/dev/urandom", O_RDONLY,0); - if (urand_fd != -1) { - smb_set_close_on_exec(urand_fd); - } - } - if(urand_fd != -1 && (read(urand_fd, out, len) == len)) { - return; - } - } - - urand_fd = do_reseed(urand_fd); - done_reseed = true; - } - - /* - * Generate random numbers in chunks of 64 bytes, - * then md4 them & copy to the output buffer. - * This way the raw state of the stream is never externally - * seen. - */ + ssize_t rw_ret; - p = out; - while(len > 0) { - int copy_len = len > 16 ? 16 : len; + open_urandom(); - get_random_stream(md4_buf, sizeof(md4_buf)); - mdfour(tmp_buf, md4_buf, sizeof(md4_buf)); - memcpy(p, tmp_buf, copy_len); - p += copy_len; - len -= copy_len; + rw_ret = read_data(urand_fd, out, len); + if (rw_ret != len) { + abort(); } } -/** - Interface to the (hopefully) good crypto random number generator. - Will always use /dev/urandom if available. -**/ +/* + * Keep generate_secret_buffer in case we ever want to do something + * different + */ _PUBLIC_ void generate_secret_buffer(uint8_t *out, int len) { - if (urand_fd == -1) { - urand_fd = open( "/dev/urandom", O_RDONLY,0); - if (urand_fd != -1) { - smb_set_close_on_exec(urand_fd); - } - } - if(urand_fd != -1 && (read(urand_fd, out, len) == len)) { - return; - } - generate_random_buffer(out, len); } diff --git a/lib/util/genrand.h b/lib/util/genrand.h index 73ca601..ef6bbc6 100644 --- a/lib/util/genrand.h +++ b/lib/util/genrand.h @@ -20,17 +20,6 @@ */ /** - Copy any user given reseed data. -**/ - -void set_rand_reseed_callback(void (*fn)(void *, int *), void *userdata); - -/** - * Tell the random number generator it needs to reseed. - */ -void set_need_random_reseed(void); - -/** Interface to the (hopefully) good crypto random number generator. Will use our internal PRNG if more than 40 bytes of random generation has been requested, otherwise tries to read from /dev/random diff --git a/lib/util/tests/genrand.c b/lib/util/tests/genrand.c index 3d48be0..81c20bc 100644 --- a/lib/util/tests/genrand.c +++ b/lib/util/tests/genrand.c @@ -23,17 +23,6 @@ #include "torture/torture.h" #include "torture/local/proto.h" -static void dummy_reseed(void *userdata, int *d) -{ - *d = 42; -} - -static bool test_reseed_callback(struct torture_context *tctx) -{ - set_rand_reseed_callback(dummy_reseed, NULL); - return true; -} - static bool test_check_password_quality(struct torture_context *tctx) { torture_assert(tctx, !check_password_quality(""), "empty password"); @@ -64,7 +53,6 @@ static bool test_generate_random_str(struct torture_context *tctx) struct torture_suite *torture_local_genrand(TALLOC_CTX *mem_ctx) { struct torture_suite *suite = torture_suite_create(mem_ctx, "genrand"); - torture_suite_add_simple_test(suite, "reseed_callback", test_reseed_callback); torture_suite_add_simple_test(suite, "check_password_quality", test_check_password_quality); torture_suite_add_simple_test(suite, "generate_random_str", test_generate_random_str); return suite; diff --git a/lib/util/wscript_build b/lib/util/wscript_build index 2c4d093..81578a9 100755 --- a/lib/util/wscript_build +++ b/lib/util/wscript_build @@ -84,7 +84,7 @@ if not bld.env.SAMBA_UTIL_CORE_ONLY: bld.SAMBA_LIBRARY('genrand', source='genrand.c', - deps='time-basic socket-blocking LIBCRYPTO', + deps='replace socket-blocking sys_rw', local_include=False, private_library=True) diff --git a/source3/lib/util.c b/source3/lib/util.c index f633575..a0da087 100644 --- a/source3/lib/util.c +++ b/source3/lib/util.c @@ -441,12 +441,6 @@ NTSTATUS reinit_after_fork(struct messaging_context *msg_ctx, reinit_after_fork_pipe[1] = -1; } - /* Reset the state of the random - * number generation system, so - * children do not get the same random - * numbers as each other */ - set_need_random_reseed(); - /* tdb needs special fork handling */ if (tdb_reopen_all(parent_longlived ? 1 : 0) != 0) { DEBUG(0,("tdb_reopen_all failed.\n")); diff --git a/source3/passdb/secrets.c b/source3/passdb/secrets.c index 7071fd9..4372c63 100644 --- a/source3/passdb/secrets.c +++ b/source3/passdb/secrets.c @@ -37,28 +37,10 @@ static struct db_context *db_ctx; -/** - * Use a TDB to store an incrementing random seed. - * - * Initialised to the current pid, the very first time Samba starts, - * and incremented by one each time it is needed. - * - * @note Not called by systems with a working /dev/urandom. - */ -static void get_rand_seed(void *userdata, int *new_seed) -{ - *new_seed = getpid(); - if (db_ctx) { - dbwrap_trans_change_int32_atomic_bystring( - db_ctx, "INFO/random_seed", new_seed, 1); - } -} - /* open up the secrets database with specified private_dir path */ bool secrets_init_path(const char *private_dir) { char *fname = NULL; - unsigned char dummy; TALLOC_CTX *frame; if (db_ctx != NULL) { @@ -86,17 +68,6 @@ bool secrets_init_path(const char *private_dir) return False; } - /** - * Set a reseed function for the crypto random generator - * - * This avoids a problem where systems without /dev/urandom - * could send the same challenge to multiple clients - */ - set_rand_reseed_callback(get_rand_seed, NULL); - - /* Ensure that the reseed is done now, while we are root, etc */ - generate_random_buffer(&dummy, sizeof(dummy)); - TALLOC_FREE(frame); return True; } diff --git a/source4/param/secrets.c b/source4/param/secrets.c index 92e338a..9874088 100644 --- a/source4/param/secrets.c +++ b/source4/param/secrets.c @@ -33,59 +33,6 @@ #include "dsdb/samdb/samdb.h" /** - * Use a TDB to store an incrementing random seed. - * - * Initialised to the current pid, the very first time Samba starts, - * and incremented by one each time it is needed. - * - * @note Not called by systems with a working /dev/urandom. - */ -static void get_rand_seed(struct tdb_wrap *secretsdb, int *new_seed) -{ - *new_seed = getpid(); - if (secretsdb != NULL) { - tdb_change_int32_atomic(secretsdb->tdb, "INFO/random_seed", new_seed, 1); - } -} - -/** - * open up the randseed database and set the random number generator callback - */ -bool randseed_init(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx) -{ - char *fname; - uint8_t dummy; - struct tdb_wrap *tdb; - - fname = lpcfg_private_path(mem_ctx, lp_ctx, "randseed.tdb"); - - tdb = tdb_wrap_open(mem_ctx, fname, - lpcfg_tdb_hash_size(lp_ctx, fname), - lpcfg_tdb_flags(lp_ctx, TDB_DEFAULT), - O_RDWR|O_CREAT, 0600); - - if (!tdb) { - DEBUG(0,("Failed to open %s\n", fname)); - talloc_free(fname); - return false; - } - talloc_free(fname); - - /** - * Set a reseed function for the crypto random generator - * - * This avoids a problem where systems without /dev/urandom - * could send the same challenge to multiple clients - */ - set_rand_reseed_callback((void (*) (void *, int *))get_rand_seed, tdb); - - /* Ensure that the reseed is done now, while we are root, etc */ - generate_random_buffer(&dummy, sizeof(dummy)); - - return true; -} - -/** connect to the secrets ldb */ struct ldb_context *secrets_db_connect(TALLOC_CTX *mem_ctx, diff --git a/source4/param/secrets.h b/source4/param/secrets.h index 1e7849f..015ea12 100644 --- a/source4/param/secrets.h +++ b/source4/param/secrets.h @@ -28,14 +28,6 @@ #define SECRETS_PRINCIPAL_SEARCH "(&(|(realm=%s)(flatname=%s))(servicePrincipalName=%s))" #define SECRETS_LDAP_FILTER "(&(objectclass=ldapSecret)(cn=SAMDB Credentials))" -/** - * Use a TDB to store an incrementing random seed. - * - * Initialised to the current pid, the very first time Samba starts, - * and incremented by one each time it is needed. - * - * @note Not called by systems with a working /dev/urandom. - */ struct loadparm_context; struct tevent_context; struct ldb_message; diff --git a/source4/smbd/process_standard.c b/source4/smbd/process_standard.c index b55a1a7..d223776 100644 --- a/source4/smbd/process_standard.c +++ b/source4/smbd/process_standard.c @@ -277,9 +277,6 @@ static void standard_accept_connection(struct tevent_context *ev, child_pipe[1] = -1; } - /* Ensure that the forked children do not expose identical random streams */ - set_need_random_reseed(); - /* setup the process title */ c = socket_get_peer_addr(sock2, ev); s = socket_get_my_addr(sock2, ev); @@ -356,9 +353,6 @@ static void standard_new_task(struct tevent_context *ev, child_pipe[1] = -1; } - /* Ensure that the forked children do not expose identical random streams */ - set_need_random_reseed(); - setproctitle("task %s server_id[%d]", service_name, (int)pid); /* setup this new task. Cluster ID is PID based for this process model */ diff --git a/source4/smbd/server.c b/source4/smbd/server.c index b0f67c9..cb1a20b 100644 --- a/source4/smbd/server.c +++ b/source4/smbd/server.c @@ -392,12 +392,6 @@ static int binary_smbd_main(const char *binary_name, int argc, const char *argv[ pidfile_create(lpcfg_pid_directory(cmdline_lp_ctx), binary_name); - /* Set up a database to hold a random seed, in case we don't - * have /dev/urandom */ - if (!randseed_init(talloc_autofree_context(), cmdline_lp_ctx)) { - return 1; - } - if (lpcfg_server_role(cmdline_lp_ctx) == ROLE_ACTIVE_DIRECTORY_DC) { if (!open_schannel_session_store(talloc_autofree_context(), cmdline_lp_ctx)) { exit_daemon("Samba cannot open schannel store for secured NETLOGON operations.", EACCES); From 96108058d0d89593ac9f59433213ed2f66663186 Mon Sep 17 00:00:00 2001 From: Thomas Nagy Date: Sat, 3 Oct 2015 22:29:15 +0200 Subject: [PATCH 128/136] build:wafsamba: Enable feature-compatible declaration for Waf 1.8 In Waf 1.8 the declaration is features='c', not features='cc'. These changes prepare the replacement of Waf 1.5 by Waf 1.8 for Samba. Signed-off-by: Thomas Nagy Reviewed-by: David Disseldorp Reviewed-by: Andrew Bartlett --- buildtools/wafsamba/gccdeps.py | 2 +- buildtools/wafsamba/samba_autoconf.py | 2 +- buildtools/wafsamba/samba_conftests.py | 10 +++++----- buildtools/wafsamba/samba_optimisation.py | 6 +++--- buildtools/wafsamba/samba_utils.py | 2 +- buildtools/wafsamba/wafsamba.py | 6 +++--- buildtools/wafsamba/wscript | 2 +- source4/heimdal_build/wscript_build | 10 +++++----- 8 files changed, 20 insertions(+), 20 deletions(-) diff --git a/buildtools/wafsamba/gccdeps.py b/buildtools/wafsamba/gccdeps.py index 2da42e6..47505f0 100644 --- a/buildtools/wafsamba/gccdeps.py +++ b/buildtools/wafsamba/gccdeps.py @@ -14,7 +14,7 @@ preprocessor_flag = '-MD' -@feature('cc') +@feature('c', 'cc') @before('apply_core') def add_mmd_cc(self): if self.env.get_flat('CCFLAGS').find(preprocessor_flag) < 0: diff --git a/buildtools/wafsamba/samba_autoconf.py b/buildtools/wafsamba/samba_autoconf.py index ef34b00..d7273f9 100644 --- a/buildtools/wafsamba/samba_autoconf.py +++ b/buildtools/wafsamba/samba_autoconf.py @@ -569,7 +569,7 @@ def CHECK_LIB(conf, libs, mandatory=False, empty_decl=True, set_target=True, shl (ccflags, ldflags, cpppath) = library_flags(conf, lib) if shlib: - res = conf.check(features='cc cshlib', fragment=fragment, lib=lib, uselib_store=lib, ccflags=ccflags, ldflags=ldflags, uselib=lib.upper()) + res = conf.check(features='c cshlib', fragment=fragment, lib=lib, uselib_store=lib, ccflags=ccflags, ldflags=ldflags, uselib=lib.upper()) else: res = conf.check(lib=lib, uselib_store=lib, ccflags=ccflags, ldflags=ldflags, uselib=lib.upper()) diff --git a/buildtools/wafsamba/samba_conftests.py b/buildtools/wafsamba/samba_conftests.py index fe8c30b..9c0b651 100644 --- a/buildtools/wafsamba/samba_conftests.py +++ b/buildtools/wafsamba/samba_conftests.py @@ -197,7 +197,7 @@ def CHECK_SHLIB_INTRASINC_NAME_FLAGS(conf, msg): return v * 2; } ''' - return conf.check(features='cc cshlib',vnum="1",fragment=snip,msg=msg) + return conf.check(features='c cshlib',vnum="1",fragment=snip,msg=msg) @conf def CHECK_NEED_LC(conf, msg): @@ -227,7 +227,7 @@ def CHECK_NEED_LC(conf, msg): bld.rescan(bld.srcnode) - bld(features='cc cshlib', + bld(features='c cshlib', source='liblctest/liblc1.c', ldflags=conf.env['EXTRA_LDFLAGS'], target='liblc', @@ -262,7 +262,7 @@ def CHECK_SHLIB_W_PYTHON(conf, msg): ldb_module = PyImport_ImportModule("ldb"); return v * 2; }''' - return conf.check(features='cc cshlib',uselib='PYEMBED',fragment=snip,msg=msg) + return conf.check(features='c cshlib',uselib='PYEMBED',fragment=snip,msg=msg) # this one is quite complex, and should probably be broken up # into several parts. I'd quite like to create a set of CHECK_COMPOUND() @@ -306,13 +306,13 @@ def CHECK_LIBRARY_SUPPORT(conf, rpath=False, version_script=False, msg=None): ldflags.append("-Wl,--version-script=%s/vscript" % bld.path.abspath()) Utils.writef(os.path.join(dir,'vscript'), 'TEST_1.0A2 { global: *; };\n') - bld(features='cc cshlib', + bld(features='c cshlib', source='libdir/lib1.c', target='libdir/lib1', ldflags=ldflags, name='lib1') - o = bld(features='cc cprogram', + o = bld(features='c cprogram', source='main.c', target='prog1', uselib_local='lib1') diff --git a/buildtools/wafsamba/samba_optimisation.py b/buildtools/wafsamba/samba_optimisation.py index 43b12a2..9d4fad1 100644 --- a/buildtools/wafsamba/samba_optimisation.py +++ b/buildtools/wafsamba/samba_optimisation.py @@ -11,7 +11,7 @@ from TaskGen import feature, after, before import preproc -@feature('cc', 'cxx') +@feature('c', 'cc', 'cxx') @after('apply_type_vars', 'apply_lib_vars', 'apply_core') def apply_incpaths(self): lst = [] @@ -59,7 +59,7 @@ def apply_incpaths(self): if node: self.env.append_value('INC_PATHS', node) -@feature('cc') +@feature('c', 'cc') @after('apply_incpaths') def apply_obj_vars_cc(self): """after apply_incpaths for INC_PATHS""" @@ -187,7 +187,7 @@ def shared_ancestors(self): return ret TaskGen.task_gen.shared_ancestors = shared_ancestors -@feature('cc', 'cxx') +@feature('c', 'cc', 'cxx') @after('apply_link', 'init_cc', 'init_cxx', 'apply_core') def apply_lib_vars(self): """after apply_link because of 'link_task' diff --git a/buildtools/wafsamba/samba_utils.py b/buildtools/wafsamba/samba_utils.py index 9bbe6ac..e6e7901 100644 --- a/buildtools/wafsamba/samba_utils.py +++ b/buildtools/wafsamba/samba_utils.py @@ -164,7 +164,7 @@ def ADD_COMMAND(opt, name, function): Options.Handler.ADD_COMMAND = ADD_COMMAND -@feature('cc', 'cshlib', 'cprogram') +@feature('c', 'cc', 'cshlib', 'cprogram') @before('apply_core','exec_rule') def process_depends_on(self): '''The new depends_on attribute for build rules diff --git a/buildtools/wafsamba/wafsamba.py b/buildtools/wafsamba/wafsamba.py index 078e411..ef9d430 100644 --- a/buildtools/wafsamba/wafsamba.py +++ b/buildtools/wafsamba/wafsamba.py @@ -243,7 +243,7 @@ def SAMBA_LIBRARY(bld, libname, source, if bld.env['ENABLE_RELRO'] is True: ldflags.extend(TO_LIST('-Wl,-z,relro,-z,now')) - features = 'cc cshlib symlink_lib install_lib' + features = 'c cshlib symlink_lib install_lib' if pyext: features += ' pyext' if pyembed: @@ -354,7 +354,7 @@ def SAMBA_BINARY(bld, binname, source, if not SET_TARGET_TYPE(bld, binname, 'BINARY'): return - features = 'cc cprogram symlink_bin install_bin' + features = 'c cprogram symlink_bin install_bin' if pyembed: features += ' pyembed' @@ -578,7 +578,7 @@ def SAMBA_SUBSYSTEM(bld, modname, source, bld.SET_BUILD_GROUP(group) - features = 'cc' + features = 'c' if pyext: features += ' pyext' if pyembed: diff --git a/buildtools/wafsamba/wscript b/buildtools/wafsamba/wscript index 422b742..aca444b 100755 --- a/buildtools/wafsamba/wscript +++ b/buildtools/wafsamba/wscript @@ -241,7 +241,7 @@ def configure(conf): cc.run = Task.compile_fun_noshell('cc', '${CC} ${CCFLAGS} ${CPPFLAGS} ${_CCINCFLAGS} ${_CCDEFFLAGS} ${CC_SRC_F}${SRC} ${CC_TGT_F}${TGT[0].abspath(env)}')[0] try: try: - conf.check(features='cc testd', fragment='int main() {return 0;}\n', ccflags=['-MD'], mandatory=True, msg='Check for -MD') + conf.check(features='c testd', fragment='int main() {return 0;}\n', ccflags=['-MD'], mandatory=True, msg='Check for -MD') except: pass else: diff --git a/source4/heimdal_build/wscript_build b/source4/heimdal_build/wscript_build index 4f1d895..c733b8f 100644 --- a/source4/heimdal_build/wscript_build +++ b/source4/heimdal_build/wscript_build @@ -69,7 +69,7 @@ def HEIMDAL_ASN1(name, source, t = bld(rule=asn1_rule, ext_out = '.x', - before = 'cc', + before = 'c', update_outputs = True, shell = True, source = source, @@ -123,7 +123,7 @@ def HEIMDAL_ASN1(name, source, includes = to_list(includes) includes.append(os.path.dirname(out_files[0])) - t = bld(features = 'cc', + t = bld(features = 'c', source = cfile, target = name, samba_cflags = CURRENT_CFLAGS(bld, name, ''), @@ -241,7 +241,7 @@ def HEIMDAL_LIBRARY(libname, source, deps, vnum, version_script, includes=''): bundled_name = libname version = "%s_%s" % (Utils.g_module.APPNAME, Utils.g_module.VERSION) - features = 'cc cshlib symlink_lib install_lib' + features = 'c cshlib symlink_lib install_lib' bld.set_group('main') t = bld( @@ -277,7 +277,7 @@ def HEIMDAL_SUBSYSTEM(modname, source, bld.set_group(group) return bld( - features = 'cc', + features = 'c', source = source, target = modname, samba_cflags = CURRENT_CFLAGS(bld, modname, cflags, allow_warnings=True), @@ -306,7 +306,7 @@ def HEIMDAL_BINARY(binname, source, if not SET_TARGET_TYPE(bld, binname, 'BINARY'): return - features = 'cc cprogram symlink_bin install_bin' + features = 'c cprogram symlink_bin install_bin' obj_target = binname + '.objlist' From 65e4829e880f5c4cd548791d462352e39968be1c Mon Sep 17 00:00:00 2001 From: Marc Muehlfeld Date: Mon, 12 Oct 2015 22:49:10 +0200 Subject: [PATCH 129/136] Fixes for server role parameter in smb.conf manpage The manpage says that the value for an AD DC is "ACTIVE DIRECTORY DOMAIN CONTROLLER", not "DOMAIN CONTROLLER", like mentioned in the example. Additinally the correct value for BDC is "CLASSIC BACKUP DOMAIN CONTROLLER" Signed-off-by: Marc Muehlfeld Reviewed-by: Andrew Bartlett Autobuild-User(master): Andrew Bartlett Autobuild-Date(master): Tue Oct 13 09:38:01 CEST 2015 on sn-devel-104 --- docs-xml/smbdotconf/security/serverrole.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs-xml/smbdotconf/security/serverrole.xml b/docs-xml/smbdotconf/security/serverrole.xml index ce3ef13..b46f04b 100644 --- a/docs-xml/smbdotconf/security/serverrole.xml +++ b/docs-xml/smbdotconf/security/serverrole.xml @@ -61,7 +61,7 @@ only one PDC per NetBIOS scope (typcially a broadcast network or clients served by a single WINS server). - SERVER ROLE = NETBIOS BACKUP DOMAIN CONTROLLER + SERVER ROLE = CLASSIC BACKUP DOMAIN CONTROLLER This mode of operation runs a classic Samba backup domain controller, providing domain logon services to Windows and Samba @@ -85,5 +85,5 @@ encrypt passwords AUTO -DOMAIN CONTROLLER +ACTIVE DIRECTORY DOMAIN CONTROLLER From d527ab10940d58337e3972e6bbcf9d26f56b7e0d Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Mon, 12 Oct 2015 16:52:49 +0200 Subject: [PATCH 130/136] ctdbd: Fix a typo Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- ctdb/server/ctdb_recoverd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ctdb/server/ctdb_recoverd.c b/ctdb/server/ctdb_recoverd.c index 1165318..e945d51 100644 --- a/ctdb/server/ctdb_recoverd.c +++ b/ctdb/server/ctdb_recoverd.c @@ -1276,7 +1276,7 @@ static int update_local_flags(struct ctdb_recoverd *rec, struct ctdb_node_map *n } -/* Create a new random generation ip. +/* Create a new random generation id. The generation id can not be the INVALID_GENERATION id */ static uint32_t new_generation(void) From 8eedd5c48b95624eb61ab0b4b332ac35e05a98b7 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Mon, 12 Oct 2015 22:10:51 +0200 Subject: [PATCH 131/136] libdap: Fix a '\0' vs NULL mixup Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- libcli/ldap/ldap_message.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcli/ldap/ldap_message.c b/libcli/ldap/ldap_message.c index 0c664b7..bf83627 100644 --- a/libcli/ldap/ldap_message.c +++ b/libcli/ldap/ldap_message.c @@ -762,7 +762,7 @@ static struct ldb_val **ldap_decode_substring(TALLOC_CTX *mem_ctx, struct ldb_va } chunks[chunk_num]->length = strlen(value); - chunks[chunk_num + 1] = '\0'; + chunks[chunk_num + 1] = NULL; return chunks; } From 826bffc7e6fcb1585833acd0d7822e7b09063b0d Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Tue, 13 Oct 2015 20:34:24 +0200 Subject: [PATCH 132/136] lib: Fix CID 1327227 Uninitialized scalar variable Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- source3/lib/dbwrap/dbwrap_ctdb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source3/lib/dbwrap/dbwrap_ctdb.c b/source3/lib/dbwrap/dbwrap_ctdb.c index e024fe5..9066beb 100644 --- a/source3/lib/dbwrap/dbwrap_ctdb.c +++ b/source3/lib/dbwrap/dbwrap_ctdb.c @@ -852,7 +852,7 @@ static NTSTATUS db_ctdb_store(struct db_record *rec, TDB_DATA data, int flag) static NTSTATUS db_ctdb_send_schedule_for_deletion(struct db_record *rec) { - NTSTATUS status; + NTSTATUS status = NT_STATUS_OK; int ret; struct ctdb_control_schedule_for_deletion *dd; TDB_DATA indata; @@ -888,6 +888,8 @@ static NTSTATUS db_ctdb_send_schedule_for_deletion(struct db_record *rec) "SCHEDULE_FOR_DELETION: %s, cstatus = %d\n", strerror(ret), cstatus)); if (ret != 0) { + status = map_nt_error_from_unix(ret); + } else { status = NT_STATUS_UNSUCCESSFUL; } } From 593bdb97840d9fd29a2eaf04fc265c9dcc66886c Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Tue, 13 Oct 2015 20:40:54 +0200 Subject: [PATCH 133/136] ctdb: Fix CID 1327224 Unbounded source buffer Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- ctdb/tests/src/comm_client_test.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ctdb/tests/src/comm_client_test.c b/ctdb/tests/src/comm_client_test.c index d3f5f9e..e1ebe1c 100644 --- a/ctdb/tests/src/comm_client_test.c +++ b/ctdb/tests/src/comm_client_test.c @@ -157,10 +157,13 @@ static int socket_init(char *sockpath) { struct sockaddr_un addr; int fd, ret; + size_t len; memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; - strcpy(addr.sun_path, sockpath); + + len = strlcpy(addr.sun_path, sockpath, sizeof(addr.sun_path)); + assert(len < sizeof(addr.sun_path)); fd = socket(AF_UNIX, SOCK_STREAM, 0); assert(fd != -1); From 74013aeee38a5c40e8c9c01d2ea46143593840b0 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Tue, 13 Oct 2015 20:42:06 +0200 Subject: [PATCH 134/136] ctdb: Fix CID 1327223 Unbounded source buffer Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison Autobuild-User(master): Jeremy Allison Autobuild-Date(master): Wed Oct 14 05:22:28 CEST 2015 on sn-devel-104 --- ctdb/tests/src/comm_server_test.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ctdb/tests/src/comm_server_test.c b/ctdb/tests/src/comm_server_test.c index fe0fffd..7a7656f 100644 --- a/ctdb/tests/src/comm_server_test.c +++ b/ctdb/tests/src/comm_server_test.c @@ -313,10 +313,13 @@ static int socket_init(char *sockpath) { struct sockaddr_un addr; int fd, ret; + size_t len; memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; - strcpy(addr.sun_path, sockpath); + + len = strlcpy(addr.sun_path, sockpath, sizeof(addr.sun_path)); + assert(len < sizeof(addr.sun_path)); fd = socket(AF_UNIX, SOCK_STREAM, 0); assert(fd != -1); From 880b79addc80486e857174b13e63bc98b13f208c Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Tue, 13 Oct 2015 19:08:00 +0200 Subject: [PATCH 135/136] s3:lib/messages: fix error check in messaging_filtered_read_send() Signed-off-by: Ralph Boehme Reviewed-by: Volker Lendecke Autobuild-User(master): Volker Lendecke Autobuild-Date(master): Wed Oct 14 10:21:09 CEST 2015 on sn-devel-104 --- source3/lib/messages.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source3/lib/messages.c b/source3/lib/messages.c index 03e6097..d059f23 100644 --- a/source3/lib/messages.c +++ b/source3/lib/messages.c @@ -642,7 +642,7 @@ struct tevent_req *messaging_filtered_read_send( state->tevent_handle = messaging_dgm_register_tevent_context( state, ev); - if (tevent_req_nomem(state, req)) { + if (tevent_req_nomem(state->tevent_handle, req)) { return tevent_req_post(req, ev); } From cf89c7f42ef7f2a8954cb3a9920f80ee4fddfb5f Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Wed, 14 Oct 2015 10:09:08 +1100 Subject: [PATCH 136/136] ctdb-tests: Fix CID 1327218-1327221 Signed-off-by: Amitay Isaacs Autobuild-User(master): Volker Lendecke Autobuild-Date(master): Wed Oct 14 13:32:02 CEST 2015 on sn-devel-104 --- ctdb/tests/src/db_hash_test.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ctdb/tests/src/db_hash_test.c b/ctdb/tests/src/db_hash_test.c index e05d116..cc8a689 100644 --- a/ctdb/tests/src/db_hash_test.c +++ b/ctdb/tests/src/db_hash_test.c @@ -27,9 +27,8 @@ static void do_test(enum db_hash_type type) { struct db_hash_context *dh; TALLOC_CTX *mem_ctx = talloc_new(NULL); - TALLOC_CTX *tmp_ctx = talloc_new(NULL); - uint8_t *key = (uint8_t *)talloc_strdup(tmp_ctx, "This is a long key"); - uint8_t *value = (uint8_t *)talloc_strdup(tmp_ctx, "This is a long value"); + uint8_t key[] = "This is a long key"; + uint8_t value[] = "This is a long value"; int ret; ret = db_hash_init(mem_ctx, "foobar", 1024, type, &dh);