Line data Source code
1 : /* We save the locks so we can reaquire them. */
2 : #include "../common/tdb_private.h"
3 : #include <unistd.h>
4 : #include <fcntl.h>
5 : #include <stdarg.h>
6 : #include <stdlib.h>
7 : #include "tap-interface.h"
8 : #include "lock-tracking.h"
9 :
10 : struct testlock {
11 : struct testlock *next;
12 : unsigned int off;
13 : unsigned int len;
14 : int type;
15 : };
16 : static struct testlock *testlocks;
17 : int locking_errors = 0;
18 : bool suppress_lockcheck = false;
19 : bool nonblocking_locks;
20 : int locking_would_block = 0;
21 : void (*unlock_callback)(int fd);
22 :
23 2712 : int fcntl_with_lockcheck(int fd, int cmd, ... /* arg */ )
24 : {
25 : va_list ap;
26 : int ret, arg3;
27 : struct flock *fl;
28 2712 : bool may_block = false;
29 :
30 2712 : if (cmd != F_SETLK && cmd != F_SETLKW) {
31 : /* This may be totally bogus, but we don't know in general. */
32 414 : va_start(ap, cmd);
33 414 : arg3 = va_arg(ap, int);
34 414 : va_end(ap);
35 :
36 414 : return fcntl(fd, cmd, arg3);
37 : }
38 :
39 2298 : va_start(ap, cmd);
40 2298 : fl = va_arg(ap, struct flock *);
41 2298 : va_end(ap);
42 :
43 2298 : if (cmd == F_SETLKW && nonblocking_locks) {
44 619 : cmd = F_SETLK;
45 619 : may_block = true;
46 : }
47 2298 : ret = fcntl(fd, cmd, fl);
48 :
49 : /* Detect when we failed, but might have been OK if we waited. */
50 2298 : if (may_block && ret == -1 && (errno == EAGAIN || errno == EACCES)) {
51 27 : locking_would_block++;
52 : }
53 :
54 2298 : if (fl->l_type == F_UNLCK) {
55 : struct testlock **l;
56 1027 : struct testlock *old = NULL;
57 :
58 1155 : for (l = &testlocks; *l; l = &(*l)->next) {
59 1008 : if ((*l)->off == fl->l_start
60 880 : && (*l)->len == fl->l_len) {
61 880 : if (ret == 0) {
62 880 : old = *l;
63 880 : *l = (*l)->next;
64 880 : free(old);
65 : }
66 880 : break;
67 : }
68 128 : if (((*l)->off == fl->l_start)
69 0 : && ((*l)->len == 0)
70 0 : && (ret == 0)) {
71 : /*
72 : * Remove a piece from the start of the
73 : * allrecord_lock
74 : */
75 0 : old = *l;
76 0 : (*l)->off += fl->l_len;
77 0 : break;
78 : }
79 : }
80 1027 : if (!old && !suppress_lockcheck) {
81 0 : diag("Unknown unlock %u@%u - %i",
82 : (int)fl->l_len, (int)fl->l_start, ret);
83 0 : locking_errors++;
84 : }
85 : } else {
86 : struct testlock *new, *i;
87 1271 : unsigned int fl_end = fl->l_start + fl->l_len;
88 1271 : if (fl->l_len == 0)
89 247 : fl_end = (unsigned int)-1;
90 :
91 : /* Check for overlaps: we shouldn't do this. */
92 2091 : for (i = testlocks; i; i = i->next) {
93 1012 : unsigned int i_end = i->off + i->len;
94 1012 : if (i->len == 0)
95 144 : i_end = (unsigned int)-1;
96 :
97 1012 : if (fl->l_start >= i->off && fl->l_start < i_end)
98 67 : break;
99 945 : if (fl_end >= i->off && fl_end < i_end)
100 0 : break;
101 :
102 : /* tdb_allrecord_lock does this, handle adjacent: */
103 945 : if (fl->l_start == i_end && fl->l_type == i->type) {
104 125 : if (ret == 0) {
105 125 : i->len = fl->l_len
106 0 : ? i->len + fl->l_len
107 : : 0;
108 : }
109 125 : goto done;
110 : }
111 : }
112 1146 : if (i) {
113 : /* Special case: upgrade of allrecord lock. */
114 67 : if (i->type == F_RDLCK && fl->l_type == F_WRLCK
115 62 : && i->off == FREELIST_TOP
116 60 : && fl->l_start == FREELIST_TOP
117 60 : && i->len == 0
118 60 : && fl->l_len == 0) {
119 60 : if (ret == 0)
120 58 : i->type = F_WRLCK;
121 60 : goto done;
122 : }
123 7 : if (!suppress_lockcheck) {
124 7 : diag("%s testlock %u@%u overlaps %u@%u",
125 : fl->l_type == F_WRLCK ? "write" : "read",
126 : (int)fl->l_len, (int)fl->l_start,
127 : i->len, (int)i->off);
128 7 : locking_errors++;
129 : }
130 : }
131 :
132 1086 : if (ret == 0) {
133 1059 : new = malloc(sizeof *new);
134 1059 : new->off = fl->l_start;
135 1059 : new->len = fl->l_len;
136 1059 : new->type = fl->l_type;
137 1059 : new->next = testlocks;
138 1059 : testlocks = new;
139 : }
140 : }
141 2325 : done:
142 2298 : if (ret == 0 && fl->l_type == F_UNLCK && unlock_callback)
143 767 : unlock_callback(fd);
144 2289 : return ret;
145 : }
146 :
147 120 : unsigned int forget_locking(void)
148 : {
149 120 : unsigned int num = 0;
150 408 : while (testlocks) {
151 168 : struct testlock *next = testlocks->next;
152 168 : free(testlocks);
153 168 : testlocks = next;
154 168 : num++;
155 : }
156 120 : return num;
157 : }
|