1 /* We save the locks so we can reaquire them. */
6 #include <ccan/tap/tap.h>
7 #include <ccan/tdb/tdb_private.h>
15 static struct lock *locks;
16 int locking_errors = 0;
17 bool suppress_lockcheck = false;
18 bool nonblocking_locks;
19 int locking_would_block = 0;
20 void (*unlock_callback)(int fd);
22 int fcntl_with_lockcheck(int fd, int cmd, ... /* arg */ )
27 bool may_block = false;
29 if (cmd != F_SETLK && cmd != F_SETLKW) {
30 /* This may be totally bogus, but we don't know in general. */
32 arg3 = va_arg(ap, int);
35 return fcntl(fd, cmd, arg3);
39 fl = va_arg(ap, struct flock *);
42 if (cmd == F_SETLKW && nonblocking_locks) {
46 ret = fcntl(fd, cmd, fl);
48 /* Detect when we failed, but might have been OK if we waited. */
49 if (may_block && ret == -1 && (errno == EAGAIN || errno == EACCES)) {
50 locking_would_block++;
53 if (fl->l_type == F_UNLCK) {
55 struct lock *old = NULL;
57 for (l = &locks; *l; l = &(*l)->next) {
58 if ((*l)->off == fl->l_start
59 && (*l)->len == fl->l_len) {
68 if (!old && !suppress_lockcheck) {
69 diag("Unknown unlock %u@%u - %i",
70 (int)fl->l_len, (int)fl->l_start, ret);
75 unsigned int fl_end = fl->l_start + fl->l_len;
77 fl_end = (unsigned int)-1;
79 /* Check for overlaps: we shouldn't do this. */
80 for (i = locks; i; i = i->next) {
81 unsigned int i_end = i->off + i->len;
83 i_end = (unsigned int)-1;
85 if (fl->l_start >= i->off && fl->l_start < i_end)
87 if (fl_end >= i->off && fl_end < i_end)
90 /* tdb_allrecord_lock does this, handle adjacent: */
91 if (fl->l_start == i_end && fl->l_type == i->type) {
101 /* Special case: upgrade of allrecord lock. */
102 if (i->type == F_RDLCK && fl->l_type == F_WRLCK
103 && i->off == FREELIST_TOP
104 && fl->l_start == FREELIST_TOP
111 if (!suppress_lockcheck) {
112 diag("%s lock %u@%u overlaps %u@%u",
113 fl->l_type == F_WRLCK ? "write" : "read",
114 (int)fl->l_len, (int)fl->l_start,
115 i->len, (int)i->off);
121 new = malloc(sizeof *new);
122 new->off = fl->l_start;
123 new->len = fl->l_len;
124 new->type = fl->l_type;
130 if (ret == 0 && fl->l_type == F_UNLCK && unlock_callback)
135 int forget_locking(void)
137 unsigned int num = 0;
139 struct lock *next = locks->next;