lock-tracking.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. /* We save the locks so we can reaquire them. */
  2. #include "../private.h" /* For NTDB_HASH_LOCK_START, etc. */
  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. struct lock {
  10. struct lock *next;
  11. unsigned int off;
  12. unsigned int len;
  13. int type;
  14. };
  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);
  21. int fcntl_with_lockcheck(int fd, int cmd, ... /* arg */ )
  22. {
  23. va_list ap;
  24. int ret, arg3;
  25. struct flock *fl;
  26. bool may_block = false;
  27. if (cmd != F_SETLK && cmd != F_SETLKW) {
  28. /* This may be totally bogus, but we don't know in general. */
  29. va_start(ap, cmd);
  30. arg3 = va_arg(ap, int);
  31. va_end(ap);
  32. return fcntl(fd, cmd, arg3);
  33. }
  34. va_start(ap, cmd);
  35. fl = va_arg(ap, struct flock *);
  36. va_end(ap);
  37. if (cmd == F_SETLKW && nonblocking_locks) {
  38. cmd = F_SETLK;
  39. may_block = true;
  40. }
  41. ret = fcntl(fd, cmd, fl);
  42. /* Detect when we failed, but might have been OK if we waited. */
  43. if (may_block && ret == -1 && (errno == EAGAIN || errno == EACCES)) {
  44. locking_would_block++;
  45. }
  46. if (fl->l_type == F_UNLCK) {
  47. struct lock **l;
  48. struct lock *old = NULL;
  49. for (l = &locks; *l; l = &(*l)->next) {
  50. if ((*l)->off == fl->l_start
  51. && (*l)->len == fl->l_len) {
  52. if (ret == 0) {
  53. old = *l;
  54. *l = (*l)->next;
  55. free(old);
  56. }
  57. break;
  58. }
  59. }
  60. if (!old && !suppress_lockcheck) {
  61. diag("Unknown unlock %u@%u - %i",
  62. (int)fl->l_len, (int)fl->l_start, ret);
  63. locking_errors++;
  64. }
  65. } else {
  66. struct lock *new, *i;
  67. unsigned int fl_end = fl->l_start + fl->l_len;
  68. if (fl->l_len == 0)
  69. fl_end = (unsigned int)-1;
  70. /* Check for overlaps: we shouldn't do this. */
  71. for (i = locks; i; i = i->next) {
  72. unsigned int i_end = i->off + i->len;
  73. if (i->len == 0)
  74. i_end = (unsigned int)-1;
  75. if (fl->l_start >= i->off && fl->l_start < i_end)
  76. break;
  77. if (fl_end > i->off && fl_end < i_end)
  78. break;
  79. /* ntdb_allrecord_lock does this, handle adjacent: */
  80. if (fl->l_start > NTDB_HASH_LOCK_START
  81. && fl->l_start == i_end && fl->l_type == i->type) {
  82. if (ret == 0) {
  83. i->len = fl->l_len
  84. ? i->len + fl->l_len
  85. : 0;
  86. }
  87. goto done;
  88. }
  89. }
  90. if (i) {
  91. /* Special case: upgrade of allrecord lock. */
  92. if (i->type == F_RDLCK && fl->l_type == F_WRLCK
  93. && i->off == NTDB_HASH_LOCK_START
  94. && fl->l_start == NTDB_HASH_LOCK_START
  95. && i->len == 0
  96. && fl->l_len == 0) {
  97. if (ret == 0)
  98. i->type = F_WRLCK;
  99. goto done;
  100. }
  101. if (!suppress_lockcheck) {
  102. diag("%s lock %u@%u overlaps %u@%u",
  103. fl->l_type == F_WRLCK ? "write" : "read",
  104. (int)fl->l_len, (int)fl->l_start,
  105. i->len, (int)i->off);
  106. locking_errors++;
  107. }
  108. }
  109. if (ret == 0) {
  110. new = malloc(sizeof *new);
  111. new->off = fl->l_start;
  112. new->len = fl->l_len;
  113. new->type = fl->l_type;
  114. new->next = locks;
  115. locks = new;
  116. }
  117. }
  118. done:
  119. if (ret == 0 && fl->l_type == F_UNLCK && unlock_callback)
  120. unlock_callback(fd);
  121. return ret;
  122. }
  123. unsigned int forget_locking(void)
  124. {
  125. unsigned int num = 0;
  126. while (locks) {
  127. struct lock *next = locks->next;
  128. free(locks);
  129. locks = next;
  130. num++;
  131. }
  132. return num;
  133. }