static BOOL retrieve_all_messages(char **msgs_buf, size_t *total_len) { TDB_DATA kbuf; TDB_DATA dbuf; TDB_DATA null_dbuf; ZERO_STRUCT(null_dbuf); *msgs_buf = NULL; *total_len = 0; kbuf = message_key_pid(pid_to_procid(sys_getpid())); if (tdb_chainlock(tdb, kbuf) == -1) return False; dbuf = tdb_fetch(tdb, kbuf); /* * Replace with an empty record to keep the allocated * space in the tdb. */ tdb_store(tdb, kbuf, null_dbuf, TDB_REPLACE); tdb_chainunlock(tdb, kbuf); if (dbuf.dptr == NULL || dbuf.dsize == 0) { SAFE_FREE(dbuf.dptr); return False; } *msgs_buf = dbuf.dptr; *total_len = dbuf.dsize; return True; }
static int tdb_chainlock_with_timeout_internal( TDB_CONTEXT *tdb, TDB_DATA key, unsigned int timeout, int rw_type) { /* Allow tdb_chainlock to be interrupted by an alarm. */ int ret; gotalarm = 0; if (timeout) { CatchSignal(SIGALRM, gotalarm_sig); tdb_setalarm_sigptr(tdb, &gotalarm); alarm(timeout); } if (rw_type == F_RDLCK) ret = tdb_chainlock_read(tdb, key); else ret = tdb_chainlock(tdb, key); if (timeout) { alarm(0); tdb_setalarm_sigptr(tdb, NULL); CatchSignal(SIGALRM, SIG_IGN); if (gotalarm && (ret != 0)) { DEBUG(0,("tdb_chainlock_with_timeout_internal: alarm (%u) timed out for key %s in tdb %s\n", timeout, key.dptr, tdb_name(tdb))); /* TODO: If we time out waiting for a lock, it might * be nice to use F_GETLK to get the pid of the * process currently holding the lock and print that * as part of the debugging message. -- mbp */ return -1; } } return ret == 0 ? 0 : -1; }
static int lock_record(const char *dbpath, const char *dbflags, const char *dbkey) { TDB_DATA key; struct tdb_context *tdb; int tdb_flags; /* No error checking since CTDB always passes sane values */ tdb_flags = strtol(dbflags, NULL, 0); /* Convert hex key to key */ if (strcmp(dbkey, "NULL") == 0) { key.dptr = NULL; key.dsize = 0; } else { key.dptr = hex_decode_talloc(NULL, dbkey, &key.dsize); } tdb = tdb_open(dbpath, 0, tdb_flags, O_RDWR, 0600); if (tdb == NULL) { fprintf(stderr, "%s: Error opening database %s\n", progname, dbpath); return 1; } if (tdb_chainlock(tdb, key) < 0) { fprintf(stderr, "%s: Error getting record lock (%s)\n", progname, tdb_errorstr(tdb)); return 1; } return 0; }
int smb_lock_share_mode_entry(struct smbdb_ctx *db_ctx, uint64_t dev, uint64_t ino, uint64_t extid) { struct locking_key lk; return tdb_chainlock(db_ctx->smb_tdb, get_locking_key(&lk, dev, ino, extid)) == 0 ? 0 : -1; }
BOOL brl_locktest(SMB_DEV_T dev, SMB_INO_T ino, int fnum, uint16 smbpid, pid_t pid, uint16 tid, br_off start, br_off size, enum brl_type lock_type, int check_self) { TDB_DATA kbuf, dbuf; int count, i; struct lock_struct lock, *locks; kbuf = locking_key(dev,ino); dbuf.dptr = NULL; tdb_chainlock(tdb, kbuf); dbuf = tdb_fetch(tdb, kbuf); lock.context.smbpid = smbpid; lock.context.pid = pid; lock.context.tid = tid; lock.start = start; lock.size = size; lock.fnum = fnum; lock.lock_type = lock_type; if (dbuf.dptr) { /* there are existing locks - make sure they don't conflict */ locks = (struct lock_struct *)dbuf.dptr; count = dbuf.dsize / sizeof(*locks); for (i=0; i<count; i++) { if (check_self) { if (brl_conflict(&locks[i], &lock)) goto fail; } else { /* * Our own locks don't conflict. */ if (brl_conflict_other(&locks[i], &lock)) goto fail; } } } /* no conflicts - we could have added it */ SAFE_FREE(dbuf.dptr); tdb_chainunlock(tdb, kbuf); return True; fail: SAFE_FREE(dbuf.dptr); tdb_chainunlock(tdb, kbuf); return False; }
static struct db_record *db_tdb_fetch_locked( struct db_context *db, TALLOC_CTX *mem_ctx, TDB_DATA key) { struct db_tdb_ctx *ctx = talloc_get_type_abort(db->private_data, struct db_tdb_ctx); db_tdb_log_key("Locking", key); if (tdb_chainlock(ctx->wtdb->tdb, key) != 0) { DEBUG(3, ("tdb_chainlock failed\n")); return NULL; } return db_tdb_fetch_locked_internal(db, mem_ctx, key); }
static int delete_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state) { struct locking_data *data; share_mode_entry *shares; int i, del_count=0; pid_t mypid = sys_getpid(); BOOL check_self = *(BOOL *)state; int ret = 0; tdb_chainlock(tdb, kbuf); data = (struct locking_data *)dbuf.dptr; shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data)); for (i=0;i<data->u.num_share_mode_entries;) { if (check_self && (shares[i].pid == mypid)) { DEBUG(0,("locking : delete_fn. LOGIC ERROR ! Shutting down and a record for my pid (%u) exists !\n", (unsigned int)shares[i].pid )); } else if (!process_exists(shares[i].pid)) { DEBUG(0,("locking : delete_fn. LOGIC ERROR ! Entry for pid %u and it no longer exists !\n", (unsigned int)shares[i].pid )); } else { /* Process exists, leave this record alone. */ i++; continue; } data->u.num_share_mode_entries--; memmove(&shares[i], &shares[i+1], dbuf.dsize - (sizeof(*data) + (i+1)*sizeof(*shares))); del_count++; } /* the record has shrunk a bit */ dbuf.dsize -= del_count * sizeof(*shares); /* store it back in the database */ if (data->u.num_share_mode_entries == 0) { if (tdb_delete(ttdb, kbuf) == -1) ret = -1; } else { if (tdb_store(ttdb, kbuf, dbuf, TDB_REPLACE) == -1) ret = -1; } tdb_chainunlock(tdb, kbuf); return ret; }
static BOOL message_recv(int *msg_type, pid_t *src, void **buf, size_t *len) { TDB_DATA kbuf; TDB_DATA dbuf; struct message_rec rec; kbuf = message_key_pid(sys_getpid()); tdb_chainlock(tdb, kbuf); dbuf = tdb_fetch(tdb, kbuf); if (dbuf.dptr == NULL || dbuf.dsize == 0) goto failed; memcpy(&rec, dbuf.dptr, sizeof(rec)); if (rec.msg_version != MESSAGE_VERSION) { DEBUG(0,("message version %d received (expected %d)\n", rec.msg_version, MESSAGE_VERSION)); goto failed; } if (rec.len > 0) { (*buf) = (void *)malloc(rec.len); if (!(*buf)) goto failed; memcpy(*buf, dbuf.dptr+sizeof(rec), rec.len); } else { *buf = NULL; } *len = rec.len; *msg_type = rec.msg_type; *src = rec.src; if (dbuf.dsize - (sizeof(rec)+rec.len) > 0) memmove(dbuf.dptr, dbuf.dptr+sizeof(rec)+rec.len, dbuf.dsize - (sizeof(rec)+rec.len)); dbuf.dsize -= sizeof(rec)+rec.len; if (dbuf.dsize == 0) tdb_delete(tdb, kbuf); else tdb_store(tdb, kbuf, dbuf, TDB_REPLACE); SAFE_FREE(dbuf.dptr); tdb_chainunlock(tdb, kbuf); return True; failed: tdb_chainunlock(tdb, kbuf); return False; }
static int delete_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state) { struct lock_struct *locks; int count, i; BOOL check_self = *(BOOL *)state; pid_t mypid = sys_getpid(); tdb_chainlock(tdb, kbuf); locks = (struct lock_struct *)dbuf.dptr; count = dbuf.dsize / sizeof(*locks); for (i=0; i<count; i++) { struct lock_struct *lock = &locks[i]; /* If check_self is true we want to remove our own records. */ if (check_self && (mypid == lock->context.pid)) { DEBUG(0,("brlock : delete_fn. LOGIC ERROR ! Shutting down and a record for my pid (%u) exists !\n", (unsigned int)lock->context.pid )); } else if (process_exists(lock->context.pid)) { DEBUG(10,("brlock : delete_fn. pid %u exists.\n", (unsigned int)lock->context.pid )); continue; } DEBUG(10,("brlock : delete_fn. Deleting record for process %u\n", (unsigned int)lock->context.pid )); if (count > 1 && i < count-1) { memmove(&locks[i], &locks[i+1], sizeof(*locks)*((count-1) - i)); } count--; i--; } if (count == 0) { tdb_delete(tdb, kbuf); } else if (count < (dbuf.dsize / sizeof(*locks))) { dbuf.dsize = count * sizeof(*locks); tdb_store(tdb, kbuf, dbuf, TDB_REPLACE); } tdb_chainunlock(tdb, kbuf); return 0; }
PyObject *py_tdb_hnd_chainlock(PyObject *self, PyObject *args) { tdb_hnd_object *obj = (tdb_hnd_object *)self; TDB_DATA key; int result; if (!obj->tdb) { PyErr_SetString(py_tdb_error, "tdb object has been closed"); return NULL; } if (!PyArg_ParseTuple(args, "s#", &key.dptr, &key.dsize)) return NULL; result = tdb_chainlock(obj->tdb, key); return PyInt_FromLong(result != -1); }
/* ----------------------- */ static cnid_t get_cnid(struct _cnid_tdb_private *db) { TDB_DATA rootinfo_key, data; cnid_t hint,id; memset(&rootinfo_key, 0, sizeof(rootinfo_key)); memset(&data, 0, sizeof(data)); rootinfo_key.dptr = ROOTINFO_KEY; rootinfo_key.dsize = ROOTINFO_KEYLEN; tdb_chainlock(db->tdb_didname, rootinfo_key); data = tdb_fetch(db->tdb_didname, rootinfo_key); if (data.dptr) { memcpy(&hint, data.dptr, sizeof(cnid_t)); free(data.dptr); id = ntohl(hint); /* If we've hit the max CNID allowed, we return a fatal error. CNID * needs to be recycled before proceding. */ if (++id == CNID_INVALID) { LOG(log_error, logtype_default, "cnid_add: FATAL: CNID database has reached its limit."); errno = CNID_ERR_MAX; goto cleanup; } hint = htonl(id); } else { hint = htonl(CNID_START); } memset(&data, 0, sizeof(data)); data.dptr = (char *)&hint; data.dsize = sizeof(hint); if (tdb_store(db->tdb_didname, rootinfo_key, data, TDB_REPLACE)) { goto cleanup; } tdb_chainunlock(db->tdb_didname, rootinfo_key ); return hint; cleanup: tdb_chainunlock(db->tdb_didname, rootinfo_key); return CNID_INVALID; }
static struct db_record *db_tdb_fetch_locked(struct db_context *db, TALLOC_CTX *mem_ctx, TDB_DATA key) { struct db_tdb_ctx *ctx = talloc_get_type_abort(db->private_data, struct db_tdb_ctx); struct tdb_fetch_locked_state state; db_tdb_log_key("Locking", key); if (tdb_chainlock(ctx->wtdb->tdb, key) != 0) { DEBUG(3, ("tdb_chainlock failed\n")); return NULL; } state.mem_ctx = mem_ctx; state.result = NULL; tdb_parse_record(ctx->wtdb->tdb, key, db_tdb_fetchlock_parse, &state); if (state.result == NULL) { db_tdb_fetchlock_parse(key, tdb_null, &state); } if (state.result == NULL) { tdb_chainunlock(ctx->wtdb->tdb, key); return NULL; } talloc_set_destructor(state.result, db_tdb_record_destr); state.result->private_data = talloc_reference(state.result, ctx); state.result->store = db_tdb_store; state.result->delete_rec = db_tdb_delete; DEBUG(10, ("Allocated locked data 0x%p\n", state.result)); return state.result; }
static int do_child(int tdb_flags, int to, int from) { struct tdb_context *tdb; unsigned int log_count; struct tdb_logging_context log_ctx = { log_fn, &log_count }; int ret; char c = 0; tdb = tdb_open_ex("mutex-allrecord-trylock.tdb", 3, tdb_flags, O_RDWR|O_CREAT, 0755, &log_ctx, NULL); ok(tdb, "tdb_open_ex should succeed"); ret = tdb_chainlock(tdb, key); ok(ret == 0, "tdb_chainlock should succeed"); write(to, &c, sizeof(c)); read(from, &c, sizeof(c)); ret = tdb_chainunlock(tdb, key); ok(ret == 0, "tdb_chainunlock should succeed"); return 0; }
int main(int argc, char *argv[]) { unsigned int i, extra_msgs; struct tdb_context *tdb; struct tdb_data key = tdb_mkdata("key", 3); struct tdb_data data = tdb_mkdata("data", 4); int flags[] = { TDB_DEFAULT, TDB_NOMMAP, TDB_CONVERT, TDB_NOMMAP|TDB_CONVERT, TDB_VERSION1, TDB_NOMMAP|TDB_VERSION1, TDB_CONVERT|TDB_VERSION1, TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 }; plan_tests(sizeof(flags) / sizeof(flags[0]) * 48); for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) { /* RW -> R0 */ tdb = tdb_open("run-92-get-set-readonly.tdb", flags[i], O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr); ok1(tdb); ok1(!(tdb_get_flags(tdb) & TDB_RDONLY)); /* TDB1 complains multiple times. */ if (flags[i] & TDB_VERSION1) { extra_msgs = 1; } else { extra_msgs = 0; } ok1(tdb_store(tdb, key, data, TDB_INSERT) == TDB_SUCCESS); tdb_add_flag(tdb, TDB_RDONLY); ok1(tdb_get_flags(tdb) & TDB_RDONLY); /* Can't store, append, delete. */ ok1(tdb_store(tdb, key, data, TDB_MODIFY) == TDB_ERR_RDONLY); ok1(tap_log_messages == 1); ok1(tdb_append(tdb, key, data) == TDB_ERR_RDONLY); tap_log_messages -= extra_msgs; ok1(tap_log_messages == 2); ok1(tdb_delete(tdb, key) == TDB_ERR_RDONLY); tap_log_messages -= extra_msgs; ok1(tap_log_messages == 3); /* Can't start a transaction, or any write lock. */ ok1(tdb_transaction_start(tdb) == TDB_ERR_RDONLY); ok1(tap_log_messages == 4); ok1(tdb_chainlock(tdb, key) == TDB_ERR_RDONLY); tap_log_messages -= extra_msgs; ok1(tap_log_messages == 5); ok1(tdb_lockall(tdb) == TDB_ERR_RDONLY); ok1(tap_log_messages == 6); ok1(tdb_wipe_all(tdb) == TDB_ERR_RDONLY); ok1(tap_log_messages == 7); /* Back to RW. */ tdb_remove_flag(tdb, TDB_RDONLY); ok1(!(tdb_get_flags(tdb) & TDB_RDONLY)); ok1(tdb_store(tdb, key, data, TDB_MODIFY) == TDB_SUCCESS); ok1(tdb_append(tdb, key, data) == TDB_SUCCESS); ok1(tdb_delete(tdb, key) == TDB_SUCCESS); ok1(tdb_transaction_start(tdb) == TDB_SUCCESS); ok1(tdb_store(tdb, key, data, TDB_INSERT) == TDB_SUCCESS); ok1(tdb_transaction_commit(tdb) == TDB_SUCCESS); ok1(tdb_chainlock(tdb, key) == TDB_SUCCESS); tdb_chainunlock(tdb, key); ok1(tdb_lockall(tdb) == TDB_SUCCESS); tdb_unlockall(tdb); ok1(tdb_wipe_all(tdb) == TDB_SUCCESS); ok1(tap_log_messages == 7); tdb_close(tdb); /* R0 -> RW */ tdb = tdb_open("run-92-get-set-readonly.tdb", flags[i], O_RDONLY, 0600, &tap_log_attr); ok1(tdb); ok1(tdb_get_flags(tdb) & TDB_RDONLY); /* Can't store, append, delete. */ ok1(tdb_store(tdb, key, data, TDB_INSERT) == TDB_ERR_RDONLY); ok1(tap_log_messages == 8); ok1(tdb_append(tdb, key, data) == TDB_ERR_RDONLY); tap_log_messages -= extra_msgs; ok1(tap_log_messages == 9); ok1(tdb_delete(tdb, key) == TDB_ERR_RDONLY); tap_log_messages -= extra_msgs; ok1(tap_log_messages == 10); /* Can't start a transaction, or any write lock. */ ok1(tdb_transaction_start(tdb) == TDB_ERR_RDONLY); ok1(tap_log_messages == 11); ok1(tdb_chainlock(tdb, key) == TDB_ERR_RDONLY); tap_log_messages -= extra_msgs; ok1(tap_log_messages == 12); ok1(tdb_lockall(tdb) == TDB_ERR_RDONLY); ok1(tap_log_messages == 13); ok1(tdb_wipe_all(tdb) == TDB_ERR_RDONLY); ok1(tap_log_messages == 14); /* Can't remove TDB_RDONLY since we opened with O_RDONLY */ tdb_remove_flag(tdb, TDB_RDONLY); ok1(tap_log_messages == 15); ok1(tdb_get_flags(tdb) & TDB_RDONLY); tdb_close(tdb); ok1(tap_log_messages == 15); tap_log_messages = 0; } return exit_status(); }
int main(int argc, char *argv[]) { unsigned int i, extra_messages; struct tdb_context *tdb, *tdb2; struct tdb_data key = { (unsigned char *)&i, sizeof(i) }; struct tdb_data data = { (unsigned char *)&i, sizeof(i) }; struct tdb_data d = { NULL, 0 }; /* Bogus GCC warning */ int flags[] = { TDB_DEFAULT, TDB_NOMMAP, TDB_CONVERT, TDB_NOMMAP|TDB_CONVERT, TDB_VERSION1, TDB_NOMMAP|TDB_VERSION1, TDB_CONVERT|TDB_VERSION1, TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 }; plan_tests(sizeof(flags) / sizeof(flags[0]) * 28); for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) { tdb = tdb_open("run-open-multiple-times.tdb", flags[i], O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr); ok1(tdb); if (!tdb) continue; if (flags[i] & TDB_VERSION1) { extra_messages = 1; } else { extra_messages = 0; } tdb2 = tdb_open("run-open-multiple-times.tdb", flags[i], O_RDWR|O_CREAT, 0600, &tap_log_attr); ok1(tdb_check(tdb, NULL, NULL) == 0); ok1(tdb_check(tdb2, NULL, NULL) == 0); /* Store in one, fetch in the other. */ ok1(tdb_store(tdb, key, data, TDB_REPLACE) == 0); ok1(tdb_fetch(tdb2, key, &d) == TDB_SUCCESS); ok1(tdb_deq(d, data)); free(d.dptr); /* Vice versa, with delete. */ ok1(tdb_delete(tdb2, key) == 0); ok1(tdb_fetch(tdb, key, &d) == TDB_ERR_NOEXIST); /* OK, now close first one, check second still good. */ ok1(tdb_close(tdb) == 0); ok1(tdb_store(tdb2, key, data, TDB_REPLACE) == 0); ok1(tdb_fetch(tdb2, key, &d) == TDB_SUCCESS); ok1(tdb_deq(d, data)); free(d.dptr); /* Reopen */ tdb = tdb_open("run-open-multiple-times.tdb", flags[i], O_RDWR|O_CREAT, 0600, &tap_log_attr); ok1(tdb); ok1(tdb_transaction_start(tdb2) == 0); /* Anything in the other one should fail. */ ok1(tdb_fetch(tdb, key, &d) == TDB_ERR_LOCK); tap_log_messages -= extra_messages; ok1(tap_log_messages == 1); ok1(tdb_store(tdb, key, data, TDB_REPLACE) == TDB_ERR_LOCK); tap_log_messages -= extra_messages; ok1(tap_log_messages == 2); ok1(tdb_transaction_start(tdb) == TDB_ERR_LOCK); ok1(tap_log_messages == 3); ok1(tdb_chainlock(tdb, key) == TDB_ERR_LOCK); tap_log_messages -= extra_messages; ok1(tap_log_messages == 4); /* Transaciton should work as normal. */ ok1(tdb_store(tdb2, key, data, TDB_REPLACE) == TDB_SUCCESS); /* Now... try closing with locks held. */ ok1(tdb_close(tdb2) == 0); ok1(tdb_fetch(tdb, key, &d) == TDB_SUCCESS); ok1(tdb_deq(d, data)); free(d.dptr); ok1(tdb_close(tdb) == 0); ok1(tap_log_messages == 4); tap_log_messages = 0; } return exit_status(); }
BOOL message_send_pid(pid_t pid, int msg_type, const void *buf, size_t len, BOOL duplicates_allowed) { TDB_DATA kbuf; TDB_DATA dbuf; struct message_rec rec; void *p; rec.msg_version = MESSAGE_VERSION; rec.msg_type = msg_type; rec.dest = pid; rec.src = sys_getpid(); rec.len = len; kbuf = message_key_pid(pid); /* lock the record for the destination */ tdb_chainlock(tdb, kbuf); dbuf = tdb_fetch(tdb, kbuf); if (!dbuf.dptr) { /* its a new record */ p = (void *)malloc(len + sizeof(rec)); if (!p) goto failed; memcpy(p, &rec, sizeof(rec)); if (len > 0) memcpy((void *)((char*)p+sizeof(rec)), buf, len); dbuf.dptr = p; dbuf.dsize = len + sizeof(rec); tdb_store(tdb, kbuf, dbuf, TDB_REPLACE); SAFE_FREE(p); goto ok; } if (!duplicates_allowed) { char *ptr; struct message_rec prec; for(ptr = (char *)dbuf.dptr; ptr < dbuf.dptr + dbuf.dsize; ) { /* * First check if the message header matches, then, if it's a non-zero * sized message, check if the data matches. If so it's a duplicate and * we can discard it. JRA. */ if (!memcmp(ptr, &rec, sizeof(rec))) { if (!len || (len && !memcmp( ptr + sizeof(rec), buf, len))) { DEBUG(10,("message_send_pid: discarding duplicate message.\n")); SAFE_FREE(dbuf.dptr); tdb_chainunlock(tdb, kbuf); return True; } } memcpy(&prec, ptr, sizeof(prec)); ptr += sizeof(rec) + prec.len; } } /* we're adding to an existing entry */ p = (void *)malloc(dbuf.dsize + len + sizeof(rec)); if (!p) goto failed; memcpy(p, dbuf.dptr, dbuf.dsize); memcpy((void *)((char*)p+dbuf.dsize), &rec, sizeof(rec)); if (len > 0) memcpy((void *)((char*)p+dbuf.dsize+sizeof(rec)), buf, len); SAFE_FREE(dbuf.dptr); dbuf.dptr = p; dbuf.dsize += len + sizeof(rec); tdb_store(tdb, kbuf, dbuf, TDB_REPLACE); SAFE_FREE(dbuf.dptr); ok: tdb_chainunlock(tdb, kbuf); errno = 0; /* paranoia */ return message_notify(pid); failed: tdb_chainunlock(tdb, kbuf); errno = 0; /* paranoia */ return False; }
/* lock a record in the ltdb, given a key */ int ctdb_ltdb_lock(struct ctdb_db_context *ctdb_db, TDB_DATA key) { return tdb_chainlock(ctdb_db->ltdb->tdb, key); }
struct share_mode_lock *get_share_mode_lock(TALLOC_CTX *mem_ctx, SMB_DEV_T dev, SMB_INO_T ino, const char *servicepath, const char *fname) { struct share_mode_lock *lck; TDB_DATA key = locking_key(dev, ino); TDB_DATA data; lck = TALLOC_P(mem_ctx, struct share_mode_lock); if (lck == NULL) { DEBUG(0, ("talloc failed\n")); return NULL; } /* Ensure we set every field here as the destructor must be valid even if parse_share_modes fails. */ lck->servicepath = NULL; lck->filename = NULL; lck->dev = dev; lck->ino = ino; lck->num_share_modes = 0; lck->share_modes = NULL; lck->delete_token = NULL; lck->delete_on_close = False; lck->initial_delete_on_close = False; lck->fresh = False; lck->modified = False; if (tdb_chainlock(tdb, key) != 0) { DEBUG(3, ("Could not lock share entry\n")); TALLOC_FREE(lck); return NULL; } /* We must set the destructor immediately after the chainlock ensure the lock is cleaned up on any of the error return paths below. */ talloc_set_destructor(lck, share_mode_lock_destructor); data = tdb_fetch(tdb, key); lck->fresh = (data.dptr == NULL); if (lck->fresh) { if (fname == NULL || servicepath == NULL) { TALLOC_FREE(lck); return NULL; } lck->filename = talloc_strdup(lck, fname); lck->servicepath = talloc_strdup(lck, servicepath); if (lck->filename == NULL || lck->servicepath == NULL) { DEBUG(0, ("talloc failed\n")); TALLOC_FREE(lck); return NULL; } } else { if (!parse_share_modes(data, lck)) { DEBUG(0, ("Could not parse share modes\n")); TALLOC_FREE(lck); SAFE_FREE(data.dptr); return NULL; } } SAFE_FREE(data.dptr); return lck; }
BOOL lock_share_entry(connection_struct *conn, SMB_DEV_T dev, SMB_INO_T inode) { return tdb_chainlock(tdb, locking_key(dev, inode)) == 0; }
void brl_close(SMB_DEV_T dev, SMB_INO_T ino, pid_t pid, int tid, int fnum) { TDB_DATA kbuf, dbuf; int count, i, j, dcount=0; struct lock_struct *locks; kbuf = locking_key(dev,ino); dbuf.dptr = NULL; tdb_chainlock(tdb, kbuf); dbuf = tdb_fetch(tdb, kbuf); if (!dbuf.dptr) goto fail; /* there are existing locks - remove any for this fnum */ locks = (struct lock_struct *)dbuf.dptr; count = dbuf.dsize / sizeof(*locks); for (i=0; i<count; i++) { struct lock_struct *lock = &locks[i]; if (lock->context.tid == tid && lock->context.pid == pid && lock->fnum == fnum) { /* Send unlock messages to any pending waiters that overlap. */ for (j=0; j<count; j++) { struct lock_struct *pend_lock = &locks[j]; /* Ignore our own or non-pending locks. */ if (pend_lock->lock_type != PENDING_LOCK) continue; if (pend_lock->context.tid == tid && pend_lock->context.pid == pid && pend_lock->fnum == fnum) continue; /* We could send specific lock info here... */ if (brl_pending_overlap(lock, pend_lock)) message_send_pid(pend_lock->context.pid, MSG_SMB_UNLOCK, NULL, 0, True); } /* found it - delete it */ if (count > 1 && i < count-1) { memmove(&locks[i], &locks[i+1], sizeof(*locks)*((count-1) - i)); } count--; i--; dcount++; } } if (count == 0) { tdb_delete(tdb, kbuf); } else if (count < (dbuf.dsize / sizeof(*locks))) { dbuf.dsize -= dcount * sizeof(*locks); tdb_store(tdb, kbuf, dbuf, TDB_REPLACE); } /* we didn't find it */ fail: SAFE_FREE(dbuf.dptr); tdb_chainunlock(tdb, kbuf); }
NTSTATUS brl_lock(SMB_DEV_T dev, SMB_INO_T ino, int fnum, uint16 smbpid, pid_t pid, uint16 tid, br_off start, br_off size, enum brl_type lock_type) { TDB_DATA kbuf, dbuf; int count, i; struct lock_struct lock, *locks; char *tp; NTSTATUS status = NT_STATUS_OK; static int last_failed = -1; static br_off last_failed_start; kbuf = locking_key(dev,ino); dbuf.dptr = NULL; #if !ZERO_ZERO if (start == 0 && size == 0) { DEBUG(0,("client sent 0/0 lock - please report this\n")); } #endif tdb_chainlock(tdb, kbuf); dbuf = tdb_fetch(tdb, kbuf); lock.context.smbpid = smbpid; lock.context.pid = pid; lock.context.tid = tid; lock.start = start; lock.size = size; lock.fnum = fnum; lock.lock_type = lock_type; if (dbuf.dptr) { /* there are existing locks - make sure they don't conflict */ locks = (struct lock_struct *)dbuf.dptr; count = dbuf.dsize / sizeof(*locks); for (i=0; i<count; i++) { if (brl_conflict(&locks[i], &lock)) { status = NT_STATUS_LOCK_NOT_GRANTED; goto fail; } #if ZERO_ZERO if (lock.start == 0 && lock.size == 0 && locks[i].size == 0) { break; } #endif } } /* no conflicts - add it to the list of locks */ tp = Realloc(dbuf.dptr, dbuf.dsize + sizeof(*locks)); if (!tp) { status = NT_STATUS_NO_MEMORY; goto fail; } else { dbuf.dptr = tp; } memcpy(dbuf.dptr + dbuf.dsize, &lock, sizeof(lock)); dbuf.dsize += sizeof(lock); #if ZERO_ZERO /* sort the lock list */ qsort(dbuf.dptr, dbuf.dsize/sizeof(lock), sizeof(lock), lock_compare); #endif tdb_store(tdb, kbuf, dbuf, TDB_REPLACE); SAFE_FREE(dbuf.dptr); tdb_chainunlock(tdb, kbuf); return NT_STATUS_OK; fail: /* this is a nasty hack to try to simulate the lock result cache code in w2k. It isn't completely accurate as I haven't yet worked out the correct semantics (tridge) */ if (last_failed == fnum && last_failed_start == start && NT_STATUS_EQUAL(status, NT_STATUS_LOCK_NOT_GRANTED)) { status = NT_STATUS_FILE_LOCK_CONFLICT; } last_failed = fnum; last_failed_start = start; SAFE_FREE(dbuf.dptr); tdb_chainunlock(tdb, kbuf); return status; }
BOOL brl_unlock(SMB_DEV_T dev, SMB_INO_T ino, int fnum, uint16 smbpid, pid_t pid, uint16 tid, br_off start, br_off size, BOOL remove_pending_locks_only) { TDB_DATA kbuf, dbuf; int count, i, j; struct lock_struct *locks; struct lock_context context; kbuf = locking_key(dev,ino); dbuf.dptr = NULL; tdb_chainlock(tdb, kbuf); dbuf = tdb_fetch(tdb, kbuf); if (!dbuf.dptr) { DEBUG(10,("brl_unlock: tdb_fetch failed !\n")); goto fail; } context.smbpid = smbpid; context.pid = pid; context.tid = tid; /* there are existing locks - find a match */ locks = (struct lock_struct *)dbuf.dptr; count = dbuf.dsize / sizeof(*locks); #if ZERO_ZERO for (i=0; i<count; i++) { struct lock_struct *lock = &locks[i]; if (lock->lock_type == WRITE_LOCK && brl_same_context(&lock->context, &context) && lock->fnum == fnum && lock->start == start && lock->size == size) { /* found it - delete it */ if (count == 1) { tdb_delete(tdb, kbuf); } else { if (i < count-1) { memmove(&locks[i], &locks[i+1], sizeof(*locks)*((count-1) - i)); } dbuf.dsize -= sizeof(*locks); tdb_store(tdb, kbuf, dbuf, TDB_REPLACE); } SAFE_FREE(dbuf.dptr); tdb_chainunlock(tdb, kbuf); return True; } } #endif locks = (struct lock_struct *)dbuf.dptr; count = dbuf.dsize / sizeof(*locks); for (i=0; i<count; i++) { struct lock_struct *lock = &locks[i]; if (brl_same_context(&lock->context, &context) && lock->fnum == fnum && lock->start == start && lock->size == size) { if (remove_pending_locks_only && lock->lock_type != PENDING_LOCK) continue; if (lock->lock_type != PENDING_LOCK) { /* Send unlock messages to any pending waiters that overlap. */ for (j=0; j<count; j++) { struct lock_struct *pend_lock = &locks[j]; /* Ignore non-pending locks. */ if (pend_lock->lock_type != PENDING_LOCK) continue; /* We could send specific lock info here... */ if (brl_pending_overlap(lock, pend_lock)) { DEBUG(10,("brl_unlock: sending unlock message to pid %u\n", (unsigned int)pend_lock->context.pid )); message_send_pid(pend_lock->context.pid, MSG_SMB_UNLOCK, NULL, 0, True); } } } /* found it - delete it */ if (count == 1) { tdb_delete(tdb, kbuf); } else { if (i < count-1) { memmove(&locks[i], &locks[i+1], sizeof(*locks)*((count-1) - i)); } dbuf.dsize -= sizeof(*locks); tdb_store(tdb, kbuf, dbuf, TDB_REPLACE); } SAFE_FREE(dbuf.dptr); tdb_chainunlock(tdb, kbuf); return True; } } /* we didn't find it */ fail: SAFE_FREE(dbuf.dptr); tdb_chainunlock(tdb, kbuf); return False; }
static void addrec_db(void) { int klen, dlen; char *k, *d; TDB_DATA key, data; klen = 1 + (rand() % KEYLEN); dlen = 1 + (rand() % DATALEN); k = randbuf(klen); d = randbuf(dlen); key.dptr = (unsigned char *)k; key.dsize = klen+1; data.dptr = (unsigned char *)d; data.dsize = dlen+1; #if REOPEN_PROB if (in_transaction == 0 && random() % REOPEN_PROB == 0) { tdb_reopen_all(0); goto next; } #endif #if TRANSACTION_PROB if (in_transaction == 0 && (always_transaction || random() % TRANSACTION_PROB == 0)) { if (tdb_transaction_start(db) != 0) { fatal("tdb_transaction_start failed"); } in_transaction++; goto next; } if (in_transaction && random() % TRANSACTION_PROB == 0) { if (random() % TRANSACTION_PREPARE_PROB == 0) { if (tdb_transaction_prepare_commit(db) != 0) { fatal("tdb_transaction_prepare_commit failed"); } } if (tdb_transaction_commit(db) != 0) { fatal("tdb_transaction_commit failed"); } in_transaction--; goto next; } if (in_transaction && random() % TRANSACTION_PROB == 0) { if (tdb_transaction_cancel(db) != 0) { fatal("tdb_transaction_cancel failed"); } in_transaction--; goto next; } #endif #if DELETE_PROB if (random() % DELETE_PROB == 0) { tdb_delete(db, key); goto next; } #endif #if STORE_PROB if (random() % STORE_PROB == 0) { if (tdb_store(db, key, data, TDB_REPLACE) != 0) { fatal("tdb_store failed"); } goto next; } #endif #if APPEND_PROB if (random() % APPEND_PROB == 0) { if (tdb_append(db, key, data) != 0) { fatal("tdb_append failed"); } goto next; } #endif #if LOCKSTORE_PROB if (random() % LOCKSTORE_PROB == 0) { tdb_chainlock(db, key); data = tdb_fetch(db, key); if (tdb_store(db, key, data, TDB_REPLACE) != 0) { fatal("tdb_store failed"); } if (data.dptr) free(data.dptr); tdb_chainunlock(db, key); goto next; } #endif #if TRAVERSE_PROB if (random() % TRAVERSE_PROB == 0) { tdb_traverse(db, cull_traverse, NULL); goto next; } #endif #if TRAVERSE_READ_PROB if (random() % TRAVERSE_READ_PROB == 0) { tdb_traverse_read(db, NULL, NULL); goto next; } #endif data = tdb_fetch(db, key); if (data.dptr) free(data.dptr); next: free(k); free(d); }
static BOOL message_send_pid_internal(struct process_id pid, int msg_type, const void *buf, size_t len, BOOL duplicates_allowed, unsigned int timeout) { TDB_DATA kbuf; TDB_DATA dbuf; TDB_DATA old_dbuf; struct message_rec rec; char *ptr; struct message_rec prec; /* NULL pointer means implicit length zero. */ if (!buf) { SMB_ASSERT(len == 0); } /* * Doing kill with a non-positive pid causes messages to be * sent to places we don't want. */ SMB_ASSERT(procid_to_pid(&pid) > 0); rec.msg_version = MESSAGE_VERSION; rec.msg_type = msg_type; rec.dest = pid; rec.src = procid_self(); rec.len = buf ? len : 0; kbuf = message_key_pid(pid); dbuf.dptr = (void *)SMB_MALLOC(len + sizeof(rec)); if (!dbuf.dptr) return False; memcpy(dbuf.dptr, &rec, sizeof(rec)); if (len > 0 && buf) memcpy((void *)((char*)dbuf.dptr+sizeof(rec)), buf, len); dbuf.dsize = len + sizeof(rec); if (duplicates_allowed) { /* If duplicates are allowed we can just append the message and return. */ /* lock the record for the destination */ if (timeout) { if (tdb_chainlock_with_timeout(tdb, kbuf, timeout) == -1) { DEBUG(0,("message_send_pid_internal: failed to get chainlock with timeout %ul.\n", timeout)); return False; } } else { if (tdb_chainlock(tdb, kbuf) == -1) { DEBUG(0,("message_send_pid_internal: failed to get chainlock.\n")); return False; } } tdb_append(tdb, kbuf, dbuf); tdb_chainunlock(tdb, kbuf); SAFE_FREE(dbuf.dptr); errno = 0; /* paranoia */ return message_notify(pid); } /* lock the record for the destination */ if (timeout) { if (tdb_chainlock_with_timeout(tdb, kbuf, timeout) == -1) { DEBUG(0,("message_send_pid_internal: failed to get chainlock with timeout %ul.\n", timeout)); return False; } } else { if (tdb_chainlock(tdb, kbuf) == -1) { DEBUG(0,("message_send_pid_internal: failed to get chainlock.\n")); return False; } } old_dbuf = tdb_fetch(tdb, kbuf); if (!old_dbuf.dptr) { /* its a new record */ tdb_store(tdb, kbuf, dbuf, TDB_REPLACE); tdb_chainunlock(tdb, kbuf); SAFE_FREE(dbuf.dptr); errno = 0; /* paranoia */ return message_notify(pid); } /* Not a new record. Check for duplicates. */ for(ptr = (char *)old_dbuf.dptr; ptr < old_dbuf.dptr + old_dbuf.dsize; ) { /* * First check if the message header matches, then, if it's a non-zero * sized message, check if the data matches. If so it's a duplicate and * we can discard it. JRA. */ if (!memcmp(ptr, &rec, sizeof(rec))) { if (!len || (len && !memcmp( ptr + sizeof(rec), buf, len))) { tdb_chainunlock(tdb, kbuf); DEBUG(10,("message_send_pid_internal: discarding duplicate message.\n")); SAFE_FREE(dbuf.dptr); SAFE_FREE(old_dbuf.dptr); return True; } } memcpy(&prec, ptr, sizeof(prec)); ptr += sizeof(rec) + prec.len; } /* we're adding to an existing entry */ tdb_append(tdb, kbuf, dbuf); tdb_chainunlock(tdb, kbuf); SAFE_FREE(old_dbuf.dptr); SAFE_FREE(dbuf.dptr); errno = 0; /* paranoia */ return message_notify(pid); }
BOOL lock_share_entry_fsp(files_struct *fsp) { return tdb_chainlock(tdb, locking_key(fsp->dev, fsp->inode)) == 0; }
int tdb_lock_bystring(struct tdb_context *tdb, const char *keyval) { TDB_DATA key = string_term_tdb_data(keyval); return tdb_chainlock(tdb, key); }
int smb_lock_share_mode_entry(struct smbdb_ctx *db_ctx, uint64_t dev, uint64_t ino) { return tdb_chainlock(db_ctx->smb_tdb, get_locking_key(dev, ino)); }