Andi Kleen a écrit :
On Wednesday 08 February 2006 01:44, David S. Miller wrote:
From: Ben Greear <[EMAIL PROTECTED]>
Date: Tue, 07 Feb 2006 16:39:52 -0800
Rick Jones wrote:
In the realm of straw ideas, how often are netdevs added and removed,
and would leaving a tombstone behind consume too much memory?
In certain cases...say, with vlans, you could very often create and
destroy net devices. I think that giving up and leaking the memory
is not a good idea.
I think he's suggesting another thing. Reattach the skb->dev
to some dummy device that always persists, when a device goes
down.
One possible way would be to combine the tombstone with a global
generation number.
tombstone would be just the netdevice memory itself not freed, but
possibly reused.
Instead of just having a pointer to struct netdevice in the skb have
a pointer and a generation number. Each use checks the generation
number and if it doesn't match the net devices throw away the
skb because its device is gone. This check is cheap on SMP because
it's fully read only and can happen with shared cache lines.
Then never free struct net_devices, but only reuse them with
higher generation numbers.
The "use" could be some central place like dev_queue_xmit()
and perhaps some places in netfilter. I don't think every
reference of skb->dev would need to check it because most could
probably tolerate stale devices
Disadvantages:
- When the device is freed but not reused yet it must be
in a state that it can be safely accessed by all users
[should be easy]
- If there is some workload that only needs temporarily a lot
of devices then the system can never recover to use less for them.
Probably not a big issue.
- It would need a few bytes in the skb (and possibly other data structures
referencing the device) to store the generation count.
- The generation number check would add a few cycles, but I guess it's much
cheaper
than the cache misses from the reference counts.
- If the generation count wraps then skbs could be sent to the wrong devices.
With 32bit probably not a big issue.
1) Instead of storing a 2-uple {pointer,generation} (and using 12 or 16 bytes
on 64 bits platforms), we could just use a 32 bit quantity
[(ifindex<<8)+(gen_number)]
And have a global table (yes... thats tricky) :
struct {
struct net_device *dev;
unsigned int netgen;
} iftable[MAXDEVICES];
/*
* We assume 'gen' is valid : not out of bounds
*/
static void *get_dev_by_netgen(unsigned int netgen)
{
unsigned int idx = (netgen >> 8);
struct net_device *dev;
BUG_ON(idx >= MAXDEVICES);
dev = iftable[idx];
if (dev && iftable[idx].netgen != netgen)
dev = NULL;
return dev;
}
This would actually save some bytes on 64bits platforms, and the cpu cycles we
loose in validating a 'netgen' are still beter than cache misses.
2) Not easy to not free the devices because their size is variable (see
alloc_netdev()) depending on private data for the driver.
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at http://vger.kernel.org/majordomo-info.html