Switch from using an sx lock to a mutex for the mac_portacl rule chain:

the sx lock was used previously because we might sleep allocating
additional memory by using auto-extending sbufs.  However, we no longer
do this, instead retaining the user-submitted rule string, so mutexes
can be used instead.  Annotate the reason for not using the sbuf-related
rule-to-string code with a comment.

Switch to using TAILQ_CONCAT() instead of manual list copying, as it's
O(1), reducing the rule replacement step under the mutex from O(2N) to
O(2).

Remove now uneeded vnode-related includes.

MFC after:	2 weeks
This commit is contained in:
Robert Watson 2004-12-06 19:43:45 +00:00
parent fc2857ad10
commit d461245f5d
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=138477

View File

@ -61,21 +61,21 @@
#include <sys/domain.h>
#include <sys/kernel.h>
#include <sys/libkern.h>
#include <sys/lock.h>
#include <sys/mac.h>
#include <sys/malloc.h>
#include <sys/mount.h>
#include <sys/mutex.h>
#include <sys/proc.h>
#include <sys/protosw.h>
#include <sys/queue.h>
#include <sys/systm.h>
#include <sys/sysproto.h>
#include <sys/sysent.h>
#include <sys/vnode.h>
#include <sys/file.h>
#include <sys/sbuf.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/sx.h>
#include <sys/sysctl.h>
#include <netinet/in.h>
@ -134,7 +134,7 @@ struct rule {
* for the specified binding.
*/
static struct sx rule_sx;
static struct mtx rule_mtx;
static TAILQ_HEAD(rulehead, rule) rule_head;
static char rule_string[MAC_RULE_STRING_LEN];
@ -157,7 +157,7 @@ static void
destroy(struct mac_policy_conf *mpc)
{
sx_destroy(&rule_sx);
mtx_destroy(&rule_mtx);
toast_rules(&rule_head);
}
@ -165,7 +165,7 @@ static void
init(struct mac_policy_conf *mpc)
{
sx_init(&rule_sx, "rule_sx");
mtx_init(&rule_mtx, "rule_mtx", NULL, MTX_DEF);
TAILQ_INIT(&rule_head);
}
@ -260,6 +260,12 @@ parse_rules(char *string, struct rulehead *head)
return (error);
}
/*
* rule_printf() and rules_to_string() are unused currently because they rely
* on sbufs with auto-extension, which may sleep while holding a mutex.
* Instead, the non-canonical user-generated rule string is returned to the
* user when the rules are queried, which is faster anyway.
*/
#if 0
static void
rule_printf(struct sbuf *sb, struct rule *rule)
@ -302,7 +308,7 @@ rules_to_string(void)
sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
needcomma = 0;
sx_slock(&rule_sx);
mtx_lock(&rule_mtx);
for (rule = TAILQ_FIRST(&rule_head); rule != NULL;
rule = TAILQ_NEXT(rule, r_entries)) {
if (!needcomma)
@ -311,7 +317,7 @@ rules_to_string(void)
sbuf_printf(sb, ",");
rule_printf(sb, rule);
}
sx_sunlock(&rule_sx);
mtx_unlock(&rule_mtx);
sbuf_finish(sb);
temp = strdup(sbuf_data(sb), M_PORTACL);
sbuf_delete(sb);
@ -328,7 +334,6 @@ sysctl_rules(SYSCTL_HANDLER_ARGS)
{
char *string, *copy_string, *new_string;
struct rulehead head, save_head;
struct rule *rule;
int error;
new_string = NULL;
@ -353,23 +358,11 @@ sysctl_rules(SYSCTL_HANDLER_ARGS)
goto out;
TAILQ_INIT(&save_head);
sx_xlock(&rule_sx);
/*
* XXX: Unfortunately, TAILQ doesn't yet have a supported
* assignment operator to copy one queue to another, due
* to a self-referential pointer in the tailq header.
* For now, do it the old-fashioned way.
*/
while ((rule = TAILQ_FIRST(&rule_head)) != NULL) {
TAILQ_REMOVE(&rule_head, rule, r_entries);
TAILQ_INSERT_HEAD(&save_head, rule, r_entries);
}
while ((rule = TAILQ_FIRST(&head)) != NULL) {
TAILQ_REMOVE(&head, rule, r_entries);
TAILQ_INSERT_HEAD(&rule_head, rule, r_entries);
}
mtx_lock(&rule_mtx);
TAILQ_CONCAT(&save_head, &rule_head, r_entries);
TAILQ_CONCAT(&rule_head, &head, r_entries);
strcpy(rule_string, string);
sx_xunlock(&rule_sx);
mtx_unlock(&rule_mtx);
toast_rules(&save_head);
}
out:
@ -396,7 +389,7 @@ rules_check(struct ucred *cred, int family, int type, u_int16_t port)
return (0);
error = EPERM;
sx_slock(&rule_sx);
mtx_lock(&rule_mtx);
for (rule = TAILQ_FIRST(&rule_head);
rule != NULL;
rule = TAILQ_NEXT(rule, r_entries)) {
@ -423,7 +416,7 @@ rules_check(struct ucred *cred, int family, int type, u_int16_t port)
panic("rules_check: unknown rule type %d",
rule->r_idtype);
}
sx_sunlock(&rule_sx);
mtx_unlock(&rule_mtx);
if (error != 0 && mac_portacl_suser_exempt != 0)
error = suser_cred(cred, 0);