s3:g_lock: remove a nested event loop, replacing the inner loop by select
authorMichael Adam <obnox@samba.org>
Sat, 23 Jan 2010 00:17:06 +0000 (01:17 +0100)
committerMichael Adam <obnox@samba.org>
Mon, 25 Jan 2010 14:08:41 +0000 (15:08 +0100)
commit83ca4995b1afb9ee57ef5c3610b35ee05af8fbf1
treeb54a87d57db9931673bdb541a50ca60931adf4fe
parent2b8ad811f1679659753be763684f379e20f2a142
s3:g_lock: remove a nested event loop, replacing the inner loop by select

This made smbd crash in g_lock_lock() when trying to start a
transaction on a db with an already started transaction,
e.g. in a tcon_and_X where the share_info.tdb was not yet
initialized but share_info.tdb was already locked by another
process or writing acces to the winreg rpc pipe where the
registry tdb was already locked by another process.

What we really _want_ to do here by design is to react to
MSG_DBWRAP_G_LOCK_RETRY messages that are either sent
by a client doing g_lock_unlock or by ourselves when
we receive a CTDB_SRVID_SAMBA_NOTIFY or
CTDB_SRVID_RECONFIGURE message from ctdbd, i.e. when
either a client holding a lock or a complete node
has died.

Doing this properly involves calling tevent_loop_once(),
but doing this here with the main ctdbd messaging context
creates a nested event loop when g_lock_lock() is called
from the main event loop.

So as a quick fix, we act a little corasely here: we do
a select on the ctdb connection fd and when it is readable
or we get EINTR, then we retry without actually parsing
any ctdb packages or dispatching messages. This means that
we retry more often than necessary and intended by design,
but this does not harm and it is unobtrusive. When we have
finished, the main loop will pick up all the messages and
ctdb packets. The only extra twist is that we cannot use
timed events here but have to handcode a timeout for select.

Michael
source3/lib/g_lock.c