smack: convert smack to standard linux lists

the following patch (on top of 2.6.29) converts Smack lists to standard linux lists
Please review and consider for inclusion in 2.6.30-rc

regards,
Etienne

Signed-off-by: Etienne Basset <etienne.basset@numericable.fr>
Acked-by: Casey Schaufler <casey@schaufler-ca.com>
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index a1b57e4..856c8a2 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -80,10 +80,11 @@
  * Packets are sent there unlabeled, but only from tasks that
  * can write to the specified label.
  */
-struct smk_netlbladdr *smack_netlbladdrs;
+
+LIST_HEAD(smk_netlbladdr_list);
+LIST_HEAD(smack_rule_list);
 
 static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT;
-struct smk_list_entry *smack_list;
 
 #define	SEQ_READ_FINISHED	1
 
@@ -134,24 +135,27 @@
 {
 	if (*pos == SEQ_READ_FINISHED)
 		return NULL;
-
-	return smack_list;
+	if (list_empty(&smack_rule_list))
+		return NULL;
+	return smack_rule_list.next;
 }
 
 static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos)
 {
-	struct smk_list_entry *skp = ((struct smk_list_entry *) v)->smk_next;
+	struct list_head *list = v;
 
-	if (skp == NULL)
+	if (list_is_last(list, &smack_rule_list)) {
 		*pos = SEQ_READ_FINISHED;
-
-	return skp;
+		return NULL;
+	}
+	return list->next;
 }
 
 static int load_seq_show(struct seq_file *s, void *v)
 {
-	struct smk_list_entry *slp = (struct smk_list_entry *) v;
-	struct smack_rule *srp = &slp->smk_rule;
+	struct list_head *list = v;
+	struct smack_rule *srp =
+		 list_entry(list, struct smack_rule, list);
 
 	seq_printf(s, "%s %s", (char *)srp->smk_subject,
 		   (char *)srp->smk_object);
@@ -212,32 +216,23 @@
  */
 static int smk_set_access(struct smack_rule *srp)
 {
-	struct smk_list_entry *sp;
-	struct smk_list_entry *newp;
+	struct smack_rule *sp;
 	int ret = 0;
-
+	int found;
 	mutex_lock(&smack_list_lock);
 
-	for (sp = smack_list; sp != NULL; sp = sp->smk_next)
-		if (sp->smk_rule.smk_subject == srp->smk_subject &&
-		    sp->smk_rule.smk_object == srp->smk_object) {
-			sp->smk_rule.smk_access = srp->smk_access;
+	found = 0;
+	list_for_each_entry_rcu(sp, &smack_rule_list, list) {
+		if (sp->smk_subject == srp->smk_subject &&
+		    sp->smk_object == srp->smk_object) {
+			found = 1;
+			sp->smk_access = srp->smk_access;
 			break;
 		}
-
-	if (sp == NULL) {
-		newp = kzalloc(sizeof(struct smk_list_entry), GFP_KERNEL);
-		if (newp == NULL) {
-			ret = -ENOMEM;
-			goto out;
-		}
-
-		newp->smk_rule = *srp;
-		newp->smk_next = smack_list;
-		smack_list = newp;
 	}
+	if (found == 0)
+		list_add_rcu(&srp->list, &smack_rule_list);
 
-out:
 	mutex_unlock(&smack_list_lock);
 
 	return ret;
@@ -261,7 +256,7 @@
 static ssize_t smk_write_load(struct file *file, const char __user *buf,
 			      size_t count, loff_t *ppos)
 {
-	struct smack_rule rule;
+	struct smack_rule *rule;
 	char *data;
 	int rc = -EINVAL;
 
@@ -272,9 +267,8 @@
 	 */
 	if (!capable(CAP_MAC_ADMIN))
 		return -EPERM;
-	if (*ppos != 0)
-		return -EINVAL;
-	if (count != SMK_LOADLEN)
+
+	if (*ppos != 0 || count != SMK_LOADLEN)
 		return -EINVAL;
 
 	data = kzalloc(count, GFP_KERNEL);
@@ -286,25 +280,31 @@
 		goto out;
 	}
 
-	rule.smk_subject = smk_import(data, 0);
-	if (rule.smk_subject == NULL)
+	rule = kzalloc(sizeof(*rule), GFP_KERNEL);
+	if (rule == NULL) {
+		rc = -ENOMEM;
 		goto out;
+	}
 
-	rule.smk_object = smk_import(data + SMK_LABELLEN, 0);
-	if (rule.smk_object == NULL)
-		goto out;
+	rule->smk_subject = smk_import(data, 0);
+	if (rule->smk_subject == NULL)
+		goto out_free_rule;
 
-	rule.smk_access = 0;
+	rule->smk_object = smk_import(data + SMK_LABELLEN, 0);
+	if (rule->smk_object == NULL)
+		goto out_free_rule;
+
+	rule->smk_access = 0;
 
 	switch (data[SMK_LABELLEN + SMK_LABELLEN]) {
 	case '-':
 		break;
 	case 'r':
 	case 'R':
-		rule.smk_access |= MAY_READ;
+		rule->smk_access |= MAY_READ;
 		break;
 	default:
-		goto out;
+		goto out_free_rule;
 	}
 
 	switch (data[SMK_LABELLEN + SMK_LABELLEN + 1]) {
@@ -312,10 +312,10 @@
 		break;
 	case 'w':
 	case 'W':
-		rule.smk_access |= MAY_WRITE;
+		rule->smk_access |= MAY_WRITE;
 		break;
 	default:
-		goto out;
+		goto out_free_rule;
 	}
 
 	switch (data[SMK_LABELLEN + SMK_LABELLEN + 2]) {
@@ -323,10 +323,10 @@
 		break;
 	case 'x':
 	case 'X':
-		rule.smk_access |= MAY_EXEC;
+		rule->smk_access |= MAY_EXEC;
 		break;
 	default:
-		goto out;
+		goto out_free_rule;
 	}
 
 	switch (data[SMK_LABELLEN + SMK_LABELLEN + 3]) {
@@ -334,17 +334,20 @@
 		break;
 	case 'a':
 	case 'A':
-		rule.smk_access |= MAY_APPEND;
+		rule->smk_access |= MAY_APPEND;
 		break;
 	default:
-		goto out;
+		goto out_free_rule;
 	}
 
-	rc = smk_set_access(&rule);
+	rc = smk_set_access(rule);
 
 	if (!rc)
 		rc = count;
+	goto out;
 
+out_free_rule:
+	kfree(rule);
 out:
 	kfree(data);
 	return rc;
@@ -433,24 +436,26 @@
 {
 	if (*pos == SEQ_READ_FINISHED)
 		return NULL;
+	if (list_empty(&smack_known_list))
+		return NULL;
 
-	return smack_known;
+	return smack_known_list.next;
 }
 
 static void *cipso_seq_next(struct seq_file *s, void *v, loff_t *pos)
 {
-	struct smack_known *skp = ((struct smack_known *) v)->smk_next;
+	struct list_head  *list = v;
 
 	/*
-	 * Omit labels with no associated cipso value
+	 * labels with no associated cipso value wont be printed
+	 * in cipso_seq_show
 	 */
-	while (skp != NULL && !skp->smk_cipso)
-		skp = skp->smk_next;
-
-	if (skp == NULL)
+	if (list_is_last(list, &smack_known_list)) {
 		*pos = SEQ_READ_FINISHED;
+		return NULL;
+	}
 
-	return skp;
+	return list->next;
 }
 
 /*
@@ -459,7 +464,9 @@
  */
 static int cipso_seq_show(struct seq_file *s, void *v)
 {
-	struct smack_known *skp = (struct smack_known *) v;
+	struct list_head  *list = v;
+	struct smack_known *skp =
+		 list_entry(list, struct smack_known, list);
 	struct smack_cipso *scp = skp->smk_cipso;
 	char *cbp;
 	char sep = '/';
@@ -638,18 +645,21 @@
 {
 	if (*pos == SEQ_READ_FINISHED)
 		return NULL;
-
-	return smack_netlbladdrs;
+	if (list_empty(&smk_netlbladdr_list))
+		return NULL;
+	return smk_netlbladdr_list.next;
 }
 
 static void *netlbladdr_seq_next(struct seq_file *s, void *v, loff_t *pos)
 {
-	struct smk_netlbladdr *skp = ((struct smk_netlbladdr *) v)->smk_next;
+	struct list_head *list = v;
 
-	if (skp == NULL)
+	if (list_is_last(list, &smk_netlbladdr_list)) {
 		*pos = SEQ_READ_FINISHED;
+		return NULL;
+	}
 
-	return skp;
+	return list->next;
 }
 #define BEBITS	(sizeof(__be32) * 8)
 
@@ -658,7 +668,9 @@
  */
 static int netlbladdr_seq_show(struct seq_file *s, void *v)
 {
-	struct smk_netlbladdr *skp = (struct smk_netlbladdr *) v;
+	struct list_head *list = v;
+	struct smk_netlbladdr *skp =
+			 list_entry(list, struct smk_netlbladdr, list);
 	unsigned char *hp = (char *) &skp->smk_host.sin_addr.s_addr;
 	int maskn;
 	u32 temp_mask = be32_to_cpu(skp->smk_mask.s_addr);
@@ -702,30 +714,36 @@
  *
  * This helper insert netlabel in the smack_netlbladdrs list
  * sorted by netmask length (longest to smallest)
+ * locked by &smk_netlbladdr_lock in smk_write_netlbladdr
+ *
  */
 static void smk_netlbladdr_insert(struct smk_netlbladdr *new)
 {
-	struct smk_netlbladdr *m;
+	struct smk_netlbladdr *m, *m_next;
 
-	if (smack_netlbladdrs == NULL) {
-		smack_netlbladdrs = new;
+	if (list_empty(&smk_netlbladdr_list)) {
+		list_add_rcu(&new->list, &smk_netlbladdr_list);
 		return;
 	}
 
+	m = list_entry(rcu_dereference(smk_netlbladdr_list.next),
+			 struct smk_netlbladdr, list);
+
 	/* the comparison '>' is a bit hacky, but works */
-	if (new->smk_mask.s_addr > smack_netlbladdrs->smk_mask.s_addr) {
-		new->smk_next = smack_netlbladdrs;
-		smack_netlbladdrs = new;
+	if (new->smk_mask.s_addr > m->smk_mask.s_addr) {
+		list_add_rcu(&new->list, &smk_netlbladdr_list);
 		return;
 	}
-	for (m = smack_netlbladdrs; m != NULL; m = m->smk_next) {
-		if (m->smk_next == NULL) {
-			m->smk_next = new;
+
+	list_for_each_entry_rcu(m, &smk_netlbladdr_list, list) {
+		if (list_is_last(&m->list, &smk_netlbladdr_list)) {
+			list_add_rcu(&new->list, &m->list);
 			return;
 		}
-		if (new->smk_mask.s_addr > m->smk_next->smk_mask.s_addr) {
-			new->smk_next = m->smk_next;
-			m->smk_next = new;
+		m_next = list_entry(rcu_dereference(m->list.next),
+				 struct smk_netlbladdr, list);
+		if (new->smk_mask.s_addr > m_next->smk_mask.s_addr) {
+			list_add_rcu(&new->list, &m->list);
 			return;
 		}
 	}
@@ -755,6 +773,7 @@
 	struct netlbl_audit audit_info;
 	struct in_addr mask;
 	unsigned int m;
+	int found;
 	u32 mask_bits = (1<<31);
 	__be32 nsa;
 	u32 temp_mask;
@@ -808,14 +827,17 @@
 
 	nsa = newname.sin_addr.s_addr;
 	/* try to find if the prefix is already in the list */
-	for (skp = smack_netlbladdrs; skp != NULL; skp = skp->smk_next)
+	found = 0;
+	list_for_each_entry_rcu(skp, &smk_netlbladdr_list, list) {
 		if (skp->smk_host.sin_addr.s_addr == nsa &&
-		    skp->smk_mask.s_addr == mask.s_addr)
+		    skp->smk_mask.s_addr == mask.s_addr) {
+			found = 1;
 			break;
-
+		}
+	}
 	smk_netlabel_audit_set(&audit_info);
 
-	if (skp == NULL) {
+	if (found == 0) {
 		skp = kzalloc(sizeof(*skp), GFP_KERNEL);
 		if (skp == NULL)
 			rc = -ENOMEM;