Possible ABA in use of llist.h llist_del_first() in tty_buffer and ib_rdma
A message that is not in the archive (sent off-list or not yet received): [email protected]
CCing LKML.
Quoted 50 lines · ----- On Mar 31, 2016, at 5:39 AM, Mathieu Desnoyers…
Hi,
Code review (really: grepping the Linux kernel for
llist_del_first) leads me to notice two possible ABA issues. The first one is indrivers/tty/tty_buffer.c, and is due to its use ofllist_del_allandllist_del_firstwithout locking since commit809850b7a5"tty: Use lockless flip buffer free list".Unfortunately, it appears to do so without respecting the locking requirements associated with
llist_del_first.Quoting
llist.h:" * If there are multiple producers and one consumer,
llist_addcan be
* used in producers andllist_del_allorllist_del_firstcan be used
* in the consumer.
*
* This can be summarized as follow:
** | add | del_first | del_all * add | - | - | - * del_first | | L | L * del_all | | | -*
* Where "-" stands for no lock is needed, while "L" stands for lock
* is needed.
"As soon as a
llist_del_first()is used, then bothllist_del_first()andllist_del_all()need to be protected by a lock, thus preventing ABA inllist_del_first().An alternative to locking would be to only use
llist_del_all()and neverllist_del_first().I'm also noticing a similar concurrent use of
llist_del_first()andllist_del_all()in commit1bc144b625"net, rds, Replace xlist innet/rds/xlist.hwith llist".
The locking surrounding their use (especially inrds_ib_reuse_mr) don't appear clearly documented there. Perhaps there was a preexisting issue with thexlist.huse too ?Thanks,
Mathieu
--
Mathieu Desnoyers
EfficiOS Inc.
http://www.efficios.com
Signature · 3 lines
Mathieu Desnoyers EfficiOS Inc. http://www.efficios.com
Hi Mathieu,
Quoted 20 lines · Mathieu Desnoyers
CCing LKML.
Quoted 16 lines · ----- On Mar 31, 2016, at 5:39 AM, Mathieu Desnoyers…
Hi,
Code review (really: grepping the Linux kernel for
llist_del_first) leads me to notice two possible ABA issues. The first one is indrivers/tty/tty_buffer.c, and is due to its use ofllist_del_allandllist_del_firstwithout locking since commit809850b7a5"tty: Use lockless flip buffer free list".Unfortunately, it appears to do so without respecting the locking requirements associated with
llist_del_first.Quoting
llist.h:" * If there are multiple producers and one consumer,
llist_addcan be
* used in producers andllist_del_allorllist_del_firstcan be used
* in the consumer.
The use of llist_del_all in tty_buffer_free_all() is not concurrent with any other use of the free list; the comments for tty_buffer_free_all() even note the special condition.
Only the llist_del_first() and llist_add() usage are concurrent, and fwiw, that usage is single-producer/single-consumer.
Regards,
Peter Hurley
Quoted 34 lines
Quoted 33 lines
* This can be summarized as follow:
** | add | del_first | del_all * add | - | - | - * del_first | | L | L * del_all | | | -*
* Where "-" stands for no lock is needed, while "L" stands for lock
* is needed.
"As soon as a
llist_del_first()is used, then bothllist_del_first()andllist_del_all()need to be protected by a lock, thus preventing ABA inllist_del_first().An alternative to locking would be to only use
llist_del_all()and neverllist_del_first().I'm also noticing a similar concurrent use of
llist_del_first()andllist_del_all()in commit1bc144b625"net, rds, Replace xlist innet/rds/xlist.hwith llist".
The locking surrounding their use (especially inrds_ib_reuse_mr) don't appear clearly documented there. Perhaps there was a preexisting issue with thexlist.huse too ?Thanks,
Mathieu
--
Mathieu Desnoyers
EfficiOS Inc.
http://www.efficios.com
Quoted 21 lines · ----- On Mar 31, 2016, at 9:58 AM, Peter Hurley [email protected] wrote:
Hi Mathieu,
Quoted 18 lines · Mathieu Desnoyers
CCing LKML.
----- On Mar 31, 2016, at 5:39 AM, Mathieu Desnoyers
Quoted 13 lines · [email protected] wrote:
Hi,
Code review (really: grepping the Linux kernel for
llist_del_first) leads me to notice two possible ABA issues. The first one is indrivers/tty/tty_buffer.c, and is due to its use ofllist_del_allandllist_del_firstwithout locking since commit809850b7a5"tty: Use lockless flip buffer free list".Unfortunately, it appears to do so without respecting the locking requirements associated with
llist_del_first.Quoting
llist.h:
Quoted 7 lines
Quoted 3 lines
Quoted 3 lines
" * If there are multiple producers and one consumer,
llist_addcan be
* used in producers andllist_del_allorllist_del_firstcan be used
* in the consumer.The use of
llist_del_allintty_buffer_free_all()is not concurrent with any other use of the free list; the comments fortty_buffer_free_all()even note the special condition.
This one looks OK indeed.
Quoted 3 lines
Only the
llist_del_first()andllist_add()usage are concurrent, and fwiw, that usage is single-producer/single-consumer.
I see that tty_buffer_request_room is an exported symbol, and no documentation indicate that it should never be called concurrently for a struct tty_port. Also, there does not appear to be any locking within this function preventing concurrent execution on a struct tty_port. Is there some documentation about this interface that I am missing ?
If it's possible to call llist_del_first() concurrently, then we can run into ABA scenarios, even if llist_add() is protected from concurrent llist_add() by a lock.
Thanks,
Mathieu
Quoted 37 lines
Regards,
Peter HurleyQuoted 33 lines
Quoted 33 lines
* This can be summarized as follow:
** | add | del_first | del_all * add | - | - | - * del_first | | L | L * del_all | | | -*
* Where "-" stands for no lock is needed, while "L" stands for lock
* is needed.
"As soon as a
llist_del_first()is used, then bothllist_del_first()andllist_del_all()need to be protected by a lock, thus preventing ABA inllist_del_first().An alternative to locking would be to only use
llist_del_all()and neverllist_del_first().I'm also noticing a similar concurrent use of
llist_del_first()andllist_del_all()in commit1bc144b625"net, rds, Replace xlist innet/rds/xlist.hwith llist".
The locking surrounding their use (especially inrds_ib_reuse_mr) don't appear clearly documented there. Perhaps there was a preexisting issue with thexlist.huse too ?Thanks,
Mathieu
--
Mathieu Desnoyers
EfficiOS Inc.
http://www.efficios.com
Signature · 3 lines
Mathieu Desnoyers EfficiOS Inc. http://www.efficios.com
Quoted 31 lines · Mathieu Desnoyers
Quoted 19 lines · ----- On Mar 31, 2016, at 9:58 AM, Peter Hurley [email protected] wrote:
Quoted 18 lines · Mathieu Desnoyers
CCing LKML.
----- On Mar 31, 2016, at 5:39 AM, Mathieu Desnoyers
Quoted 13 lines · [email protected] wrote:
Hi,
Code review (really: grepping the Linux kernel for
llist_del_first) leads me to notice two possible ABA issues. The first one is indrivers/tty/tty_buffer.c, and is due to its use ofllist_del_allandllist_del_firstwithout locking since commit809850b7a5"tty: Use lockless flip buffer free list".Unfortunately, it appears to do so without respecting the locking requirements associated with
llist_del_first.Quoting
llist.h:Quoted 7 lines
Quoted 3 lines
Quoted 3 lines
" * If there are multiple producers and one consumer,
llist_addcan be
* used in producers andllist_del_allorllist_del_firstcan be used
* in the consumer.The use of
llist_del_allintty_buffer_free_all()is not concurrent with any other use of the free list; the comments fortty_buffer_free_all()even note the special condition.This one looks OK indeed.
Quoted 1 line
Quoted 8 lines
Quoted 2 lines
Only the
llist_del_first()andllist_add()usage are concurrent, and fwiw, that usage is single-producer/single-consumer.I see that
tty_buffer_request_roomis an exported symbol, and no documentation indicate that it should never be called concurrently for a structtty_port. Also, there does not appear to be any locking within this function preventing concurrent execution on a structtty_port. Is there some documentation about this interface that I am missing ?
There is little to no documentation on the tty flip buffer interface, so you're not missing anything there.
The driver-side flip buffer interface is purely single-threaded; it is exclusively called from interrupt handlers and single-threaded bottom halves.
None of the functions are atomic, nor is the interface design.
For example, ignoring tty_buffer_request_room() for a moment, consider how broken concurrent use of tty_insert_flip_string_flags() would be; input from multiple threads would be overwritten/lost/mixed.
The interface itself is not atomic because tty_flip_buffer_push() marks the conclusion of input and the hand-off to kworker, which may already be running at the time.
The tty core doesn't support multi-channel input directly; the driver is expected to deliver input from each channel to a separate tty, or mux the inputs before tty_insert_flip_string_fixed_flag().
Quoted 3 lines
If it's possible to call
llist_del_first()concurrently, then we can run into ABA scenarios, even ifllist_add()is protected from concurrentllist_add()by a lock.
And way more obvious problems than that, such as I wrote above, if used concurrently.
Regards,
Peter Hurley