summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVolker Lendecke <vl@samba.org>2023-01-04 12:18:44 +0100
committerJeremy Allison <jra@samba.org>2023-01-10 01:23:38 +0000
commit8ee203467455da0b9f774acbcc44e9b58570d811 (patch)
tree409cc5f41da09f14ae00e3ede56ea4f1954deaa6
parentb73ecb28a7ac5996e1a8c455d15f41f59d9d8765 (diff)
downloadsamba-8ee203467455da0b9f774acbcc44e9b58570d811.tar.gz
smbd: Use an idtree for local IDs
Volatile file handle IDs are purely per-process, in fact we used a dbwrap_rbt for this. To get a unique ID we however have the specialized idtree data structure, we don't need to repeat the allocation algorithm that already exists there. Signed-off-by: Volker Lendecke <vl@samba.org> Reviewed-by: Jeremy Allison <jra@samba.org> Autobuild-User(master): Jeremy Allison <jra@samba.org> Autobuild-Date(master): Tue Jan 10 01:23:38 UTC 2023 on sn-devel-184
-rw-r--r--source3/smbd/smbXsrv_open.c370
1 files changed, 44 insertions, 326 deletions
diff --git a/source3/smbd/smbXsrv_open.c b/source3/smbd/smbXsrv_open.c
index 9c446a95499..c67556545be 100644
--- a/source3/smbd/smbXsrv_open.c
+++ b/source3/smbd/smbXsrv_open.c
@@ -33,10 +33,11 @@
#include "librpc/gen_ndr/ndr_smbXsrv.h"
#include "serverid.h"
#include "source3/include/util_tdb.h"
+#include "lib/util/idtree_random.h"
struct smbXsrv_open_table {
struct {
- struct db_context *db_ctx;
+ struct idr_context *idr;
struct db_context *replay_cache_db_ctx;
uint32_t lowest_id;
uint32_t highest_id;
@@ -124,35 +125,6 @@ static NTSTATUS smbXsrv_open_global_key_to_id(TDB_DATA key, uint32_t *id)
}
#endif
-#define SMBXSRV_OPEN_LOCAL_TDB_KEY_SIZE sizeof(uint32_t)
-
-static TDB_DATA smbXsrv_open_local_id_to_key(uint32_t id,
- uint8_t *key_buf)
-{
- TDB_DATA key;
-
- RSIVAL(key_buf, 0, id);
-
- key = make_tdb_data(key_buf, SMBXSRV_OPEN_LOCAL_TDB_KEY_SIZE);
-
- return key;
-}
-
-static NTSTATUS smbXsrv_open_local_key_to_id(TDB_DATA key, uint32_t *id)
-{
- if (id == NULL) {
- return NT_STATUS_INVALID_PARAMETER;
- }
-
- if (key.dsize != SMBXSRV_OPEN_LOCAL_TDB_KEY_SIZE) {
- return NT_STATUS_INTERNAL_DB_CORRUPTION;
- }
-
- *id = RIVAL(key.dptr, 0);
-
- return NT_STATUS_OK;
-}
-
static struct db_record *smbXsrv_open_global_fetch_locked(
struct db_context *db,
uint32_t id,
@@ -174,27 +146,6 @@ static struct db_record *smbXsrv_open_global_fetch_locked(
return rec;
}
-static struct db_record *smbXsrv_open_local_fetch_locked(
- struct db_context *db,
- uint32_t id,
- TALLOC_CTX *mem_ctx)
-{
- TDB_DATA key;
- uint8_t key_buf[SMBXSRV_OPEN_LOCAL_TDB_KEY_SIZE];
- struct db_record *rec = NULL;
-
- key = smbXsrv_open_local_id_to_key(id, key_buf);
-
- rec = dbwrap_fetch_locked(db, mem_ctx, key);
-
- if (rec == NULL) {
- DBG_DEBUG("Failed to lock local id 0x%08x, key '%s'\n", id,
- tdb_data_dbg(key));
- }
-
- return rec;
-}
-
static NTSTATUS smbXsrv_open_table_init(struct smbXsrv_connection *conn,
uint32_t lowest_id,
uint32_t highest_id,
@@ -222,8 +173,8 @@ static NTSTATUS smbXsrv_open_table_init(struct smbXsrv_connection *conn,
return NT_STATUS_NO_MEMORY;
}
- table->local.db_ctx = db_open_rbt(table);
- if (table->local.db_ctx == NULL) {
+ table->local.idr = idr_init(table);
+ if (table->local.idr == NULL) {
TALLOC_FREE(table);
return NT_STATUS_NO_MEMORY;
}
@@ -248,204 +199,13 @@ static NTSTATUS smbXsrv_open_table_init(struct smbXsrv_connection *conn,
return NT_STATUS_OK;
}
-struct smbXsrv_open_local_allocate_state {
- const uint32_t lowest_id;
- const uint32_t highest_id;
- uint32_t last_id;
- uint32_t useable_id;
- NTSTATUS status;
-};
-
-static int smbXsrv_open_local_allocate_traverse(struct db_record *rec,
- void *private_data)
-{
- struct smbXsrv_open_local_allocate_state *state =
- (struct smbXsrv_open_local_allocate_state *)private_data;
- TDB_DATA key = dbwrap_record_get_key(rec);
- uint32_t id = 0;
- NTSTATUS status;
-
- status = smbXsrv_open_local_key_to_id(key, &id);
- if (!NT_STATUS_IS_OK(status)) {
- state->status = status;
- return -1;
- }
-
- if (id <= state->last_id) {
- state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
- return -1;
- }
- state->last_id = id;
-
- if (id > state->useable_id) {
- state->status = NT_STATUS_OK;
- return -1;
- }
-
- if (state->useable_id == state->highest_id) {
- state->status = NT_STATUS_INSUFFICIENT_RESOURCES;
- return -1;
- }
-
- state->useable_id +=1;
- return 0;
-}
-
-static NTSTATUS smbXsrv_open_local_allocate_id(struct db_context *db,
- uint32_t lowest_id,
- uint32_t highest_id,
- TALLOC_CTX *mem_ctx,
- struct db_record **_rec,
- uint32_t *_id)
-{
- struct smbXsrv_open_local_allocate_state state = {
- .lowest_id = lowest_id,
- .highest_id = highest_id,
- .last_id = 0,
- .useable_id = lowest_id,
- .status = NT_STATUS_INTERNAL_ERROR,
- };
- uint32_t i;
- uint32_t range;
- NTSTATUS status;
- int count = 0;
-
- *_rec = NULL;
- *_id = 0;
-
- if (lowest_id > highest_id) {
- return NT_STATUS_INSUFFICIENT_RESOURCES;
- }
-
- /*
- * first we try randomly
- */
- range = (highest_id - lowest_id) + 1;
-
- for (i = 0; i < (range / 2); i++) {
- uint32_t id;
- TDB_DATA val;
- struct db_record *rec = NULL;
-
- id = generate_random() % range;
- id += lowest_id;
-
- if (id < lowest_id) {
- id = lowest_id;
- }
- if (id > highest_id) {
- id = highest_id;
- }
-
- rec = smbXsrv_open_local_fetch_locked(db, id, mem_ctx);
- if (rec == NULL) {
- return NT_STATUS_INSUFFICIENT_RESOURCES;
- }
-
- val = dbwrap_record_get_value(rec);
- if (val.dsize != 0) {
- TALLOC_FREE(rec);
- continue;
- }
-
- *_rec = rec;
- *_id = id;
- return NT_STATUS_OK;
- }
-
- /*
- * if the range is almost full,
- * we traverse the whole table
- * (this relies on sorted behavior of dbwrap_rbt)
- */
- status = dbwrap_traverse_read(db, smbXsrv_open_local_allocate_traverse,
- &state, &count);
- if (NT_STATUS_IS_OK(status)) {
- if (NT_STATUS_IS_OK(state.status)) {
- return NT_STATUS_INTERNAL_ERROR;
- }
-
- if (!NT_STATUS_EQUAL(state.status, NT_STATUS_INTERNAL_ERROR)) {
- return state.status;
- }
-
- if (state.useable_id <= state.highest_id) {
- state.status = NT_STATUS_OK;
- } else {
- return NT_STATUS_INSUFFICIENT_RESOURCES;
- }
- } else if (!NT_STATUS_EQUAL(status, NT_STATUS_INTERNAL_DB_CORRUPTION)) {
- /*
- * Here we really expect NT_STATUS_INTERNAL_DB_CORRUPTION!
- *
- * If we get anything else it is an error, because it
- * means we did not manage to find a free slot in
- * the db.
- */
- return NT_STATUS_INSUFFICIENT_RESOURCES;
- }
-
- if (NT_STATUS_IS_OK(state.status)) {
- uint32_t id;
- TDB_DATA val;
- struct db_record *rec = NULL;
-
- id = state.useable_id;
-
- rec = smbXsrv_open_local_fetch_locked(db, id, mem_ctx);
- if (rec == NULL) {
- return NT_STATUS_INSUFFICIENT_RESOURCES;
- }
-
- val = dbwrap_record_get_value(rec);
- if (val.dsize != 0) {
- TALLOC_FREE(rec);
- return NT_STATUS_INTERNAL_DB_CORRUPTION;
- }
-
- *_rec = rec;
- *_id = id;
- return NT_STATUS_OK;
- }
-
- return state.status;
-}
-
-struct smbXsrv_open_local_fetch_state {
- struct smbXsrv_open *op;
- NTSTATUS status;
-};
-
-static void smbXsrv_open_local_fetch_parser(TDB_DATA key, TDB_DATA data,
- void *private_data)
-{
- struct smbXsrv_open_local_fetch_state *state =
- (struct smbXsrv_open_local_fetch_state *)private_data;
- void *ptr;
-
- if (data.dsize != sizeof(ptr)) {
- state->status = NT_STATUS_INTERNAL_DB_ERROR;
- return;
- }
-
- memcpy(&ptr, data.dptr, data.dsize);
- state->op = talloc_get_type_abort(ptr, struct smbXsrv_open);
- state->status = NT_STATUS_OK;
-}
-
static NTSTATUS smbXsrv_open_local_lookup(struct smbXsrv_open_table *table,
uint32_t open_local_id,
uint32_t open_global_id,
NTTIME now,
struct smbXsrv_open **_open)
{
- struct smbXsrv_open_local_fetch_state state = {
- .op = NULL,
- .status = NT_STATUS_INTERNAL_ERROR,
- };
- uint8_t key_buf[SMBXSRV_OPEN_LOCAL_TDB_KEY_SIZE];
- TDB_DATA key;
- NTSTATUS status;
+ struct smbXsrv_open *op = NULL;
*_open = NULL;
@@ -458,44 +218,30 @@ static NTSTATUS smbXsrv_open_local_lookup(struct smbXsrv_open_table *table,
return NT_STATUS_FILE_CLOSED;
}
- if (table->local.db_ctx == NULL) {
+ if (table->local.idr == NULL) {
return NT_STATUS_INTERNAL_ERROR;
}
- key = smbXsrv_open_local_id_to_key(open_local_id, key_buf);
-
- status = dbwrap_parse_record(table->local.db_ctx, key,
- smbXsrv_open_local_fetch_parser,
- &state);
- if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
- return NT_STATUS_FILE_CLOSED;
- }
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
- if (!NT_STATUS_IS_OK(state.status)) {
- return state.status;
- }
-
- if (NT_STATUS_EQUAL(state.op->status, NT_STATUS_FILE_CLOSED)) {
+ op = idr_find(table->local.idr, open_local_id);
+ if (op == NULL) {
return NT_STATUS_FILE_CLOSED;
}
if (open_global_id == 0) {
/* make the global check a no-op for SMB1 */
- open_global_id = state.op->global->open_global_id;
+ open_global_id = op->global->open_global_id;
}
- if (state.op->global->open_global_id != open_global_id) {
+ if (op->global->open_global_id != open_global_id) {
return NT_STATUS_FILE_CLOSED;
}
if (now != 0) {
- state.op->idle_time = now;
+ op->idle_time = now;
}
- *_open = state.op;
- return state.op->status;
+ *_open = op;
+ return NT_STATUS_OK;
}
static int smbXsrv_open_global_destructor(struct smbXsrv_open_global0 *global)
@@ -817,14 +563,12 @@ NTSTATUS smbXsrv_open_create(struct smbXsrv_connection *conn,
struct smbXsrv_open **_open)
{
struct smbXsrv_open_table *table = conn->client->open_table;
- struct db_record *local_rec = NULL;
struct smbXsrv_open *op = NULL;
- void *ptr = NULL;
- TDB_DATA val;
struct smbXsrv_open_global0 *global = NULL;
NTSTATUS status;
struct dom_sid *current_sid = NULL;
struct security_token *current_token = NULL;
+ int local_id;
if (session_info == NULL) {
return NT_STATUS_INVALID_HANDLE;
@@ -863,16 +607,16 @@ NTSTATUS smbXsrv_open_create(struct smbXsrv_connection *conn,
}
op->global = global;
- status = smbXsrv_open_local_allocate_id(table->local.db_ctx,
- table->local.lowest_id,
- table->local.highest_id,
- op,
- &local_rec,
- &op->local_id);
- if (!NT_STATUS_IS_OK(status)) {
+ local_id = idr_get_new_random(
+ table->local.idr,
+ op,
+ table->local.lowest_id,
+ table->local.highest_id);
+ if (local_id == -1) {
TALLOC_FREE(op);
- return status;
+ return NT_STATUS_INSUFFICIENT_RESOURCES;
}
+ op->local_id = local_id;
global->open_persistent_id = global->open_global_id;
global->open_volatile_id = op->local_id;
@@ -884,14 +628,6 @@ NTSTATUS smbXsrv_open_create(struct smbXsrv_connection *conn,
global->client_guid = conn->smb2.client.guid;
}
- ptr = op;
- val = make_tdb_data((uint8_t const *)&ptr, sizeof(ptr));
- status = dbwrap_record_store(local_rec, val, TDB_REPLACE);
- TALLOC_FREE(local_rec);
- if (!NT_STATUS_IS_OK(status)) {
- TALLOC_FREE(op);
- return status;
- }
table->local.num_opens += 1;
talloc_set_destructor(op, smbXsrv_open_destructor);
@@ -1077,10 +813,10 @@ NTSTATUS smbXsrv_open_update(struct smbXsrv_open *op)
NTSTATUS smbXsrv_open_close(struct smbXsrv_open *op, NTTIME now)
{
struct smbXsrv_open_table *table;
- struct db_record *local_rec = NULL;
struct db_record *global_rec = NULL;
NTSTATUS status;
NTSTATUS error = NT_STATUS_OK;
+ int ret;
error = smbXsrv_open_clear_replay_cache(op);
if (!NT_STATUS_IS_OK(error)) {
@@ -1161,28 +897,11 @@ NTSTATUS smbXsrv_open_close(struct smbXsrv_open *op, NTTIME now)
}
TALLOC_FREE(global_rec);
- local_rec = smbXsrv_open_local_fetch_locked(table->local.db_ctx,
- op->local_id,
- op /* TALLOC_CTX*/);
- if (local_rec == NULL) {
- error = NT_STATUS_INTERNAL_ERROR;
- }
-
- status = dbwrap_record_delete(local_rec);
- if (!NT_STATUS_IS_OK(status)) {
- TDB_DATA key = dbwrap_record_get_key(local_rec);
+ ret = idr_remove(table->local.idr, op->local_id);
+ SMB_ASSERT(ret == 0);
- DEBUG(0, ("smbXsrv_open_close(0x%08x): "
- "failed to delete local key '%s': %s\n",
- op->global->open_global_id,
- tdb_data_dbg(key),
- nt_errstr(status)));
- error = status;
- }
table->local.num_opens -= 1;
- TALLOC_FREE(local_rec);
-
if (op->compat) {
op->compat->op = NULL;
file_free(NULL, op->compat);
@@ -1224,6 +943,7 @@ NTSTATUS smb1srv_open_lookup(struct smbXsrv_connection *conn,
NTSTATUS smb2srv_open_table_init(struct smbXsrv_connection *conn)
{
uint32_t max_opens;
+ uint32_t highest_id;
/*
* Allow a range from 1..4294967294.
@@ -1241,7 +961,14 @@ NTSTATUS smb2srv_open_table_init(struct smbXsrv_connection *conn)
max_opens = conn->client->sconn->real_max_open_files;
max_opens = MIN(max_opens, UINT16_MAX - 1);
- return smbXsrv_open_table_init(conn, 1, UINT32_MAX - 1, max_opens);
+ /*
+ * idtree uses "int" for local IDs. Limit the maximum ID to
+ * what "int" can hold.
+ */
+ highest_id = UINT32_MAX-1;
+ highest_id = MIN(highest_id, INT_MAX);
+
+ return smbXsrv_open_table_init(conn, 1, highest_id, max_opens);
}
NTSTATUS smb2srv_open_lookup(struct smbXsrv_connection *conn,
@@ -1483,14 +1210,12 @@ NTSTATUS smb2srv_open_recreate(struct smbXsrv_connection *conn,
struct smbXsrv_open **_open)
{
struct smbXsrv_open_table *table = conn->client->open_table;
- struct db_record *local_rec = NULL;
struct smbXsrv_open *op = NULL;
- void *ptr = NULL;
- TDB_DATA val;
uint32_t global_id = persistent_id & UINT32_MAX;
uint64_t global_zeros = persistent_id & 0xFFFFFFFF00000000LLU;
NTSTATUS status;
struct security_token *current_token = NULL;
+ int local_id;
if (session_info == NULL) {
DEBUG(10, ("session_info=NULL\n"));
@@ -1550,31 +1275,24 @@ NTSTATUS smb2srv_open_recreate(struct smbXsrv_connection *conn,
return NT_STATUS_INSUFFICIENT_RESOURCES;
}
- status = smbXsrv_open_local_allocate_id(table->local.db_ctx,
- table->local.lowest_id,
- table->local.highest_id,
- op,
- &local_rec,
- &op->local_id);
- if (!NT_STATUS_IS_OK(status)) {
+ local_id = idr_get_new_random(
+ table->local.idr,
+ op,
+ table->local.lowest_id,
+ table->local.highest_id);
+ if (local_id == -1) {
TALLOC_FREE(op);
- return status;
+ return NT_STATUS_INSUFFICIENT_RESOURCES;
}
+ op->local_id = local_id;
+
op->idle_time = now;
op->status = NT_STATUS_FILE_CLOSED;
op->global->open_volatile_id = op->local_id;
op->global->server_id = messaging_server_id(conn->client->msg_ctx);
- ptr = op;
- val = make_tdb_data((uint8_t const *)&ptr, sizeof(ptr));
- status = dbwrap_record_store(local_rec, val, TDB_REPLACE);
- TALLOC_FREE(local_rec);
- if (!NT_STATUS_IS_OK(status)) {
- TALLOC_FREE(op);
- return status;
- }
table->local.num_opens += 1;
talloc_set_destructor(op, smbXsrv_open_destructor);