Index: pf_if.c =================================================================== --- pf_if.c +++ pf_if.c @@ -120,6 +120,8 @@ kif = malloc(sizeof(*kif), PFI_MTYPE, M_WAITOK); PF_RULES_WLOCK(); V_pfi_all = pfi_kif_attach(kif, IFG_ALL); + /* Make sure it does not go away */ + pfi_kif_ref(kif); PF_RULES_WUNLOCK(); IFNET_RLOCK(); @@ -207,6 +209,7 @@ */ kif->pfik_tzero = time_second > 1 ? time_second : 0; TAILQ_INIT(&kif->pfik_dynaddrs); + refcount_init(&kif->pfik_rulerefs, 0); RB_INSERT(pfi_ifhead, &V_pfi_ifs, kif); @@ -217,8 +220,7 @@ pfi_kif_ref(struct pfi_kif *kif) { - PF_RULES_WASSERT(); - kif->pfik_rulerefs++; + refcount_acquire(&kif->pfik_rulerefs); } void @@ -225,10 +227,9 @@ pfi_kif_unref(struct pfi_kif *kif) { - PF_RULES_WASSERT(); KASSERT(kif->pfik_rulerefs > 0, ("%s: %p has zero refs", __func__, kif)); - kif->pfik_rulerefs--; + refcount_release(&kif->pfik_rulerefs); if (kif->pfik_rulerefs > 0) return; @@ -237,6 +238,7 @@ if (kif->pfik_ifp != NULL || kif->pfik_group != NULL || kif == V_pfi_all) return; + PF_RULES_WASSERT(); RB_REMOVE(pfi_ifhead, &V_pfi_ifs, kif); kif->pfik_flags |= PFI_IFLAG_REFS; Index: pf_ioctl.c =================================================================== --- pf_ioctl.c +++ pf_ioctl.c @@ -1163,8 +1163,23 @@ rule = malloc(sizeof(*rule), M_PFRULE, M_WAITOK); bcopy(&pr->rule, rule, sizeof(struct pf_rule)); - if (rule->ifname[0]) - kif = malloc(sizeof(*kif), PFI_MTYPE, M_WAITOK); + /* This is done here to hold RULES_WLOCK at a minimum */ + if (rule->ifname[0]) { + if ((rule->kif = pfi_kif_find(rule->ifname)) == NULL) { + /* + * This happens rarely! + * Only for rules with non-existant interfaces + */ + kif = malloc(sizeof(*kif), PFI_MTYPE, M_WAITOK); + PF_RULES_WLOCK(); + rule->kif = pfi_kif_attach(kif, rule->ifname); + if (rule->kif != kif) + free(kif, PFI_MTYPE); + PF_RULES_WUNLOCK(); + } + pfi_kif_ref(rule->kif); + } else + rule->kif = NULL; rule->states_cur = counter_u64_alloc(M_WAITOK); rule->states_tot = counter_u64_alloc(M_WAITOK); rule->src_nodes = counter_u64_alloc(M_WAITOK); @@ -1174,7 +1189,8 @@ #define ERROUT(x) { error = (x); goto DIOCADDRULE_error; } - PF_RULES_WLOCK(); + sx_xlock(&pf_ioctl_lock); + PF_RULES_RLOCK(); pr->anchor[sizeof(pr->anchor) - 1] = 0; ruleset = pf_find_ruleset(pr->anchor); if (ruleset == NULL) @@ -1201,11 +1217,6 @@ rule->nr = tail->nr + 1; else rule->nr = 0; - if (rule->ifname[0]) { - rule->kif = pfi_kif_attach(kif, rule->ifname); - pfi_kif_ref(rule->kif); - } else - rule->kif = NULL; if (rule->rtableid > 0 && rule->rtableid >= rt_numfibs) error = EBUSY; @@ -1268,7 +1279,8 @@ if (error) { pf_free_rule(rule); - PF_RULES_WUNLOCK(); + PF_RULES_RUNLOCK(); + sx_xunlock(&pf_ioctl_lock); break; } @@ -1278,18 +1290,23 @@ TAILQ_INSERT_TAIL(ruleset->rules[rs_num].inactive.ptr, rule, entries); ruleset->rules[rs_num].inactive.rcount++; - PF_RULES_WUNLOCK(); + PF_RULES_RUNLOCK(); + sx_xunlock(&pf_ioctl_lock); break; #undef ERROUT DIOCADDRULE_error: - PF_RULES_WUNLOCK(); + PF_RULES_RUNLOCK(); + sx_xunlock(&pf_ioctl_lock); counter_u64_free(rule->states_cur); counter_u64_free(rule->states_tot); counter_u64_free(rule->src_nodes); free(rule, M_PFRULE); - if (kif) - free(kif, PFI_MTYPE); + if (rule->kif != NULL) { + PF_RULES_WLOCK(); + pfi_kif_unref(rule->kif); + PF_RULES_WUNLOCK(); + } break; } @@ -1299,17 +1316,20 @@ struct pf_rule *tail; int rs_num; - PF_RULES_WLOCK(); + sx_slock(&pf_ioctl_lock); + PF_RULES_RLOCK(); pr->anchor[sizeof(pr->anchor) - 1] = 0; ruleset = pf_find_ruleset(pr->anchor); if (ruleset == NULL) { - PF_RULES_WUNLOCK(); + PF_RULES_RUNLOCK(); + sx_sunlock(&pf_ioctl_lock); error = EINVAL; break; } rs_num = pf_get_ruleset_number(pr->rule.action); if (rs_num >= PF_RULESET_MAX) { - PF_RULES_WUNLOCK(); + PF_RULES_RUNLOCK(); + sx_sunlock(&pf_ioctl_lock); error = EINVAL; break; } @@ -1320,7 +1340,8 @@ else pr->nr = 0; pr->ticket = ruleset->rules[rs_num].active.ticket; - PF_RULES_WUNLOCK(); + PF_RULES_RUNLOCK(); + sx_sunlock(&pf_ioctl_lock); break; } @@ -1330,22 +1351,26 @@ struct pf_rule *rule; int rs_num, i; - PF_RULES_WLOCK(); + sx_slock(&pf_ioctl_lock); + PF_RULES_RLOCK(); pr->anchor[sizeof(pr->anchor) - 1] = 0; ruleset = pf_find_ruleset(pr->anchor); if (ruleset == NULL) { - PF_RULES_WUNLOCK(); + PF_RULES_RUNLOCK(); + sx_sunlock(&pf_ioctl_lock); error = EINVAL; break; } rs_num = pf_get_ruleset_number(pr->rule.action); if (rs_num >= PF_RULESET_MAX) { - PF_RULES_WUNLOCK(); + PF_RULES_RUNLOCK(); + sx_sunlock(&pf_ioctl_lock); error = EINVAL; break; } if (pr->ticket != ruleset->rules[rs_num].active.ticket) { - PF_RULES_WUNLOCK(); + PF_RULES_RUNLOCK(); + sx_sunlock(&pf_ioctl_lock); error = EBUSY; break; } @@ -1353,7 +1378,8 @@ while ((rule != NULL) && (rule->nr != pr->nr)) rule = TAILQ_NEXT(rule, entries); if (rule == NULL) { - PF_RULES_WUNLOCK(); + PF_RULES_RUNLOCK(); + sx_sunlock(&pf_ioctl_lock); error = EBUSY; break; } @@ -1362,7 +1388,8 @@ pr->rule.u_states_tot = counter_u64_fetch(rule->states_tot); pr->rule.u_src_nodes = counter_u64_fetch(rule->src_nodes); if (pf_anchor_copyout(ruleset, rule, pr)) { - PF_RULES_WUNLOCK(); + PF_RULES_RUNLOCK(); + sx_sunlock(&pf_ioctl_lock); error = EBUSY; break; } @@ -1381,7 +1408,8 @@ rule->bytes[0] = rule->bytes[1] = 0; counter_u64_zero(rule->states_tot); } - PF_RULES_WUNLOCK(); + PF_RULES_RUNLOCK(); + sx_sunlock(&pf_ioctl_lock); break; } @@ -1456,6 +1484,9 @@ if (newrule->ifname[0]) { newrule->kif = pfi_kif_attach(kif, newrule->ifname); + if (newrule->kif != kif) + free(kif, PFI_MTYPE); + kif = NULL; pfi_kif_ref(newrule->kif); } else newrule->kif = NULL; @@ -2235,6 +2266,8 @@ if (pa->ifname[0]) { pa->kif = pfi_kif_attach(kif, pa->ifname); pfi_kif_ref(pa->kif); + if (pa->kif != kif) + free(kif, PFI_MTYPE); } else pa->kif = NULL; if (pa->addr.type == PF_ADDR_DYNIFTL && ((error = @@ -2354,6 +2387,8 @@ if (newpa->ifname[0]) { newpa->kif = pfi_kif_attach(kif, newpa->ifname); pfi_kif_ref(newpa->kif); + if (newpa->kif != kif) + free(kif, PFI_MTYPE); kif = NULL; }