#include <stdlib.h>
#include <ccan/tap/tap.h>
#include <ccan/tdb/tdb_private.h>
+#include "lock-tracking.h"
struct lock {
struct lock *next;
static struct lock *locks;
int locking_errors = 0;
bool suppress_lockcheck = false;
+bool nonblocking_locks;
+int locking_would_block = 0;
void (*unlock_callback)(int fd);
int fcntl_with_lockcheck(int fd, int cmd, ... /* arg */ )
va_list ap;
int ret, arg3;
struct flock *fl;
+ bool may_block = false;
if (cmd != F_SETLK && cmd != F_SETLKW) {
/* This may be totally bogus, but we don't know in general. */
fl = va_arg(ap, struct flock *);
va_end(ap);
+ if (cmd == F_SETLKW && nonblocking_locks) {
+ cmd = F_SETLK;
+ may_block = true;
+ }
+ ret = fcntl(fd, cmd, fl);
+
+ /* Detect when we failed, but might have been OK if we waited. */
+ if (may_block && ret == -1 && (errno == EAGAIN || errno == EACCES)) {
+ locking_would_block++;
+ }
+
if (fl->l_type == F_UNLCK) {
struct lock **l;
struct lock *old = NULL;
for (l = &locks; *l; l = &(*l)->next) {
if ((*l)->off == fl->l_start
&& (*l)->len == fl->l_len) {
- old = *l;
- *l = (*l)->next;
- free(old);
+ if (ret == 0) {
+ old = *l;
+ *l = (*l)->next;
+ free(old);
+ }
break;
}
}
if (!old && !suppress_lockcheck) {
- diag("Unknown unlock %u@%u",
- (int)fl->l_len, (int)fl->l_start);
+ diag("Unknown unlock %u@%u - %i",
+ (int)fl->l_len, (int)fl->l_start, ret);
locking_errors++;
}
} else {
break;
if (fl_end >= i->off && fl_end < i_end)
break;
+
+ /* tdb_allrecord_lock does this, handle adjacent: */
+ if (fl->l_start == i_end && fl->l_type == i->type) {
+ if (ret == 0) {
+ i->len = fl->l_len
+ ? i->len + fl->l_len
+ : 0;
+ }
+ goto done;
+ }
}
if (i) {
/* Special case: upgrade of allrecord lock. */
&& fl->l_start == FREELIST_TOP
&& i->len == 0
&& fl->l_len == 0) {
- i->type = F_WRLCK;
- goto ok;
+ if (ret == 0)
+ i->type = F_WRLCK;
+ goto done;
}
if (!suppress_lockcheck) {
diag("%s lock %u@%u overlaps %u@%u",
locking_errors++;
}
}
- new = malloc(sizeof *new);
- new->off = fl->l_start;
- new->len = fl->l_len;
- new->type = fl->l_type;
- new->next = locks;
- locks = new;
+
+ if (ret == 0) {
+ new = malloc(sizeof *new);
+ new->off = fl->l_start;
+ new->len = fl->l_len;
+ new->type = fl->l_type;
+ new->next = locks;
+ locks = new;
+ }
}
-ok:
- ret = fcntl(fd, cmd, fl);
+done:
if (ret == 0 && fl->l_type == F_UNLCK && unlock_callback)
unlock_callback(fd);
return ret;
}
-int forget_locking(void)
+unsigned int forget_locking(void)
{
unsigned int num = 0;
while (locks) {