mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-07 07:37:02 +02:00
BUG/MEDIUM: fd: avoid infinite loops in fd_add_to_fd_list and fd_rm_from_fd_list
With4d9888c
("CLEANUP: fd: get rid of the __GET_{NEXT,PREV} macros") some "volatile" keywords were dropped at various assignment places in fd's code. In fd_add_to_fd_list() and fd_add_to_fd_list(), because of the absence of the "volatile" keyword: the compiler was able to perform some code optimizations that prevented prev and next variables from being reloaded between locking attempts (goto loop). The result was that fd_add_to_fd_list() and fd_rm_from_fd_list() could enter in infinite loops, preventing other threads from working further and ultimately resulting in the watchdog being triggered as described in GH #2011. To fix this, we made sure to re-audit4d9888c
in order to restore the required memory barriers / compilers hints to prevent the compiler from mis-optimizing the code around the fd's locks. That is: using atomic loads to fetch the prev and next values, and restoring the "volatile" cast for cur_list.ent variable assignment in fd_rm_from_fd_list() Big thanks to @xanaxalan for his help and patience and to @wtarreau for his findings and explanations in regard to compiler's optimizations. This must be backported in 2.7 with4d9888c
("CLEANUP: fd: get rid of the __GET_{NEXT,PREV} macros")
This commit is contained in:
parent
83540ed429
commit
e51891a01d
8
src/fd.c
8
src/fd.c
@ -127,7 +127,7 @@ void fd_add_to_fd_list(volatile struct fdlist *list, int fd)
|
||||
int last;
|
||||
|
||||
redo_next:
|
||||
next = fdtab[fd].update.next;
|
||||
next = HA_ATOMIC_LOAD(&fdtab[fd].update.next);
|
||||
/* Check that we're not already in the cache, and if not, lock us. */
|
||||
if (next > -2)
|
||||
goto done;
|
||||
@ -194,7 +194,7 @@ void fd_rm_from_fd_list(volatile struct fdlist *list, int fd)
|
||||
lock_self:
|
||||
#if (defined(HA_CAS_IS_8B) || defined(HA_HAVE_CAS_DW))
|
||||
next_list.ent.next = next_list.ent.prev = -2;
|
||||
cur_list.ent = fdtab[fd].update;
|
||||
cur_list.ent = *(volatile typeof(fdtab->update)*)&fdtab[fd].update;
|
||||
/* First, attempt to lock our own entries */
|
||||
do {
|
||||
/* The FD is not in the FD cache, give up */
|
||||
@ -214,7 +214,7 @@ void fd_rm_from_fd_list(volatile struct fdlist *list, int fd)
|
||||
|
||||
#else
|
||||
lock_self_next:
|
||||
next = fdtab[fd].update.next;
|
||||
next = HA_ATOMIC_LOAD(&fdtab[fd].update.next);
|
||||
if (next == -2)
|
||||
goto lock_self_next;
|
||||
if (next <= -3)
|
||||
@ -222,7 +222,7 @@ void fd_rm_from_fd_list(volatile struct fdlist *list, int fd)
|
||||
if (unlikely(!_HA_ATOMIC_CAS(&fdtab[fd].update.next, &next, -2)))
|
||||
goto lock_self_next;
|
||||
lock_self_prev:
|
||||
prev = fdtab[fd].update.prev;
|
||||
prev = HA_ATOMIC_LOAD(&fdtab[fd].update.prev);
|
||||
if (prev == -2)
|
||||
goto lock_self_prev;
|
||||
if (unlikely(!_HA_ATOMIC_CAS(&fdtab[fd].update.prev, &prev, -2)))
|
||||
|
Loading…
Reference in New Issue
Block a user