summaryrefslogtreecommitdiff
path: root/ctdb
diff options
context:
space:
mode:
authorVolker Lendecke <vl@samba.org>2019-10-08 13:02:41 +0200
committerAmitay Isaacs <amitay@samba.org>2019-10-24 04:06:42 +0000
commit9f41a9fc1ee10a28d379c8fda49ccfd295d66770 (patch)
treeb179d6718204c3251f25444acbfdf22f1a0b152a /ctdb
parent6e8c3ae6e9be38fdd1d1693b93c8629391799b19 (diff)
downloadsamba-9f41a9fc1ee10a28d379c8fda49ccfd295d66770.tar.gz
ctdb: Avoid malloc/memcpy/free in ctdb_ltdb_fetch()
Make use of tdb_parse_record() Signed-off-by: Volker Lendecke <vl@samba.org> Signed-off-by: Amitay Isaacs <amitay@gmail.com>
Diffstat (limited to 'ctdb')
-rw-r--r--ctdb/common/ctdb_ltdb.c103
1 files changed, 72 insertions, 31 deletions
diff --git a/ctdb/common/ctdb_ltdb.c b/ctdb/common/ctdb_ltdb.c
index 73458754def..0b79ab44281 100644
--- a/ctdb/common/ctdb_ltdb.c
+++ b/ctdb/common/ctdb_ltdb.c
@@ -167,55 +167,96 @@ static void ltdb_initial_header(struct ctdb_db_context *ctdb_db,
header->flags = CTDB_REC_FLAG_AUTOMATIC;
}
+struct ctdb_ltdb_fetch_state {
+ struct ctdb_ltdb_header *header;
+ TALLOC_CTX *mem_ctx;
+ TDB_DATA *data;
+ int ret;
+ bool found;
+};
+
+static int ctdb_ltdb_fetch_fn(TDB_DATA key, TDB_DATA data, void *private_data)
+{
+ struct ctdb_ltdb_fetch_state *state = private_data;
+ struct ctdb_ltdb_header *header = state->header;
+ TDB_DATA *dstdata = state->data;
+
+ if (data.dsize < sizeof(*header)) {
+ return 0;
+ }
+
+ state->found = true;
+ memcpy(header, data.dptr, sizeof(*header));
+
+ if (dstdata != NULL) {
+ dstdata->dsize = data.dsize - sizeof(struct ctdb_ltdb_header);
+ dstdata->dptr = talloc_memdup(
+ state->mem_ctx,
+ data.dptr + sizeof(struct ctdb_ltdb_header),
+ dstdata->dsize);
+ if (dstdata->dptr == NULL) {
+ state->ret = -1;
+ }
+ }
+
+ return 0;
+}
/*
fetch a record from the ltdb, separating out the header information
and returning the body of the record. A valid (initial) header is
returned if the record is not present
*/
-int ctdb_ltdb_fetch(struct ctdb_db_context *ctdb_db,
- TDB_DATA key, struct ctdb_ltdb_header *header,
+int ctdb_ltdb_fetch(struct ctdb_db_context *ctdb_db,
+ TDB_DATA key, struct ctdb_ltdb_header *header,
TALLOC_CTX *mem_ctx, TDB_DATA *data)
{
- TDB_DATA rec;
struct ctdb_context *ctdb = ctdb_db->ctdb;
+ struct ctdb_ltdb_fetch_state state = {
+ .header = header,
+ .mem_ctx = mem_ctx,
+ .data = data,
+ .found = false,
+ };
+ int ret;
- rec = tdb_fetch(ctdb_db->ltdb->tdb, key);
- if (rec.dsize < sizeof(*header)) {
- /* return an initial header */
- if (rec.dptr) free(rec.dptr);
- if (ctdb->vnn_map == NULL) {
- /* called from the client */
- ZERO_STRUCTP(data);
- header->dmaster = (uint32_t)-1;
+ ret = tdb_parse_record(
+ ctdb_db->ltdb->tdb, key, ctdb_ltdb_fetch_fn, &state);
+
+ if (ret == -1) {
+ enum TDB_ERROR err = tdb_error(ctdb_db->ltdb->tdb);
+ if (err != TDB_ERR_NOEXIST) {
return -1;
}
- ltdb_initial_header(ctdb_db, key, header);
- if (data) {
- *data = tdb_null;
- }
- if (ctdb_db_persistent(ctdb_db) ||
- header->dmaster == ctdb_db->ctdb->pnn) {
- if (ctdb_ltdb_store(ctdb_db, key, header, tdb_null) != 0) {
- DEBUG(DEBUG_NOTICE,
- (__location__ "failed to store initial header\n"));
- }
- }
+ }
+
+ if (state.ret != 0) {
+ DBG_DEBUG("ctdb_ltdb_fetch_fn failed\n");
+ return state.ret;
+ }
+
+ if (state.found) {
return 0;
}
- *header = *(struct ctdb_ltdb_header *)rec.dptr;
+ if (data != NULL) {
+ *data = tdb_null;
+ }
- if (data) {
- data->dsize = rec.dsize - sizeof(struct ctdb_ltdb_header);
- data->dptr = talloc_memdup(mem_ctx,
- sizeof(struct ctdb_ltdb_header)+rec.dptr,
- data->dsize);
+ if (ctdb->vnn_map == NULL) {
+ /* called from the client */
+ header->dmaster = (uint32_t)-1;
+ return -1;
}
- free(rec.dptr);
- if (data) {
- CTDB_NO_MEMORY(ctdb, data->dptr);
+ ltdb_initial_header(ctdb_db, key, header);
+ if (ctdb_db_persistent(ctdb_db) ||
+ header->dmaster == ctdb_db->ctdb->pnn) {
+
+ ret = ctdb_ltdb_store(ctdb_db, key, header, tdb_null);
+ if (ret != 0) {
+ DBG_NOTICE("failed to store initial header\n");
+ }
}
return 0;