Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F143032427
D54535.id169919.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
17 KB
Referenced Files
None
Subscribers
None
D54535.id169919.diff
View Options
diff --git a/sys/netpfil/ipfw/ip_fw2.c b/sys/netpfil/ipfw/ip_fw2.c
--- a/sys/netpfil/ipfw/ip_fw2.c
+++ b/sys/netpfil/ipfw/ip_fw2.c
@@ -3741,12 +3741,9 @@
last = IS_DEFAULT_VNET(curvnet) ? 1 : 0;
IPFW_UH_WLOCK(chain);
- IPFW_UH_WUNLOCK(chain);
ipfw_dyn_uninit(0); /* run the callout_drain */
- IPFW_UH_WLOCK(chain);
-
reap = NULL;
IPFW_WLOCK(chain);
for (i = 0; i < chain->n_rules; i++)
diff --git a/sys/netpfil/ipfw/ip_fw_dynamic.c b/sys/netpfil/ipfw/ip_fw_dynamic.c
--- a/sys/netpfil/ipfw/ip_fw_dynamic.c
+++ b/sys/netpfil/ipfw/ip_fw_dynamic.c
@@ -663,6 +663,8 @@
ipfw_obj_ntlv *ntlv;
char *name;
+ IPFW_UH_WLOCK_ASSERT(ch);
+
DYN_DEBUG("uidx %u", ti->uidx);
if (ti->uidx != 0) {
if (ti->tlvs == NULL)
@@ -681,7 +683,6 @@
obj->no.etlv = IPFW_TLV_STATE_NAME;
strlcpy(obj->name, name, sizeof(obj->name));
- IPFW_UH_WLOCK(ch);
no = ipfw_objhash_lookup_name_type(ni, 0,
IPFW_TLV_STATE_NAME, name);
if (no != NULL) {
@@ -691,14 +692,12 @@
*/
*pkidx = no->kidx;
no->refcnt++;
- IPFW_UH_WUNLOCK(ch);
free(obj, M_IPFW);
DYN_DEBUG("\tfound kidx %u for name '%s'", *pkidx, no->name);
return (0);
}
if (ipfw_objhash_alloc_idx(ni, &obj->no.kidx) != 0) {
DYN_DEBUG("\talloc_idx failed for %s", name);
- IPFW_UH_WUNLOCK(ch);
free(obj, M_IPFW);
return (ENOSPC);
}
@@ -706,7 +705,6 @@
SRV_OBJECT(ch, obj->no.kidx) = obj;
obj->no.refcnt++;
*pkidx = obj->no.kidx;
- IPFW_UH_WUNLOCK(ch);
DYN_DEBUG("\tcreated kidx %u for name '%s'", *pkidx, name);
return (0);
}
@@ -2145,9 +2143,6 @@
* Userland can invoke ipfw_expire_dyn_states() to delete
* specific states, this will lead to modification of expired
* lists.
- *
- * XXXAE: do we need DYN_EXPIRED_LOCK? We can just use
- * IPFW_UH_WLOCK to protect access to these lists.
*/
DYN_EXPIRED_LOCK();
DYN_FREE_STATES(s4, s4n, ipv4);
@@ -2306,8 +2301,6 @@
void *rule;
int bucket, removed, length, max_length;
- IPFW_UH_WLOCK_ASSERT(ch);
-
/*
* Unlink expired states from each bucket.
* With acquired bucket lock iterate entries of each lists:
@@ -2733,10 +2726,6 @@
s, entry); \
} \
} while (0)
- /*
- * Prevent rules changing from userland.
- */
- IPFW_UH_WLOCK(chain);
/*
* Hold traffic processing until we finish resize to
* prevent access to states lists.
@@ -2780,7 +2769,6 @@
V_curr_dyn_buckets = new;
IPFW_WUNLOCK(chain);
- IPFW_UH_WUNLOCK(chain);
/* Release old resources */
while (bucket-- != 0)
@@ -2818,15 +2806,8 @@
* First free states unlinked in previous passes.
*/
dyn_free_states(&V_layer3_chain);
- /*
- * Now unlink others expired states.
- * We use IPFW_UH_WLOCK to avoid concurrent call of
- * dyn_expire_states(). It is the only function that does
- * deletion of state entries from states lists.
- */
- IPFW_UH_WLOCK(&V_layer3_chain);
dyn_expire_states(&V_layer3_chain, NULL);
- IPFW_UH_WUNLOCK(&V_layer3_chain);
+
/*
* Send keepalives if they are enabled and the time has come.
*/
@@ -2863,14 +2844,24 @@
void
ipfw_expire_dyn_states(struct ip_fw_chain *chain, ipfw_range_tlv *rt)
{
+ IPFW_RLOCK_TRACKER;
+
/*
* Do not perform any checks if we currently have no dynamic states
*/
if (V_dyn_count == 0)
return;
- IPFW_UH_WLOCK_ASSERT(chain);
+ /*
+ * Acquire read lock to prevent race with dyn_grow_hashtable() called
+ * via dyn_tick(). Note that dyn_tick() also calls dyn_expire_states(),
+ * but doesn't acquire the chain lock. A race between dyn_tick() and
+ * this function should be safe, as dyn_expire_states() does all proper
+ * locking of buckets and expire lists.
+ */
+ IPFW_RLOCK(chain);
dyn_expire_states(chain, rt);
+ IPFW_RUNLOCK(chain);
}
/*
diff --git a/sys/netpfil/ipfw/ip_fw_iface.c b/sys/netpfil/ipfw/ip_fw_iface.c
--- a/sys/netpfil/ipfw/ip_fw_iface.c
+++ b/sys/netpfil/ipfw/ip_fw_iface.c
@@ -320,9 +320,7 @@
* First request to subsystem.
* Let's perform init.
*/
- IPFW_UH_WUNLOCK(ch);
vnet_ipfw_iface_init(ch);
- IPFW_UH_WLOCK(ch);
ii = CHAIN_TO_II(ch);
}
@@ -335,8 +333,6 @@
return (0);
}
- IPFW_UH_WUNLOCK(ch);
-
/* Not found. Let's create one */
iif = malloc(sizeof(struct ipfw_iface), M_IPFW, M_WAITOK | M_ZERO);
TAILQ_INIT(&iif->consumers);
@@ -350,7 +346,6 @@
* are not holding any locks.
*/
iif->no.refcnt = 1;
- IPFW_UH_WLOCK(ch);
tmp = (struct ipfw_iface *)ipfw_objhash_lookup_name(ii, 0, name);
if (tmp != NULL) {
diff --git a/sys/netpfil/ipfw/ip_fw_nat.c b/sys/netpfil/ipfw/ip_fw_nat.c
--- a/sys/netpfil/ipfw/ip_fw_nat.c
+++ b/sys/netpfil/ipfw/ip_fw_nat.c
@@ -503,7 +503,6 @@
gencnt = chain->gencnt;
ptr = lookup_nat_name(&chain->nat, ucfg->name);
if (ptr == NULL) {
- IPFW_UH_WUNLOCK(chain);
/* New rule: allocate and init new instance. */
ptr = malloc(sizeof(struct cfg_nat), M_IPFW, M_WAITOK | M_ZERO);
ptr->lib = LibAliasInit(NULL);
@@ -514,7 +513,6 @@
LIST_REMOVE(ptr, _next);
flush_nat_ptrs(chain, ptr->id);
IPFW_WUNLOCK(chain);
- IPFW_UH_WUNLOCK(chain);
}
/*
@@ -543,7 +541,6 @@
del_redir_spool_cfg(ptr, &ptr->redir_chain);
/* Add new entries. */
add_redir_spool_cfg((char *)(ucfg + 1), ptr);
- IPFW_UH_WLOCK(chain);
/* Extra check to avoid race with another ipfw_nat_cfg() */
tcfg = NULL;
@@ -1049,7 +1046,6 @@
len += sizeof(struct cfg_spool_legacy);
}
}
- IPFW_UH_RUNLOCK(chain);
data = malloc(len, M_TEMP, M_WAITOK | M_ZERO);
bcopy(&nat_cnt, data, sizeof(nat_cnt));
@@ -1057,7 +1053,6 @@
nat_cnt = 0;
len = sizeof(nat_cnt);
- IPFW_UH_RLOCK(chain);
if (gencnt != chain->gencnt) {
free(data, M_TEMP);
goto retry;
diff --git a/sys/netpfil/ipfw/ip_fw_private.h b/sys/netpfil/ipfw/ip_fw_private.h
--- a/sys/netpfil/ipfw/ip_fw_private.h
+++ b/sys/netpfil/ipfw/ip_fw_private.h
@@ -323,7 +323,7 @@
#if defined( __linux__ ) || defined( _WIN32 )
spinlock_t uh_lock;
#else
- struct rwlock uh_lock; /* lock for upper half */
+ struct sx uh_lock; /* lock for upper half */
#endif
};
@@ -451,12 +451,12 @@
#else /* FreeBSD */
#define IPFW_LOCK_INIT(_chain) do { \
rm_init_flags(&(_chain)->rwmtx, "IPFW static rules", RM_RECURSE); \
- rw_init(&(_chain)->uh_lock, "IPFW UH lock"); \
+ sx_init(&(_chain)->uh_lock, "IPFW UH lock"); \
} while (0)
#define IPFW_LOCK_DESTROY(_chain) do { \
rm_destroy(&(_chain)->rwmtx); \
- rw_destroy(&(_chain)->uh_lock); \
+ sx_destroy(&(_chain)->uh_lock); \
} while (0)
#define IPFW_RLOCK_ASSERT(_chain) rm_assert(&(_chain)->rwmtx, RA_RLOCKED)
@@ -471,14 +471,14 @@
#define IPFW_PF_RUNLOCK(p) IPFW_RUNLOCK(p)
#endif
-#define IPFW_UH_RLOCK_ASSERT(_chain) rw_assert(&(_chain)->uh_lock, RA_RLOCKED)
-#define IPFW_UH_WLOCK_ASSERT(_chain) rw_assert(&(_chain)->uh_lock, RA_WLOCKED)
-#define IPFW_UH_UNLOCK_ASSERT(_chain) rw_assert(&(_chain)->uh_lock, RA_UNLOCKED)
+#define IPFW_UH_RLOCK_ASSERT(_chain) sx_assert(&(_chain)->uh_lock, SA_SLOCKED)
+#define IPFW_UH_WLOCK_ASSERT(_chain) sx_assert(&(_chain)->uh_lock, SA_XLOCKED)
+#define IPFW_UH_UNLOCK_ASSERT(_chain) sx_assert(&(_chain)->uh_lock, SA_UNLOCKED)
-#define IPFW_UH_RLOCK(p) rw_rlock(&(p)->uh_lock)
-#define IPFW_UH_RUNLOCK(p) rw_runlock(&(p)->uh_lock)
-#define IPFW_UH_WLOCK(p) rw_wlock(&(p)->uh_lock)
-#define IPFW_UH_WUNLOCK(p) rw_wunlock(&(p)->uh_lock)
+#define IPFW_UH_RLOCK(p) sx_slock(&(p)->uh_lock)
+#define IPFW_UH_RUNLOCK(p) sx_sunlock(&(p)->uh_lock)
+#define IPFW_UH_WLOCK(p) sx_xlock(&(p)->uh_lock)
+#define IPFW_UH_WUNLOCK(p) sx_xunlock(&(p)->uh_lock)
struct obj_idx {
uint32_t uidx; /* internal index supplied by userland */
diff --git a/sys/netpfil/ipfw/ip_fw_sockopt.c b/sys/netpfil/ipfw/ip_fw_sockopt.c
--- a/sys/netpfil/ipfw/ip_fw_sockopt.c
+++ b/sys/netpfil/ipfw/ip_fw_sockopt.c
@@ -337,44 +337,15 @@
}
/*
- * allocate a new map, returns the chain locked. extra is the number
- * of entries to add or delete.
- */
-static struct ip_fw **
-get_map(struct ip_fw_chain *chain, int extra, int locked)
-{
-
- for (;;) {
- struct ip_fw **map;
- u_int i, mflags;
-
- mflags = M_ZERO | ((locked != 0) ? M_NOWAIT : M_WAITOK);
-
- i = chain->n_rules + extra;
- map = malloc(i * sizeof(struct ip_fw *), M_IPFW, mflags);
- if (map == NULL) {
- printf("%s: cannot allocate map\n", __FUNCTION__);
- return NULL;
- }
- if (!locked)
- IPFW_UH_WLOCK(chain);
- if (i >= chain->n_rules + extra) /* good */
- return map;
- /* otherwise we lost the race, free and retry */
- if (!locked)
- IPFW_UH_WUNLOCK(chain);
- free(map, M_IPFW);
- }
-}
-
-/*
- * swap the maps. It is supposed to be called with IPFW_UH_WLOCK
+ * swap the maps.
*/
static struct ip_fw **
swap_map(struct ip_fw_chain *chain, struct ip_fw **new_map, int new_len)
{
struct ip_fw **old_map;
+ IPFW_UH_WLOCK_ASSERT(chain);
+
IPFW_WLOCK(chain);
chain->id++;
chain->n_rules = new_len;
@@ -459,6 +430,7 @@
struct ip_fw *krule;
struct ip_fw **map; /* the new array of pointers */
+ IPFW_UH_WLOCK(chain);
/* Check if we need to do table/obj index remap */
tcount = 0;
for (ci = rci, i = 0; i < count; ci++, i++) {
@@ -484,8 +456,6 @@
* We have some more table rules
* we need to rollback.
*/
-
- IPFW_UH_WLOCK(chain);
while (ci != rci) {
ci--;
if (ci->object_opcodes == 0)
@@ -493,33 +463,16 @@
unref_rule_objects(chain,ci->krule);
}
- IPFW_UH_WUNLOCK(chain);
-
}
-
+ IPFW_UH_WUNLOCK(chain);
return (error);
}
tcount++;
}
- /* get_map returns with IPFW_UH_WLOCK if successful */
- map = get_map(chain, count, 0 /* not locked */);
- if (map == NULL) {
- if (tcount > 0) {
- /* Unbind tables */
- IPFW_UH_WLOCK(chain);
- for (ci = rci, i = 0; i < count; ci++, i++) {
- if (ci->object_opcodes == 0)
- continue;
-
- unref_rule_objects(chain, ci->krule);
- }
- IPFW_UH_WUNLOCK(chain);
- }
-
- return (ENOSPC);
- }
+ map = malloc((chain->n_rules + count) * sizeof(struct ip_fw *),
+ M_IPFW, M_ZERO | M_WAITOK);
if (V_autoinc_step < 1)
V_autoinc_step = 1;
@@ -572,9 +525,9 @@
{
struct ip_fw **map;
- map = get_map(chain, 1, 0);
- if (map == NULL)
- return (ENOMEM);
+ IPFW_UH_WLOCK(chain);
+ map = malloc((chain->n_rules + 1) * sizeof(struct ip_fw *),
+ M_IPFW, M_ZERO | M_WAITOK);
if (chain->n_rules > 0)
bcopy(chain->map, map,
chain->n_rules * sizeof(struct ip_fw *));
@@ -812,12 +765,8 @@
}
/* Allocate new map of the same size */
- map = get_map(chain, 0, 1 /* locked */);
- if (map == NULL) {
- IPFW_UH_WUNLOCK(chain);
- return (ENOMEM);
- }
-
+ map = malloc(chain->n_rules * sizeof(struct ip_fw *),
+ M_IPFW, M_ZERO | M_WAITOK);
n = 0;
ndyn = 0;
ofs = start;
@@ -2227,7 +2176,7 @@
cmdlen = 0;
error = 0;
- IPFW_UH_WLOCK(ch);
+ IPFW_UH_WLOCK_ASSERT(ch);
/* Increase refcount on each existing referenced table. */
for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
@@ -2250,10 +2199,8 @@
if (error != 0) {
/* Unref everything we have already done */
unref_oib_objects(ch, rule->cmd, oib, pidx);
- IPFW_UH_WUNLOCK(ch);
return (error);
}
- IPFW_UH_WUNLOCK(ch);
/* Perform auto-creation for non-existing objects */
if (pidx != oib)
diff --git a/sys/netpfil/ipfw/ip_fw_table.c b/sys/netpfil/ipfw/ip_fw_table.c
--- a/sys/netpfil/ipfw/ip_fw_table.c
+++ b/sys/netpfil/ipfw/ip_fw_table.c
@@ -277,7 +277,6 @@
* creating new one.
*
* Saves found table config into @ptc.
- * Note function may drop/acquire UH_WLOCK.
* Returns 0 if table was found/created and referenced
* or non-zero return code.
*/
@@ -321,9 +320,7 @@
if ((tei->flags & TEI_FLAGS_COMPAT) == 0)
return (ESRCH);
- IPFW_UH_WUNLOCK(ch);
error = create_table_compat(ch, ti, &kidx);
- IPFW_UH_WLOCK(ch);
if (error != 0)
return (error);
@@ -560,12 +557,10 @@
*/
restart:
if (ts.modified != 0) {
- IPFW_UH_WUNLOCK(ch);
flush_batch_buffer(ch, ta, tei, count, rollback,
ta_buf_m, ta_buf);
memset(&ts, 0, sizeof(ts));
ta = NULL;
- IPFW_UH_WLOCK(ch);
}
error = find_ref_table(ch, ti, tei, count, OP_ADD, &tc);
@@ -586,14 +581,12 @@
ts.count = count;
rollback = 0;
add_toperation_state(ch, &ts);
- IPFW_UH_WUNLOCK(ch);
/* Allocate memory and prepare record(s) */
/* Pass stack buffer by default */
ta_buf_m = ta_buf;
error = prepare_batch_buffer(ch, ta, tei, count, OP_ADD, &ta_buf_m);
- IPFW_UH_WLOCK(ch);
del_toperation_state(ch, &ts);
/* Drop reference we've used in first search */
tc->no.refcnt--;
@@ -612,8 +605,6 @@
/*
* Link all values values to shared/per-table value array.
- *
- * May release/reacquire UH_WLOCK.
*/
error = ipfw_link_table_values(ch, &ts, flags);
if (error != 0)
@@ -623,7 +614,7 @@
/*
* Ensure we are able to add all entries without additional
- * memory allocations. May release/reacquire UH_WLOCK.
+ * memory allocations.
*/
kidx = tc->no.kidx;
error = check_table_space(ch, &ts, tc, KIDX_TO_TI(ch, kidx), count);
@@ -730,7 +721,6 @@
return (error);
}
ta = tc->ta;
- IPFW_UH_WUNLOCK(ch);
/* Allocate memory and prepare record(s) */
/* Pass stack buffer by default */
@@ -739,8 +729,6 @@
if (error != 0)
goto cleanup;
- IPFW_UH_WLOCK(ch);
-
/* Drop reference we've used in first search */
tc->no.refcnt--;
@@ -841,12 +829,10 @@
/* We have to shrink/grow table */
if (ts != NULL)
add_toperation_state(ch, ts);
- IPFW_UH_WUNLOCK(ch);
memset(&ta_buf, 0, sizeof(ta_buf));
error = ta->prepare_mod(ta_buf, &pflags);
- IPFW_UH_WLOCK(ch);
if (ts != NULL)
del_toperation_state(ch, ts);
@@ -866,8 +852,6 @@
/* Check if we still need to alter table */
ti = KIDX_TO_TI(ch, tc->no.kidx);
if (ta->need_modify(tc->astate, ti, count, &pflags) == 0) {
- IPFW_UH_WUNLOCK(ch);
-
/*
* Other thread has already performed resize.
* Flush our state and return.
@@ -1185,7 +1169,6 @@
tflags = tc->tflags;
tc->no.refcnt++;
add_toperation_state(ch, &ts);
- IPFW_UH_WUNLOCK(ch);
/*
* Stage 1.5: if this is not the first attempt, destroy previous state
@@ -1205,7 +1188,6 @@
* Stage 3: swap old state pointers with newly-allocated ones.
* Decrease refcount.
*/
- IPFW_UH_WLOCK(ch);
tc->no.refcnt--;
del_toperation_state(ch, &ts);
@@ -1742,6 +1724,7 @@
char *tname, *aname;
struct tid_info ti;
struct namedobj_instance *ni;
+ int rv;
if (sd->valsize != sizeof(*oh) + sizeof(ipfw_xtable_info))
return (EINVAL);
@@ -1769,14 +1752,15 @@
ni = CHAIN_TO_NI(ch);
- IPFW_UH_RLOCK(ch);
+ IPFW_UH_WLOCK(ch);
if (find_table(ni, &ti) != NULL) {
- IPFW_UH_RUNLOCK(ch);
+ IPFW_UH_WUNLOCK(ch);
return (EEXIST);
}
- IPFW_UH_RUNLOCK(ch);
+ rv = create_table_internal(ch, &ti, aname, i, NULL, 0);
+ IPFW_UH_WUNLOCK(ch);
- return (create_table_internal(ch, &ti, aname, i, NULL, 0));
+ return (rv);
}
/*
@@ -1797,6 +1781,8 @@
struct table_algo *ta;
uint32_t kidx;
+ IPFW_UH_WLOCK_ASSERT(ch);
+
ni = CHAIN_TO_NI(ch);
ta = find_table_algo(CHAIN_TO_TCFG(ch), ti, aname);
@@ -1814,8 +1800,6 @@
else
tc->locked = (i->flags & IPFW_TGFLAGS_LOCKED) != 0;
- IPFW_UH_WLOCK(ch);
-
/* Check if table has been already created */
tc_new = find_table(ni, ti);
if (tc_new != NULL) {
@@ -1825,7 +1809,6 @@
* which has the same type
*/
if (compat == 0 || tc_new->no.subtype != tc->no.subtype) {
- IPFW_UH_WUNLOCK(ch);
free_table_config(ni, tc);
return (EEXIST);
}
@@ -1837,7 +1820,6 @@
} else {
/* New table */
if (ipfw_objhash_alloc_idx(ni, &kidx) != 0) {
- IPFW_UH_WUNLOCK(ch);
printf("Unable to allocate table index."
" Consider increasing net.inet.ip.fw.tables_max");
free_table_config(ni, tc);
@@ -1854,8 +1836,6 @@
if (pkidx != NULL)
*pkidx = tc->no.kidx;
- IPFW_UH_WUNLOCK(ch);
-
if (tc_new != NULL)
free_table_config(ni, tc_new);
diff --git a/sys/netpfil/ipfw/ip_fw_table_value.c b/sys/netpfil/ipfw/ip_fw_table_value.c
--- a/sys/netpfil/ipfw/ip_fw_table_value.c
+++ b/sys/netpfil/ipfw/ip_fw_table_value.c
@@ -167,7 +167,6 @@
/*
* Grows value storage shared among all tables.
- * Drops/reacquires UH locks.
* Notifies other running adds on @ch shared storage resize.
* Note function does not guarantee that free space
* will be available after invocation, so one caller needs
@@ -200,15 +199,11 @@
if (val_size == (1 << 30))
return (ENOSPC);
- IPFW_UH_WUNLOCK(ch);
-
valuestate = malloc(sizeof(struct table_value) * val_size, M_IPFW,
M_WAITOK | M_ZERO);
ipfw_objhash_bitmap_alloc(val_size, (void *)&new_idx,
&new_blocks);
- IPFW_UH_WLOCK(ch);
-
/*
* Check if we still need to resize
*/
@@ -359,7 +354,6 @@
/*
* Allocate new value index in either shared or per-table array.
- * Function may drop/reacquire UH lock.
*
* Returns 0 on success.
*/
@@ -375,9 +369,7 @@
error = ipfw_objhash_alloc_idx(vi, &vidx);
if (error != 0) {
/*
- * We need to resize array. This involves
- * lock/unlock, so we need to check "modified"
- * state.
+ * We need to resize array.
*/
ts->opstate.func(ts->tc, &ts->opstate);
error = resize_shared_value_storage(ch);
@@ -525,7 +517,6 @@
add_toperation_state(ch, ts);
/* Ensure table won't disappear */
tc_ref(tc);
- IPFW_UH_WUNLOCK(ch);
/*
* Stage 2: allocate objects for non-existing values.
@@ -544,7 +535,6 @@
* Stage 3: allocate index numbers for new values
* and link them to index.
*/
- IPFW_UH_WLOCK(ch);
tc_unref(tc);
del_toperation_state(ch, ts);
if (ts->modified != 0) {
@@ -572,7 +562,6 @@
continue;
}
- /* May perform UH unlock/lock */
error = alloc_table_vidx(ch, ts, vi, &vidx, flags);
if (error != 0) {
ts->opstate.func(ts->tc, &ts->opstate);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Jan 26, 9:41 AM (15 h, 39 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28019426
Default Alt Text
D54535.id169919.diff (17 KB)
Attached To
Mode
D54535: ipfw: make the upper half lock sleepable
Attached
Detach File
Event Timeline
Log In to Comment