/** * q2_get_counter - get ref to counter or create new * @name: name of counter */ static struct xt_quota_counter * q2_get_counter(const struct xt_quota_mtinfo2 *q) { struct proc_dir_entry *p; struct xt_quota_counter *e = NULL; struct xt_quota_counter *new_e; if (*q->name == '\0') return q2_new_counter(q, true); /* No need to hold a lock while getting a new counter */ new_e = q2_new_counter(q, false); if (new_e == NULL) goto out; spin_lock_bh(&counter_list_lock); list_for_each_entry(e, &counter_list, list) if (strcmp(e->name, q->name) == 0) { atomic_inc(&e->ref); spin_unlock_bh(&counter_list_lock); kfree(new_e); pr_debug("xt_quota2: old counter name=%s", e->name); return e; } e = new_e; pr_debug("xt_quota2: new_counter name=%s", e->name); list_add_tail(&e->list, &counter_list); /* The entry having a refcount of 1 is not directly destructible. * This func has not yet returned the new entry, thus iptables * has not references for destroying this entry. * For another rule to try to destroy it, it would 1st need for this * func* to be re-invoked, acquire a new ref for the same named quota. * Nobody will access the e->procfs_entry either. * So release the lock. */ spin_unlock_bh(&counter_list_lock); /* create_proc_entry() is not spin_lock happy */ p = e->procfs_entry = create_proc_entry(e->name, quota_list_perms, proc_xt_quota); if (IS_ERR_OR_NULL(p)) { spin_lock_bh(&counter_list_lock); list_del(&e->list); spin_unlock_bh(&counter_list_lock); goto out; } p->data = e; p->read_proc = quota_proc_read; p->write_proc = quota_proc_write; p->uid = quota_list_uid; p->gid = quota_list_gid; return e; out: kfree(e); return NULL; }
/** * q2_get_counter - get ref to counter or create new * @name: name of counter */ static struct xt_quota_counter * q2_get_counter(const struct xt_quota_mtinfo2 *q) { struct proc_dir_entry *p; struct xt_quota_counter *e; if (*q->name == '\0') return q2_new_counter(q, true); spin_lock_bh(&counter_list_lock); list_for_each_entry(e, &counter_list, list) if (strcmp(e->name, q->name) == 0) { atomic_inc(&e->ref); spin_unlock_bh(&counter_list_lock); return e; } e = q2_new_counter(q, false); if (e == NULL) goto out; p = e->procfs_entry = create_proc_entry(e->name, quota_list_perms, proc_xt_quota); if (p == NULL || IS_ERR(p)) goto out; p->data = e; p->read_proc = quota_proc_read; p->write_proc = quota_proc_write; p->uid = quota_list_uid; p->gid = quota_list_gid; list_add_tail(&e->list, &counter_list); spin_unlock_bh(&counter_list_lock); return e; out: spin_unlock_bh(&counter_list_lock); kfree(e); return NULL; }