Fix for deadlock situation in cuse(3)

The final server unref should be done by the server thread to prevent
deadlock in the client cdevpriv destructor, which cannot destroy
itself.

MFC after:	1 week
Sponsored by:	Mellanox Technologies
This commit is contained in:
Hans Petter Selasky 2019-06-25 11:42:53 +00:00
parent 019c8c9330
commit c7ffaed92e
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=349367

View File

@ -699,12 +699,38 @@ cuse_server_unref(struct cuse_server *pcs)
free(pcs, M_CUSE);
}
static int
cuse_server_do_close(struct cuse_server *pcs)
{
int retval;
cuse_lock();
cuse_server_is_closing(pcs);
/* final client wakeup, if any */
cuse_server_wakeup_all_client_locked(pcs);
knlist_clear(&pcs->selinfo.si_note, 1);
retval = pcs->refs;
cuse_unlock();
return (retval);
}
static void
cuse_server_free(void *arg)
{
struct cuse_server *pcs = arg;
/* drop refcount */
/*
* The final server unref should be done by the server thread
* to prevent deadlock in the client cdevpriv destructor,
* which cannot destroy itself.
*/
while (cuse_server_do_close(pcs) != 1)
pause("W", hz);
/* drop final refcount */
cuse_server_unref(pcs);
}
@ -746,21 +772,10 @@ static int
cuse_server_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
{
struct cuse_server *pcs;
int error;
error = cuse_server_get(&pcs);
if (error != 0)
goto done;
if (cuse_server_get(&pcs) == 0)
cuse_server_do_close(pcs);
cuse_lock();
cuse_server_is_closing(pcs);
/* final client wakeup, if any */
cuse_server_wakeup_all_client_locked(pcs);
knlist_clear(&pcs->selinfo.si_note, 1);
cuse_unlock();
done:
return (0);
}