00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "tdb_private.h"
00030
00031 void tdb_setalarm_sigptr(struct tdb_context *tdb, volatile sig_atomic_t *ptr)
00032 {
00033 tdb->interrupt_sig_ptr = ptr;
00034 }
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044 int tdb_brlock(struct tdb_context *tdb, tdb_off_t offset,
00045 int rw_type, int lck_type, int probe, size_t len)
00046 {
00047 struct flock fl;
00048 int ret;
00049
00050 if (tdb->flags & TDB_NOLOCK) {
00051 return 0;
00052 }
00053
00054 if ((rw_type == F_WRLCK) && (tdb->read_only || tdb->traverse_read)) {
00055 tdb->ecode = TDB_ERR_RDONLY;
00056 return -1;
00057 }
00058
00059 fl.l_type = rw_type;
00060 fl.l_whence = SEEK_SET;
00061 fl.l_start = offset;
00062 fl.l_len = len;
00063 fl.l_pid = 0;
00064
00065 do {
00066 ret = fcntl(tdb->fd,lck_type,&fl);
00067
00068
00069 if (ret == -1 && errno == EINTR &&
00070 tdb->interrupt_sig_ptr &&
00071 *tdb->interrupt_sig_ptr) {
00072 break;
00073 }
00074 } while (ret == -1 && errno == EINTR);
00075
00076 if (ret == -1) {
00077
00078
00079
00080 if (!probe && lck_type != F_SETLK) {
00081
00082 tdb->ecode = TDB_ERR_LOCK;
00083 TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_brlock failed (fd=%d) at offset %d rw_type=%d lck_type=%d len=%d\n",
00084 tdb->fd, offset, rw_type, lck_type, (int)len));
00085 }
00086 return TDB_ERRCODE(TDB_ERR_LOCK, -1);
00087 }
00088 return 0;
00089 }
00090
00091
00092
00093
00094
00095
00096
00097
00098 int tdb_brlock_upgrade(struct tdb_context *tdb, tdb_off_t offset, size_t len)
00099 {
00100 int count = 1000;
00101 while (count--) {
00102 struct timeval tv;
00103 if (tdb_brlock(tdb, offset, F_WRLCK, F_SETLKW, 1, len) == 0) {
00104 return 0;
00105 }
00106 if (errno != EDEADLK) {
00107 break;
00108 }
00109
00110 tv.tv_sec = 0;
00111 tv.tv_usec = 1;
00112 select(0, NULL, NULL, NULL, &tv);
00113 }
00114 TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_brlock_upgrade failed at offset %d\n", offset));
00115 return -1;
00116 }
00117
00118
00119
00120 int tdb_lock(struct tdb_context *tdb, int list, int ltype)
00121 {
00122 struct tdb_lock_type *new_lck;
00123 int i;
00124
00125
00126 if (tdb->global_lock.count &&
00127 (ltype == tdb->global_lock.ltype || ltype == F_RDLCK)) {
00128 return 0;
00129 }
00130
00131 if (tdb->global_lock.count) {
00132 return TDB_ERRCODE(TDB_ERR_LOCK, -1);
00133 }
00134
00135 if (list < -1 || list >= (int)tdb->header.hash_size) {
00136 TDB_LOG((tdb, TDB_DEBUG_ERROR,"tdb_lock: invalid list %d for ltype=%d\n",
00137 list, ltype));
00138 return -1;
00139 }
00140 if (tdb->flags & TDB_NOLOCK)
00141 return 0;
00142
00143 for (i=0; i<tdb->num_lockrecs; i++) {
00144 if (tdb->lockrecs[i].list == list) {
00145 if (tdb->lockrecs[i].count == 0) {
00146
00147
00148
00149
00150 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_lock: "
00151 "lck->count == 0 for list %d", list));
00152 }
00153
00154
00155
00156
00157 tdb->lockrecs[i].count++;
00158 return 0;
00159 }
00160 }
00161
00162 new_lck = (struct tdb_lock_type *)realloc(
00163 tdb->lockrecs,
00164 sizeof(*tdb->lockrecs) * (tdb->num_lockrecs+1));
00165 if (new_lck == NULL) {
00166 errno = ENOMEM;
00167 return -1;
00168 }
00169 tdb->lockrecs = new_lck;
00170
00171
00172
00173 if (tdb->methods->tdb_brlock(tdb,FREELIST_TOP+4*list,ltype,F_SETLKW,
00174 0, 1)) {
00175 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_lock failed on list %d "
00176 "ltype=%d (%s)\n", list, ltype, strerror(errno)));
00177 return -1;
00178 }
00179
00180 tdb->num_locks++;
00181
00182 tdb->lockrecs[tdb->num_lockrecs].list = list;
00183 tdb->lockrecs[tdb->num_lockrecs].count = 1;
00184 tdb->lockrecs[tdb->num_lockrecs].ltype = ltype;
00185 tdb->num_lockrecs += 1;
00186
00187 return 0;
00188 }
00189
00190
00191
00192
00193 int tdb_unlock(struct tdb_context *tdb, int list, int ltype)
00194 {
00195 int ret = -1;
00196 int i;
00197 struct tdb_lock_type *lck = NULL;
00198
00199
00200 if (tdb->global_lock.count &&
00201 (ltype == tdb->global_lock.ltype || ltype == F_RDLCK)) {
00202 return 0;
00203 }
00204
00205 if (tdb->global_lock.count) {
00206 return TDB_ERRCODE(TDB_ERR_LOCK, -1);
00207 }
00208
00209 if (tdb->flags & TDB_NOLOCK)
00210 return 0;
00211
00212
00213 if (list < -1 || list >= (int)tdb->header.hash_size) {
00214 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: list %d invalid (%d)\n", list, tdb->header.hash_size));
00215 return ret;
00216 }
00217
00218 for (i=0; i<tdb->num_lockrecs; i++) {
00219 if (tdb->lockrecs[i].list == list) {
00220 lck = &tdb->lockrecs[i];
00221 break;
00222 }
00223 }
00224
00225 if ((lck == NULL) || (lck->count == 0)) {
00226 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: count is 0\n"));
00227 return -1;
00228 }
00229
00230 if (lck->count > 1) {
00231 lck->count--;
00232 return 0;
00233 }
00234
00235
00236
00237
00238
00239
00240
00241
00242 ret = tdb->methods->tdb_brlock(tdb, FREELIST_TOP+4*list, F_UNLCK,
00243 F_SETLKW, 0, 1);
00244 tdb->num_locks--;
00245
00246
00247
00248
00249
00250
00251 if (tdb->num_lockrecs > 1) {
00252 *lck = tdb->lockrecs[tdb->num_lockrecs-1];
00253 }
00254 tdb->num_lockrecs -= 1;
00255
00256
00257
00258
00259
00260
00261 if (tdb->num_lockrecs == 0) {
00262 SAFE_FREE(tdb->lockrecs);
00263 }
00264
00265 if (ret)
00266 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: An error occurred unlocking!\n"));
00267 return ret;
00268 }
00269
00270
00271
00272
00273 static int _tdb_lockall(struct tdb_context *tdb, int ltype)
00274 {
00275
00276 if (tdb->read_only || tdb->traverse_read)
00277 return TDB_ERRCODE(TDB_ERR_LOCK, -1);
00278
00279 if (tdb->global_lock.count && tdb->global_lock.ltype == ltype) {
00280 tdb->global_lock.count++;
00281 return 0;
00282 }
00283
00284 if (tdb->global_lock.count) {
00285
00286 return TDB_ERRCODE(TDB_ERR_LOCK, -1);
00287 }
00288
00289 if (tdb->num_locks != 0) {
00290
00291 return TDB_ERRCODE(TDB_ERR_LOCK, -1);
00292 }
00293
00294 if (tdb->methods->tdb_brlock(tdb, FREELIST_TOP, ltype, F_SETLKW,
00295 0, 4*tdb->header.hash_size)) {
00296 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_lockall failed (%s)\n", strerror(errno)));
00297 return -1;
00298 }
00299
00300 tdb->global_lock.count = 1;
00301 tdb->global_lock.ltype = ltype;
00302
00303 return 0;
00304 }
00305
00306
00307 static int _tdb_unlockall(struct tdb_context *tdb, int ltype)
00308 {
00309
00310 if (tdb->read_only || tdb->traverse_read) {
00311 return TDB_ERRCODE(TDB_ERR_LOCK, -1);
00312 }
00313
00314 if (tdb->global_lock.ltype != ltype || tdb->global_lock.count == 0) {
00315 return TDB_ERRCODE(TDB_ERR_LOCK, -1);
00316 }
00317
00318 if (tdb->global_lock.count > 1) {
00319 tdb->global_lock.count--;
00320 return 0;
00321 }
00322
00323 if (tdb->methods->tdb_brlock(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW,
00324 0, 4*tdb->header.hash_size)) {
00325 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlockall failed (%s)\n", strerror(errno)));
00326 return -1;
00327 }
00328
00329 tdb->global_lock.count = 0;
00330 tdb->global_lock.ltype = 0;
00331
00332 return 0;
00333 }
00334
00335
00336 int tdb_lockall(struct tdb_context *tdb)
00337 {
00338 return _tdb_lockall(tdb, F_WRLCK);
00339 }
00340
00341
00342 int tdb_unlockall(struct tdb_context *tdb)
00343 {
00344 return _tdb_unlockall(tdb, F_WRLCK);
00345 }
00346
00347
00348 int tdb_lockall_read(struct tdb_context *tdb)
00349 {
00350 return _tdb_lockall(tdb, F_RDLCK);
00351 }
00352
00353
00354 int tdb_unlockall_read(struct tdb_context *tdb)
00355 {
00356 return _tdb_unlockall(tdb, F_RDLCK);
00357 }
00358
00359
00360
00361 int tdb_chainlock(struct tdb_context *tdb, TDB_DATA key)
00362 {
00363 return tdb_lock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK);
00364 }
00365
00366 int tdb_chainunlock(struct tdb_context *tdb, TDB_DATA key)
00367 {
00368 return tdb_unlock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK);
00369 }
00370
00371 int tdb_chainlock_read(struct tdb_context *tdb, TDB_DATA key)
00372 {
00373 return tdb_lock(tdb, BUCKET(tdb->hash_fn(&key)), F_RDLCK);
00374 }
00375
00376 int tdb_chainunlock_read(struct tdb_context *tdb, TDB_DATA key)
00377 {
00378 return tdb_unlock(tdb, BUCKET(tdb->hash_fn(&key)), F_RDLCK);
00379 }
00380
00381
00382
00383
00384 int tdb_lock_record(struct tdb_context *tdb, tdb_off_t off)
00385 {
00386 return off ? tdb->methods->tdb_brlock(tdb, off, F_RDLCK, F_SETLKW, 0, 1) : 0;
00387 }
00388
00389
00390
00391
00392
00393
00394 int tdb_write_lock_record(struct tdb_context *tdb, tdb_off_t off)
00395 {
00396 struct tdb_traverse_lock *i;
00397 for (i = &tdb->travlocks; i; i = i->next)
00398 if (i->off == off)
00399 return -1;
00400 return tdb->methods->tdb_brlock(tdb, off, F_WRLCK, F_SETLK, 1, 1);
00401 }
00402
00403
00404
00405
00406
00407 int tdb_write_unlock_record(struct tdb_context *tdb, tdb_off_t off)
00408 {
00409 return tdb->methods->tdb_brlock(tdb, off, F_UNLCK, F_SETLK, 0, 1);
00410 }
00411
00412
00413 int tdb_unlock_record(struct tdb_context *tdb, tdb_off_t off)
00414 {
00415 struct tdb_traverse_lock *i;
00416 u32 count = 0;
00417
00418 if (off == 0)
00419 return 0;
00420 for (i = &tdb->travlocks; i; i = i->next)
00421 if (i->off == off)
00422 count++;
00423 return (count == 1 ? tdb->methods->tdb_brlock(tdb, off, F_UNLCK, F_SETLKW, 0, 1) : 0);
00424 }