summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2008-12-05 21:19:24 +0000
committerjhb <jhb@FreeBSD.org>2008-12-05 21:19:24 +0000
commit1c56af0e2d11d9778380f810b3e428ec6026961c (patch)
tree62e57e816b1b7ab03b1bc94691d4a51f653b3332 /sys
parentffffd56bb1825f5b368552057f4ec22d7a8d091c (diff)
downloadFreeBSD-src-1c56af0e2d11d9778380f810b3e428ec6026961c.zip
FreeBSD-src-1c56af0e2d11d9778380f810b3e428ec6026961c.tar.gz
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
Diffstat (limited to 'sys')
-rw-r--r--sys/libkern/iconv.c32
1 files changed, 27 insertions, 5 deletions
diff --git a/sys/libkern/iconv.c b/sys/libkern/iconv.c
index 401252a..289c400 100644
--- a/sys/libkern/iconv.c
+++ b/sys/libkern/iconv.c
@@ -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;
OpenPOWER on IntegriCloud