* Re: KS8695: possible NAPI issue
From: Dick Hollenbeck @ 2010-03-03 5:01 UTC (permalink / raw)
To: figo zhang; +Cc: Yegor Yefremov, netdev, zealcook
In-Reply-To: <c6ed1ac51003021746n2b246591g880b584550ec5e84@mail.gmail.com>
figo zhang wrote:
> 2010/3/2 Dick Hollenbeck <dick@softplc.com>:
>
>> Yegor Yefremov wrote:
>>
>>> I'm using 2.6.33 kernel and I noticed such a strange behavior:
>>>
>>> after system start I transfer one file via netcat from my development
>>> host, after this transfer the network is not functioning i.e. no pings
>>> possible etc.
>>>
>>> To narrow down the problem I checked out this commit
>>>
>>> http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=451f14439847db302e5104c44458b2dbb4b1829d.
>>> Till here the network driver is functioning as intended, but after
>>> NAPI introduction I have this issue. With latest git-pull of "Linus'
>>> kernel tree" I can't even ping right after the systems start.
>>>
>>> Any Ideas? What am I missing?
>>>
>>>
>> No idea, although I am using the same ARM chip, my kernel is at 2.6.30.5,
>> and except for this occasional loss of connection I get, the ethernet driver
>> seems to work better than what you are reporting.
>>
>
> from linux-2.6.32, this ethernet driver have add NAPI support, would
> you like to
> try using this version?
>
Seems like a lot of work for me, given that my 2.6.30.5 kernel is mostly
working. Yegor is having the problems on the newer kernels, newer than
mine. Sounds like a warning flag to me, not an incentive.
What is NAPI and why do I care?
Dick
^ permalink raw reply
* Re: 2.6.33 dies on modprobe
From: Andrew Morton @ 2010-03-03 2:52 UTC (permalink / raw)
To: Américo Wang
Cc: M G Berberich, linux-kernel, Linux Kernel Network Developers
In-Reply-To: <2375c9f91002282022n29e83858jd8cadbb2e664b436@mail.gmail.com>
On Mon, 1 Mar 2010 12:22:59 +0800 Am__rico Wang <xiyou.wangcong@gmail.com> wrote:
>
> You snipped too much. The full backtrace is useful:
>
> BUG: unable to handle kernel paging request at ffffffffa001b57f
> IP: [<ffffffff811895db>] strcmp+0xb/0x30
> PGD 1498067 PUD 149c063 PMD 12daf2067 PTE 0
> Oops: 0000 [#1] SMP
> last sysfs file:
> /sys/devices/pci0000:00/0000:00:05.0/host0/target0:0:0/0:0:0:0/type
> CPU 1
> Pid: 1249, comm: modprobe Not tainted 2.6.33-bmg #1 M55S-S3/
> RIP: 0010:[<ffffffff811895db>] [<ffffffff811895db>] strcmp+0xb/0x30
> RSP: 0018:ffff88012ebe9e58 EFLAGS: 00010282
> RAX: 0000000000000070 RBX: ffff88012f8f4f00 RCX: 00000000ffffffff
> RDX: ffff88012f808800 RSI: ffffffffa001b57f RDI: ffff88012fab2420
> RBP: ffff88012ebe9e58 R08: 0000000000000000 R09: 0000000000000000
> R10: ffff8800284017c0 R11: dead000000200200 R12: ffff88012f9a29c8
> R13: ffff88012f8842a0 R14: ffffffffa001b57f R15: 000000000081c050
> FS: 00007f16bd8916f0(0000) GS:ffff880028280000(0000) knlGS:0000000000000000
> CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b
> CR2: ffffffffa001b57f CR3: 000000012da7c000 CR4: 00000000000006e0
> DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
> DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
> Process modprobe (pid: 1249, threadinfo ffff88012ebe8000, task ffff88012edec0a0)
> Stack:
> ffff88012ebe9e88 ffffffff811852e8 ffffffffa0013080 ffffffffa00130e0
> <0> 000000000081e970 000000000081e970 ffff88012ebe9e98 ffffffff81236b87
> <0> ffff88012ebe9ed8 ffffffff81236ca7 0000000000000021 0000000000000021
> Call Trace:
> [<ffffffff811852e8>] kset_find_obj+0x38/0x80
> [<ffffffff81236b87>] driver_find+0x17/0x30
> [<ffffffff81236ca7>] driver_register+0x67/0x140
> [<ffffffff8119b771>] __pci_register_driver+0x51/0xd0
> [<ffffffffa0017000>] ? init_nic+0x0/0x20 [forcedeth]
> [<ffffffffa001701e>] init_nic+0x1e/0x20 [forcedeth]
>
>
It could be that some kobject on that list has become invalid (memory
was freed, module was unloaded, etc) and later code stumbled across the
now-invalid object on that list and then crashed.
What we can do to find this is to add a diagnostic each time an object
is registered, and a diagnostic each time kset_find_obj() looks at the
objects. Then we'll see which kobject caused the crash, then we can
look back and see where that kobject was registered from.
Something like this:
--- a/lib/kobject.c~a
+++ a/lib/kobject.c
@@ -717,6 +717,8 @@ int kset_register(struct kset *k)
return -EINVAL;
kset_init(k);
+ printk("kset_register:%p\n", &k->kobj);
+ dump_stack();
err = kobject_add_internal(&k->kobj);
if (err)
return err;
@@ -751,9 +753,12 @@ struct kobject *kset_find_obj(struct kse
spin_lock(&kset->list_lock);
list_for_each_entry(k, &kset->list, entry) {
- if (kobject_name(k) && !strcmp(kobject_name(k), name)) {
- ret = kobject_get(k);
- break;
+ if (kobject_name(k)) {
+ printk("kset_find_obj:%p\n", k);
+ if (!strcmp(kobject_name(k), name)) {
+ ret = kobject_get(k);
+ break;
+ }
}
}
spin_unlock(&kset->list_lock);
_
This will generate a lot of output and we don't want to lose any of it.
I'd suggest setting up netconsole so all the output can be reliably
saved: Documentation/networking/netconsole.txt
Thanks.
^ permalink raw reply
* Re: Current wireless-testing breaks libpcap: mr_alen should be set
From: John W. Linville @ 2010-03-03 2:36 UTC (permalink / raw)
To: Pavel Roskin
Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA,
tcpdump-workers-YE1jQ5a0g24KACXWX4p+q9i2O/JbrIOy, Jiri Pirko
In-Reply-To: <1267578048.14049.11.camel@mj>
On Tue, Mar 02, 2010 at 08:00:48PM -0500, Pavel Roskin wrote:
> Also, pulling bleeding edge stuff into wireless-testing before rc1
> appears to be either a mistake or a bad decision.
Feel free to use an earlier commit...
--
John W. Linville Someday the world will need a hero, and you
linville-2XuSBdqkA4R54TAoqtyWWQ@public.gmane.org might be all we have. Be ready.
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [RFC v2 00/10] snet: Security for NETwork syscalls
From: Tetsuo Handa @ 2010-03-03 1:56 UTC (permalink / raw)
To: sam
Cc: linux-kernel, netdev, netfilter-devel, hadi, kaber, zbr, nhorman,
root, linux-security-module
In-Reply-To: <1267561394-13626-1-git-send-email-sam@synack.fr>
Hello.
Regarding [RFC v2 02/10] Revert "lsm: Remove the socket_post_accept() hook"
@@ -1538,6 +1538,8 @@ SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr,
fd_install(newfd, newfile);
err = newfd;
+ security_socket_post_accept(sock, newsock);
+
out_put:
fput_light(sock->file, fput_needed);
out:
Please move security_socket_post_accept() to before fd_install().
Otherwise, other threads which share fd tables can use
security-informations-not-yet-updated accept()ed sockets.
Regarding [RFC v2 04/10] snet: introduce snet_core
+static __init int snet_init(void)
+{
+ int ret;
+
+ pr_debug("initializing: event_hash_size=%u "
+ "verdict_hash_size=%u verdict_delay=%usecs "
+ "default_policy=%s\n",
+ snet_evh_size, snet_vdh_size, snet_verdict_delay,
+ snet_verdict_name(snet_verdict_policy));
Why not to stop here if snet_evh_size == 0 or snet_vdh_size == 0 in order to
avoid "division by 0".
Regarding [RFC v2 05/10] snet: introduce snet_event
+static rwlock_t snet_evh_lock = __RW_LOCK_UNLOCKED();
You can use "static DEFINE_RWLOCK(snet_evh_lock);".
+int snet_event_is_registered(const enum snet_syscall syscall, const u8 protocol)
Maybe rcu_read_lock() is better than rw spinlock because this function is
frequently called.
Regarding [RFC v2 06/10] snet: introduce snet_hooks
+ if ((verdict = snet_ticket_check(&info)) != SNET_VERDICT_NONE)
Please avoid assignment in "if" statement, as scripts/checkpatch.pl suggests.
Regarding [RFC v2 09/10] snet: introduce snet_ticket
+enum snet_verdict snet_ticket_check(struct snet_info *info)
+{
+ struct snet_ticket *st = NULL;
+ unsigned int h = 0, verdict = SNET_VERDICT_NONE;
+ struct list_head *l = NULL;
+ struct snet_task_security *tsec = NULL;
+
+ if (snet_ticket_mode == SNET_TICKET_OFF)
+ goto out;
+
+ tsec = (struct snet_task_security*) current_security();
+
+ h = jhash_2words(info->syscall, info->protocol, 0) % HSIZE;
+ l = &tsec->hash[h];
+
+ read_lock_bh(&tsec->lock);
Credentials are allocated for copy-on-write basis.
Sharing "tsec" among multiple "struct task_struct" is what you intended?
Regards.
^ permalink raw reply
* [PATCH] Bluetooth: Use single_open() for inquiry cache within debugfs
From: Marcel Holtmann @ 2010-03-03 1:48 UTC (permalink / raw)
To: David Miller; +Cc: netdev
The inquiry cache information in debugfs should be using seq_file support
and not allocating memory on the stack for the string. Since the usage of
these information is really seldom, using single_open() for it is good
enough.
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
net/bluetooth/hci_sysfs.c | 41 ++++++++++++++++++++---------------------
1 files changed, 20 insertions(+), 21 deletions(-)
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index 1a79a6c..cafb55b 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -3,6 +3,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/debugfs.h>
+#include <linux/seq_file.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
@@ -405,20 +406,11 @@ static struct device_type bt_host = {
.release = bt_host_release,
};
-static int inquiry_cache_open(struct inode *inode, struct file *file)
-{
- file->private_data = inode->i_private;
- return 0;
-}
-
-static ssize_t inquiry_cache_read(struct file *file, char __user *userbuf,
- size_t count, loff_t *ppos)
+static int inquiry_cache_show(struct seq_file *f, void *p)
{
- struct hci_dev *hdev = file->private_data;
+ struct hci_dev *hdev = f->private;
struct inquiry_cache *cache = &hdev->inq_cache;
struct inquiry_entry *e;
- char buf[4096];
- int n = 0;
hci_dev_lock_bh(hdev);
@@ -426,23 +418,30 @@ static ssize_t inquiry_cache_read(struct file *file, char __user *userbuf,
struct inquiry_data *data = &e->data;
bdaddr_t bdaddr;
baswap(&bdaddr, &data->bdaddr);
- n += sprintf(buf + n, "%s %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %d %u\n",
- batostr(&bdaddr),
- data->pscan_rep_mode, data->pscan_period_mode,
- data->pscan_mode, data->dev_class[2],
- data->dev_class[1], data->dev_class[0],
- __le16_to_cpu(data->clock_offset),
- data->rssi, data->ssp_mode, e->timestamp);
+ seq_printf(f, "%s %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %d %u\n",
+ batostr(&bdaddr),
+ data->pscan_rep_mode, data->pscan_period_mode,
+ data->pscan_mode, data->dev_class[2],
+ data->dev_class[1], data->dev_class[0],
+ __le16_to_cpu(data->clock_offset),
+ data->rssi, data->ssp_mode, e->timestamp);
}
hci_dev_unlock_bh(hdev);
- return simple_read_from_buffer(userbuf, count, ppos, buf, n);
+ return 0;
+}
+
+static int inquiry_cache_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, inquiry_cache_show, inode->i_private);
}
static const struct file_operations inquiry_cache_fops = {
- .open = inquiry_cache_open,
- .read = inquiry_cache_read,
+ .open = inquiry_cache_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
};
int hci_register_sysfs(struct hci_dev *hdev)
--
1.6.6.1
^ permalink raw reply related
* Re: KS8695: possible NAPI issue
From: figo zhang @ 2010-03-03 1:46 UTC (permalink / raw)
To: Dick Hollenbeck; +Cc: Yegor Yefremov, netdev, zealcook
In-Reply-To: <4B8D1C02.1010204@softplc.com>
2010/3/2 Dick Hollenbeck <dick@softplc.com>:
> Yegor Yefremov wrote:
>>
>> I'm using 2.6.33 kernel and I noticed such a strange behavior:
>>
>> after system start I transfer one file via netcat from my development
>> host, after this transfer the network is not functioning i.e. no pings
>> possible etc.
>>
>> To narrow down the problem I checked out this commit
>>
>> http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=451f14439847db302e5104c44458b2dbb4b1829d.
>> Till here the network driver is functioning as intended, but after
>> NAPI introduction I have this issue. With latest git-pull of "Linus'
>> kernel tree" I can't even ping right after the systems start.
>>
>> Any Ideas? What am I missing?
>>
>
> No idea, although I am using the same ARM chip, my kernel is at 2.6.30.5,
> and except for this occasional loss of connection I get, the ethernet driver
> seems to work better than what you are reporting.
from linux-2.6.32, this ethernet driver have add NAPI support, would
you like to
try using this version?
^ permalink raw reply
* Re: linux-next: Tree for March 1 (bluetooth/hci_sysfs)
From: Marcel Holtmann @ 2010-03-03 1:23 UTC (permalink / raw)
To: David Miller
Cc: sfr, randy.dunlap, linux-next, linux-kernel, linux-bluetooth,
netdev
In-Reply-To: <20100301.181415.266447389.davem@davemloft.net>
Hi Dave,
> >> static ssize_t inquiry_cache_read(struct file *file, char __user *userbuf,
> >> size_t count, loff_t *ppos)
> >> {
> >> struct hci_dev *hdev = file->private_data;
> >> struct inquiry_cache *cache = &hdev->inq_cache;
> >> struct inquiry_entry *e;
> >> char buf[4096]; // <<<<<<<<<<<<<<<<<<<<<<<<<<< huh? don't do that on stack.
> >> int n = 0;
> >
> > Dave Miller is following up on that.
>
> This looks like a job for.... SEQ FILE! :-)
>
> I'm testing the following fix.
I have a working and tested patch that uses single_open(). Will send a
patch with commit message and everything in a bit so you can apply it.
Regards
Marcel
^ permalink raw reply
* Current wireless-testing breaks libpcap: mr_alen should be set
From: Pavel Roskin @ 2010-03-03 1:00 UTC (permalink / raw)
To: linux-wireless, netdev, tcpdump-workers; +Cc: Jiri Pirko
Hello!
The current wireless-testing appears to have some non-wireless bits from
the upcoming Linux 2.6.34. As a result, libpcap and all capture
programs that use it are broken.
This patch to libpcap helps:
--- a/pcap-linux.c
+++ b/pcap-linux.c
@@ -1563,6 +1563,7 @@ live_open_new(pcap_t *handle, const char
memset(&mr, 0, sizeof(mr));
mr.mr_ifindex = handle->md.ifindex;
mr.mr_type = PACKET_MR_PROMISC;
+ mr.mr_alen = 6;
if (setsockopt(sock_fd, SOL_PACKET,
PACKET_ADD_MEMBERSHIP, &mr, sizeof(mr)) == -1)
{
libpcap git doesn't have the fix yet.
The breakage must be coming from the commit 914c8ad2 by Jiri Pirko to
net/packet/af_packet.c
I think it's very unhelpful to introduce patches that break significant
userspace functionality without giving the affected programs an advance
warning.
Also, pulling bleeding edge stuff into wireless-testing before rc1
appears to be either a mistake or a bad decision.
Sorry for cross-post, but it's an urgent issue. Repliers are encouraged
to trim the recipient list as necessary.
--
Regards,
Pavel Roskin
^ permalink raw reply
* Re: 2.6.33 problems
From: Tejun Heo @ 2010-03-03 0:56 UTC (permalink / raw)
To: Andrew Morton; +Cc: werner, linux-kernel, netdev
In-Reply-To: <20100302135032.e3d11bbf.akpm@linux-foundation.org>
Hello,
On 03/03/2010 06:50 AM, Andrew Morton wrote:
> On Sat, 27 Feb 2010 14:09:11 -0300 (GFT)
> werner@guyane.dyn-o-saur.com wrote:
>
>> For better error searching / correction, I add below the whole syslog.
>>
>> This is refered to 2.6.33 published (without patchs)
>>
>> This are different errors.
>>
>> The most of them exists since 2.6.33-rc1 or appr. -rc5.
>>
>> I posted here already the whole syslog.bz2 but nobody toke care.
>>
>> the boot_vga error occurs only after I start the grafics mode. It's the mainboard's embedded nvidia grafics. I use the vesa framebuffer driver of X 1.8
>>
>> the int6_init error occurs also in text mode. I think it have something to do with internet.
>>
>> Also the printk errors occur only when start the computer in the grafics mode, but not when starting it in the text mode.
>>
>> Below is also the kernel config. Its the same like since -rc7 (but the errors are also the same)
Hmmmm... it seems like the percpu allocator failed to allocate space
for a new chunk in the vmalloc area. Looking through the config.
Hmmm, w/ 3G split, there should be enough vmalloc area. Strange.
Does kernel parameter "percpu_alloc=page" make the machine boot? If
so, can you please post the output of dmesg right after boot?
Thanks.
--
tejun
^ permalink raw reply
* Re: [RFC PATCH]xfrm: fix perpetual bundles
From: jamal @ 2010-03-03 0:47 UTC (permalink / raw)
To: Steffen Klassert
Cc: Herbert Xu, davem, kaber, yoshfuji, nakam, eric.dumazet, netdev
In-Reply-To: <20100302140631.GD20508@secunet.com>
> Acked-by: Steffen Klassert <steffen.klassert@secunet.com>
tested - Looks good.
Acked-by: Jamal Hadi Salim <hadi@cyberus.ca>
cheers,
jamal
^ permalink raw reply
* Re: [RFC][PATCH] ns: Syscalls for better namespace sharing control.
From: Eric W. Biederman @ 2010-03-03 0:46 UTC (permalink / raw)
To: Sukadev Bhattiprolu
Cc: Pavel Emelyanov, Daniel Lezcano, Linux Netdev List, containers,
Netfilter Development Mailinglist, Ben Greear
In-Reply-To: <20100303000743.GA13744@us.ibm.com>
Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com> writes:
> Eric W. Biederman [ebiederm@xmission.com] wrote:
> |
> | I think replacing a struct pid for another struct pid allocated in
> | descendant pid_namespace (but has all of the same struct upid values
> | as the first struct pid) is a disastrous idea. It destroys the
>
> True. Sorry, I did not mean we would need a new 'struct pid' for an
> existing process. I think we talked earlier of finding a way of attaching
> additional pid numbers to the same struct pid.
I just played with this and if you make the semantics of unshare(CLONE_NEWPID)
to be that you become the idle task aka pid 0, and not the init task pid 1 the
implementation is trivial.
Eric
----
arch/powerpc/platforms/cell/spufs/sched.c | 2 +-
arch/um/drivers/mconsole_kern.c | 2 +-
fs/proc/root.c | 2 +-
init/main.c | 9 ---------
kernel/cgroup.c | 2 +-
kernel/fork.c | 16 +++++++++++++---
kernel/nsproxy.c | 2 +-
kernel/perf_event.c | 2 +-
kernel/pid.c | 8 ++++----
kernel/signal.c | 9 ++++-----
kernel/sysctl_binary.c | 2 +-
11 files changed, 28 insertions(+), 28 deletions(-)
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c
index 4678078..b7f2026 100644
--- a/arch/powerpc/platforms/cell/spufs/sched.c
+++ b/arch/powerpc/platforms/cell/spufs/sched.c
@@ -1094,7 +1094,7 @@ static int show_spu_loadavg(struct seq_file *s, void *private)
LOAD_INT(c), LOAD_FRAC(c),
count_active_contexts(),
atomic_read(&nr_spu_contexts),
- current->nsproxy->pid_ns->last_pid);
+ task_active_pid_ns(current)->last_pid);
return 0;
}
diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c
index 3b3c366..4e6985e 100644
--- a/arch/um/drivers/mconsole_kern.c
+++ b/arch/um/drivers/mconsole_kern.c
@@ -125,7 +125,7 @@ void mconsole_log(struct mc_request *req)
void mconsole_proc(struct mc_request *req)
{
struct nameidata nd;
- struct vfsmount *mnt = current->nsproxy->pid_ns->proc_mnt;
+ struct vfsmount *mnt = task_active_pid_ns(current)->proc_mnt;
struct file *file;
int n, err;
char *ptr = req->request.data, *buf;
diff --git a/fs/proc/root.c b/fs/proc/root.c
index b080b79..fbcd3f8 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -57,7 +57,7 @@ static int proc_get_sb(struct file_system_type *fs_type,
if (flags & MS_KERNMOUNT)
ns = (struct pid_namespace *)data;
else
- ns = current->nsproxy->pid_ns;
+ ns = task_active_pid_ns(current);
sb = sget(fs_type, proc_test_super, proc_set_super, ns);
if (IS_ERR(sb))
diff --git a/init/main.c b/init/main.c
index 4cb47a1..67e40fc 100644
--- a/init/main.c
+++ b/init/main.c
@@ -851,15 +851,6 @@ static int __init kernel_init(void * unused)
* init can run on any cpu.
*/
set_cpus_allowed_ptr(current, cpu_all_mask);
- /*
- * Tell the world that we're going to be the grim
- * reaper of innocent orphaned children.
- *
- * We don't want people to have to make incorrect
- * assumptions about where in the task array this
- * can be found.
- */
- init_pid_ns.child_reaper = current;
cad_pid = task_pid(current);
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index aa3bee5..737d2eb 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -2453,7 +2453,7 @@ static struct cgroup_pidlist *cgroup_pidlist_find(struct cgroup *cgrp,
{
struct cgroup_pidlist *l;
/* don't need task_nsproxy() if we're looking at ourself */
- struct pid_namespace *ns = get_pid_ns(current->nsproxy->pid_ns);
+ struct pid_namespace *ns = get_pid_ns(task_active_pid_ns(current));
/*
* We can't drop the pidlist_mutex before taking the l->mutex in case
* the last ref-holder is trying to remove l from the list at the same
diff --git a/kernel/fork.c b/kernel/fork.c
index f88bd98..832c035 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1172,7 +1172,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
if (!pid)
goto bad_fork_cleanup_io;
- if (clone_flags & CLONE_NEWPID) {
+ if (pid->numbers[pid->level].nr == 1) {
retval = pid_ns_prepare_proc(p->nsproxy->pid_ns);
if (retval < 0)
goto bad_fork_free_pid;
@@ -1279,7 +1279,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
tracehook_finish_clone(p, clone_flags, trace);
if (thread_group_leader(p)) {
- if (clone_flags & CLONE_NEWPID)
+ if (pid->numbers[pid->level].nr == 1)
p->nsproxy->pid_ns->child_reaper = p;
p->signal->leader_pid = pid;
@@ -1539,10 +1539,19 @@ static void check_unshare_flags(unsigned long *flags_ptr)
*flags_ptr |= CLONE_THREAD;
/*
+ * If unsharing the pid namespace and the task was created
+ * using CLONE_THREAD, then must unshare the thread.
+ */
+ if ((*flags_ptr & CLONE_NEWPID) &&
+ (atomic_read(¤t->signal->count) > 1))
+ *flags_ptr |= CLONE_THREAD;
+
+ /*
* If unsharing namespace, must also unshare filesystem information.
*/
if (*flags_ptr & CLONE_NEWNS)
*flags_ptr |= CLONE_FS;
+
}
/*
@@ -1647,7 +1656,8 @@ SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags)
err = -EINVAL;
if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_NEWNS|CLONE_SIGHAND|
CLONE_VM|CLONE_FILES|CLONE_SYSVSEM|
- CLONE_NEWUTS|CLONE_NEWIPC|CLONE_NEWNET))
+ CLONE_NEWUTS|CLONE_NEWIPC|CLONE_NEWNET|
+ CLONE_NEWPID))
goto bad_unshare_out;
/*
diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c
index e3be4ef..1d023d5 100644
--- a/kernel/nsproxy.c
+++ b/kernel/nsproxy.c
@@ -173,7 +173,7 @@ int unshare_nsproxy_namespaces(unsigned long unshare_flags,
int err = 0;
if (!(unshare_flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |
- CLONE_NEWNET)))
+ CLONE_NEWNET | CLONE_NEWPID)))
return 0;
if (!capable(CAP_SYS_ADMIN))
diff --git a/kernel/perf_event.c b/kernel/perf_event.c
index 2ae7409..74865cd 100644
--- a/kernel/perf_event.c
+++ b/kernel/perf_event.c
@@ -4436,7 +4436,7 @@ perf_event_alloc(struct perf_event_attr *attr,
event->parent = parent_event;
- event->ns = get_pid_ns(current->nsproxy->pid_ns);
+ event->ns = get_pid_ns(task_active_pid_ns(current));
event->id = atomic64_inc_return(&perf_event_id);
event->state = PERF_EVENT_STATE_INACTIVE;
diff --git a/kernel/pid.c b/kernel/pid.c
index 2e17c9c..6b64a82 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -305,7 +305,7 @@ EXPORT_SYMBOL_GPL(find_pid_ns);
struct pid *find_vpid(int nr)
{
- return find_pid_ns(nr, current->nsproxy->pid_ns);
+ return find_pid_ns(nr, task_active_pid_ns(current));
}
EXPORT_SYMBOL_GPL(find_vpid);
@@ -385,7 +385,7 @@ struct task_struct *find_task_by_pid_ns(pid_t nr, struct pid_namespace *ns)
struct task_struct *find_task_by_vpid(pid_t vnr)
{
- return find_task_by_pid_ns(vnr, current->nsproxy->pid_ns);
+ return find_task_by_pid_ns(vnr, task_active_pid_ns(current));
}
struct pid *get_task_pid(struct task_struct *task, enum pid_type type)
@@ -437,7 +437,7 @@ pid_t pid_nr_ns(struct pid *pid, struct pid_namespace *ns)
pid_t pid_vnr(struct pid *pid)
{
- return pid_nr_ns(pid, current->nsproxy->pid_ns);
+ return pid_nr_ns(pid, task_active_pid_ns(current));
}
EXPORT_SYMBOL_GPL(pid_vnr);
@@ -448,7 +448,7 @@ pid_t __task_pid_nr_ns(struct task_struct *task, enum pid_type type,
rcu_read_lock();
if (!ns)
- ns = current->nsproxy->pid_ns;
+ ns = task_active_pid_ns(current);
if (likely(pid_alive(task))) {
if (type != PIDTYPE_PID)
task = task->group_leader;
diff --git a/kernel/signal.c b/kernel/signal.c
index 934ae5e..885b699 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1438,16 +1438,15 @@ int do_notify_parent(struct task_struct *tsk, int sig)
* we are under tasklist_lock here so our parent is tied to
* us and cannot exit and release its namespace.
*
- * the only it can is to switch its nsproxy with sys_unshare,
- * bu uncharing pid namespaces is not allowed, so we'll always
- * see relevant namespace
+ * The only it can is to switch its nsproxy with sys_unshare,
+ * but we use the pid_namespace for task_pid which never changes.
*
* write_lock() currently calls preempt_disable() which is the
* same as rcu_read_lock(), but according to Oleg, this is not
* correct to rely on this
*/
rcu_read_lock();
- info.si_pid = task_pid_nr_ns(tsk, tsk->parent->nsproxy->pid_ns);
+ info.si_pid = task_pid_nr_ns(tsk, task_active_pid_ns(tsk->parent));
info.si_uid = __task_cred(tsk)->uid;
rcu_read_unlock();
@@ -1518,7 +1517,7 @@ static void do_notify_parent_cldstop(struct task_struct *tsk, int why)
* see comment in do_notify_parent() abot the following 3 lines
*/
rcu_read_lock();
- info.si_pid = task_pid_nr_ns(tsk, parent->nsproxy->pid_ns);
+ info.si_pid = task_pid_nr_ns(tsk, task_active_pid_ns(parent));
info.si_uid = __task_cred(tsk)->uid;
rcu_read_unlock();
diff --git a/kernel/sysctl_binary.c b/kernel/sysctl_binary.c
index 8f5d16e..1e4da59 100644
--- a/kernel/sysctl_binary.c
+++ b/kernel/sysctl_binary.c
@@ -1356,7 +1356,7 @@ static ssize_t binary_sysctl(const int *name, int nlen,
goto out_putname;
}
- mnt = current->nsproxy->pid_ns->proc_mnt;
+ mnt = task_active_pid_ns(current)->proc_mnt;
result = vfs_path_lookup(mnt->mnt_root, mnt, pathname, 0, &nd);
if (result)
goto out_putname;
^ permalink raw reply related
* Re: [RFC v2 03/10] snet: introduce security/snet, Makefile and Kconfig changes
From: Samir Bellabes @ 2010-03-03 0:23 UTC (permalink / raw)
To: Greg KH
Cc: linux-security-module, linux-kernel, netdev, netfilter-devel,
jamal, Patrick McHardy, Evgeniy Polyakov, Neil Horman,
Grzegorz Nosek
In-Reply-To: <20100303000347.GA3017@kroah.com>
Greg KH <greg@kroah.com> writes:
> On Tue, Mar 02, 2010 at 09:23:07PM +0100, Samir Bellabes wrote:
>> this patch creates folder security/snet and adds changes for Kconfig and Makefile
>
> But it breaks the build, as you are referring to files here that are not
> present yet. Please put this at the end of your patch series to make
> the tree always build for every individual patch.
yes, sure.
thank you Greg
sam
^ permalink raw reply
* [RFC][ PATCH 3/3] vhost-net: Add mergeable RX buffer support to vhost-net
From: David Stevens @ 2010-03-03 0:20 UTC (permalink / raw)
To: mst, rusty; +Cc: netdev, kvm, virtualization
[-- Attachment #1: Type: text/plain, Size: 7770 bytes --]
This patch glues them all together and makes sure we
notify whenever we don't have enough buffers to receive
a max-sized packet, and adds the feature bit.
Signed-off-by: David L Stevens <dlstevens@us.ibm.com>
diff -ruN net-next-p2/drivers/vhost/net.c net-next-p3/drivers/vhost/net.c
--- net-next-p2/drivers/vhost/net.c 2010-03-02 13:01:34.000000000
-0800
+++ net-next-p3/drivers/vhost/net.c 2010-03-02 15:25:15.000000000
-0800
@@ -54,26 +54,6 @@
enum vhost_net_poll_state tx_poll_state;
};
-/* Pop first len bytes from iovec. Return number of segments used. */
-static int move_iovec_hdr(struct iovec *from, struct iovec *to,
- size_t len, int iov_count)
-{
- int seg = 0;
- size_t size;
- while (len && seg < iov_count) {
- size = min(from->iov_len, len);
- to->iov_base = from->iov_base;
- to->iov_len = size;
- from->iov_len -= size;
- from->iov_base += size;
- len -= size;
- ++from;
- ++to;
- ++seg;
- }
- return seg;
-}
-
/* Caller must have TX VQ lock */
static void tx_poll_stop(struct vhost_net *net)
{
@@ -97,7 +77,7 @@
static void handle_tx(struct vhost_net *net)
{
struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_TX];
- unsigned out, in, s;
+ unsigned out, in;
struct iovec head;
struct msghdr msg = {
.msg_name = NULL,
@@ -110,6 +90,7 @@
size_t len, total_len = 0;
int err, wmem;
struct socket *sock = rcu_dereference(vq->private_data);
+
if (!sock)
return;
@@ -166,11 +147,11 @@
/* Skip header. TODO: support TSO. */
msg.msg_iovlen = out;
head.iov_len = len = iov_length(vq->iov, out);
+
/* Sanity check */
if (!len) {
vq_err(vq, "Unexpected header len for TX: "
- "%zd expected %zd\n",
- len, vq->guest_hlen);
+ "%zd expected %zd\n", len, vq->guest_hlen);
break;
}
/* TODO: Check specific error and bomb out unless ENOBUFS?
*/
@@ -214,7 +195,7 @@
static void handle_rx(struct vhost_net *net)
{
struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_RX];
- unsigned in, log, s;
+ unsigned in, log;
struct vhost_log *vq_log;
struct msghdr msg = {
.msg_name = NULL,
@@ -245,30 +226,36 @@
if (!headcount) {
vhost_enable_notify(vq);
break;
- }
+ } else if (vq->maxheadcount < headcount)
+ vq->maxheadcount = headcount;
/* Skip header. TODO: support TSO/mergeable rx buffers. */
msg.msg_iovlen = in;
len = iov_length(vq->iov, in);
-
/* Sanity check */
if (!len) {
vq_err(vq, "Unexpected header len for RX: "
- "%zd expected %zd\n",
- len, vq->guest_hlen);
+ "%zd expected %zd\n", len, vq->guest_hlen);
break;
}
err = sock->ops->recvmsg(NULL, sock, &msg,
len, MSG_DONTWAIT | MSG_TRUNC);
- /* TODO: Check specific error and bomb out unless EAGAIN?
*/
if (err < 0) {
- vhost_discard(vq, 1);
+ vhost_discard(vq, headcount);
break;
}
/* TODO: Should check and handle checksum. */
+ if (vhost_has_feature(&net->dev, VIRTIO_NET_F_MRG_RXBUF))
{
+ struct virtio_net_hdr_mrg_rxbuf *vhdr =
+ (struct virtio_net_hdr_mrg_rxbuf *)
+ vq->iov[0].iov_base;
+ /* add num_bufs */
+ vq->iov[0].iov_len = vq->guest_hlen;
+ vhdr->num_buffers = headcount;
+ }
if (err > len) {
pr_err("Discarded truncated rx packet: "
" len %d > %zd\n", err, len);
- vhost_discard(vq, 1);
+ vhost_discard(vq, headcount);
continue;
}
len = err;
@@ -573,8 +560,6 @@
static int vhost_net_set_features(struct vhost_net *n, u64 features)
{
- size_t hdr_size = features & (1 << VHOST_NET_F_VIRTIO_NET_HDR) ?
- sizeof(struct virtio_net_hdr) : 0;
int i;
mutex_lock(&n->dev.mutex);
if ((features & (1 << VHOST_F_LOG_ALL)) &&
diff -ruN net-next-p2/drivers/vhost/vhost.c
net-next-p3/drivers/vhost/vhost.c
--- net-next-p2/drivers/vhost/vhost.c 2010-03-02 12:53:02.000000000
-0800
+++ net-next-p3/drivers/vhost/vhost.c 2010-03-02 15:24:50.000000000
-0800
@@ -115,6 +115,7 @@
vq->log_addr = -1ull;
vq->guest_hlen = 0;
vq->sock_hlen = 0;
+ vq->maxheadcount = 0;
vq->private_data = NULL;
vq->log_base = NULL;
vq->error_ctx = NULL;
@@ -410,6 +411,7 @@
vq->last_avail_idx = s.num;
/* Forget the cached index value. */
vq->avail_idx = vq->last_avail_idx;
+ vq->maxheadcount = 0;
break;
case VHOST_GET_VRING_BASE:
s.index = idx;
@@ -1114,10 +1116,23 @@
return 0;
}
+int vhost_available(struct vhost_virtqueue *vq)
+{
+ int avail;
+
+ if (!vq->maxheadcount) /* haven't got any yet */
+ return 1;
+ avail = vq->avail_idx - vq->last_avail_idx;
+ if (avail < 0)
+ avail += 0x10000; /* wrapped */
+ return avail;
+}
+
/* This actually signals the guest, using eventfd. */
void vhost_signal(struct vhost_dev *dev, struct vhost_virtqueue *vq)
{
__u16 flags = 0;
+
if (get_user(flags, &vq->avail->flags)) {
vq_err(vq, "Failed to get flags");
return;
@@ -1125,7 +1140,7 @@
/* If they don't want an interrupt, don't signal, unless empty. */
if ((flags & VRING_AVAIL_F_NO_INTERRUPT) &&
- (vq->avail_idx != vq->last_avail_idx ||
+ (vhost_available(vq) > vq->maxheadcount ||
!vhost_has_feature(dev, VIRTIO_F_NOTIFY_ON_EMPTY)))
return;
diff -ruN net-next-p2/drivers/vhost/vhost.h
net-next-p3/drivers/vhost/vhost.h
--- net-next-p2/drivers/vhost/vhost.h 2010-03-02 13:02:03.000000000
-0800
+++ net-next-p3/drivers/vhost/vhost.h 2010-03-02 14:29:44.000000000
-0800
@@ -85,6 +85,7 @@
struct iovec iov[VHOST_NET_MAX_SG+1]; /* an extra for vnet hdr */
struct iovec heads[VHOST_NET_MAX_SG];
size_t guest_hlen, sock_hlen;
+ int maxheadcount;
/* We use a kind of RCU to access private pointer.
* All readers access it from workqueue, which makes it possible
to
* flush the workqueue instead of synchronize_rcu. Therefore
readers do
@@ -151,7 +152,8 @@
VHOST_FEATURES = (1 << VIRTIO_F_NOTIFY_ON_EMPTY) |
(1 << VIRTIO_RING_F_INDIRECT_DESC) |
(1 << VHOST_F_LOG_ALL) |
- (1 << VHOST_NET_F_VIRTIO_NET_HDR),
+ (1 << VHOST_NET_F_VIRTIO_NET_HDR) |
+ (1 << VIRTIO_NET_F_MRG_RXBUF),
};
static inline int vhost_has_feature(struct vhost_dev *dev, int bit)
[-- Attachment #2: MRXB3.patch --]
[-- Type: application/octet-stream, Size: 5852 bytes --]
diff -ruN net-next-p2/drivers/vhost/net.c net-next-p3/drivers/vhost/net.c
--- net-next-p2/drivers/vhost/net.c 2010-03-02 13:01:34.000000000 -0800
+++ net-next-p3/drivers/vhost/net.c 2010-03-02 15:25:15.000000000 -0800
@@ -54,26 +54,6 @@
enum vhost_net_poll_state tx_poll_state;
};
-/* Pop first len bytes from iovec. Return number of segments used. */
-static int move_iovec_hdr(struct iovec *from, struct iovec *to,
- size_t len, int iov_count)
-{
- int seg = 0;
- size_t size;
- while (len && seg < iov_count) {
- size = min(from->iov_len, len);
- to->iov_base = from->iov_base;
- to->iov_len = size;
- from->iov_len -= size;
- from->iov_base += size;
- len -= size;
- ++from;
- ++to;
- ++seg;
- }
- return seg;
-}
-
/* Caller must have TX VQ lock */
static void tx_poll_stop(struct vhost_net *net)
{
@@ -97,7 +77,7 @@
static void handle_tx(struct vhost_net *net)
{
struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_TX];
- unsigned out, in, s;
+ unsigned out, in;
struct iovec head;
struct msghdr msg = {
.msg_name = NULL,
@@ -110,6 +90,7 @@
size_t len, total_len = 0;
int err, wmem;
struct socket *sock = rcu_dereference(vq->private_data);
+
if (!sock)
return;
@@ -166,11 +147,11 @@
/* Skip header. TODO: support TSO. */
msg.msg_iovlen = out;
head.iov_len = len = iov_length(vq->iov, out);
+
/* Sanity check */
if (!len) {
vq_err(vq, "Unexpected header len for TX: "
- "%zd expected %zd\n",
- len, vq->guest_hlen);
+ "%zd expected %zd\n", len, vq->guest_hlen);
break;
}
/* TODO: Check specific error and bomb out unless ENOBUFS? */
@@ -214,7 +195,7 @@
static void handle_rx(struct vhost_net *net)
{
struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_RX];
- unsigned in, log, s;
+ unsigned in, log;
struct vhost_log *vq_log;
struct msghdr msg = {
.msg_name = NULL,
@@ -245,30 +226,36 @@
if (!headcount) {
vhost_enable_notify(vq);
break;
- }
+ } else if (vq->maxheadcount < headcount)
+ vq->maxheadcount = headcount;
/* Skip header. TODO: support TSO/mergeable rx buffers. */
msg.msg_iovlen = in;
len = iov_length(vq->iov, in);
-
/* Sanity check */
if (!len) {
vq_err(vq, "Unexpected header len for RX: "
- "%zd expected %zd\n",
- len, vq->guest_hlen);
+ "%zd expected %zd\n", len, vq->guest_hlen);
break;
}
err = sock->ops->recvmsg(NULL, sock, &msg,
len, MSG_DONTWAIT | MSG_TRUNC);
- /* TODO: Check specific error and bomb out unless EAGAIN? */
if (err < 0) {
- vhost_discard(vq, 1);
+ vhost_discard(vq, headcount);
break;
}
/* TODO: Should check and handle checksum. */
+ if (vhost_has_feature(&net->dev, VIRTIO_NET_F_MRG_RXBUF)) {
+ struct virtio_net_hdr_mrg_rxbuf *vhdr =
+ (struct virtio_net_hdr_mrg_rxbuf *)
+ vq->iov[0].iov_base;
+ /* add num_bufs */
+ vq->iov[0].iov_len = vq->guest_hlen;
+ vhdr->num_buffers = headcount;
+ }
if (err > len) {
pr_err("Discarded truncated rx packet: "
" len %d > %zd\n", err, len);
- vhost_discard(vq, 1);
+ vhost_discard(vq, headcount);
continue;
}
len = err;
@@ -573,8 +560,6 @@
static int vhost_net_set_features(struct vhost_net *n, u64 features)
{
- size_t hdr_size = features & (1 << VHOST_NET_F_VIRTIO_NET_HDR) ?
- sizeof(struct virtio_net_hdr) : 0;
int i;
mutex_lock(&n->dev.mutex);
if ((features & (1 << VHOST_F_LOG_ALL)) &&
diff -ruN net-next-p2/drivers/vhost/vhost.c net-next-p3/drivers/vhost/vhost.c
--- net-next-p2/drivers/vhost/vhost.c 2010-03-02 12:53:02.000000000 -0800
+++ net-next-p3/drivers/vhost/vhost.c 2010-03-02 15:24:50.000000000 -0800
@@ -115,6 +115,7 @@
vq->log_addr = -1ull;
vq->guest_hlen = 0;
vq->sock_hlen = 0;
+ vq->maxheadcount = 0;
vq->private_data = NULL;
vq->log_base = NULL;
vq->error_ctx = NULL;
@@ -410,6 +411,7 @@
vq->last_avail_idx = s.num;
/* Forget the cached index value. */
vq->avail_idx = vq->last_avail_idx;
+ vq->maxheadcount = 0;
break;
case VHOST_GET_VRING_BASE:
s.index = idx;
@@ -1114,10 +1116,23 @@
return 0;
}
+int vhost_available(struct vhost_virtqueue *vq)
+{
+ int avail;
+
+ if (!vq->maxheadcount) /* haven't got any yet */
+ return 1;
+ avail = vq->avail_idx - vq->last_avail_idx;
+ if (avail < 0)
+ avail += 0x10000; /* wrapped */
+ return avail;
+}
+
/* This actually signals the guest, using eventfd. */
void vhost_signal(struct vhost_dev *dev, struct vhost_virtqueue *vq)
{
__u16 flags = 0;
+
if (get_user(flags, &vq->avail->flags)) {
vq_err(vq, "Failed to get flags");
return;
@@ -1125,7 +1140,7 @@
/* If they don't want an interrupt, don't signal, unless empty. */
if ((flags & VRING_AVAIL_F_NO_INTERRUPT) &&
- (vq->avail_idx != vq->last_avail_idx ||
+ (vhost_available(vq) > vq->maxheadcount ||
!vhost_has_feature(dev, VIRTIO_F_NOTIFY_ON_EMPTY)))
return;
diff -ruN net-next-p2/drivers/vhost/vhost.h net-next-p3/drivers/vhost/vhost.h
--- net-next-p2/drivers/vhost/vhost.h 2010-03-02 13:02:03.000000000 -0800
+++ net-next-p3/drivers/vhost/vhost.h 2010-03-02 14:29:44.000000000 -0800
@@ -85,6 +85,7 @@
struct iovec iov[VHOST_NET_MAX_SG+1]; /* an extra for vnet hdr */
struct iovec heads[VHOST_NET_MAX_SG];
size_t guest_hlen, sock_hlen;
+ int maxheadcount;
/* We use a kind of RCU to access private pointer.
* All readers access it from workqueue, which makes it possible to
* flush the workqueue instead of synchronize_rcu. Therefore readers do
@@ -151,7 +152,8 @@
VHOST_FEATURES = (1 << VIRTIO_F_NOTIFY_ON_EMPTY) |
(1 << VIRTIO_RING_F_INDIRECT_DESC) |
(1 << VHOST_F_LOG_ALL) |
- (1 << VHOST_NET_F_VIRTIO_NET_HDR),
+ (1 << VHOST_NET_F_VIRTIO_NET_HDR) |
+ (1 << VIRTIO_NET_F_MRG_RXBUF),
};
static inline int vhost_has_feature(struct vhost_dev *dev, int bit)
^ permalink raw reply
* [RFC][ PATCH 1/3] vhost-net: support multiple buffer heads in receiver
From: David Stevens @ 2010-03-03 0:20 UTC (permalink / raw)
To: mst, rusty; +Cc: netdev, kvm, virtualization
[-- Attachment #1: Type: text/plain, Size: 12556 bytes --]
This patch generalizes buffer handling functions to
support multiple buffer heads.
In-line for viewing, attached for applying.
Signed-off-by: David L Stevens <dlstevens@us.ibm.com>
diff -ruN net-next-p0/drivers/vhost/net.c net-next-p1/drivers/vhost/net.c
--- net-next-p0/drivers/vhost/net.c 2010-02-24 12:59:24.000000000
-0800
+++ net-next-p1/drivers/vhost/net.c 2010-03-01 11:44:22.000000000
-0800
@@ -97,7 +97,8 @@
static void handle_tx(struct vhost_net *net)
{
struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_TX];
- unsigned head, out, in, s;
+ unsigned out, in, s;
+ struct iovec head;
struct msghdr msg = {
.msg_name = NULL,
.msg_namelen = 0,
@@ -126,12 +127,10 @@
hdr_size = vq->hdr_size;
for (;;) {
- head = vhost_get_vq_desc(&net->dev, vq, vq->iov,
- ARRAY_SIZE(vq->iov),
- &out, &in,
- NULL, NULL);
+ head.iov_base = (void *)vhost_get_vq_desc(&net->dev, vq,
+ vq->iov, ARRAY_SIZE(vq->iov), &out, &in, NULL,
NULL);
/* Nothing new? Wait for eventfd to tell us they
refilled. */
- if (head == vq->num) {
+ if (head.iov_base == (void *)vq->num) {
wmem = atomic_read(&sock->sk->sk_wmem_alloc);
if (wmem >= sock->sk->sk_sndbuf * 3 / 4) {
tx_poll_start(net, sock);
@@ -152,7 +151,7 @@
/* Skip header. TODO: support TSO. */
s = move_iovec_hdr(vq->iov, vq->hdr, hdr_size, out);
msg.msg_iovlen = out;
- len = iov_length(vq->iov, out);
+ head.iov_len = len = iov_length(vq->iov, out);
/* Sanity check */
if (!len) {
vq_err(vq, "Unexpected header len for TX: "
@@ -163,14 +162,14 @@
/* TODO: Check specific error and bomb out unless ENOBUFS?
*/
err = sock->ops->sendmsg(NULL, sock, &msg, len);
if (unlikely(err < 0)) {
- vhost_discard_vq_desc(vq);
+ vhost_discard(vq, 1);
tx_poll_start(net, sock);
break;
}
if (err != len)
pr_err("Truncated TX packet: "
" len %d != %zd\n", err, len);
- vhost_add_used_and_signal(&net->dev, vq, head, 0);
+ vhost_add_used_and_signal(&net->dev, vq, &head, 1);
total_len += len;
if (unlikely(total_len >= VHOST_NET_WEIGHT)) {
vhost_poll_queue(&vq->poll);
@@ -182,12 +181,22 @@
unuse_mm(net->dev.mm);
}
+static int skb_head_len(struct sk_buff_head *skq)
+{
+ struct sk_buff *head;
+
+ head = skb_peek(skq);
+ if (head)
+ return head->len;
+ return 0;
+}
+
/* Expects to be always run from workqueue - which acts as
* read-size critical section for our kind of RCU. */
static void handle_rx(struct vhost_net *net)
{
struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_RX];
- unsigned head, out, in, log, s;
+ unsigned in, log, s;
struct vhost_log *vq_log;
struct msghdr msg = {
.msg_name = NULL,
@@ -204,10 +213,11 @@
};
size_t len, total_len = 0;
- int err;
+ int err, headcount, datalen;
size_t hdr_size;
struct socket *sock = rcu_dereference(vq->private_data);
- if (!sock || skb_queue_empty(&sock->sk->sk_receive_queue))
+
+ if (!sock || !skb_head_len(&sock->sk->sk_receive_queue))
return;
use_mm(net->dev.mm);
@@ -218,13 +228,10 @@
vq_log = unlikely(vhost_has_feature(&net->dev, VHOST_F_LOG_ALL)) ?
vq->log : NULL;
- for (;;) {
- head = vhost_get_vq_desc(&net->dev, vq, vq->iov,
- ARRAY_SIZE(vq->iov),
- &out, &in,
- vq_log, &log);
+ while ((datalen = skb_head_len(&sock->sk->sk_receive_queue))) {
+ headcount = vhost_get_heads(vq, datalen, &in, vq_log,
&log);
/* OK, now we need to know about added descriptors. */
- if (head == vq->num) {
+ if (!headcount) {
if (unlikely(vhost_enable_notify(vq))) {
/* They have slipped one in as we were
* doing that: check again. */
@@ -235,13 +242,6 @@
* they refilled. */
break;
}
- /* We don't need to be notified again. */
- if (out) {
- vq_err(vq, "Unexpected descriptor format for RX: "
- "out %d, int %d\n",
- out, in);
- break;
- }
/* Skip header. TODO: support TSO/mergeable rx buffers. */
s = move_iovec_hdr(vq->iov, vq->hdr, hdr_size, in);
msg.msg_iovlen = in;
@@ -257,14 +257,14 @@
len, MSG_DONTWAIT | MSG_TRUNC);
/* TODO: Check specific error and bomb out unless EAGAIN?
*/
if (err < 0) {
- vhost_discard_vq_desc(vq);
+ vhost_discard(vq, 1);
break;
}
/* TODO: Should check and handle checksum. */
if (err > len) {
pr_err("Discarded truncated rx packet: "
" len %d > %zd\n", err, len);
- vhost_discard_vq_desc(vq);
+ vhost_discard(vq, 1);
continue;
}
len = err;
@@ -275,7 +275,7 @@
break;
}
len += hdr_size;
- vhost_add_used_and_signal(&net->dev, vq, head, len);
+ vhost_add_used_and_signal(&net->dev, vq, vq->heads,
headcount);
if (unlikely(vq_log))
vhost_log_write(vq, vq_log, log, len);
total_len += len;
diff -ruN net-next-p0/drivers/vhost/vhost.c
net-next-p1/drivers/vhost/vhost.c
--- net-next-p0/drivers/vhost/vhost.c 2010-02-15 20:08:35.000000000
-0800
+++ net-next-p1/drivers/vhost/vhost.c 2010-03-01 11:44:06.000000000
-0800
@@ -848,6 +848,38 @@
return 0;
}
+unsigned vhost_get_heads(struct vhost_virtqueue *vq, int datalen, int
*iovcount,
+ struct vhost_log *log, unsigned int *log_num)
+{
+ struct iovec *heads = vq->heads;
+ int out, in;
+ int hc = 0;
+
+ while (datalen > 0) {
+ if (hc >= VHOST_NET_MAX_SG) {
+ vhost_discard(vq, hc);
+ return 0;
+ }
+ heads[hc].iov_base = (void *)vhost_get_vq_desc(vq->dev,
vq,
+ vq->iov, ARRAY_SIZE(vq->iov), &out, &in, log,
log_num);
+ if (heads[hc].iov_base == (void *)vq->num) {
+ vhost_discard(vq, hc);
+ return 0;
+ }
+ if (out || in <= 0) {
+ vq_err(vq, "unexpected descriptor format for RX: "
+ "out %d, in %d\n", out, in);
+ vhost_discard(vq, hc);
+ return 0;
+ }
+ heads[hc].iov_len = iov_length(vq->iov, in);
+ hc++;
+ datalen -= heads[hc].iov_len;
+ }
+ *iovcount = in;
+ return hc;
+}
+
/* This looks in the virtqueue and for the first available buffer, and
converts
* it to an iovec for convenient access. Since descriptors consist of
some
* number of output then some number of input descriptors, it's actually
two
@@ -973,31 +1005,32 @@
}
/* Reverse the effect of vhost_get_vq_desc. Useful for error handling. */
-void vhost_discard_vq_desc(struct vhost_virtqueue *vq)
+void vhost_discard(struct vhost_virtqueue *vq, int n)
{
- vq->last_avail_idx--;
+ vq->last_avail_idx -= n;
}
/* After we've used one of their buffers, we tell them about it. We'll
then
* want to notify the guest, using eventfd. */
-int vhost_add_used(struct vhost_virtqueue *vq, unsigned int head, int
len)
+int vhost_add_used(struct vhost_virtqueue *vq, struct iovec *heads, int
count)
{
struct vring_used_elem *used;
+ int i;
- /* The virtqueue contains a ring of used buffers. Get a pointer
to the
- * next entry in that used ring. */
- used = &vq->used->ring[vq->last_used_idx % vq->num];
- if (put_user(head, &used->id)) {
- vq_err(vq, "Failed to write used id");
- return -EFAULT;
- }
- if (put_user(len, &used->len)) {
- vq_err(vq, "Failed to write used len");
- return -EFAULT;
+ for (i=0; i<count; i++, vq->last_used_idx++) {
+ used = &vq->used->ring[vq->last_used_idx % vq->num];
+ if (put_user((unsigned)heads[i].iov_base, &used->id)) {
+ vq_err(vq, "Failed to write used id");
+ return -EFAULT;
+ }
+ if (put_user(heads[i].iov_len, &used->len)) {
+ vq_err(vq, "Failed to write used len");
+ return -EFAULT;
+ }
}
/* Make sure buffer is written before we update index. */
smp_wmb();
- if (put_user(vq->last_used_idx + 1, &vq->used->idx)) {
+ if (put_user(vq->last_used_idx, &vq->used->idx)) {
vq_err(vq, "Failed to increment used idx");
return -EFAULT;
}
@@ -1011,7 +1044,6 @@
if (vq->log_ctx)
eventfd_signal(vq->log_ctx, 1);
}
- vq->last_used_idx++;
return 0;
}
@@ -1038,9 +1070,9 @@
/* And here's the combo meal deal. Supersize me! */
void vhost_add_used_and_signal(struct vhost_dev *dev,
struct vhost_virtqueue *vq,
- unsigned int head, int len)
+ struct iovec *heads, int count)
{
- vhost_add_used(vq, head, len);
+ vhost_add_used(vq, heads, count);
vhost_signal(dev, vq);
}
diff -ruN net-next-p0/drivers/vhost/vhost.h
net-next-p1/drivers/vhost/vhost.h
--- net-next-p0/drivers/vhost/vhost.h 2010-02-15 20:08:35.000000000
-0800
+++ net-next-p1/drivers/vhost/vhost.h 2010-03-01 11:42:18.000000000
-0800
@@ -84,6 +84,7 @@
struct iovec indirect[VHOST_NET_MAX_SG];
struct iovec iov[VHOST_NET_MAX_SG];
struct iovec hdr[VHOST_NET_MAX_SG];
+ struct iovec heads[VHOST_NET_MAX_SG];
size_t hdr_size;
/* We use a kind of RCU to access private pointer.
* All readers access it from workqueue, which makes it possible
to
@@ -120,16 +121,18 @@
int vhost_vq_access_ok(struct vhost_virtqueue *vq);
int vhost_log_access_ok(struct vhost_dev *);
+unsigned vhost_get_heads(struct vhost_virtqueue *, int datalen, int
*iovcount,
+ struct vhost_log *log, unsigned int *log_num);
unsigned vhost_get_vq_desc(struct vhost_dev *, struct vhost_virtqueue *,
struct iovec iov[], unsigned int iov_count,
unsigned int *out_num, unsigned int *in_num,
struct vhost_log *log, unsigned int *log_num);
-void vhost_discard_vq_desc(struct vhost_virtqueue *);
+void vhost_discard(struct vhost_virtqueue *, int);
-int vhost_add_used(struct vhost_virtqueue *, unsigned int head, int len);
-void vhost_signal(struct vhost_dev *, struct vhost_virtqueue *);
+int vhost_add_used(struct vhost_virtqueue *, struct iovec *heads, int
count);
void vhost_add_used_and_signal(struct vhost_dev *, struct vhost_virtqueue
*,
- unsigned int head, int len);
+ struct iovec *heads, int count);
+void vhost_signal(struct vhost_dev *, struct vhost_virtqueue *);
void vhost_disable_notify(struct vhost_virtqueue *);
bool vhost_enable_notify(struct vhost_virtqueue *);
[-- Attachment #2: MRXB1.patch --]
[-- Type: application/octet-stream, Size: 9612 bytes --]
diff -ruN net-next-p0/drivers/vhost/net.c net-next-p1/drivers/vhost/net.c
--- net-next-p0/drivers/vhost/net.c 2010-02-24 12:59:24.000000000 -0800
+++ net-next-p1/drivers/vhost/net.c 2010-03-01 11:44:22.000000000 -0800
@@ -97,7 +97,8 @@
static void handle_tx(struct vhost_net *net)
{
struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_TX];
- unsigned head, out, in, s;
+ unsigned out, in, s;
+ struct iovec head;
struct msghdr msg = {
.msg_name = NULL,
.msg_namelen = 0,
@@ -126,12 +127,10 @@
hdr_size = vq->hdr_size;
for (;;) {
- head = vhost_get_vq_desc(&net->dev, vq, vq->iov,
- ARRAY_SIZE(vq->iov),
- &out, &in,
- NULL, NULL);
+ head.iov_base = (void *)vhost_get_vq_desc(&net->dev, vq,
+ vq->iov, ARRAY_SIZE(vq->iov), &out, &in, NULL, NULL);
/* Nothing new? Wait for eventfd to tell us they refilled. */
- if (head == vq->num) {
+ if (head.iov_base == (void *)vq->num) {
wmem = atomic_read(&sock->sk->sk_wmem_alloc);
if (wmem >= sock->sk->sk_sndbuf * 3 / 4) {
tx_poll_start(net, sock);
@@ -152,7 +151,7 @@
/* Skip header. TODO: support TSO. */
s = move_iovec_hdr(vq->iov, vq->hdr, hdr_size, out);
msg.msg_iovlen = out;
- len = iov_length(vq->iov, out);
+ head.iov_len = len = iov_length(vq->iov, out);
/* Sanity check */
if (!len) {
vq_err(vq, "Unexpected header len for TX: "
@@ -163,14 +162,14 @@
/* TODO: Check specific error and bomb out unless ENOBUFS? */
err = sock->ops->sendmsg(NULL, sock, &msg, len);
if (unlikely(err < 0)) {
- vhost_discard_vq_desc(vq);
+ vhost_discard(vq, 1);
tx_poll_start(net, sock);
break;
}
if (err != len)
pr_err("Truncated TX packet: "
" len %d != %zd\n", err, len);
- vhost_add_used_and_signal(&net->dev, vq, head, 0);
+ vhost_add_used_and_signal(&net->dev, vq, &head, 1);
total_len += len;
if (unlikely(total_len >= VHOST_NET_WEIGHT)) {
vhost_poll_queue(&vq->poll);
@@ -182,12 +181,22 @@
unuse_mm(net->dev.mm);
}
+static int skb_head_len(struct sk_buff_head *skq)
+{
+ struct sk_buff *head;
+
+ head = skb_peek(skq);
+ if (head)
+ return head->len;
+ return 0;
+}
+
/* Expects to be always run from workqueue - which acts as
* read-size critical section for our kind of RCU. */
static void handle_rx(struct vhost_net *net)
{
struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_RX];
- unsigned head, out, in, log, s;
+ unsigned in, log, s;
struct vhost_log *vq_log;
struct msghdr msg = {
.msg_name = NULL,
@@ -204,10 +213,11 @@
};
size_t len, total_len = 0;
- int err;
+ int err, headcount, datalen;
size_t hdr_size;
struct socket *sock = rcu_dereference(vq->private_data);
- if (!sock || skb_queue_empty(&sock->sk->sk_receive_queue))
+
+ if (!sock || !skb_head_len(&sock->sk->sk_receive_queue))
return;
use_mm(net->dev.mm);
@@ -218,13 +228,10 @@
vq_log = unlikely(vhost_has_feature(&net->dev, VHOST_F_LOG_ALL)) ?
vq->log : NULL;
- for (;;) {
- head = vhost_get_vq_desc(&net->dev, vq, vq->iov,
- ARRAY_SIZE(vq->iov),
- &out, &in,
- vq_log, &log);
+ while ((datalen = skb_head_len(&sock->sk->sk_receive_queue))) {
+ headcount = vhost_get_heads(vq, datalen, &in, vq_log, &log);
/* OK, now we need to know about added descriptors. */
- if (head == vq->num) {
+ if (!headcount) {
if (unlikely(vhost_enable_notify(vq))) {
/* They have slipped one in as we were
* doing that: check again. */
@@ -235,13 +242,6 @@
* they refilled. */
break;
}
- /* We don't need to be notified again. */
- if (out) {
- vq_err(vq, "Unexpected descriptor format for RX: "
- "out %d, int %d\n",
- out, in);
- break;
- }
/* Skip header. TODO: support TSO/mergeable rx buffers. */
s = move_iovec_hdr(vq->iov, vq->hdr, hdr_size, in);
msg.msg_iovlen = in;
@@ -257,14 +257,14 @@
len, MSG_DONTWAIT | MSG_TRUNC);
/* TODO: Check specific error and bomb out unless EAGAIN? */
if (err < 0) {
- vhost_discard_vq_desc(vq);
+ vhost_discard(vq, 1);
break;
}
/* TODO: Should check and handle checksum. */
if (err > len) {
pr_err("Discarded truncated rx packet: "
" len %d > %zd\n", err, len);
- vhost_discard_vq_desc(vq);
+ vhost_discard(vq, 1);
continue;
}
len = err;
@@ -275,7 +275,7 @@
break;
}
len += hdr_size;
- vhost_add_used_and_signal(&net->dev, vq, head, len);
+ vhost_add_used_and_signal(&net->dev, vq, vq->heads, headcount);
if (unlikely(vq_log))
vhost_log_write(vq, vq_log, log, len);
total_len += len;
diff -ruN net-next-p0/drivers/vhost/vhost.c net-next-p1/drivers/vhost/vhost.c
--- net-next-p0/drivers/vhost/vhost.c 2010-02-15 20:08:35.000000000 -0800
+++ net-next-p1/drivers/vhost/vhost.c 2010-03-01 11:44:06.000000000 -0800
@@ -848,6 +848,38 @@
return 0;
}
+unsigned vhost_get_heads(struct vhost_virtqueue *vq, int datalen, int *iovcount,
+ struct vhost_log *log, unsigned int *log_num)
+{
+ struct iovec *heads = vq->heads;
+ int out, in;
+ int hc = 0;
+
+ while (datalen > 0) {
+ if (hc >= VHOST_NET_MAX_SG) {
+ vhost_discard(vq, hc);
+ return 0;
+ }
+ heads[hc].iov_base = (void *)vhost_get_vq_desc(vq->dev, vq,
+ vq->iov, ARRAY_SIZE(vq->iov), &out, &in, log, log_num);
+ if (heads[hc].iov_base == (void *)vq->num) {
+ vhost_discard(vq, hc);
+ return 0;
+ }
+ if (out || in <= 0) {
+ vq_err(vq, "unexpected descriptor format for RX: "
+ "out %d, in %d\n", out, in);
+ vhost_discard(vq, hc);
+ return 0;
+ }
+ heads[hc].iov_len = iov_length(vq->iov, in);
+ hc++;
+ datalen -= heads[hc].iov_len;
+ }
+ *iovcount = in;
+ return hc;
+}
+
/* This looks in the virtqueue and for the first available buffer, and converts
* it to an iovec for convenient access. Since descriptors consist of some
* number of output then some number of input descriptors, it's actually two
@@ -973,31 +1005,32 @@
}
/* Reverse the effect of vhost_get_vq_desc. Useful for error handling. */
-void vhost_discard_vq_desc(struct vhost_virtqueue *vq)
+void vhost_discard(struct vhost_virtqueue *vq, int n)
{
- vq->last_avail_idx--;
+ vq->last_avail_idx -= n;
}
/* After we've used one of their buffers, we tell them about it. We'll then
* want to notify the guest, using eventfd. */
-int vhost_add_used(struct vhost_virtqueue *vq, unsigned int head, int len)
+int vhost_add_used(struct vhost_virtqueue *vq, struct iovec *heads, int count)
{
struct vring_used_elem *used;
+ int i;
- /* The virtqueue contains a ring of used buffers. Get a pointer to the
- * next entry in that used ring. */
- used = &vq->used->ring[vq->last_used_idx % vq->num];
- if (put_user(head, &used->id)) {
- vq_err(vq, "Failed to write used id");
- return -EFAULT;
- }
- if (put_user(len, &used->len)) {
- vq_err(vq, "Failed to write used len");
- return -EFAULT;
+ for (i=0; i<count; i++, vq->last_used_idx++) {
+ used = &vq->used->ring[vq->last_used_idx % vq->num];
+ if (put_user((unsigned)heads[i].iov_base, &used->id)) {
+ vq_err(vq, "Failed to write used id");
+ return -EFAULT;
+ }
+ if (put_user(heads[i].iov_len, &used->len)) {
+ vq_err(vq, "Failed to write used len");
+ return -EFAULT;
+ }
}
/* Make sure buffer is written before we update index. */
smp_wmb();
- if (put_user(vq->last_used_idx + 1, &vq->used->idx)) {
+ if (put_user(vq->last_used_idx, &vq->used->idx)) {
vq_err(vq, "Failed to increment used idx");
return -EFAULT;
}
@@ -1011,7 +1044,6 @@
if (vq->log_ctx)
eventfd_signal(vq->log_ctx, 1);
}
- vq->last_used_idx++;
return 0;
}
@@ -1038,9 +1070,9 @@
/* And here's the combo meal deal. Supersize me! */
void vhost_add_used_and_signal(struct vhost_dev *dev,
struct vhost_virtqueue *vq,
- unsigned int head, int len)
+ struct iovec *heads, int count)
{
- vhost_add_used(vq, head, len);
+ vhost_add_used(vq, heads, count);
vhost_signal(dev, vq);
}
diff -ruN net-next-p0/drivers/vhost/vhost.h net-next-p1/drivers/vhost/vhost.h
--- net-next-p0/drivers/vhost/vhost.h 2010-02-15 20:08:35.000000000 -0800
+++ net-next-p1/drivers/vhost/vhost.h 2010-03-01 11:42:18.000000000 -0800
@@ -84,6 +84,7 @@
struct iovec indirect[VHOST_NET_MAX_SG];
struct iovec iov[VHOST_NET_MAX_SG];
struct iovec hdr[VHOST_NET_MAX_SG];
+ struct iovec heads[VHOST_NET_MAX_SG];
size_t hdr_size;
/* We use a kind of RCU to access private pointer.
* All readers access it from workqueue, which makes it possible to
@@ -120,16 +121,18 @@
int vhost_vq_access_ok(struct vhost_virtqueue *vq);
int vhost_log_access_ok(struct vhost_dev *);
+unsigned vhost_get_heads(struct vhost_virtqueue *, int datalen, int *iovcount,
+ struct vhost_log *log, unsigned int *log_num);
unsigned vhost_get_vq_desc(struct vhost_dev *, struct vhost_virtqueue *,
struct iovec iov[], unsigned int iov_count,
unsigned int *out_num, unsigned int *in_num,
struct vhost_log *log, unsigned int *log_num);
-void vhost_discard_vq_desc(struct vhost_virtqueue *);
+void vhost_discard(struct vhost_virtqueue *, int);
-int vhost_add_used(struct vhost_virtqueue *, unsigned int head, int len);
-void vhost_signal(struct vhost_dev *, struct vhost_virtqueue *);
+int vhost_add_used(struct vhost_virtqueue *, struct iovec *heads, int count);
void vhost_add_used_and_signal(struct vhost_dev *, struct vhost_virtqueue *,
- unsigned int head, int len);
+ struct iovec *heads, int count);
+void vhost_signal(struct vhost_dev *, struct vhost_virtqueue *);
void vhost_disable_notify(struct vhost_virtqueue *);
bool vhost_enable_notify(struct vhost_virtqueue *);
^ permalink raw reply
* [RFC][ PATCH 2/3] vhost-net: handle vnet_hdr processing for MRG_RX_BUF
From: David Stevens @ 2010-03-03 0:20 UTC (permalink / raw)
To: mst, rusty; +Cc: netdev, kvm, virtualization
[-- Attachment #1: Type: text/plain, Size: 13122 bytes --]
This patch adds vnet_hdr processing for mergeable buffer
support to vhost-net.
Signed-off-by: David L Stevens <dlstevens@us.ibm.com>
diff -ruN net-next-p1/drivers/vhost/net.c net-next-p2/drivers/vhost/net.c
--- net-next-p1/drivers/vhost/net.c 2010-03-01 11:44:22.000000000
-0800
+++ net-next-p2/drivers/vhost/net.c 2010-03-02 13:01:34.000000000
-0800
@@ -109,7 +109,6 @@
};
size_t len, total_len = 0;
int err, wmem;
- size_t hdr_size;
struct socket *sock = rcu_dereference(vq->private_data);
if (!sock)
return;
@@ -124,7 +123,6 @@
if (wmem < sock->sk->sk_sndbuf * 2)
tx_poll_stop(net);
- hdr_size = vq->hdr_size;
for (;;) {
head.iov_base = (void *)vhost_get_vq_desc(&net->dev, vq,
@@ -148,25 +146,45 @@
"out %d, int %d\n", out, in);
break;
}
+ if (vq->guest_hlen > vq->sock_hlen) {
+ if (msg.msg_iov[0].iov_len == vq->guest_hlen)
+ msg.msg_iov[0].iov_len = vq->sock_hlen;
+ else if (out == ARRAY_SIZE(vq->iov))
+ vq_err(vq, "handle_tx iov overflow!");
+ else {
+ int i;
+
+ /* give header its own iov */
+ for (i=out; i>0; ++i)
+ msg.msg_iov[i+1] = msg.msg_iov[i];
+ msg.msg_iov[0].iov_len = vq->sock_hlen;
+ msg.msg_iov[1].iov_base += vq->guest_hlen;
+ msg.msg_iov[1].iov_len -= vq->guest_hlen;
+ out++;
+ }
+ }
/* Skip header. TODO: support TSO. */
- s = move_iovec_hdr(vq->iov, vq->hdr, hdr_size, out);
msg.msg_iovlen = out;
head.iov_len = len = iov_length(vq->iov, out);
/* Sanity check */
if (!len) {
vq_err(vq, "Unexpected header len for TX: "
"%zd expected %zd\n",
- iov_length(vq->hdr, s), hdr_size);
+ len, vq->guest_hlen);
break;
}
/* TODO: Check specific error and bomb out unless ENOBUFS?
*/
err = sock->ops->sendmsg(NULL, sock, &msg, len);
if (unlikely(err < 0)) {
- vhost_discard(vq, 1);
- tx_poll_start(net, sock);
+ if (err == -EAGAIN) {
+ tx_poll_start(net, sock);
+ } else {
+ vq_err(vq, "sendmsg: errno %d\n", -err);
+ /* drop packet; do not discard/resend */
+ vhost_add_used_and_signal(&net->dev,vq,&head,1);
+ }
break;
- }
- if (err != len)
+ } else if (err != len)
pr_err("Truncated TX packet: "
" len %d != %zd\n", err, len);
vhost_add_used_and_signal(&net->dev, vq, &head, 1);
@@ -207,14 +225,8 @@
.msg_flags = MSG_DONTWAIT,
};
- struct virtio_net_hdr hdr = {
- .flags = 0,
- .gso_type = VIRTIO_NET_HDR_GSO_NONE
- };
-
size_t len, total_len = 0;
int err, headcount, datalen;
- size_t hdr_size;
struct socket *sock = rcu_dereference(vq->private_data);
if (!sock || !skb_head_len(&sock->sk->sk_receive_queue))
@@ -223,7 +235,6 @@
use_mm(net->dev.mm);
mutex_lock(&vq->mutex);
vhost_disable_notify(vq);
- hdr_size = vq->hdr_size;
vq_log = unlikely(vhost_has_feature(&net->dev, VHOST_F_LOG_ALL)) ?
vq->log : NULL;
@@ -232,25 +243,18 @@
headcount = vhost_get_heads(vq, datalen, &in, vq_log,
&log);
/* OK, now we need to know about added descriptors. */
if (!headcount) {
- if (unlikely(vhost_enable_notify(vq))) {
- /* They have slipped one in as we were
- * doing that: check again. */
- vhost_disable_notify(vq);
- continue;
- }
- /* Nothing new? Wait for eventfd to tell us
- * they refilled. */
+ vhost_enable_notify(vq);
break;
}
/* Skip header. TODO: support TSO/mergeable rx buffers. */
- s = move_iovec_hdr(vq->iov, vq->hdr, hdr_size, in);
msg.msg_iovlen = in;
len = iov_length(vq->iov, in);
+
/* Sanity check */
if (!len) {
vq_err(vq, "Unexpected header len for RX: "
"%zd expected %zd\n",
- iov_length(vq->hdr, s), hdr_size);
+ len, vq->guest_hlen);
break;
}
err = sock->ops->recvmsg(NULL, sock, &msg,
@@ -268,13 +272,7 @@
continue;
}
len = err;
- err = memcpy_toiovec(vq->hdr, (unsigned char *)&hdr,
hdr_size);
- if (err) {
- vq_err(vq, "Unable to write vnet_hdr at addr %p:
%d\n",
- vq->iov->iov_base, err);
- break;
- }
- len += hdr_size;
+ len += vq->guest_hlen - vq->sock_hlen;
vhost_add_used_and_signal(&net->dev, vq, vq->heads,
headcount);
if (unlikely(vq_log))
vhost_log_write(vq, vq_log, log, len);
@@ -483,6 +481,13 @@
return ERR_PTR(-ENOTSOCK);
}
+static int vhost_sock_is_raw(struct socket *sock)
+{
+ if (!sock || !sock->sk)
+ return 0;
+ return sock->sk->sk_type == SOCK_RAW;
+}
+
static long vhost_net_set_backend(struct vhost_net *n, unsigned index,
int fd)
{
struct socket *sock, *oldsock;
@@ -519,6 +524,20 @@
vhost_net_disable_vq(n, vq);
rcu_assign_pointer(vq->private_data, sock);
+
+ if (sock && sock->sk) {
+ if (!vhost_sock_is_raw(sock) ||
+ vhost_has_feature(&n->dev,
VHOST_NET_F_VIRTIO_NET_HDR)) {
+ vq->sock_hlen = sizeof(struct virtio_net_hdr);
+ if (vhost_has_feature(&n->dev,
VIRTIO_NET_F_MRG_RXBUF))
+ vq->guest_hlen =
+ sizeof(struct
virtio_net_hdr_mrg_rxbuf);
+ else
+ vq->guest_hlen = sizeof(struct
virtio_net_hdr);
+ } else
+ vq->guest_hlen = vq->sock_hlen = 0;
+ } else
+ vq_err(vq, "vhost_net_set_backend: sock->sk is NULL");
vhost_net_enable_vq(n, vq);
mutex_unlock(&vq->mutex);
done:
@@ -566,8 +585,17 @@
n->dev.acked_features = features;
smp_wmb();
for (i = 0; i < VHOST_NET_VQ_MAX; ++i) {
- mutex_lock(&n->vqs[i].mutex);
- n->vqs[i].hdr_size = hdr_size;
+ struct vhost_virtqueue *vq = n->vqs + i;
+ struct socket *sock = vq->private_data;
+
+ mutex_lock(&vq->mutex);
+ if (features & (1 << VIRTIO_NET_F_MRG_RXBUF))
+ vq->sock_hlen = sizeof(struct
virtio_net_hdr_mrg_rxbuf);
+ else if (features & (1 << VHOST_NET_F_VIRTIO_NET_HDR) ||
+ !vhost_sock_is_raw(sock))
+ vq->sock_hlen = sizeof(struct virtio_net_hdr);
+ else
+ vq->sock_hlen = 0;
mutex_unlock(&n->vqs[i].mutex);
}
vhost_net_flush(n);
diff -ruN net-next-p1/drivers/vhost/vhost.c
net-next-p2/drivers/vhost/vhost.c
--- net-next-p1/drivers/vhost/vhost.c 2010-03-01 11:44:06.000000000
-0800
+++ net-next-p2/drivers/vhost/vhost.c 2010-03-02 12:53:02.000000000
-0800
@@ -113,7 +113,8 @@
vq->used_flags = 0;
vq->log_used = false;
vq->log_addr = -1ull;
- vq->hdr_size = 0;
+ vq->guest_hlen = 0;
+ vq->sock_hlen = 0;
vq->private_data = NULL;
vq->log_base = NULL;
vq->error_ctx = NULL;
@@ -848,20 +849,85 @@
return 0;
}
+static int
+vhost_get_hdr(struct vhost_virtqueue *vq, int *in, struct vhost_log *log,
+ int *log_num)
+{
+ struct iovec *heads = vq->heads;
+ struct iovec *iov = vq->iov;
+ int out;
+
+ *in = 0;
+ iov[0].iov_len = 0;
+
+ /* get buffer, starting from iov[1] */
+ heads[0].iov_base = (void *)vhost_get_vq_desc(vq->dev, vq,
+ vq->iov+1, ARRAY_SIZE(vq->iov)-1, &out, in, log, log_num);
+ if (out || *in <= 0) {
+ vq_err(vq, "unexpected descriptor format for RX: out %d, "
+ "in %d\n", out, *in);
+ return 0;
+ }
+ if (heads[0].iov_base == (void *)vq->num)
+ return 0;
+
+ /* make iov[0] the header */
+ if (!vq->guest_hlen) {
+ if (vq->sock_hlen) {
+ static struct virtio_net_hdr junk; /* bit bucket
*/
+
+ iov[0].iov_base = &junk;
+ iov[0].iov_len = sizeof(junk);
+ } else
+ iov[0].iov_len = 0;
+ }
+ if (vq->sock_hlen < vq->guest_hlen) {
+ iov[0].iov_base = iov[1].iov_base;
+ iov[0].iov_len = vq->sock_hlen;
+
+ if (iov[1].iov_len < vq->sock_hlen) {
+ vq_err(vq, "can't fit header in one buffer!");
+ vhost_discard(vq, 1);
+ return 0;
+ }
+ if (!vq->sock_hlen) {
+ static const struct virtio_net_hdr_mrg_rxbuf hdr =
{
+ .hdr.flags = 0,
+ .hdr.gso_type = VIRTIO_NET_HDR_GSO_NONE
+ };
+ memcpy(iov[0].iov_base, &hdr, vq->guest_hlen);
+ }
+ iov[1].iov_base += vq->guest_hlen;
+ iov[1].iov_len -= vq->guest_hlen;
+ }
+ return 1;
+}
+
unsigned vhost_get_heads(struct vhost_virtqueue *vq, int datalen, int
*iovcount,
struct vhost_log *log, unsigned int *log_num)
{
struct iovec *heads = vq->heads;
- int out, in;
+ int out, in = 0;
+ int seg = 0;
int hc = 0;
+ if (vq->guest_hlen != vq->sock_hlen) {
+ seg = vhost_get_hdr(vq, &in, log, log_num);
+ if (!seg)
+ return 0;
+ hc++;
+ datalen -= iov_length(vq->iov+seg, in);
+ seg += in;
+ }
+
while (datalen > 0) {
if (hc >= VHOST_NET_MAX_SG) {
vhost_discard(vq, hc);
return 0;
}
heads[hc].iov_base = (void *)vhost_get_vq_desc(vq->dev,
vq,
- vq->iov, ARRAY_SIZE(vq->iov), &out, &in, log,
log_num);
+ vq->iov+seg, ARRAY_SIZE(vq->iov)-seg, &out, &in,
+ log, log_num);
if (heads[hc].iov_base == (void *)vq->num) {
vhost_discard(vq, hc);
return 0;
@@ -872,11 +938,12 @@
vhost_discard(vq, hc);
return 0;
}
- heads[hc].iov_len = iov_length(vq->iov, in);
- hc++;
+ heads[hc].iov_len = iov_length(vq->iov+seg, in);
datalen -= heads[hc].iov_len;
+ hc++;
+ seg += in;
}
- *iovcount = in;
+ *iovcount = seg;
return hc;
}
diff -ruN net-next-p1/drivers/vhost/vhost.h
net-next-p2/drivers/vhost/vhost.h
--- net-next-p1/drivers/vhost/vhost.h 2010-03-01 11:42:18.000000000
-0800
+++ net-next-p2/drivers/vhost/vhost.h 2010-03-02 13:02:03.000000000
-0800
@@ -82,10 +82,9 @@
u64 log_addr;
struct iovec indirect[VHOST_NET_MAX_SG];
- struct iovec iov[VHOST_NET_MAX_SG];
- struct iovec hdr[VHOST_NET_MAX_SG];
+ struct iovec iov[VHOST_NET_MAX_SG+1]; /* an extra for vnet hdr */
struct iovec heads[VHOST_NET_MAX_SG];
- size_t hdr_size;
+ size_t guest_hlen, sock_hlen;
/* We use a kind of RCU to access private pointer.
* All readers access it from workqueue, which makes it possible
to
* flush the workqueue instead of synchronize_rcu. Therefore
readers do
[-- Attachment #2: MRXB2.patch --]
[-- Type: application/octet-stream, Size: 9374 bytes --]
diff -ruN net-next-p1/drivers/vhost/net.c net-next-p2/drivers/vhost/net.c
--- net-next-p1/drivers/vhost/net.c 2010-03-01 11:44:22.000000000 -0800
+++ net-next-p2/drivers/vhost/net.c 2010-03-02 13:01:34.000000000 -0800
@@ -109,7 +109,6 @@
};
size_t len, total_len = 0;
int err, wmem;
- size_t hdr_size;
struct socket *sock = rcu_dereference(vq->private_data);
if (!sock)
return;
@@ -124,7 +123,6 @@
if (wmem < sock->sk->sk_sndbuf * 2)
tx_poll_stop(net);
- hdr_size = vq->hdr_size;
for (;;) {
head.iov_base = (void *)vhost_get_vq_desc(&net->dev, vq,
@@ -148,25 +146,45 @@
"out %d, int %d\n", out, in);
break;
}
+ if (vq->guest_hlen > vq->sock_hlen) {
+ if (msg.msg_iov[0].iov_len == vq->guest_hlen)
+ msg.msg_iov[0].iov_len = vq->sock_hlen;
+ else if (out == ARRAY_SIZE(vq->iov))
+ vq_err(vq, "handle_tx iov overflow!");
+ else {
+ int i;
+
+ /* give header its own iov */
+ for (i=out; i>0; ++i)
+ msg.msg_iov[i+1] = msg.msg_iov[i];
+ msg.msg_iov[0].iov_len = vq->sock_hlen;
+ msg.msg_iov[1].iov_base += vq->guest_hlen;
+ msg.msg_iov[1].iov_len -= vq->guest_hlen;
+ out++;
+ }
+ }
/* Skip header. TODO: support TSO. */
- s = move_iovec_hdr(vq->iov, vq->hdr, hdr_size, out);
msg.msg_iovlen = out;
head.iov_len = len = iov_length(vq->iov, out);
/* Sanity check */
if (!len) {
vq_err(vq, "Unexpected header len for TX: "
"%zd expected %zd\n",
- iov_length(vq->hdr, s), hdr_size);
+ len, vq->guest_hlen);
break;
}
/* TODO: Check specific error and bomb out unless ENOBUFS? */
err = sock->ops->sendmsg(NULL, sock, &msg, len);
if (unlikely(err < 0)) {
- vhost_discard(vq, 1);
- tx_poll_start(net, sock);
+ if (err == -EAGAIN) {
+ tx_poll_start(net, sock);
+ } else {
+ vq_err(vq, "sendmsg: errno %d\n", -err);
+ /* drop packet; do not discard/resend */
+ vhost_add_used_and_signal(&net->dev,vq,&head,1);
+ }
break;
- }
- if (err != len)
+ } else if (err != len)
pr_err("Truncated TX packet: "
" len %d != %zd\n", err, len);
vhost_add_used_and_signal(&net->dev, vq, &head, 1);
@@ -207,14 +225,8 @@
.msg_flags = MSG_DONTWAIT,
};
- struct virtio_net_hdr hdr = {
- .flags = 0,
- .gso_type = VIRTIO_NET_HDR_GSO_NONE
- };
-
size_t len, total_len = 0;
int err, headcount, datalen;
- size_t hdr_size;
struct socket *sock = rcu_dereference(vq->private_data);
if (!sock || !skb_head_len(&sock->sk->sk_receive_queue))
@@ -223,7 +235,6 @@
use_mm(net->dev.mm);
mutex_lock(&vq->mutex);
vhost_disable_notify(vq);
- hdr_size = vq->hdr_size;
vq_log = unlikely(vhost_has_feature(&net->dev, VHOST_F_LOG_ALL)) ?
vq->log : NULL;
@@ -232,25 +243,18 @@
headcount = vhost_get_heads(vq, datalen, &in, vq_log, &log);
/* OK, now we need to know about added descriptors. */
if (!headcount) {
- if (unlikely(vhost_enable_notify(vq))) {
- /* They have slipped one in as we were
- * doing that: check again. */
- vhost_disable_notify(vq);
- continue;
- }
- /* Nothing new? Wait for eventfd to tell us
- * they refilled. */
+ vhost_enable_notify(vq);
break;
}
/* Skip header. TODO: support TSO/mergeable rx buffers. */
- s = move_iovec_hdr(vq->iov, vq->hdr, hdr_size, in);
msg.msg_iovlen = in;
len = iov_length(vq->iov, in);
+
/* Sanity check */
if (!len) {
vq_err(vq, "Unexpected header len for RX: "
"%zd expected %zd\n",
- iov_length(vq->hdr, s), hdr_size);
+ len, vq->guest_hlen);
break;
}
err = sock->ops->recvmsg(NULL, sock, &msg,
@@ -268,13 +272,7 @@
continue;
}
len = err;
- err = memcpy_toiovec(vq->hdr, (unsigned char *)&hdr, hdr_size);
- if (err) {
- vq_err(vq, "Unable to write vnet_hdr at addr %p: %d\n",
- vq->iov->iov_base, err);
- break;
- }
- len += hdr_size;
+ len += vq->guest_hlen - vq->sock_hlen;
vhost_add_used_and_signal(&net->dev, vq, vq->heads, headcount);
if (unlikely(vq_log))
vhost_log_write(vq, vq_log, log, len);
@@ -483,6 +481,13 @@
return ERR_PTR(-ENOTSOCK);
}
+static int vhost_sock_is_raw(struct socket *sock)
+{
+ if (!sock || !sock->sk)
+ return 0;
+ return sock->sk->sk_type == SOCK_RAW;
+}
+
static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd)
{
struct socket *sock, *oldsock;
@@ -519,6 +524,20 @@
vhost_net_disable_vq(n, vq);
rcu_assign_pointer(vq->private_data, sock);
+
+ if (sock && sock->sk) {
+ if (!vhost_sock_is_raw(sock) ||
+ vhost_has_feature(&n->dev, VHOST_NET_F_VIRTIO_NET_HDR)) {
+ vq->sock_hlen = sizeof(struct virtio_net_hdr);
+ if (vhost_has_feature(&n->dev, VIRTIO_NET_F_MRG_RXBUF))
+ vq->guest_hlen =
+ sizeof(struct virtio_net_hdr_mrg_rxbuf);
+ else
+ vq->guest_hlen = sizeof(struct virtio_net_hdr);
+ } else
+ vq->guest_hlen = vq->sock_hlen = 0;
+ } else
+ vq_err(vq, "vhost_net_set_backend: sock->sk is NULL");
vhost_net_enable_vq(n, vq);
mutex_unlock(&vq->mutex);
done:
@@ -566,8 +585,17 @@
n->dev.acked_features = features;
smp_wmb();
for (i = 0; i < VHOST_NET_VQ_MAX; ++i) {
- mutex_lock(&n->vqs[i].mutex);
- n->vqs[i].hdr_size = hdr_size;
+ struct vhost_virtqueue *vq = n->vqs + i;
+ struct socket *sock = vq->private_data;
+
+ mutex_lock(&vq->mutex);
+ if (features & (1 << VIRTIO_NET_F_MRG_RXBUF))
+ vq->sock_hlen = sizeof(struct virtio_net_hdr_mrg_rxbuf);
+ else if (features & (1 << VHOST_NET_F_VIRTIO_NET_HDR) ||
+ !vhost_sock_is_raw(sock))
+ vq->sock_hlen = sizeof(struct virtio_net_hdr);
+ else
+ vq->sock_hlen = 0;
mutex_unlock(&n->vqs[i].mutex);
}
vhost_net_flush(n);
diff -ruN net-next-p1/drivers/vhost/vhost.c net-next-p2/drivers/vhost/vhost.c
--- net-next-p1/drivers/vhost/vhost.c 2010-03-01 11:44:06.000000000 -0800
+++ net-next-p2/drivers/vhost/vhost.c 2010-03-02 12:53:02.000000000 -0800
@@ -113,7 +113,8 @@
vq->used_flags = 0;
vq->log_used = false;
vq->log_addr = -1ull;
- vq->hdr_size = 0;
+ vq->guest_hlen = 0;
+ vq->sock_hlen = 0;
vq->private_data = NULL;
vq->log_base = NULL;
vq->error_ctx = NULL;
@@ -848,20 +849,85 @@
return 0;
}
+static int
+vhost_get_hdr(struct vhost_virtqueue *vq, int *in, struct vhost_log *log,
+ int *log_num)
+{
+ struct iovec *heads = vq->heads;
+ struct iovec *iov = vq->iov;
+ int out;
+
+ *in = 0;
+ iov[0].iov_len = 0;
+
+ /* get buffer, starting from iov[1] */
+ heads[0].iov_base = (void *)vhost_get_vq_desc(vq->dev, vq,
+ vq->iov+1, ARRAY_SIZE(vq->iov)-1, &out, in, log, log_num);
+ if (out || *in <= 0) {
+ vq_err(vq, "unexpected descriptor format for RX: out %d, "
+ "in %d\n", out, *in);
+ return 0;
+ }
+ if (heads[0].iov_base == (void *)vq->num)
+ return 0;
+
+ /* make iov[0] the header */
+ if (!vq->guest_hlen) {
+ if (vq->sock_hlen) {
+ static struct virtio_net_hdr junk; /* bit bucket */
+
+ iov[0].iov_base = &junk;
+ iov[0].iov_len = sizeof(junk);
+ } else
+ iov[0].iov_len = 0;
+ }
+ if (vq->sock_hlen < vq->guest_hlen) {
+ iov[0].iov_base = iov[1].iov_base;
+ iov[0].iov_len = vq->sock_hlen;
+
+ if (iov[1].iov_len < vq->sock_hlen) {
+ vq_err(vq, "can't fit header in one buffer!");
+ vhost_discard(vq, 1);
+ return 0;
+ }
+ if (!vq->sock_hlen) {
+ static const struct virtio_net_hdr_mrg_rxbuf hdr = {
+ .hdr.flags = 0,
+ .hdr.gso_type = VIRTIO_NET_HDR_GSO_NONE
+ };
+ memcpy(iov[0].iov_base, &hdr, vq->guest_hlen);
+ }
+ iov[1].iov_base += vq->guest_hlen;
+ iov[1].iov_len -= vq->guest_hlen;
+ }
+ return 1;
+}
+
unsigned vhost_get_heads(struct vhost_virtqueue *vq, int datalen, int *iovcount,
struct vhost_log *log, unsigned int *log_num)
{
struct iovec *heads = vq->heads;
- int out, in;
+ int out, in = 0;
+ int seg = 0;
int hc = 0;
+ if (vq->guest_hlen != vq->sock_hlen) {
+ seg = vhost_get_hdr(vq, &in, log, log_num);
+ if (!seg)
+ return 0;
+ hc++;
+ datalen -= iov_length(vq->iov+seg, in);
+ seg += in;
+ }
+
while (datalen > 0) {
if (hc >= VHOST_NET_MAX_SG) {
vhost_discard(vq, hc);
return 0;
}
heads[hc].iov_base = (void *)vhost_get_vq_desc(vq->dev, vq,
- vq->iov, ARRAY_SIZE(vq->iov), &out, &in, log, log_num);
+ vq->iov+seg, ARRAY_SIZE(vq->iov)-seg, &out, &in,
+ log, log_num);
if (heads[hc].iov_base == (void *)vq->num) {
vhost_discard(vq, hc);
return 0;
@@ -872,11 +938,12 @@
vhost_discard(vq, hc);
return 0;
}
- heads[hc].iov_len = iov_length(vq->iov, in);
- hc++;
+ heads[hc].iov_len = iov_length(vq->iov+seg, in);
datalen -= heads[hc].iov_len;
+ hc++;
+ seg += in;
}
- *iovcount = in;
+ *iovcount = seg;
return hc;
}
diff -ruN net-next-p1/drivers/vhost/vhost.h net-next-p2/drivers/vhost/vhost.h
--- net-next-p1/drivers/vhost/vhost.h 2010-03-01 11:42:18.000000000 -0800
+++ net-next-p2/drivers/vhost/vhost.h 2010-03-02 13:02:03.000000000 -0800
@@ -82,10 +82,9 @@
u64 log_addr;
struct iovec indirect[VHOST_NET_MAX_SG];
- struct iovec iov[VHOST_NET_MAX_SG];
- struct iovec hdr[VHOST_NET_MAX_SG];
+ struct iovec iov[VHOST_NET_MAX_SG+1]; /* an extra for vnet hdr */
struct iovec heads[VHOST_NET_MAX_SG];
- size_t hdr_size;
+ size_t guest_hlen, sock_hlen;
/* We use a kind of RCU to access private pointer.
* All readers access it from workqueue, which makes it possible to
* flush the workqueue instead of synchronize_rcu. Therefore readers do
^ permalink raw reply
* [RFC][ PATCH 0/3] vhost-net: Add mergeable RX buffer support to vhost-net
From: David Stevens @ 2010-03-03 0:20 UTC (permalink / raw)
To: mst, rusty; +Cc: netdev, kvm, virtualization
These patches add support for mergeable receive buffers to
vhost-net, allowing it to use multiple virtio buffer heads for a single
receive packet.
+-DLS
Signed-off-by: David L Stevens <dlstevens@us.ibm.com>
^ permalink raw reply
* Re: [RFC][PATCH] ns: Syscalls for better namespace sharing control.
From: Sukadev Bhattiprolu @ 2010-03-03 0:07 UTC (permalink / raw)
To: Eric W. Biederman
Cc: Pavel Emelyanov, Daniel Lezcano, Linux Netdev List, containers,
Netfilter Development Mailinglist, Ben Greear
In-Reply-To: <m1y6iaqsmm.fsf@fess.ebiederm.org>
Eric W. Biederman [ebiederm@xmission.com] wrote:
|
| I think replacing a struct pid for another struct pid allocated in
| descendant pid_namespace (but has all of the same struct upid values
| as the first struct pid) is a disastrous idea. It destroys the
True. Sorry, I did not mean we would need a new 'struct pid' for an
existing process. I think we talked earlier of finding a way of attaching
additional pid numbers to the same struct pid.
Sukadev
^ permalink raw reply
* Re: [RFC v2 03/10] snet: introduce security/snet, Makefile and Kconfig changes
From: Greg KH @ 2010-03-03 0:03 UTC (permalink / raw)
To: Samir Bellabes
Cc: linux-security-module, linux-kernel, netdev, netfilter-devel,
jamal, Patrick McHardy, Evgeniy Polyakov, Neil Horman,
Grzegorz Nosek
In-Reply-To: <1267561394-13626-4-git-send-email-sam@synack.fr>
On Tue, Mar 02, 2010 at 09:23:07PM +0100, Samir Bellabes wrote:
> this patch creates folder security/snet and adds changes for Kconfig and Makefile
But it breaks the build, as you are referring to files here that are not
present yet. Please put this at the end of your patch series to make
the tree always build for every individual patch.
thanks,
greg k-h
^ permalink raw reply
* [PATCH 12/12] IPv6: addrconf cleanup addrconf_verify
From: Stephen Hemminger @ 2010-03-02 23:32 UTC (permalink / raw)
To: David S. Miller, Hideaki YOSHIFUJI; +Cc: netdev
In-Reply-To: <20100302233243.259794027@vyatta.com>
[-- Attachment #1: addrconf-verify-clean.patch --]
[-- Type: text/plain, Size: 1403 bytes --]
The variable regen_advance is only used in the privacy case.
Move it to simplify code and eliminate ifdef's
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
--- a/net/ipv6/addrconf.c 2010-03-02 14:46:44.709576675 -0800
+++ b/net/ipv6/addrconf.c 2010-03-02 14:46:46.017202416 -0800
@@ -3122,9 +3122,6 @@ restart:
hlist_for_each_entry_rcu(ifp, node,
&inet6_addr_lst[i], addr_lst) {
unsigned long age;
-#ifdef CONFIG_IPV6_PRIVACY
- unsigned long regen_advance;
-#endif
if (ifp->flags & IFA_F_PERMANENT)
continue;
@@ -3132,12 +3129,6 @@ restart:
spin_lock(&ifp->lock);
age = (now - ifp->tstamp) / HZ;
-#ifdef CONFIG_IPV6_PRIVACY
- regen_advance = ifp->idev->cnf.regen_max_retry *
- ifp->idev->cnf.dad_transmits *
- ifp->idev->nd_parms->retrans_time / HZ;
-#endif
-
if (ifp->valid_lft != INFINITY_LIFE_TIME &&
age >= ifp->valid_lft) {
spin_unlock(&ifp->lock);
@@ -3171,6 +3162,10 @@ restart:
#ifdef CONFIG_IPV6_PRIVACY
} else if ((ifp->flags&IFA_F_TEMPORARY) &&
!(ifp->flags&IFA_F_TENTATIVE)) {
+ unsigned long regen_advance = ifp->idev->cnf.regen_max_retry *
+ ifp->idev->cnf.dad_transmits *
+ ifp->idev->nd_parms->retrans_time / HZ;
+
if (age >= ifp->prefered_lft - regen_advance) {
struct inet6_ifaddr *ifpub = ifp->ifpub;
if (time_before(ifp->tstamp + ifp->prefered_lft * HZ, next))
--
^ permalink raw reply
* [PATCH 11/12] ipv6: addrconf timer changes
From: Stephen Hemminger @ 2010-03-02 23:32 UTC (permalink / raw)
To: David S. Miller, Hideaki YOSHIFUJI; +Cc: netdev
In-Reply-To: <20100302233243.259794027@vyatta.com>
[-- Attachment #1: addrconf-timer.patch --]
[-- Type: text/plain, Size: 677 bytes --]
For addrconf timer:
* use round_jiffies since this timer doesn't need to happen sub-second
* use mod_timer for safer timer modification
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
---
net/ipv6/addrconf.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/net/ipv6/addrconf.c 2010-03-02 14:46:40.529202001 -0800
+++ b/net/ipv6/addrconf.c 2010-03-02 14:46:44.709576675 -0800
@@ -3202,7 +3202,7 @@ restart:
}
}
- addr_chk_timer.expires = time_before(next, jiffies + HZ) ? jiffies + HZ : next;
+ addr_chk_timer.expires = round_jiffies(next);
add_timer(&addr_chk_timer);
spin_unlock(&addrconf_verify_lock);
rcu_read_unlock_bh();
--
^ permalink raw reply
* [PATCH 10/12] IPv6: addrconf checkpatch fixes
From: Stephen Hemminger @ 2010-03-02 23:32 UTC (permalink / raw)
To: David S. Miller, Hideaki YOSHIFUJI; +Cc: netdev
In-Reply-To: <20100302233243.259794027@vyatta.com>
[-- Attachment #1: addrconf-checkpatch.patch --]
[-- Type: text/plain, Size: 16752 bytes --]
This resolves a number of checkpatch complaints.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
--- a/net/ipv6/addrconf.c 2010-03-02 14:46:37.933576182 -0800
+++ b/net/ipv6/addrconf.c 2010-03-02 14:46:40.529202001 -0800
@@ -81,7 +81,7 @@
#include <linux/random.h>
#endif
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <asm/unaligned.h>
#include <linux/proc_fs.h>
@@ -97,7 +97,7 @@
#endif
#define INFINITY_LIFE_TIME 0xFFFFFFFF
-#define TIME_DELTA(a,b) ((unsigned long)((long)(a) - (long)(b)))
+#define TIME_DELTA(a, b) ((unsigned long)((long)(a) - (long)(b)))
#ifdef CONFIG_SYSCTL
static void addrconf_sysctl_register(struct inet6_dev *idev);
@@ -249,8 +249,7 @@ static void addrconf_del_timer(struct in
__in6_ifa_put(ifp);
}
-enum addrconf_timer_t
-{
+enum addrconf_timer_t {
AC_NONE,
AC_DAD,
AC_RS,
@@ -270,7 +269,8 @@ static void addrconf_mod_timer(struct in
case AC_RS:
ifp->timer.function = addrconf_rs_timer;
break;
- default:;
+ default:
+ break;
}
ifp->timer.expires = jiffies + when;
add_timer(&ifp->timer);
@@ -325,7 +325,7 @@ void in6_dev_finish_destroy(struct inet6
#endif
dev_put(dev);
if (!idev->dead) {
- printk("Freeing alive inet6 device %p\n", idev);
+ pr_warning("Freeing alive inet6 device %p\n", idev);
return;
}
snmp6_free_dev(idev);
@@ -441,8 +441,10 @@ static struct inet6_dev * ipv6_find_idev
ASSERT_RTNL();
- if ((idev = __in6_dev_get(dev)) == NULL) {
- if ((idev = ipv6_add_dev(dev)) == NULL)
+ idev = __in6_dev_get(dev);
+ if (!idev) {
+ idev = ipv6_add_dev(dev);
+ if (!idev)
return NULL;
}
@@ -544,10 +546,10 @@ void inet6_ifa_finish_destroy(struct ine
in6_dev_put(ifp->idev);
if (del_timer(&ifp->timer))
- printk("Timer is still running, when freeing ifa=%p\n", ifp);
+ pr_notice("Timer is still running, when freeing ifa=%p\n", ifp);
if (!ifp->dead) {
- printk("Freeing alive inet6 address %p\n", ifp);
+ pr_warning("Freeing alive inet6 address %p\n", ifp);
return;
}
dst_release(&ifp->rt->u.dst);
@@ -1225,7 +1227,6 @@ try_nextdev:
in6_ifa_put(hiscore->ifa);
return 0;
}
-
EXPORT_SYMBOL(ipv6_dev_get_saddr);
int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr,
@@ -1235,7 +1236,8 @@ int ipv6_get_lladdr(struct net_device *d
int err = -EADDRNOTAVAIL;
rcu_read_lock();
- if ((idev = __in6_dev_get(dev)) != NULL) {
+ idev = __in6_dev_get(dev);
+ if (idev) {
struct inet6_ifaddr *ifp;
read_lock_bh(&idev->lock);
@@ -1723,7 +1725,8 @@ static struct inet6_dev *addrconf_add_de
ASSERT_RTNL();
- if ((idev = ipv6_find_idev(dev)) == NULL)
+ idev = ipv6_find_idev(dev);
+ if (!idev)
return NULL;
/* Add default multicast route */
@@ -2431,7 +2434,8 @@ static void addrconf_ip6_tnl_config(stru
ASSERT_RTNL();
- if ((idev = addrconf_add_dev(dev)) == NULL) {
+ idev = addrconf_add_dev(dev);
+ if (!idev) {
printk(KERN_DEBUG "init ip6-ip6: add_dev failed\n");
return;
}
@@ -2446,7 +2450,7 @@ static int addrconf_notify(struct notifi
int run_pending = 0;
int err;
- switch(event) {
+ switch (event) {
case NETDEV_REGISTER:
if (!idev && dev->mtu >= IPV6_MIN_MTU) {
idev = ipv6_add_dev(dev);
@@ -2498,7 +2502,7 @@ static int addrconf_notify(struct notifi
run_pending = 1;
}
- switch(dev->type) {
+ switch (dev->type) {
#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)
case ARPHRD_SIT:
addrconf_sit_config(dev);
@@ -2835,7 +2839,7 @@ static void addrconf_dad_start(struct in
* Optimistic nodes can start receiving
* Frames right away
*/
- if(ifp->flags & IFA_F_OPTIMISTIC)
+ if (ifp->flags & IFA_F_OPTIMISTIC)
ip6_ins_rt(ifp->rt);
addrconf_dad_kick(ifp);
@@ -2885,7 +2889,7 @@ out:
static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
{
- struct net_device * dev = ifp->idev->dev;
+ struct net_device *dev = ifp->idev->dev;
/*
* Configure the address for reception. Now it is valid.
@@ -2916,7 +2920,8 @@ static void addrconf_dad_completed(struc
}
}
-static void addrconf_dad_run(struct inet6_dev *idev) {
+static void addrconf_dad_run(struct inet6_dev *idev)
+{
struct inet6_ifaddr *ifp;
read_lock_bh(&idev->lock);
@@ -2981,7 +2986,7 @@ static struct inet6_ifaddr *if6_get_idx(
struct inet6_ifaddr *ifa = if6_get_first(seq);
if (ifa)
- while(pos && (ifa = if6_get_next(seq, ifa)) != NULL)
+ while (pos && (ifa = if6_get_next(seq, ifa)) != NULL)
--pos;
return pos ? NULL : ifa;
}
@@ -3490,8 +3495,7 @@ static int inet6_fill_ifacaddr(struct sk
return nlmsg_end(skb, nlh);
}
-enum addr_type_t
-{
+enum addr_type_t {
UNICAST_ADDR,
MULTICAST_ADDR,
ANYCAST_ADDR,
@@ -3590,7 +3594,8 @@ static int inet6_dump_addr(struct sk_buf
if (idx > s_idx)
s_ip_idx = 0;
ip_idx = 0;
- if ((idev = __in6_dev_get(dev)) == NULL)
+ idev = __in6_dev_get(dev);
+ if (!idev)
goto cont;
if (in6_dump_addrs(idev, skb, cb, type,
@@ -3657,12 +3662,14 @@ static int inet6_rtm_getaddr(struct sk_b
if (ifm->ifa_index)
dev = __dev_get_by_index(net, ifm->ifa_index);
- if ((ifa = ipv6_get_ifaddr(net, addr, dev, 1)) == NULL) {
+ ifa = ipv6_get_ifaddr(net, addr, dev, 1);
+ if (!ifa) {
err = -EADDRNOTAVAIL;
goto errout;
}
- if ((skb = nlmsg_new(inet6_ifaddr_msgsize(), GFP_KERNEL)) == NULL) {
+ skb = nlmsg_new(inet6_ifaddr_msgsize(), GFP_KERNEL);
+ if (!skb) {
err = -ENOBUFS;
goto errout_ifa;
}
@@ -3787,7 +3794,7 @@ static inline void __snmp6_fill_stats(u6
static void snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype,
int bytes)
{
- switch(attrtype) {
+ switch (attrtype) {
case IFLA_INET6_STATS:
__snmp6_fill_stats(stats, (void __percpu **)idev->stats.ipv6, IPSTATS_MIB_MAX, bytes);
break;
@@ -4139,211 +4146,211 @@ static struct addrconf_sysctl_table
.sysctl_header = NULL,
.addrconf_vars = {
{
- .procname = "forwarding",
- .data = &ipv6_devconf.forwarding,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = addrconf_sysctl_forward,
+ .procname = "forwarding",
+ .data = &ipv6_devconf.forwarding,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = addrconf_sysctl_forward,
},
{
- .procname = "hop_limit",
- .data = &ipv6_devconf.hop_limit,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "hop_limit",
+ .data = &ipv6_devconf.hop_limit,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
{
- .procname = "mtu",
- .data = &ipv6_devconf.mtu6,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "mtu",
+ .data = &ipv6_devconf.mtu6,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
{
- .procname = "accept_ra",
- .data = &ipv6_devconf.accept_ra,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "accept_ra",
+ .data = &ipv6_devconf.accept_ra,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
{
- .procname = "accept_redirects",
- .data = &ipv6_devconf.accept_redirects,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "accept_redirects",
+ .data = &ipv6_devconf.accept_redirects,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
{
- .procname = "autoconf",
- .data = &ipv6_devconf.autoconf,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "autoconf",
+ .data = &ipv6_devconf.autoconf,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
{
- .procname = "dad_transmits",
- .data = &ipv6_devconf.dad_transmits,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "dad_transmits",
+ .data = &ipv6_devconf.dad_transmits,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
{
- .procname = "router_solicitations",
- .data = &ipv6_devconf.rtr_solicits,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "router_solicitations",
+ .data = &ipv6_devconf.rtr_solicits,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
{
- .procname = "router_solicitation_interval",
- .data = &ipv6_devconf.rtr_solicit_interval,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_jiffies,
+ .procname = "router_solicitation_interval",
+ .data = &ipv6_devconf.rtr_solicit_interval,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec_jiffies,
},
{
- .procname = "router_solicitation_delay",
- .data = &ipv6_devconf.rtr_solicit_delay,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_jiffies,
+ .procname = "router_solicitation_delay",
+ .data = &ipv6_devconf.rtr_solicit_delay,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec_jiffies,
},
{
- .procname = "force_mld_version",
- .data = &ipv6_devconf.force_mld_version,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "force_mld_version",
+ .data = &ipv6_devconf.force_mld_version,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
#ifdef CONFIG_IPV6_PRIVACY
{
- .procname = "use_tempaddr",
- .data = &ipv6_devconf.use_tempaddr,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "use_tempaddr",
+ .data = &ipv6_devconf.use_tempaddr,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
{
- .procname = "temp_valid_lft",
- .data = &ipv6_devconf.temp_valid_lft,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "temp_valid_lft",
+ .data = &ipv6_devconf.temp_valid_lft,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
{
- .procname = "temp_prefered_lft",
- .data = &ipv6_devconf.temp_prefered_lft,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "temp_prefered_lft",
+ .data = &ipv6_devconf.temp_prefered_lft,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
{
- .procname = "regen_max_retry",
- .data = &ipv6_devconf.regen_max_retry,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "regen_max_retry",
+ .data = &ipv6_devconf.regen_max_retry,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
{
- .procname = "max_desync_factor",
- .data = &ipv6_devconf.max_desync_factor,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "max_desync_factor",
+ .data = &ipv6_devconf.max_desync_factor,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
#endif
{
- .procname = "max_addresses",
- .data = &ipv6_devconf.max_addresses,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "max_addresses",
+ .data = &ipv6_devconf.max_addresses,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
{
- .procname = "accept_ra_defrtr",
- .data = &ipv6_devconf.accept_ra_defrtr,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "accept_ra_defrtr",
+ .data = &ipv6_devconf.accept_ra_defrtr,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
{
- .procname = "accept_ra_pinfo",
- .data = &ipv6_devconf.accept_ra_pinfo,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "accept_ra_pinfo",
+ .data = &ipv6_devconf.accept_ra_pinfo,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
#ifdef CONFIG_IPV6_ROUTER_PREF
{
- .procname = "accept_ra_rtr_pref",
- .data = &ipv6_devconf.accept_ra_rtr_pref,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "accept_ra_rtr_pref",
+ .data = &ipv6_devconf.accept_ra_rtr_pref,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
{
- .procname = "router_probe_interval",
- .data = &ipv6_devconf.rtr_probe_interval,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_jiffies,
+ .procname = "router_probe_interval",
+ .data = &ipv6_devconf.rtr_probe_interval,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec_jiffies,
},
#ifdef CONFIG_IPV6_ROUTE_INFO
{
- .procname = "accept_ra_rt_info_max_plen",
- .data = &ipv6_devconf.accept_ra_rt_info_max_plen,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "accept_ra_rt_info_max_plen",
+ .data = &ipv6_devconf.accept_ra_rt_info_max_plen,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
#endif
#endif
{
- .procname = "proxy_ndp",
- .data = &ipv6_devconf.proxy_ndp,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "proxy_ndp",
+ .data = &ipv6_devconf.proxy_ndp,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
{
- .procname = "accept_source_route",
- .data = &ipv6_devconf.accept_source_route,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "accept_source_route",
+ .data = &ipv6_devconf.accept_source_route,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
{
- .procname = "optimistic_dad",
- .data = &ipv6_devconf.optimistic_dad,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "optimistic_dad",
+ .data = &ipv6_devconf.optimistic_dad,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
#endif
#ifdef CONFIG_IPV6_MROUTE
{
- .procname = "mc_forwarding",
- .data = &ipv6_devconf.mc_forwarding,
- .maxlen = sizeof(int),
- .mode = 0444,
- .proc_handler = proc_dointvec,
+ .procname = "mc_forwarding",
+ .data = &ipv6_devconf.mc_forwarding,
+ .maxlen = sizeof(int),
+ .mode = 0444,
+ .proc_handler = proc_dointvec,
},
#endif
{
- .procname = "disable_ipv6",
- .data = &ipv6_devconf.disable_ipv6,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = addrconf_sysctl_disable,
+ .procname = "disable_ipv6",
+ .data = &ipv6_devconf.disable_ipv6,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = addrconf_sysctl_disable,
},
{
- .procname = "accept_dad",
- .data = &ipv6_devconf.accept_dad,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "accept_dad",
+ .data = &ipv6_devconf.accept_dad,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
{
.procname = "force_tllao",
@@ -4380,7 +4387,7 @@ static int __addrconf_sysctl_register(st
goto out;
for (i = 0; t->addrconf_vars[i].data; i++) {
- t->addrconf_vars[i].data += (char*)p - (char*)&ipv6_devconf;
+ t->addrconf_vars[i].data += (char *)p - (char *)&ipv6_devconf;
t->addrconf_vars[i].extra1 = idev; /* embedded; no ref */
t->addrconf_vars[i].extra2 = net;
}
@@ -4517,14 +4524,12 @@ int register_inet6addr_notifier(struct n
{
return atomic_notifier_chain_register(&inet6addr_chain, nb);
}
-
EXPORT_SYMBOL(register_inet6addr_notifier);
int unregister_inet6addr_notifier(struct notifier_block *nb)
{
- return atomic_notifier_chain_unregister(&inet6addr_chain,nb);
+ return atomic_notifier_chain_unregister(&inet6addr_chain, nb);
}
-
EXPORT_SYMBOL(unregister_inet6addr_notifier);
/*
@@ -4535,9 +4540,10 @@ int __init addrconf_init(void)
{
int i, err;
- if ((err = ipv6_addr_label_init()) < 0) {
- printk(KERN_CRIT "IPv6 Addrconf: cannot initialize default policy table: %d.\n",
- err);
+ err = ipv6_addr_label_init();
+ if (err < 0) {
+ printk(KERN_CRIT "IPv6 Addrconf:"
+ " cannot initialize default policy table: %d.\n", err);
return err;
}
--
^ permalink raw reply
* [PATCH 09/12] IPv6: addrconf cleanups
From: Stephen Hemminger @ 2010-03-02 23:32 UTC (permalink / raw)
To: David S. Miller, Hideaki YOSHIFUJI; +Cc: netdev
In-Reply-To: <20100302233243.259794027@vyatta.com>
[-- Attachment #1: addrconf-ifdown-comment.patch --]
[-- Type: text/plain, Size: 6076 bytes --]
Some minor stuff:
* Use bool where appropriate
* Reformat comments and add whitespace for clarity
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
---
net/ipv6/addrconf.c | 57 ++++++++++++++++++++++++++++------------------------
1 file changed, 31 insertions(+), 26 deletions(-)
--- a/net/ipv6/addrconf.c 2010-03-02 14:46:33.868952041 -0800
+++ b/net/ipv6/addrconf.c 2010-03-02 14:46:37.933576182 -0800
@@ -139,7 +139,7 @@ static void addrconf_leave_anycast(struc
static void addrconf_bonding_change(struct net_device *dev,
unsigned long event);
-static int addrconf_ifdown(struct net_device *dev, int how);
+static int addrconf_ifdown(struct net_device *dev, bool how);
static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags);
static void addrconf_dad_timer(unsigned long data);
@@ -2171,7 +2171,7 @@ static int inet6_addr_del(struct net *ne
disable IPv6 on this interface.
*/
if (list_empty(&idev->addr_list))
- addrconf_ifdown(idev->dev, 1);
+ addrconf_ifdown(idev->dev, true);
return 0;
}
}
@@ -2454,6 +2454,7 @@ static int addrconf_notify(struct notifi
return notifier_from_errno(-ENOMEM);
}
break;
+
case NETDEV_UP:
case NETDEV_CHANGE:
if (dev->flags & IFF_SLAVE)
@@ -2483,10 +2484,9 @@ static int addrconf_notify(struct notifi
}
if (idev) {
- if (idev->if_flags & IF_READY) {
+ if (idev->if_flags & IF_READY)
/* device is already configured. */
break;
- }
idev->if_flags |= IF_READY;
}
@@ -2515,25 +2515,30 @@ static int addrconf_notify(struct notifi
addrconf_dev_config(dev);
break;
}
+
if (idev) {
if (run_pending)
addrconf_dad_run(idev);
- /* If the MTU changed during the interface down, when the
- interface up, the changed MTU must be reflected in the
- idev as well as routers.
+ /*
+ * If the MTU changed during the interface down,
+ * when the interface up, the changed MTU must be
+ * reflected in the idev as well as routers.
*/
- if (idev->cnf.mtu6 != dev->mtu && dev->mtu >= IPV6_MIN_MTU) {
+ if (idev->cnf.mtu6 != dev->mtu &&
+ dev->mtu >= IPV6_MIN_MTU) {
rt6_mtu_change(dev, dev->mtu);
idev->cnf.mtu6 = dev->mtu;
}
idev->tstamp = jiffies;
inet6_ifinfo_notify(RTM_NEWLINK, idev);
- /* If the changed mtu during down is lower than IPV6_MIN_MTU
- stop IPv6 on this interface.
+
+ /*
+ * If the changed mtu during down is lower than
+ * IPV6_MIN_MTU stop IPv6 on this interface.
*/
if (dev->mtu < IPV6_MIN_MTU)
- addrconf_ifdown(dev, event != NETDEV_DOWN);
+ addrconf_ifdown(dev, true);
}
break;
@@ -2550,7 +2555,10 @@ static int addrconf_notify(struct notifi
break;
}
- /* MTU falled under IPV6_MIN_MTU. Stop IPv6 on this interface. */
+ /*
+ * MTU falled under IPV6_MIN_MTU.
+ * Stop IPv6 on this interface.
+ */
case NETDEV_DOWN:
case NETDEV_UNREGISTER:
@@ -2570,6 +2578,7 @@ static int addrconf_notify(struct notifi
return notifier_from_errno(err);
}
break;
+
case NETDEV_BONDING_OLDTYPE:
case NETDEV_BONDING_NEWTYPE:
addrconf_bonding_change(dev, event);
@@ -2584,7 +2593,6 @@ static int addrconf_notify(struct notifi
*/
static struct notifier_block ipv6_dev_notf = {
.notifier_call = addrconf_notify,
- .priority = 0
};
static void addrconf_bonding_change(struct net_device *dev, unsigned long event)
@@ -2600,7 +2608,7 @@ static void addrconf_bonding_change(stru
ipv6_mc_unmap(idev);
}
-static int addrconf_ifdown(struct net_device *dev, int how)
+static int addrconf_ifdown(struct net_device *dev, bool how)
{
struct inet6_dev *idev;
struct inet6_ifaddr *ifa;
@@ -2616,8 +2624,9 @@ static int addrconf_ifdown(struct net_de
if (idev == NULL)
return -ENODEV;
- /* Step 1: remove reference to ipv6 device from parent device.
- Do not dev_put!
+ /*
+ * Step 1: remove reference to ipv6 device from parent device.
+ * Do not dev_put!
*/
if (how) {
idev->dead = 1;
@@ -2632,16 +2641,15 @@ static int addrconf_ifdown(struct net_de
write_lock_bh(&idev->lock);
- /* Step 3: clear flags for stateless addrconf */
+ /* Step 2: clear flags for stateless addrconf */
if (!how)
idev->if_flags &= ~(IF_RS_SENT|IF_RA_RCVD|IF_READY);
- /* Step 4: clear address list */
#ifdef CONFIG_IPV6_PRIVACY
if (how && del_timer(&idev->regen_timer))
in6_dev_put(idev);
- /* clear tempaddr list */
+ /* Step 3: clear tempaddr list */
while (!list_empty(&idev->tempaddr_list)) {
ifa = list_first_entry(&idev->tempaddr_list,
struct inet6_ifaddr, tmp_list);
@@ -2667,7 +2675,7 @@ static int addrconf_ifdown(struct net_de
/* If just doing link down, and address is permanent
and not link-local, then retain it. */
- if (how == 0 &&
+ if (!how &&
(ifa->flags&IFA_F_PERMANENT) &&
!(ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL)) {
list_move_tail(&ifa->if_list, &keep_list);
@@ -2709,7 +2717,6 @@ static int addrconf_ifdown(struct net_de
write_unlock_bh(&idev->lock);
/* Step 5: Discard multicast list */
-
if (how)
ipv6_mc_destroy_dev(idev);
else
@@ -2717,8 +2724,7 @@ static int addrconf_ifdown(struct net_de
idev->tstamp = jiffies;
- /* Shot the device (if unregistered) */
-
+ /* Last: Shot the device (if unregistered) */
if (how) {
addrconf_sysctl_unregister(idev);
neigh_parms_release(&nd_tbl, idev->nd_parms);
@@ -3106,8 +3112,7 @@ static void addrconf_verify(unsigned lon
del_timer(&addr_chk_timer);
- for (i=0; i < IN6_ADDR_HSIZE; i++) {
-
+ for (i = 0; i < IN6_ADDR_HSIZE; i++) {
restart:
hlist_for_each_entry_rcu(ifp, node,
&inet6_addr_lst[i], addr_lst) {
@@ -4374,7 +4379,7 @@ static int __addrconf_sysctl_register(st
if (t == NULL)
goto out;
- for (i=0; t->addrconf_vars[i].data; i++) {
+ for (i = 0; t->addrconf_vars[i].data; i++) {
t->addrconf_vars[i].data += (char*)p - (char*)&ipv6_devconf;
t->addrconf_vars[i].extra1 = idev; /* embedded; no ref */
t->addrconf_vars[i].extra2 = net;
--
^ permalink raw reply
* [PATCH 08/12] ipv6: convert idev_list to list macros
From: Stephen Hemminger @ 2010-03-02 23:32 UTC (permalink / raw)
To: David S. Miller, Hideaki YOSHIFUJI; +Cc: netdev
In-Reply-To: <20100302233243.259794027@vyatta.com>
[-- Attachment #1: ipv6-idev-list.patch --]
[-- Type: text/plain, Size: 10491 bytes --]
Convert to list macro's for the list of addresses per interface
in IPv6.
This also solves a potential race problem during the cleanup process.
The issue is that addrconf_ifdown() needs to traverse address list,
but then drop lock to call the notifier. The version in -next
could get confused if add/delete happened during this window.
Original code (2.6.32 and earlier) was okay because all addresses
were always deleted.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
---
drivers/net/bonding/bond_ipv6.c | 9 ++--
include/net/if_inet6.h | 6 +--
net/ipv6/addrconf.c | 74 ++++++++++++++++++++++------------------
net/sctp/ipv6.c | 2 -
4 files changed, 50 insertions(+), 41 deletions(-)
--- a/drivers/net/bonding/bond_ipv6.c 2010-03-02 14:29:25.436951570 -0800
+++ b/drivers/net/bonding/bond_ipv6.c 2010-03-02 14:46:33.864952850 -0800
@@ -37,7 +37,6 @@
static void bond_glean_dev_ipv6(struct net_device *dev, struct in6_addr *addr)
{
struct inet6_dev *idev;
- struct inet6_ifaddr *ifa;
if (!dev)
return;
@@ -47,10 +46,12 @@ static void bond_glean_dev_ipv6(struct n
return;
read_lock_bh(&idev->lock);
- ifa = idev->addr_list;
- if (ifa)
+ if (!list_empty(&idev->addr_list)) {
+ struct inet6_ifaddr *ifa
+ = list_first_entry(&idev->addr_list,
+ struct inet6_ifaddr, if_list);
ipv6_addr_copy(addr, &ifa->addr);
- else
+ } else
ipv6_addr_set(addr, 0, 0, 0, 0);
read_unlock_bh(&idev->lock);
--- a/include/net/if_inet6.h 2010-03-02 14:38:15.169701060 -0800
+++ b/include/net/if_inet6.h 2010-03-02 14:46:33.864952850 -0800
@@ -55,7 +55,7 @@ struct inet6_ifaddr {
struct rt6_info *rt;
struct hlist_node addr_lst;
- struct inet6_ifaddr *if_next; /* next addr in inet6_dev */
+ struct list_head if_list;
#ifdef CONFIG_IPV6_PRIVACY
struct list_head tmp_list;
@@ -152,9 +152,9 @@ struct ipv6_devstat {
};
struct inet6_dev {
- struct net_device *dev;
+ struct net_device *dev;
- struct inet6_ifaddr *addr_list;
+ struct list_head addr_list;
struct ifmcaddr6 *mc_list;
struct ifmcaddr6 *mc_tomb;
--- a/net/ipv6/addrconf.c 2010-03-02 14:34:41.516826671 -0800
+++ b/net/ipv6/addrconf.c 2010-03-02 14:46:33.868952041 -0800
@@ -317,7 +317,7 @@ void in6_dev_finish_destroy(struct inet6
{
struct net_device *dev = idev->dev;
- WARN_ON(idev->addr_list != NULL);
+ WARN_ON(!list_empty(&idev->addr_list));
WARN_ON(idev->mc_list != NULL);
#ifdef NET_REFCNT_DEBUG
@@ -350,6 +350,8 @@ static struct inet6_dev * ipv6_add_dev(s
rwlock_init(&ndev->lock);
ndev->dev = dev;
+ INIT_LIST_HEAD(&ndev->addr_list);
+
memcpy(&ndev->cnf, dev_net(dev)->ipv6.devconf_dflt, sizeof(ndev->cnf));
ndev->cnf.mtu6 = dev->mtu;
ndev->cnf.sysctl = NULL;
@@ -466,7 +468,8 @@ static void dev_forward_change(struct in
else
ipv6_dev_mc_dec(dev, &in6addr_linklocal_allrouters);
}
- for (ifa=idev->addr_list; ifa; ifa=ifa->if_next) {
+
+ list_for_each_entry(ifa, &idev->addr_list, if_list) {
if (ifa->flags&IFA_F_TENTATIVE)
continue;
if (idev->cnf.forwarding)
@@ -532,7 +535,6 @@ static void inet6_ifa_finish_destroy_rcu
/* Nobody refers to this ifaddr, destroy it */
void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp)
{
- WARN_ON(ifp->if_next != NULL);
WARN_ON(!hlist_unhashed(&ifp->addr_lst));
#ifdef NET_REFCNT_DEBUG
@@ -556,21 +558,21 @@ void inet6_ifa_finish_destroy(struct ine
static void
ipv6_link_dev_addr(struct inet6_dev *idev, struct inet6_ifaddr *ifp)
{
- struct inet6_ifaddr *ifa, **ifap;
+ struct list_head *p;
int ifp_scope = ipv6_addr_src_scope(&ifp->addr);
/*
* Each device address list is sorted in order of scope -
* global before linklocal.
*/
- for (ifap = &idev->addr_list; (ifa = *ifap) != NULL;
- ifap = &ifa->if_next) {
+ list_for_each(p, &idev->addr_list) {
+ struct inet6_ifaddr *ifa
+ = list_entry(p, struct inet6_ifaddr, if_list);
if (ifp_scope >= ipv6_addr_src_scope(&ifa->addr))
break;
}
- ifp->if_next = *ifap;
- *ifap = ifp;
+ list_add(&ifp->if_list, p);
}
static u32 ipv6_addr_hash(const struct in6_addr *addr)
@@ -703,7 +705,7 @@ out:
static void ipv6_del_addr(struct inet6_ifaddr *ifp)
{
- struct inet6_ifaddr *ifa, **ifap;
+ struct inet6_ifaddr *ifa, *ifn;
struct inet6_dev *idev = ifp->idev;
int hash;
int deleted = 0, onlink = 0;
@@ -730,11 +732,11 @@ static void ipv6_del_addr(struct inet6_i
}
#endif
- for (ifap = &idev->addr_list; (ifa=*ifap) != NULL;) {
+ list_for_each_entry_safe(ifa, ifn, &idev->addr_list, if_list) {
if (ifa == ifp) {
- *ifap = ifa->if_next;
+ list_del_init(&ifp->if_list);
__in6_ifa_put(ifp);
- ifa->if_next = NULL;
+
if (!(ifp->flags & IFA_F_PERMANENT) || onlink > 0)
break;
deleted = 1;
@@ -767,7 +769,6 @@ static void ipv6_del_addr(struct inet6_i
}
}
}
- ifap = &ifa->if_next;
}
write_unlock_bh(&idev->lock);
@@ -1146,7 +1147,7 @@ int ipv6_dev_get_saddr(struct net *net,
continue;
read_lock_bh(&idev->lock);
- for (score->ifa = idev->addr_list; score->ifa; score->ifa = score->ifa->if_next) {
+ list_for_each_entry(score->ifa, &idev->addr_list, if_list) {
int i;
/*
@@ -1238,8 +1239,9 @@ int ipv6_get_lladdr(struct net_device *d
struct inet6_ifaddr *ifp;
read_lock_bh(&idev->lock);
- for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) {
- if (ifp->scope == IFA_LINK && !(ifp->flags & banned_flags)) {
+ list_for_each_entry(ifp, &idev->addr_list, if_list) {
+ if (ifp->scope == IFA_LINK &&
+ !(ifp->flags & banned_flags)) {
ipv6_addr_copy(addr, &ifp->addr);
err = 0;
break;
@@ -1257,7 +1259,7 @@ static int ipv6_count_addresses(struct i
struct inet6_ifaddr *ifp;
read_lock_bh(&idev->lock);
- for (ifp=idev->addr_list; ifp; ifp=ifp->if_next)
+ list_for_each_entry(ifp, &idev->addr_list, if_list)
cnt++;
read_unlock_bh(&idev->lock);
return cnt;
@@ -1317,7 +1319,7 @@ int ipv6_chk_prefix(struct in6_addr *add
idev = __in6_dev_get(dev);
if (idev) {
read_lock_bh(&idev->lock);
- for (ifa = idev->addr_list; ifa; ifa = ifa->if_next) {
+ list_for_each_entry(ifa, &idev->addr_list, if_list) {
onlink = ipv6_prefix_equal(addr, &ifa->addr,
ifa->prefix_len);
if (onlink)
@@ -1553,7 +1555,7 @@ static int ipv6_inherit_eui64(u8 *eui, s
struct inet6_ifaddr *ifp;
read_lock_bh(&idev->lock);
- for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) {
+ list_for_each_entry(ifp, &idev->addr_list, if_list) {
if (ifp->scope == IFA_LINK && !(ifp->flags&IFA_F_TENTATIVE)) {
memcpy(eui, ifp->addr.s6_addr+8, 8);
err = 0;
@@ -2157,7 +2159,7 @@ static int inet6_addr_del(struct net *ne
return -ENXIO;
read_lock_bh(&idev->lock);
- for (ifp = idev->addr_list; ifp; ifp=ifp->if_next) {
+ list_for_each_entry(ifp, &idev->addr_list, if_list) {
if (ifp->prefix_len == plen &&
ipv6_addr_equal(pfx, &ifp->addr)) {
in6_ifa_hold(ifp);
@@ -2168,7 +2170,7 @@ static int inet6_addr_del(struct net *ne
/* If the last address is deleted administratively,
disable IPv6 on this interface.
*/
- if (idev->addr_list == NULL)
+ if (list_empty(&idev->addr_list))
addrconf_ifdown(idev->dev, 1);
return 0;
}
@@ -2601,8 +2603,9 @@ static void addrconf_bonding_change(stru
static int addrconf_ifdown(struct net_device *dev, int how)
{
struct inet6_dev *idev;
- struct inet6_ifaddr *ifa, **bifa;
+ struct inet6_ifaddr *ifa;
struct net *net = dev_net(dev);
+ LIST_HEAD(keep_list);
ASSERT_RTNL();
@@ -2656,8 +2659,10 @@ static int addrconf_ifdown(struct net_de
write_lock_bh(&idev->lock);
}
#endif
- bifa = &idev->addr_list;
- while ((ifa = *bifa) != NULL) {
+ while (!list_empty(&idev->addr_list)) {
+ ifa = list_first_entry(&idev->addr_list,
+ struct inet6_ifaddr, if_list);
+
addrconf_del_timer(ifa);
/* If just doing link down, and address is permanent
@@ -2665,7 +2670,7 @@ static int addrconf_ifdown(struct net_de
if (how == 0 &&
(ifa->flags&IFA_F_PERMANENT) &&
!(ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL)) {
- bifa = &ifa->if_next;
+ list_move_tail(&ifa->if_list, &keep_list);
/* If not doing DAD on this address, just keep it. */
if ((dev->flags&(IFF_NOARP|IFF_LOOPBACK)) ||
@@ -2681,8 +2686,7 @@ static int addrconf_ifdown(struct net_de
ifa->flags |= IFA_F_TENTATIVE;
in6_ifa_hold(ifa);
} else {
- *bifa = ifa->if_next;
- ifa->if_next = NULL;
+ list_del(&ifa->if_list);
ifa->dead = 1;
}
write_unlock_bh(&idev->lock);
@@ -2699,6 +2703,9 @@ static int addrconf_ifdown(struct net_de
write_lock_bh(&idev->lock);
}
+
+ list_splice(&keep_list, &idev->addr_list);
+
write_unlock_bh(&idev->lock);
/* Step 5: Discard multicast list */
@@ -2907,7 +2914,7 @@ static void addrconf_dad_run(struct inet
struct inet6_ifaddr *ifp;
read_lock_bh(&idev->lock);
- for (ifp = idev->addr_list; ifp; ifp = ifp->if_next) {
+ list_for_each_entry(ifp, &idev->addr_list, if_list) {
spin_lock(&ifp->lock);
if (!(ifp->flags & IFA_F_TENTATIVE)) {
spin_unlock(&ifp->lock);
@@ -3490,7 +3497,6 @@ static int in6_dump_addrs(struct inet6_d
struct netlink_callback *cb, enum addr_type_t type,
int s_ip_idx, int *p_ip_idx)
{
- struct inet6_ifaddr *ifa;
struct ifmcaddr6 *ifmca;
struct ifacaddr6 *ifaca;
int err = 1;
@@ -3498,11 +3504,12 @@ static int in6_dump_addrs(struct inet6_d
read_lock_bh(&idev->lock);
switch (type) {
- case UNICAST_ADDR:
+ case UNICAST_ADDR: {
+ struct inet6_ifaddr *ifa;
+
/* unicast address incl. temp addr */
- for (ifa = idev->addr_list; ifa;
- ifa = ifa->if_next, ip_idx++) {
- if (ip_idx < s_ip_idx)
+ list_for_each_entry(ifa, &idev->addr_list, if_list) {
+ if (++ip_idx < s_ip_idx)
continue;
err = inet6_fill_ifaddr(skb, ifa,
NETLINK_CB(cb->skb).pid,
@@ -3513,6 +3520,7 @@ static int in6_dump_addrs(struct inet6_d
break;
}
break;
+ }
case MULTICAST_ADDR:
/* multicast address */
for (ifmca = idev->mc_list; ifmca;
--- a/net/sctp/ipv6.c 2010-03-02 14:29:25.452951406 -0800
+++ b/net/sctp/ipv6.c 2010-03-02 14:46:33.868952041 -0800
@@ -371,7 +371,7 @@ static void sctp_v6_copy_addrlist(struct
}
read_lock_bh(&in6_dev->lock);
- for (ifp = in6_dev->addr_list; ifp; ifp = ifp->if_next) {
+ list_for_each_entry(ifp, &in6_dev->addr_list, if_list) {
/* Add the address to the local list. */
addr = t_new(struct sctp_sockaddr_entry, GFP_ATOMIC);
if (addr) {
--
^ permalink raw reply
* [PATCH 07/12] ipv6: user better hash for addrconf
From: Stephen Hemminger @ 2010-03-02 23:32 UTC (permalink / raw)
To: David S. Miller, Hideaki YOSHIFUJI; +Cc: netdev
In-Reply-To: <20100302233243.259794027@vyatta.com>
[-- Attachment #1: ipv6-hash-addrconf.patch --]
[-- Type: text/plain, Size: 2752 bytes --]
The existing hash function has a couple of issues:
* it is hardwired to 16 for IN6_ADDR_HSIZE
* limited to 256 and callers using int
* use jhash2 rather than some old BSD algorithm
No need for random seed since this is local only (based on assigned
addresses) table.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
---
net/ipv6/addrconf.c | 26 +++++++++-----------------
1 file changed, 9 insertions(+), 17 deletions(-)
--- a/net/ipv6/addrconf.c 2010-03-02 14:33:59.033450885 -0800
+++ b/net/ipv6/addrconf.c 2010-03-02 14:34:41.516826671 -0800
@@ -573,23 +573,14 @@ ipv6_link_dev_addr(struct inet6_dev *ide
*ifap = ifp;
}
-/*
- * Hash function taken from net_alias.c
- */
-static u8 ipv6_addr_hash(const struct in6_addr *addr)
+static u32 ipv6_addr_hash(const struct in6_addr *addr)
{
- __u32 word;
-
/*
* We perform the hash function over the last 64 bits of the address
* This will include the IEEE address token on links that support it.
*/
-
- word = (__force u32)(addr->s6_addr32[2] ^ addr->s6_addr32[3]);
- word ^= (word >> 16);
- word ^= (word >> 8);
-
- return ((word ^ (word >> 4)) & 0x0f);
+ return jhash_2words(addr->s6_addr32[2], addr->s6_addr32[3], 0)
+ & (IN6_ADDR_HSIZE - 1);
}
/* On success it returns ifp with increased reference count */
@@ -600,7 +591,7 @@ ipv6_add_addr(struct inet6_dev *idev, co
{
struct inet6_ifaddr *ifa = NULL;
struct rt6_info *rt;
- int hash;
+ unsigned int hash;
int err = 0;
int addr_type = ipv6_addr_type(addr);
@@ -1277,7 +1268,7 @@ int ipv6_chk_addr(struct net *net, struc
{
struct inet6_ifaddr *ifp = NULL;
struct hlist_node *node;
- u8 hash = ipv6_addr_hash(addr);
+ unsigned int hash = ipv6_addr_hash(addr);
rcu_read_lock_bh();
hlist_for_each_entry_rcu(ifp, node, &inet6_addr_lst[hash], addr_lst) {
@@ -1302,7 +1293,7 @@ int ipv6_chk_same_addr(struct net *net,
{
struct inet6_ifaddr *ifp;
struct hlist_node *node;
- u8 hash = ipv6_addr_hash(addr);
+ unsigned int hash = ipv6_addr_hash(addr);
hlist_for_each_entry(ifp, node, &inet6_addr_lst[hash], addr_lst) {
if (!net_eq(dev_net(ifp->idev->dev), net))
@@ -1345,7 +1336,7 @@ struct inet6_ifaddr *ipv6_get_ifaddr(str
{
struct inet6_ifaddr *ifp = NULL;
struct hlist_node *node;
- u8 hash = ipv6_addr_hash(addr);
+ unsigned int hash = ipv6_addr_hash(addr);
rcu_read_lock_bh();
hlist_for_each_entry_rcu(ifp, node, &inet6_addr_lst[hash], addr_lst) {
@@ -3073,7 +3064,7 @@ int ipv6_chk_home_addr(struct net *net,
int ret = 0;
struct inet6_ifaddr *ifp = NULL;
struct hlist_node *n;
- u8 hash = ipv6_addr_hash(addr);
+ unsigned int hash = ipv6_addr_hash(addr);
rcu_read_lock_bh();
hlist_for_each_entry_rcu(ifp, n, &inet6_addr_lst[hash], addr_lst) {
--
^ permalink raw reply
* [PATCH 06/12] IPv6: convert addrconf hash list to RCU
From: Stephen Hemminger @ 2010-03-02 23:32 UTC (permalink / raw)
To: David S. Miller, Hideaki YOSHIFUJI; +Cc: netdev
In-Reply-To: <20100302233243.259794027@vyatta.com>
[-- Attachment #1: ipv6-addrconf-rcu.patch --]
[-- Type: text/plain, Size: 9668 bytes --]
Convert from reader/writer lock to RCU and spinlock for addrconf
hash list.
Adds an additional helper macro for hlist_for_each_entry_continue_rcu
to handle the continue case.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
---
include/linux/rculist.h | 13 +++++++
include/net/if_inet6.h | 1
net/ipv6/addrconf.c | 80 +++++++++++++++++++++++++-----------------------
3 files changed, 57 insertions(+), 37 deletions(-)
--- a/net/ipv6/addrconf.c 2010-03-02 14:29:25.444951749 -0800
+++ b/net/ipv6/addrconf.c 2010-03-02 14:33:59.033450885 -0800
@@ -127,7 +127,7 @@ static int ipv6_count_addresses(struct i
* Configured unicast address hash table
*/
static struct hlist_head inet6_addr_lst[IN6_ADDR_HSIZE];
-static DEFINE_RWLOCK(addrconf_hash_lock);
+static DEFINE_SPINLOCK(addrconf_hash_lock);
static void addrconf_verify(unsigned long);
@@ -523,8 +523,13 @@ static int addrconf_fixup_forwarding(str
}
#endif
-/* Nobody refers to this ifaddr, destroy it */
+static void inet6_ifa_finish_destroy_rcu(struct rcu_head *head)
+{
+ struct inet6_ifaddr *ifp = container_of(head, struct inet6_ifaddr, rcu);
+ kfree(ifp);
+}
+/* Nobody refers to this ifaddr, destroy it */
void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp)
{
WARN_ON(ifp->if_next != NULL);
@@ -545,7 +550,7 @@ void inet6_ifa_finish_destroy(struct ine
}
dst_release(&ifp->rt->u.dst);
- kfree(ifp);
+ call_rcu(&ifp->rcu, inet6_ifa_finish_destroy_rcu);
}
static void
@@ -616,7 +621,7 @@ ipv6_add_addr(struct inet6_dev *idev, co
goto out2;
}
- write_lock(&addrconf_hash_lock);
+ spin_lock(&addrconf_hash_lock);
/* Ignore adding duplicate addresses on an interface */
if (ipv6_chk_same_addr(dev_net(idev->dev), addr, idev->dev)) {
@@ -670,9 +675,9 @@ ipv6_add_addr(struct inet6_dev *idev, co
/* Add to big hash table */
hash = ipv6_addr_hash(addr);
- hlist_add_head(&ifa->addr_lst, &inet6_addr_lst[hash]);
+ hlist_add_head_rcu(&ifa->addr_lst, &inet6_addr_lst[hash]);
in6_ifa_hold(ifa);
- write_unlock(&addrconf_hash_lock);
+ spin_unlock(&addrconf_hash_lock);
write_lock(&idev->lock);
/* Add to inet6_dev unicast addr list. */
@@ -699,7 +704,7 @@ out2:
return ifa;
out:
- write_unlock(&addrconf_hash_lock);
+ spin_unlock(&addrconf_hash_lock);
goto out2;
}
@@ -717,10 +722,10 @@ static void ipv6_del_addr(struct inet6_i
ifp->dead = 1;
- write_lock_bh(&addrconf_hash_lock);
- hlist_del_init(&ifp->addr_lst);
+ spin_lock_bh(&addrconf_hash_lock);
+ hlist_del_init_rcu(&ifp->addr_lst);
__in6_ifa_put(ifp);
- write_unlock_bh(&addrconf_hash_lock);
+ spin_unlock_bh(&addrconf_hash_lock);
write_lock_bh(&idev->lock);
#ifdef CONFIG_IPV6_PRIVACY
@@ -1274,8 +1279,8 @@ int ipv6_chk_addr(struct net *net, struc
struct hlist_node *node;
u8 hash = ipv6_addr_hash(addr);
- read_lock_bh(&addrconf_hash_lock);
- hlist_for_each_entry(ifp, node, &inet6_addr_lst[hash], addr_lst) {
+ rcu_read_lock_bh();
+ hlist_for_each_entry_rcu(ifp, node, &inet6_addr_lst[hash], addr_lst) {
if (!net_eq(dev_net(ifp->idev->dev), net))
continue;
if (ipv6_addr_equal(&ifp->addr, addr) &&
@@ -1285,7 +1290,8 @@ int ipv6_chk_addr(struct net *net, struc
break;
}
}
- read_unlock_bh(&addrconf_hash_lock);
+ rcu_read_unlock_bh();
+
return ifp != NULL;
}
EXPORT_SYMBOL(ipv6_chk_addr);
@@ -1341,8 +1347,8 @@ struct inet6_ifaddr *ipv6_get_ifaddr(str
struct hlist_node *node;
u8 hash = ipv6_addr_hash(addr);
- read_lock_bh(&addrconf_hash_lock);
- hlist_for_each_entry(ifp, node, &inet6_addr_lst[hash], addr_lst) {
+ rcu_read_lock_bh();
+ hlist_for_each_entry_rcu(ifp, node, &inet6_addr_lst[hash], addr_lst) {
if (!net_eq(dev_net(ifp->idev->dev), net))
continue;
if (ipv6_addr_equal(&ifp->addr, addr)) {
@@ -1353,7 +1359,7 @@ struct inet6_ifaddr *ipv6_get_ifaddr(str
}
}
}
- read_unlock_bh(&addrconf_hash_lock);
+ rcu_read_unlock_bh();
return ifp;
}
@@ -2691,10 +2697,10 @@ static int addrconf_ifdown(struct net_de
write_unlock_bh(&idev->lock);
/* clear hash table */
- write_lock_bh(&addrconf_hash_lock);
- hlist_del_init(&ifa->addr_lst);
+ spin_lock_bh(&addrconf_hash_lock);
+ hlist_del_init_rcu(&ifa->addr_lst);
__in6_ifa_put(ifa);
- write_unlock_bh(&addrconf_hash_lock);
+ spin_unlock_bh(&addrconf_hash_lock);
__ipv6_ifa_notify(RTM_DELADDR, ifa);
atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa);
@@ -2936,11 +2942,10 @@ static struct inet6_ifaddr *if6_get_firs
for (state->bucket = 0; state->bucket < IN6_ADDR_HSIZE; ++state->bucket) {
struct hlist_node *n;
- hlist_for_each_entry(ifa, n,
- &inet6_addr_lst[state->bucket], addr_lst) {
+ hlist_for_each_entry_rcu(ifa, n, &inet6_addr_lst[state->bucket],
+ addr_lst)
if (net_eq(dev_net(ifa->idev->dev), net))
return ifa;
- }
}
return NULL;
}
@@ -2952,10 +2957,9 @@ static struct inet6_ifaddr *if6_get_next
struct net *net = seq_file_net(seq);
struct hlist_node *n = &ifa->addr_lst;
- hlist_for_each_entry_continue(ifa, n, addr_lst) {
+ hlist_for_each_entry_continue_rcu(ifa, n, addr_lst)
if (net_eq(dev_net(ifa->idev->dev), net))
return ifa;
- }
while (++state->bucket < IN6_ADDR_HSIZE) {
hlist_for_each_entry(ifa, n,
@@ -2979,9 +2983,9 @@ static struct inet6_ifaddr *if6_get_idx(
}
static void *if6_seq_start(struct seq_file *seq, loff_t *pos)
- __acquires(addrconf_hash_lock)
+ __acquires(rcu)
{
- read_lock_bh(&addrconf_hash_lock);
+ rcu_read_lock_bh();
return if6_get_idx(seq, *pos);
}
@@ -2995,9 +2999,9 @@ static void *if6_seq_next(struct seq_fil
}
static void if6_seq_stop(struct seq_file *seq, void *v)
- __releases(addrconf_hash_lock)
+ __releases(rcu)
{
- read_unlock_bh(&addrconf_hash_lock);
+ rcu_read_unlock_bh();
}
static int if6_seq_show(struct seq_file *seq, void *v)
@@ -3071,8 +3075,8 @@ int ipv6_chk_home_addr(struct net *net,
struct hlist_node *n;
u8 hash = ipv6_addr_hash(addr);
- read_lock_bh(&addrconf_hash_lock);
- hlist_for_each_entry(ifp, n, &inet6_addr_lst[hash], addr_lst) {
+ rcu_read_lock_bh();
+ hlist_for_each_entry_rcu(ifp, n, &inet6_addr_lst[hash], addr_lst) {
if (!net_eq(dev_net(ifp->idev->dev), net))
continue;
if (ipv6_addr_equal(&ifp->addr, addr) &&
@@ -3081,7 +3085,7 @@ int ipv6_chk_home_addr(struct net *net,
break;
}
}
- read_unlock_bh(&addrconf_hash_lock);
+ rcu_read_unlock_bh();
return ret;
}
#endif
@@ -3097,7 +3101,8 @@ static void addrconf_verify(unsigned lon
unsigned long now, next;
int i;
- spin_lock_bh(&addrconf_verify_lock);
+ rcu_read_lock_bh();
+ spin_lock(&addrconf_verify_lock);
now = jiffies;
next = now + ADDR_CHECK_FREQUENCY;
@@ -3106,8 +3111,8 @@ static void addrconf_verify(unsigned lon
for (i=0; i < IN6_ADDR_HSIZE; i++) {
restart:
- read_lock(&addrconf_hash_lock);
- hlist_for_each_entry(ifp, node, &inet6_addr_lst[i], addr_lst) {
+ hlist_for_each_entry_rcu(ifp, node,
+ &inet6_addr_lst[i], addr_lst) {
unsigned long age;
#ifdef CONFIG_IPV6_PRIVACY
unsigned long regen_advance;
@@ -3129,7 +3134,6 @@ restart:
age >= ifp->valid_lft) {
spin_unlock(&ifp->lock);
in6_ifa_hold(ifp);
- read_unlock(&addrconf_hash_lock);
ipv6_del_addr(ifp);
goto restart;
} else if (ifp->prefered_lft == INFINITY_LIFE_TIME) {
@@ -3151,7 +3155,6 @@ restart:
if (deprecate) {
in6_ifa_hold(ifp);
- read_unlock(&addrconf_hash_lock);
ipv6_ifa_notify(0, ifp);
in6_ifa_put(ifp);
@@ -3169,7 +3172,7 @@ restart:
in6_ifa_hold(ifp);
in6_ifa_hold(ifpub);
spin_unlock(&ifp->lock);
- read_unlock(&addrconf_hash_lock);
+
spin_lock(&ifpub->lock);
ifpub->regen_count = 0;
spin_unlock(&ifpub->lock);
@@ -3189,12 +3192,12 @@ restart:
spin_unlock(&ifp->lock);
}
}
- read_unlock(&addrconf_hash_lock);
}
addr_chk_timer.expires = time_before(next, jiffies + HZ) ? jiffies + HZ : next;
add_timer(&addr_chk_timer);
- spin_unlock_bh(&addrconf_verify_lock);
+ spin_unlock(&addrconf_verify_lock);
+ rcu_read_unlock_bh();
}
static struct in6_addr *extract_addr(struct nlattr *addr, struct nlattr *local)
@@ -4611,10 +4614,10 @@ void addrconf_cleanup(void)
/*
* Check hash table.
*/
- write_lock_bh(&addrconf_hash_lock);
+ spin_lock_bh(&addrconf_hash_lock);
for (i = 0; i < IN6_ADDR_HSIZE; i++)
WARN_ON(!hlist_empty(&inet6_addr_lst[i]));
- write_unlock_bh(&addrconf_hash_lock);
+ spin_unlock_bh(&addrconf_hash_lock);
del_timer(&addr_chk_timer);
rtnl_unlock();
--- a/include/linux/rculist.h 2010-03-01 08:22:23.456662311 -0800
+++ b/include/linux/rculist.h 2010-03-02 14:29:56.641076077 -0800
@@ -428,5 +428,18 @@ static inline void hlist_add_after_rcu(s
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; }); \
pos = rcu_dereference_raw(pos->next))
+/**
+ * hlist_for_each_entry_continue_rcu - iterate over a hlist continuing after current point
+ * @tpos: the type * to use as a loop cursor.
+ * @pos: the &struct hlist_node to use as a loop cursor.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_continue_rcu(tpos, pos, member) \
+ for (pos = rcu_dereference((pos)->next); \
+ pos && ({ prefetch(pos->next); 1; }) && \
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; }); \
+ pos = rcu_dereference(pos->next))
+
+
#endif /* __KERNEL__ */
#endif
--- a/include/net/if_inet6.h 2010-03-02 14:29:25.465077512 -0800
+++ b/include/net/if_inet6.h 2010-03-02 14:31:13.137385294 -0800
@@ -64,6 +64,7 @@ struct inet6_ifaddr {
#endif
int dead;
+ struct rcu_head rcu;
};
struct ip6_sf_socklist {
--
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox