Add simple locking for the in-kernel iconv code. Translation operations

do not need any locking.  Opening and closing translators is serialized
using an sx lock.

Note: This depends on the earlier fix to kern_module.c to properly order
MOD_UNLOAD events.

MFC after:	2 months
This commit is contained in:
John Baldwin 2008-12-05 21:19:24 +00:00
parent 2640173120
commit ee03ef72e3
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=185652

View File

@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$");
#include <sys/iconv.h>
#include <sys/malloc.h>
#include <sys/mount.h>
#include <sys/sx.h>
#include <sys/syslog.h>
#include "iconv_converter_if.h"
@ -52,6 +53,8 @@ MALLOC_DEFINE(M_ICONVDATA, "iconv_data", "ICONV data");
MODULE_VERSION(libiconv, 2);
static struct sx iconv_lock;
#ifdef notnow
/*
* iconv converter instance
@ -86,11 +89,16 @@ iconv_mod_unload(void)
{
struct iconv_cspair *csp;
sx_xlock(&iconv_lock);
while ((csp = TAILQ_FIRST(&iconv_cslist)) != NULL) {
if (csp->cp_refcount)
return EBUSY;
iconv_unregister_cspair(csp);
}
while ((csp = TAILQ_FIRST(&iconv_cslist)) != NULL)
iconv_unregister_cspair(csp);
sx_xunlock(&iconv_lock);
sx_destroy(&iconv_lock);
return 0;
}
@ -102,6 +110,7 @@ iconv_mod_handler(module_t mod, int type, void *data)
switch (type) {
case MOD_LOAD:
error = 0;
sx_init(&iconv_lock, "iconv");
break;
case MOD_UNLOAD:
error = iconv_mod_unload();
@ -311,7 +320,7 @@ iconv_sysctl_drvlist(SYSCTL_HANDLER_ARGS)
int error;
error = 0;
sx_slock(&iconv_lock);
TAILQ_FOREACH(dcp, &iconv_converters, cc_link) {
name = ICONV_CONVERTER_NAME(dcp);
if (name == NULL)
@ -320,6 +329,7 @@ iconv_sysctl_drvlist(SYSCTL_HANDLER_ARGS)
if (error)
break;
}
sx_sunlock(&iconv_lock);
if (error)
return error;
spc = 0;
@ -343,7 +353,7 @@ iconv_sysctl_cslist(SYSCTL_HANDLER_ARGS)
error = 0;
bzero(&csi, sizeof(csi));
csi.cs_version = ICONV_CSPAIR_INFO_VER;
sx_slock(&iconv_lock);
TAILQ_FOREACH(csp, &iconv_cslist, cp_link) {
csi.cs_id = csp->cp_id;
csi.cs_refcount = csp->cp_refcount;
@ -354,6 +364,7 @@ iconv_sysctl_cslist(SYSCTL_HANDLER_ARGS)
if (error)
break;
}
sx_sunlock(&iconv_lock);
return error;
}
@ -387,9 +398,12 @@ iconv_sysctl_add(SYSCTL_HANDLER_ARGS)
return EINVAL;
if (iconv_lookupconv(din.ia_converter, &dcp) != 0)
return EINVAL;
sx_xlock(&iconv_lock);
error = iconv_register_cspair(din.ia_to, din.ia_from, dcp, NULL, &csp);
if (error)
if (error) {
sx_xunlock(&iconv_lock);
return error;
}
if (din.ia_datalen) {
csp->cp_data = malloc(din.ia_datalen, M_ICONVDATA, M_WAITOK);
error = copyin(din.ia_data, csp->cp_data, din.ia_datalen);
@ -400,10 +414,12 @@ iconv_sysctl_add(SYSCTL_HANDLER_ARGS)
error = SYSCTL_OUT(req, &dout, sizeof(dout));
if (error)
goto bad;
sx_xunlock(&iconv_lock);
ICDEBUG("%s => %s, %d bytes\n",din.ia_from, din.ia_to, din.ia_datalen);
return 0;
bad:
iconv_unregister_cspair(csp);
sx_xunlock(&iconv_lock);
return error;
}
@ -433,16 +449,22 @@ iconv_converter_handler(module_t mod, int type, void *data)
switch (type) {
case MOD_LOAD:
sx_xlock(&iconv_lock);
error = iconv_register_converter(dcp);
if (error)
if (error) {
sx_xunlock(&iconv_lock);
break;
}
error = ICONV_CONVERTER_INIT(dcp);
if (error)
iconv_unregister_converter(dcp);
sx_xunlock(&iconv_lock);
break;
case MOD_UNLOAD:
sx_xlock(&iconv_lock);
ICONV_CONVERTER_DONE(dcp);
error = iconv_unregister_converter(dcp);
sx_xunlock(&iconv_lock);
break;
default:
error = EINVAL;