mirror of
https://github.com/samba-team/samba.git
synced 2024-12-23 17:34:34 +03:00
r21303: As discussed on samba-technical: Change the static array for the in-memory
mirrors of the hash chain locks to a dynamically allocated one. Jeremy, I count on you to revert it if the build farm freaks out, it's after midnight here :-) Volker
This commit is contained in:
parent
5c3edad860
commit
c50f099be1
@ -107,6 +107,9 @@ int tdb_brlock_upgrade(struct tdb_context *tdb, tdb_off_t offset, size_t len)
|
||||
/* lock a list in the database. list -1 is the alloc list */
|
||||
int tdb_lock(struct tdb_context *tdb, int list, int ltype)
|
||||
{
|
||||
struct tdb_lock_type *new_lck;
|
||||
int i;
|
||||
|
||||
/* a global lock allows us to avoid per chain locks */
|
||||
if (tdb->global_lock.count &&
|
||||
(ltype == tdb->global_lock.ltype || ltype == F_RDLCK)) {
|
||||
@ -125,18 +128,50 @@ int tdb_lock(struct tdb_context *tdb, int list, int ltype)
|
||||
if (tdb->flags & TDB_NOLOCK)
|
||||
return 0;
|
||||
|
||||
for (i=0; i<tdb->num_lockrecs; i++) {
|
||||
if (tdb->lockrecs[i].list == list) {
|
||||
if (tdb->lockrecs[i].count == 0) {
|
||||
/*
|
||||
* Can't happen, see tdb_unlock(). It should
|
||||
* be an assert.
|
||||
*/
|
||||
TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_lock: "
|
||||
"lck->count == 0 for list %d", list));
|
||||
}
|
||||
/*
|
||||
* Just increment the in-memory struct, posix locks
|
||||
* don't stack.
|
||||
*/
|
||||
tdb->lockrecs[i].count++;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
new_lck = (struct tdb_lock_type *)realloc(
|
||||
tdb->lockrecs,
|
||||
sizeof(*tdb->lockrecs) * (tdb->num_lockrecs+1));
|
||||
if (new_lck == NULL) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
tdb->lockrecs = new_lck;
|
||||
|
||||
/* Since fcntl locks don't nest, we do a lock for the first one,
|
||||
and simply bump the count for future ones */
|
||||
if (tdb->locked[list+1].count == 0) {
|
||||
if (tdb->methods->tdb_brlock(tdb,FREELIST_TOP+4*list,ltype,F_SETLKW, 0, 1)) {
|
||||
TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_lock failed on list %d ltype=%d (%s)\n",
|
||||
list, ltype, strerror(errno)));
|
||||
return -1;
|
||||
}
|
||||
tdb->locked[list+1].ltype = ltype;
|
||||
tdb->num_locks++;
|
||||
if (tdb->methods->tdb_brlock(tdb,FREELIST_TOP+4*list,ltype,F_SETLKW,
|
||||
0, 1)) {
|
||||
TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_lock failed on list %d "
|
||||
"ltype=%d (%s)\n", list, ltype, strerror(errno)));
|
||||
return -1;
|
||||
}
|
||||
tdb->locked[list+1].count++;
|
||||
|
||||
tdb->num_locks++;
|
||||
|
||||
tdb->lockrecs[tdb->num_lockrecs].list = list;
|
||||
tdb->lockrecs[tdb->num_lockrecs].count = 1;
|
||||
tdb->lockrecs[tdb->num_lockrecs].ltype = ltype;
|
||||
tdb->num_lockrecs += 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -146,6 +181,8 @@ int tdb_lock(struct tdb_context *tdb, int list, int ltype)
|
||||
int tdb_unlock(struct tdb_context *tdb, int list, int ltype)
|
||||
{
|
||||
int ret = -1;
|
||||
int i;
|
||||
struct tdb_lock_type *lck = NULL;
|
||||
|
||||
/* a global lock allows us to avoid per chain locks */
|
||||
if (tdb->global_lock.count &&
|
||||
@ -166,19 +203,52 @@ int tdb_unlock(struct tdb_context *tdb, int list, int ltype)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (tdb->locked[list+1].count==0) {
|
||||
TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: count is 0\n"));
|
||||
return ret;
|
||||
for (i=0; i<tdb->num_lockrecs; i++) {
|
||||
if (tdb->lockrecs[i].list == list) {
|
||||
lck = &tdb->lockrecs[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (tdb->locked[list+1].count == 1) {
|
||||
/* Down to last nested lock: unlock underneath */
|
||||
ret = tdb->methods->tdb_brlock(tdb, FREELIST_TOP+4*list, F_UNLCK, F_SETLKW, 0, 1);
|
||||
tdb->num_locks--;
|
||||
} else {
|
||||
ret = 0;
|
||||
if ((lck == NULL) || (lck->count == 0)) {
|
||||
TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: count is 0\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (lck->count > 1) {
|
||||
lck->count--;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This lock has count==1 left, so we need to unlock it in the
|
||||
* kernel. We don't bother with decrementing the in-memory array
|
||||
* element, we're about to overwrite it with the last array element
|
||||
* anyway.
|
||||
*/
|
||||
|
||||
ret = tdb->methods->tdb_brlock(tdb, FREELIST_TOP+4*list, F_UNLCK,
|
||||
F_SETLKW, 0, 1);
|
||||
tdb->num_locks--;
|
||||
|
||||
/*
|
||||
* Shrink the array by overwriting the element just unlocked with the
|
||||
* last array element.
|
||||
*/
|
||||
|
||||
if (tdb->num_lockrecs > 1) {
|
||||
*lck = tdb->lockrecs[tdb->num_lockrecs-1];
|
||||
}
|
||||
tdb->num_lockrecs -= 1;
|
||||
|
||||
/*
|
||||
* We don't bother with realloc when the array shrinks, but if we have
|
||||
* a completely idle tdb we should get rid of the locked array.
|
||||
*/
|
||||
|
||||
if (tdb->num_lockrecs == 0) {
|
||||
SAFE_FREE(tdb->lockrecs);
|
||||
}
|
||||
tdb->locked[list+1].count--;
|
||||
|
||||
if (ret)
|
||||
TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: An error occurred unlocking!\n"));
|
||||
|
@ -263,15 +263,6 @@ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
|
||||
tdb->map_size = st.st_size;
|
||||
tdb->device = st.st_dev;
|
||||
tdb->inode = st.st_ino;
|
||||
tdb->locked = (struct tdb_lock_type *)calloc(tdb->header.hash_size+1,
|
||||
sizeof(tdb->locked[0]));
|
||||
if (!tdb->locked) {
|
||||
TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: "
|
||||
"failed to allocate lock structure for %s\n",
|
||||
name));
|
||||
errno = ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
tdb_mmap(tdb);
|
||||
if (locked) {
|
||||
if (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_UNLCK, F_SETLK, 0, 1) == -1) {
|
||||
@ -324,7 +315,6 @@ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
|
||||
if (tdb->fd != -1)
|
||||
if (close(tdb->fd) != 0)
|
||||
TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to close tdb->fd on error!\n"));
|
||||
SAFE_FREE(tdb->locked);
|
||||
SAFE_FREE(tdb);
|
||||
errno = save_errno;
|
||||
return NULL;
|
||||
@ -354,7 +344,7 @@ int tdb_close(struct tdb_context *tdb)
|
||||
SAFE_FREE(tdb->name);
|
||||
if (tdb->fd != -1)
|
||||
ret = close(tdb->fd);
|
||||
SAFE_FREE(tdb->locked);
|
||||
SAFE_FREE(tdb->lockrecs);
|
||||
|
||||
/* Remove from contexts list */
|
||||
for (i = &tdbs; *i; i = &(*i)->next) {
|
||||
|
@ -123,6 +123,7 @@ struct tdb_header {
|
||||
};
|
||||
|
||||
struct tdb_lock_type {
|
||||
int list;
|
||||
u32 count;
|
||||
u32 ltype;
|
||||
};
|
||||
@ -152,7 +153,8 @@ struct tdb_context {
|
||||
int read_only; /* opened read-only */
|
||||
int traverse_read; /* read-only traversal */
|
||||
struct tdb_lock_type global_lock;
|
||||
struct tdb_lock_type *locked; /* array of chain locks */
|
||||
int num_lockrecs;
|
||||
struct tdb_lock_type *lockrecs; /* only real locks, all with count>0 */
|
||||
enum TDB_ERROR ecode; /* error code for last tdb error */
|
||||
struct tdb_header header; /* a cached copy of the header */
|
||||
u32 flags; /* the flags passed to tdb_open */
|
||||
|
@ -520,12 +520,10 @@ int tdb_transaction_cancel(struct tdb_context *tdb)
|
||||
|
||||
/* remove any locks created during the transaction */
|
||||
if (tdb->num_locks != 0) {
|
||||
int h;
|
||||
for (h=0;h<tdb->header.hash_size+1;h++) {
|
||||
if (tdb->locked[h].count != 0) {
|
||||
tdb_brlock(tdb,FREELIST_TOP+4*h,F_UNLCK,F_SETLKW, 0, 1);
|
||||
tdb->locked[h].count = 0;
|
||||
}
|
||||
int i;
|
||||
for (i=0;i<tdb->num_lockrecs;i++) {
|
||||
tdb_brlock(tdb,FREELIST_TOP+4*tdb->lockrecs[i].list,
|
||||
F_UNLCK,F_SETLKW, 0, 1);
|
||||
}
|
||||
tdb->num_locks = 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user