* RE: [PATCH V2 1/2] Export firmware assigned labels of network devices to sysfs
From: Narendra_K @ 2010-06-04 20:31 UTC (permalink / raw)
To: Narendra_K, greg; +Cc: netdev, linux-hotplug, linux-pci, Matt_Domsch
In-Reply-To: <20100603210715.GA18025@auslistsprd01.us.dell.com>
With regards,
Narendra K
> -----Original Message-----
> From: netdev-owner@vger.kernel.org [mailto:netdev-
> owner@vger.kernel.org] On Behalf Of Narendra K
> Sent: Friday, June 04, 2010 2:37 AM
> To: greg@kroah.com
> Cc: netdev@vger.kernel.org; linux-hotplug@vger.kernel.org; linux-
> pci@vger.kernel.org; Domsch, Matt
> Subject: Re: [PATCH V2 1/2] Export firmware assigned labels of network
> devices to sysfs
>
> > -----Original Message-----
> > From: Greg KH [mailto:greg@kroah.com]
> > Sent: Friday, May 28, 2010 9:11 PM
> > To: K, Narendra
> > Cc: netdev@vger.kernel.org; linux-hotplug@vger.kernel.org;
> > linux-pci@vger.kernel.org; Domsch, Matt; Hargrave, Jordan; Rose,
> > Charles; Nijhawan, Vijay
> > Subject: Re: [PATCH 1/2] Export firmware assigned labels of network
> > devices to sysfs
> >
> Thanks for the comments.
>
> > On Fri, May 28, 2010 at 06:55:21AM -0500, K, Narendra wrote:
> > > Please refer to the PCI-SIG Draft ECN
> > > "PCIe Device Labeling under Operating Systems Draft ECN" at this
> link
> > -
> > > http://www.pcisig.com/specifications/pciexpress/review_zone/.
> > >
> > > It would be great to know your views on this ECN. Please let us
> know
> > if you have
> > > have any suggestions or changes.
> >
> > Note that only members of the PCI-SIG can do this, which pretty much
> > rules out any "normal" Linux kernel developer :(
> >
> > Care to post a public version of this for us to review?
> > > --- /dev/null
> > > +++ b/drivers/pci/pci-label.c
> > > @@ -0,0 +1,242 @@
> > > +/*
> > > + * File: drivers/pci/pci-label.c
> >
> > This line is not needed, we know the file name :)
> >
> > > + * Purpose: Export the firmware label associated with a pci
> > network interface
> > > + * device to sysfs
> > > + * Copyright (C) 2010 Dell Inc.
> > > + * by Narendra K <Narendra_K@dell.com>, Jordan Hargrave
> > <Jordan_Hargrave@dell.com>
> > > + *
> > > + * This code checks if the pci network device has a related ACPI
> > _DSM. If
> > > + * available, the code calls the _DSM to retrieve the index and
> > string and
> > > + * exports them to sysfs. If the ACPI _DSM is not available, it
> falls
> > back on
> > > + * SMBIOS. SMBIOS defines type 41 for onboard pci devices. This
> code
> > retrieves
> > > + * strings associated with the type 41 and exports it to sysfs.
> > > + *
> > > + * Please see
> http://linux.dell.com/wiki/index.php/Oss/libnetdevname
> > for more
> > > + * information.
> > > + */
> > > +
> > > +#include <linux/pci-label.h>
> >
> > Why is this file in include/linux/ ? Who needs it there? Can't it
> just
> > be in in the drivers/pci/ directory? Actually all you need is 2
> > functions in there, so it could go into the internal pci.h file in
> that
> > directory without a problem, right?
> >
>
> This file is removed and functions are moved to the internal pci.h
>
> > > +
> > > +static ssize_t
> > > +smbiosname_string_exists(struct device *dev, char *buf)
> > > +{
> > > + struct pci_dev *pdev = to_pci_dev(dev);
> > > + const struct dmi_device *dmi;
> > > + struct dmi_devslot *dslot;
> > > + int bus;
> > > + int devfn;
> > > +
> > > + bus = pdev->bus->number;
> > > + devfn = pdev->devfn;
> > > +
> > > + dmi = NULL;
> > > + while ((dmi = dmi_find_device(DMI_DEV_TYPE_DEVSLOT, NULL,
> > dmi)) != NULL) {
> > > + dslot = dmi->device_data;
> > > + if (dslot && dslot->bus == bus && dslot->devfn ==
> > devfn) {
> > > + if (buf)
> > > + return scnprintf(buf, PAGE_SIZE,
> > "%s\n", dmi->name);
> > > + return strlen(dmi->name);
> > > + }
> > > + }
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +static ssize_t
> > > +smbiosname_show(struct device *dev, struct device_attribute *attr,
> > char *buf)
> > > +{
> > > + return smbiosname_string_exists(dev, buf);
> > > +}
> > > +
> > > +struct smbios_attribute smbios_attr_label = {
> > > + .attr = {.name = __stringify(label), .mode = 0444, .owner =
> > THIS_MODULE},
> >
> > Can't you just put "label" as the name?
> >
>
> This is fixed.
>
> > > + .show = smbiosname_show,
> > > + .test = smbiosname_string_exists,
> > > +};
> > > +
> > > +static int
> > > +pci_create_smbiosname_file(struct pci_dev *pdev)
> > > +{
> > > + if (smbios_attr_label.test &&
> > smbios_attr_label.test(&pdev->dev, NULL)) {
> > > + sysfs_create_file(&pdev->dev.kobj,
> > &smbios_attr_label.attr);
> > > + return 0;
> > > + }
> > > + return -1;
> > > +}
> > > +
> > > +static int
> > > +pci_remove_smbiosname_file(struct pci_dev *pdev)
> > > +{
> > > + if (smbios_attr_label.test &&
> > smbios_attr_label.test(&pdev->dev, NULL)) {
> > > + sysfs_remove_file(&pdev->dev.kobj,
> > &smbios_attr_label.attr);
> > > + return 0;
> > > + }
> > > + return -1;
> > > +}
> > > +
> > > +static const char dell_dsm_uuid[] = {
> >
> > Um, a dell specific uuid in a generic file? What happens when we
> need
> > to support another manufacturer?
> >
>
> My understanding of uuid was incorrect. I have renamed it to a more
> generic
> device_label_dsm_uuid and ACPI_DSM_FUNCTION to DEVICE_LABEL_DSM
>
> > > + 0xD0, 0x37, 0xC9, 0xE5, 0x53, 0x35, 0x7A, 0x4D,
> > > + 0x91, 0x17, 0xEA, 0x4D, 0x19, 0xC3, 0x43, 0x4D
> > > +};
> > > +
> > > +
> > > +static int
> > > +dsm_get_label(acpi_handle handle, int func,
> > > + struct acpi_buffer *output,
> > > + char *buf, char *attribute)
> > > +{
> > > + struct acpi_object_list input;
> > > + union acpi_object params[4];
> > > + union acpi_object *obj;
> > > + int len = 0;
> > > +
> > > + int err;
> > > +
> > > + input.count = 4;
> > > + input.pointer = params;
> > > + params[0].type = ACPI_TYPE_BUFFER;
> > > + params[0].buffer.length = sizeof(dell_dsm_uuid);
> > > + params[0].buffer.pointer = (char *)dell_dsm_uuid;
> > > + params[1].type = ACPI_TYPE_INTEGER;
> > > + params[1].integer.value = 0x02;
> > > + params[2].type = ACPI_TYPE_INTEGER;
> > > + params[2].integer.value = func;
> > > + params[3].type = ACPI_TYPE_PACKAGE;
> > > + params[3].package.count = 0;
> > > + params[3].package.elements = NULL;
> > > +
> > > + err = acpi_evaluate_object(handle, "_DSM", &input, output);
> > > + if (err) {
> > > + printk(KERN_INFO "failed to evaulate _DSM\n");
> > > + return -1;
> > > + }
> > > +
> > > + obj = (union acpi_object *)output->pointer;
> > > +
> > > + switch (obj->type) {
> > > + case ACPI_TYPE_PACKAGE:
> > > + if (obj->package.count == 2) {
> > > + len = obj-
> >package.elements[0].integer.value;
> > > + if (buf) {
> > > + if (!strncmp(attribute, "index",
> > strlen(attribute)))
> > > + scnprintf(buf, PAGE_SIZE,
> > "%lu\n",
> > > +
> > obj->package.elements[0].integer.value);
> > > + else
> > > + scnprintf(buf, PAGE_SIZE,
> > "%s\n",
> > > +
> > obj->package.elements[1].string.pointer);
> > > + kfree(output->pointer);
> > > + return strlen(buf);
> > > + }
> > > + }
> > > + kfree(output->pointer);
> > > + return len;
> > > + break;
> > > + default:
> > > + return -1;
> > > + }
> > > +}
> > > +
> > > +static ssize_t
> > > +acpi_index_string_exist(struct device *dev, char *buf, char
> > *attribute)
> > > +{
> > > + struct pci_dev *pdev = to_pci_dev(dev);
> > > +
> > > + struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
> > > + acpi_handle handle;
> > > + int length;
> > > + int is_addin_card = 0;
> > > +
> > > + if ((pdev->class >> 16) != PCI_BASE_CLASS_NETWORK)
> > > + return -1;
> > > +
> > > + handle = DEVICE_ACPI_HANDLE(dev);
> > > +
> > > + if (!handle) {
> > > + /*
> > > + * The device is an add-in network controller and
> does
> > have
> > > + * a valid handle. Try until we get the handle for
> the
> > parent
> > > + * bridge
> > > + */
> > > + struct pci_bus *pbus;
> > > + for (pbus = pdev->bus; pbus; pbus = pbus->parent) {
> > > + handle =
> > DEVICE_ACPI_HANDLE(&(pbus->self->dev));
> > > + if (handle)
> > > + break;
> > > +
> > > + }
> > > + }
> > > +
> > > + if ((length = dsm_get_label(handle, DELL_DSM_NETWORK,
> > > + &output, buf, attribute)) < 0)
> > > + return -1;
> > > +
> > > + return length;
> > > +}
> > > +
> > > +static ssize_t
> > > +acpilabel_show(struct device *dev, struct device_attribute *attr,
> > char *buf)
> > > +{
> > > + return acpi_index_string_exist(dev, buf, "label");
> > > +}
> > > +
> > > +static ssize_t
> > > +acpiindex_show(struct device *dev, struct device_attribute *attr,
> > char *buf)
> > > +{
> > > + return acpi_index_string_exist(dev, buf, "index");
> > > +}
> > > +
> > > +struct acpi_attribute acpi_attr_label = {
> > > + .attr = {.name = __stringify(label), .mode = 0444, .owner =
> > THIS_MODULE},
> > > + .show = acpilabel_show,
> > > + .test = acpi_index_string_exist,
> > > +};
> > > +
> > > +struct acpi_attribute acpi_attr_index = {
> > > + .attr = {.name = __stringify(index), .mode = 0444, .owner =
> > THIS_MODULE},
> > > + .show = acpiindex_show,
> > > + .test = acpi_index_string_exist,
> > > +};
> > > +
> > > +static int
> > > +pci_create_acpi_index_label_files(struct pci_dev *pdev)
> > > +{
> > > + if (acpi_attr_label.test && acpi_attr_label.test(&pdev-
> >dev,
> > NULL) > 0) {
> > > + sysfs_create_file(&pdev->dev.kobj,
> > &acpi_attr_label.attr);
> > > + sysfs_create_file(&pdev->dev.kobj,
> > &acpi_attr_index.attr);
> > > + return 0;
> > > + }
> > > + return -1;
> > > +}
> > > +
> > > +static int
> > > +pci_remove_acpi_index_label_files(struct pci_dev *pdev)
> > > +{
> > > + if (acpi_attr_label.test && acpi_attr_label.test(&pdev-
> >dev,
> > NULL) > 0) {
> > > + sysfs_remove_file(&pdev->dev.kobj,
> > &acpi_attr_label.attr);
> > > + sysfs_remove_file(&pdev->dev.kobj,
> > &acpi_attr_index.attr);
> > > + return 0;
> > > + }
> > > + return -1;
> > > +}
> > > +
> > > +int pci_create_acpi_attr_files(struct pci_dev *pdev)
> > > +{
> > > + if (!pci_create_acpi_index_label_files(pdev))
> > > + return 0;
> > > + if (!pci_create_smbiosname_file(pdev))
> > > + return 0;
> > > + return -ENODEV;
> > > +}
> > > +EXPORT_SYMBOL(pci_create_acpi_attr_files);
> >
> > EXPORT_SYMBOL_GPL?
> >
> > Wait, why does this need to be exported at all? What module is ever
> > going to call this function?
> >
> > > +int pci_remove_acpi_attr_files(struct pci_dev *pdev)
> > > +{
> > > + if (!pci_remove_acpi_index_label_files(pdev))
> > > + return 0;
> > > + if (!pci_remove_smbiosname_file(pdev))
> > > + return 0;
> > > + return -ENODEV;
> > > +
> > > +}
> > > +EXPORT_SYMBOL(pci_remove_acpi_attr_files);
> >
> > Same here, what module will call this?
> >
>
> These functions need not be exported as they are not called by any
> module.
>
> > > +++ b/include/linux/pci-label.h
> >
> > As discussed above, this whole file does not need to exist.
> >
> > > +extern int pci_create_acpi_attr_files(struct pci_dev *pdev);
> > > +extern int pci_remove_acpi_attr_files(struct pci_dev *pdev);
> >
> > Just put these two functions in the drivers/pci/pci.h file.
> >
> Fixed.
>
> In addition to these changes there are a coulple of changes i have done
> -
>
> 1.Removed the check for network devices and evaulate _DSM for any pci
> device
> that has _DSM defined in adherence to the spec.
>
> 2.Renamed the functions pci_create,remove-acpi_attr_files to
> pci_create,remove_firmware_label_files.
>
> 3.Added checks for conditional compilation of if CONFIG_ACPI ||
> CONFIG_DMI
>
> Note: While testing the patch with CONFIG_ACPI set to no, the
> compilation
> would fail with the below message.
>
> CC drivers/pci/pci-label.o
> In file included from drivers/pci/pci-label.c:24:
> include/linux/pci-acpi.h:39: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or
> ‘__attribute__’
> before ‘acpi_find_root_bridge_handle’
>
> I had to add make this change to proceed with the compilation. It would
> be
> great to know if i am missing something in the way conditional
> compilation
> is implemented or is it a issue.
>
> ---
> include/linux/pci-acpi.h | 4 ++--
> 1 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
> index c8b6473..bc40827 100644
> --- a/include/linux/pci-acpi.h
> +++ b/include/linux/pci-acpi.h
> @@ -36,8 +36,8 @@ static inline acpi_handle
> acpi_pci_get_bridge_handle(struct pci_bus *pbus)
> pbus->number);
> }
> #else
> -static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev
> *pdev)
> -{ return NULL; }
> +static inline void acpi_find_root_bridge_handle(struct pci_dev *pdev)
> +{ }
> #endif
>
> #endif /* _PCI_ACPI_H_ */
>
>
> Please find the patch with above suggestions and changes -
>
>
> From: Narendra K <narendra_k@dell.com>
> Subject: [PATCH V2 1/2] Export firmware assigned labels of pci devices
> to sysfs
>
> This patch exports the firmware assigned labels of pci devices to
> sysfs which could be used by user space.
>
> Signed-off-by: Jordan Hargrave <jordan_hargrave@dell.com>
> Signed-off-by: Narendra K <narendra_k@dell.com>
> ---
> drivers/firmware/dmi_scan.c | 24 ++++
> drivers/pci/Makefile | 2 +-
> drivers/pci/pci-label.c | 273
> +++++++++++++++++++++++++++++++++++++++++++
> drivers/pci/pci-sysfs.c | 5 +
> drivers/pci/pci.h | 2 +
> include/linux/dmi.h | 9 ++
> 6 files changed, 314 insertions(+), 1 deletions(-)
> create mode 100644 drivers/pci/pci-label.c
>
> diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
> index d464672..7d8439b 100644
> --- a/drivers/firmware/dmi_scan.c
> +++ b/drivers/firmware/dmi_scan.c
> @@ -277,6 +277,28 @@ static void __init dmi_save_ipmi_device(const
> struct dmi_header *dm)
> list_add_tail(&dev->list, &dmi_devices);
> }
>
> +static void __init dmi_save_devslot(int id, int seg, int bus, int
> devfn, const char *name)
> +{
> + struct dmi_devslot *slot;
> +
> + slot = dmi_alloc(sizeof(*slot) + strlen(name) + 1);
> + if (!slot) {
> + printk(KERN_ERR "dmi_save_devslot: out of memory.\n");
> + return;
> + }
> + slot->id = id;
> + slot->seg = seg;
> + slot->bus = bus;
> + slot->devfn = devfn;
> +
> + strcpy((char *)&slot[1], name);
> + slot->dev.type = DMI_DEV_TYPE_DEVSLOT;
> + slot->dev.name = (char *)&slot[1];
> + slot->dev.device_data = slot;
> +
> + list_add(&slot->dev.list, &dmi_devices);
> +}
> +
> static void __init dmi_save_extended_devices(const struct dmi_header
> *dm)
> {
> const u8 *d = (u8*) dm + 5;
> @@ -285,6 +307,7 @@ static void __init dmi_save_extended_devices(const
> struct dmi_header *dm)
> if ((*d & 0x80) == 0)
> return;
>
> + dmi_save_devslot(-1, *(u16 *)(d+2), *(d+4), *(d+5),
> dmi_string_nosave(dm, *(d-1)));
> dmi_save_one_device(*d & 0x7f, dmi_string_nosave(dm, *(d - 1)));
> }
>
> @@ -333,6 +356,7 @@ static void __init dmi_decode(const struct
> dmi_header *dm, void *dummy)
> break;
> case 41: /* Onboard Devices Extended Information */
> dmi_save_extended_devices(dm);
> + break;
> }
> }
>
> diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
> index 0b51857..69c503a 100644
> --- a/drivers/pci/Makefile
> +++ b/drivers/pci/Makefile
> @@ -4,7 +4,7 @@
>
> obj-y += access.o bus.o probe.o remove.o pci.o \
> pci-driver.o search.o pci-sysfs.o rom.o setup-res.o \
> - irq.o vpd.o
> + irq.o vpd.o pci-label.o
> obj-$(CONFIG_PROC_FS) += proc.o
> obj-$(CONFIG_SYSFS) += slot.o
>
> diff --git a/drivers/pci/pci-label.c b/drivers/pci/pci-label.c
> new file mode 100644
> index 0000000..b35d48c
> --- /dev/null
> +++ b/drivers/pci/pci-label.c
> @@ -0,0 +1,273 @@
> +/*
> + * Purpose: Export the firmware label associated with a pci network
> interface
> + * device to sysfs
> + * Copyright (C) 2010 Dell Inc.
> + * by Narendra K <Narendra_K@dell.com>, Jordan Hargrave
> <Jordan_Hargrave@dell.com>
> + *
> + * This code checks if the pci network device has a related ACPI _DSM.
> If
> + * available, the code calls the _DSM to retrieve the index and string
> and
> + * exports them to sysfs. If the ACPI _DSM is not available, it falls
> back on
> + * SMBIOS. SMBIOS defines type 41 for onboard pci devices. This code
> retrieves
> + * strings associated with the type 41 and exports it to sysfs.
> + *
> + * Please see http://linux.dell.com/wiki/index.php/Oss/libnetdevname
> for more
> + * information.
> + */
> +
> +#include <linux/dmi.h>
> +#include <linux/sysfs.h>
> +#include <linux/pci.h>
> +#include <linux/pci_ids.h>
> +#include <linux/module.h>
> +#include <linux/acpi.h>
> +#include <linux/pci-acpi.h>
> +#include <acpi/acpi_drivers.h>
> +#include <acpi/acpi_bus.h>
> +#include "pci.h"
> +
> +#define DEVICE_LABEL_DSM 0x07
> +
> +#if defined CONFIG_DMI
> +
> +struct smbios_attribute {
> + struct attribute attr;
> + ssize_t (*show) (struct device *dev, char *buf);
> + ssize_t (*test) (struct device *dev, char *buf);
> +};
> +
> +static ssize_t
> +smbiosname_string_exists(struct device *dev, char *buf)
> +{
> + struct pci_dev *pdev = to_pci_dev(dev);
> + const struct dmi_device *dmi;
> + struct dmi_devslot *dslot;
> + int bus;
> + int devfn;
> +
> + bus = pdev->bus->number;
> + devfn = pdev->devfn;
> +
> + dmi = NULL;
> + while ((dmi = dmi_find_device(DMI_DEV_TYPE_DEVSLOT, NULL, dmi))
> != NULL) {
> + dslot = dmi->device_data;
> + if (dslot && dslot->bus == bus && dslot->devfn == devfn) {
> + if (buf)
> + return scnprintf(buf, PAGE_SIZE, "%s\n",
> dmi->name);
> + return strlen(dmi->name);
> + }
> + }
> +
> + return 0;
> +}
> +
> +static ssize_t
> +smbiosname_show(struct device *dev, struct device_attribute *attr,
> char *buf)
> +{
> + return smbiosname_string_exists(dev, buf);
> +}
> +
> +struct smbios_attribute smbios_attr_label = {
> + .attr = {.name = "label", .mode = 0444, .owner = THIS_MODULE},
> + .show = smbiosname_show,
> + .test = smbiosname_string_exists,
> +};
> +
> +static int
> +pci_create_smbiosname_file(struct pci_dev *pdev)
> +{
> + if (smbios_attr_label.test && smbios_attr_label.test(&pdev->dev,
> NULL)) {
> + sysfs_create_file(&pdev->dev.kobj,
> &smbios_attr_label.attr);
> + return 0;
> + }
> + return -1;
> +}
> +
> +static int
> +pci_remove_smbiosname_file(struct pci_dev *pdev)
> +{
> + if (smbios_attr_label.test && smbios_attr_label.test(&pdev->dev,
> NULL)) {
> + sysfs_remove_file(&pdev->dev.kobj,
> &smbios_attr_label.attr);
> + return 0;
> + }
> + return -1;
> +}
> +#else
> +static inline int
> +pci_create_smbiosname_file(struct pci_dev *pdev)
> +{
> + return -1;
> +}
> +
> +static inline int
> +pci_remove_smbiosname_file(struct pci_dev *pdev)
> +{
> + return -1;
> +}
> +#endif
> +
> +#if defined CONFIG_ACPI
> +
> +static const char device_label_dsm_uuid[] = {
> + 0xD0, 0x37, 0xC9, 0xE5, 0x53, 0x35, 0x7A, 0x4D,
> + 0x91, 0x17, 0xEA, 0x4D, 0x19, 0xC3, 0x43, 0x4D
> +};
> +
> +struct acpi_attribute {
> + struct attribute attr;
> + ssize_t (*show) (struct device *dev, char *buf);
> + ssize_t (*test) (struct device *dev, char *buf);
> +};
> +
> +static int
> +dsm_get_label(acpi_handle handle, int func,
> + struct acpi_buffer *output,
> + char *buf, char *attribute)
> +{
> + struct acpi_object_list input;
> + union acpi_object params[4];
> + union acpi_object *obj;
> + int len = 0;
> +
> + int err;
> +
> + input.count = 4;
> + input.pointer = params;
> + params[0].type = ACPI_TYPE_BUFFER;
> + params[0].buffer.length = sizeof(device_label_dsm_uuid);
> + params[0].buffer.pointer = (char *)device_label_dsm_uuid;
> + params[1].type = ACPI_TYPE_INTEGER;
> + params[1].integer.value = 0x02;
> + params[2].type = ACPI_TYPE_INTEGER;
> + params[2].integer.value = func;
> + params[3].type = ACPI_TYPE_PACKAGE;
> + params[3].package.count = 0;
> + params[3].package.elements = NULL;
> +
> + err = acpi_evaluate_object(handle, "_DSM", &input, output);
> + if (err)
> + return -1;
> +
> +
> + obj = (union acpi_object *)output->pointer;
> +
> + switch (obj->type) {
> + case ACPI_TYPE_PACKAGE:
> + if (obj->package.count != 2)
> + break;
> + len = obj->package.elements[0].integer.value;
> + if (buf) {
> + if (!strncmp(attribute, "index", strlen(attribute)))
> + scnprintf(buf, PAGE_SIZE, "%lu\n",
> + obj->package.elements[0].integer.value);
> + else
> + scnprintf(buf, PAGE_SIZE, "%s\n",
> + obj->package.elements[1].string.pointer);
> + kfree(output->pointer);
> + return strlen(buf);
> + }
> + kfree(output->pointer);
> + return len;
> + break;
> + default:
> + kfree(output->pointer);
> + return -1;
> + }
> +}
> +
> +static ssize_t
> +acpi_index_string_exist(struct device *dev, char *buf, char
> *attribute)
> +{
> + struct pci_dev *pdev = to_pci_dev(dev);
> +
> + struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
> + acpi_handle handle;
> + int length;
> +
> + handle = DEVICE_ACPI_HANDLE(dev);
> +
> + if (!handle)
> + return -1;
> +
> + if ((length = dsm_get_label(handle, DEVICE_LABEL_DSM,
> + &output, buf, attribute)) < 0)
> + return -1;
> +
> + return length;
> +}
> +
> +static ssize_t
> +acpilabel_show(struct device *dev, struct device_attribute *attr, char
> *buf)
> +{
> + return acpi_index_string_exist(dev, buf, "label");
> +}
> +
> +static ssize_t
> +acpiindex_show(struct device *dev, struct device_attribute *attr, char
> *buf)
> +{
> + return acpi_index_string_exist(dev, buf, "index");
> +}
> +
> +struct acpi_attribute acpi_attr_label = {
> + .attr = {.name = "label", .mode = 0444, .owner = THIS_MODULE},
> + .show = acpilabel_show,
> + .test = acpi_index_string_exist,
> +};
> +
> +struct acpi_attribute acpi_attr_index = {
> + .attr = {.name = "index", .mode = 0444, .owner = THIS_MODULE},
> + .show = acpiindex_show,
> + .test = acpi_index_string_exist,
> +};
> +
> +static int
> +pci_create_acpi_index_label_files(struct pci_dev *pdev)
> +{
> + if (acpi_attr_label.test && acpi_attr_label.test(&pdev->dev,
> NULL) > 0) {
> + sysfs_create_file(&pdev->dev.kobj, &acpi_attr_label.attr);
> + sysfs_create_file(&pdev->dev.kobj, &acpi_attr_index.attr);
> + return 0;
> + }
> + return -1;
> +}
> +
> +static int
> +pci_remove_acpi_index_label_files(struct pci_dev *pdev)
> +{
> + if (acpi_attr_label.test && acpi_attr_label.test(&pdev->dev,
> NULL) > 0) {
> + sysfs_remove_file(&pdev->dev.kobj, &acpi_attr_label.attr);
> + sysfs_remove_file(&pdev->dev.kobj, &acpi_attr_index.attr);
> + return 0;
> + }
> + return -1;
> +}
> +#else
> +static inline int
> +pci_create_acpi_index_label_files(struct pci_dev *pdev)
> +{
> + return -1;
> +}
> +
> +static inline int
> +pci_remove_acpi_index_label_files(struct pci_dev *pdev)
> +{
> + return -1;
> +}
> +#endif
> +
> +int pci_create_firmware_label_files(struct pci_dev *pdev)
> +{
> + if (!pci_create_acpi_index_label_files(pdev))
> + return 0;
> + if (!pci_create_smbiosname_file(pdev))
> + return 0;
> + return -ENODEV;
> +}
> +
> +int pci_remove_firmware_label_files(struct pci_dev *pdev)
> +{
> + if (!pci_remove_acpi_index_label_files(pdev))
> + return 0;
> + if (!pci_remove_smbiosname_file(pdev))
> + return 0;
> + return -ENODEV;
> +}
> diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
> index fad9398..4ed517f 100644
> --- a/drivers/pci/pci-sysfs.c
> +++ b/drivers/pci/pci-sysfs.c
> @@ -1073,6 +1073,8 @@ int __must_check pci_create_sysfs_dev_files
> (struct pci_dev *pdev)
> if (retval)
> goto err_vga_file;
>
> + pci_create_firmware_label_files(pdev);
> +
> return 0;
>
> err_vga_file:
> @@ -1140,6 +1142,9 @@ void pci_remove_sysfs_dev_files(struct pci_dev
> *pdev)
> sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr);
> kfree(pdev->rom_attr);
> }
> +
> + pci_remove_firmware_label_files(pdev);
> +
> }
>
> static int __init pci_sysfs_init(void)
> diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
> index 4eb10f4..f223283 100644
> --- a/drivers/pci/pci.h
> +++ b/drivers/pci/pci.h
> @@ -11,6 +11,8 @@
> extern int pci_uevent(struct device *dev, struct kobj_uevent_env
> *env);
> extern int pci_create_sysfs_dev_files(struct pci_dev *pdev);
> extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev);
> +extern int pci_create_firmware_label_files(struct pci_dev *pdev);
> +extern int pci_remove_firmware_label_files(struct pci_dev *pdev);
> extern void pci_cleanup_rom(struct pci_dev *dev);
> #ifdef HAVE_PCI_MMAP
> extern int pci_mmap_fits(struct pci_dev *pdev, int resno,
> diff --git a/include/linux/dmi.h b/include/linux/dmi.h
> index a8a3e1a..cc57c3a 100644
> --- a/include/linux/dmi.h
> +++ b/include/linux/dmi.h
> @@ -20,6 +20,7 @@ enum dmi_device_type {
> DMI_DEV_TYPE_SAS,
> DMI_DEV_TYPE_IPMI = -1,
> DMI_DEV_TYPE_OEM_STRING = -2,
> + DMI_DEV_TYPE_DEVSLOT = -3,
> };
>
> struct dmi_header {
> @@ -37,6 +38,14 @@ struct dmi_device {
>
> #ifdef CONFIG_DMI
>
> +struct dmi_devslot {
> + struct dmi_device dev;
> + int id;
> + int seg;
> + int bus;
> + int devfn;
> +};
> +
> extern int dmi_check_system(const struct dmi_system_id *list);
> const struct dmi_system_id *dmi_first_match(const struct dmi_system_id
> *list);
> extern const char * dmi_get_system_info(int field);
> --
> 1.6.5.2
>
> With regards,
> Narendra K
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: still having r8169 woes with XID 18000000
From: Timo Teräs @ 2010-06-04 20:24 UTC (permalink / raw)
To: Phil Sutter; +Cc: françois romieu, netdev
In-Reply-To: <4C09387F.1050403@iki.fi>
On 06/04/2010 08:31 PM, Timo Teräs wrote:
> On 06/04/2010 04:43 PM, Phil Sutter wrote:
>> On Fri, Jun 04, 2010 at 04:02:11PM +0300, Timo Teräs wrote:
>>>> Comparing r8169-6.013 with it's predecessor 6.012, you'll find a newly
>>>> enabled function rtl8169_phy_power_up() as well as some more invocations
>>>> of rtl8169_phy_power_down().
>>>>
>>>> This is probably the solution to these (at least in our case) very
>>>> sporadic, but highly annoying, problems. In fact, when our NIC didn't
>>>> detect any link, it needed a full power-cycle (no success with
>>>> reset-button), so almost not workaroundable.
>>>
> However, removing the specific phy config code
> (rtl8169scd_hw_phy_config) which was introduced by commit 2e955856ff
> seems to solve it. At least I was not able to reproduce the failure with
> 20-30 module reloads.
Ok, I figured that either the data the phy config writes is bad, or mdio
io is failing, so I added some additional checks to mdio_write and
mdio_read. More loops (upto 2000 iterations) and debug print if it
ultimately failed. And it did!
At bootup I got this:
r8169 Gigabit Ethernet driver 2.3LK-NAPI loaded
r8169 0000:00:09.0: PCI->APIC IRQ transform: INT A -> IRQ 18
r8169 0000:00:09.0: no PCI Express capability
eth0: RTL8169sc/8110sc at 0xf835c000, 00:30:18:a6:2b:6c, XID 18000000 IRQ 18
r8169 Gigabit Ethernet driver 2.3LK-NAPI loaded
r8169 0000:00:0b.0: PCI->APIC IRQ transform: INT A -> IRQ 19
r8169 0000:00:0b.0: no PCI Express capability
eth1: RTL8169sc/8110sc at 0xf8360000, 00:30:18:a6:2b:6d, XID 18000000 IRQ 19
r8169 Gigabit Ethernet driver 2.3LK-NAPI loaded
r8169 0000:00:0c.0: PCI->APIC IRQ transform: INT A -> IRQ 16
r8169 0000:00:0c.0: no PCI Express capability
eth2: RTL8169sc/8110sc at 0xf8364000, 00:30:18:a6:2b:6e, XID 18000000 IRQ 16
r8169: mdio_write(f8364000, 0x00000003, 0000000a1) required 2000 cycles
r8169: mdio_write(f8364000, 0x00000000, 000001000) required 2000 cycles
r8169: mdio_write(f8364000, 0x00000000, 00000a0ff) required 2000 cycles
r8169: mdio_write(f8364000, 0x00000014, 00000fb54) required 2000 cycles
And eth2 was not working. Reloading the module gave a lot of other
mdio_write and mdio_read errors.
It seems to be pretty random when the errors occur, but that's the
reason why the NIC stops working: mdio_write() fails (one or more times)
at some crucial point of the board specific phy config code resulting in
bad state.
Any ideas how to debug this further?
I guess next step is to compile the Realtek driver and see if that works
right.
> One more curiosity: if i do a hard power reset, the NIC has green link
> indicator led after power up. When loading the kernel module it goes to
> orange/red. I wonder why the difference.
Figured this. At startup it goes to 100mbit/s fixed mode. After module
load it gets 1gb/s. Setting it manually to 100mbit/s changes the color
back to green. So it's just a speed indicator.
^ permalink raw reply
* [PATCH nf-next-2.6 2/2] conntrack: per_cpu untracking
From: Eric Dumazet @ 2010-06-04 20:15 UTC (permalink / raw)
To: Patrick McHardy; +Cc: Changli Gao, Netfilter Developers, netdev
In-Reply-To: <1275668732.2482.201.camel@edumazet-laptop>
NOTRACK makes all cpus share a cache line on nf_conntrack_untracked
twice per packet, slowing down performance.
This patch converts it to a per_cpu variable.
We assume same cpu is used for a given packet, entering and exiting the
NOTRACK state.
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
include/net/netfilter/nf_conntrack.h | 5 +--
net/netfilter/nf_conntrack_core.c | 36 ++++++++++++++++++-------
2 files changed, 28 insertions(+), 13 deletions(-)
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
index 3bc38c7..84a4b6f 100644
--- a/include/net/netfilter/nf_conntrack.h
+++ b/include/net/netfilter/nf_conntrack.h
@@ -261,11 +261,10 @@ extern s16 (*nf_ct_nat_offset)(const struct nf_conn *ct,
u32 seq);
/* Fake conntrack entry for untracked connections */
+DECLARE_PER_CPU(struct nf_conn, nf_conntrack_untracked);
static inline struct nf_conn *nf_ct_untracked_get(void)
{
- extern struct nf_conn nf_conntrack_untracked;
-
- return &nf_conntrack_untracked;
+ return &__raw_get_cpu_var(nf_conntrack_untracked);
}
extern void nf_ct_untracked_status_or(unsigned long bits);
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 6c1da21..9c66141 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -62,8 +62,8 @@ EXPORT_SYMBOL_GPL(nf_conntrack_htable_size);
unsigned int nf_conntrack_max __read_mostly;
EXPORT_SYMBOL_GPL(nf_conntrack_max);
-struct nf_conn nf_conntrack_untracked;
-EXPORT_SYMBOL_GPL(nf_conntrack_untracked);
+DEFINE_PER_CPU(struct nf_conn, nf_conntrack_untracked);
+EXPORT_PER_CPU_SYMBOL(nf_conntrack_untracked);
static int nf_conntrack_hash_rnd_initted;
static unsigned int nf_conntrack_hash_rnd;
@@ -1183,10 +1183,21 @@ static void nf_ct_release_dying_list(struct net *net)
spin_unlock_bh(&nf_conntrack_lock);
}
+static int untrack_refs(void)
+{
+ int cnt = 0, cpu;
+
+ for_each_possible_cpu(cpu) {
+ struct nf_conn *ct = &per_cpu(nf_conntrack_untracked, cpu);
+
+ cnt += atomic_read(&ct->ct_general.use) - 1;
+ }
+ return cnt;
+}
+
static void nf_conntrack_cleanup_init_net(void)
{
- /* wait until all references to nf_conntrack_untracked are dropped */
- while (atomic_read(&nf_conntrack_untracked.ct_general.use) > 1)
+ while (untrack_refs() > 0)
schedule();
nf_conntrack_helper_fini();
@@ -1323,14 +1334,17 @@ module_param_call(hashsize, nf_conntrack_set_hashsize, param_get_uint,
void nf_ct_untracked_status_or(unsigned long bits)
{
- nf_conntrack_untracked.status |= bits;
+ int cpu;
+
+ for_each_possible_cpu(cpu)
+ per_cpu(nf_conntrack_untracked, cpu).status |= bits;
}
EXPORT_SYMBOL_GPL(nf_ct_untracked_status_or);
static int nf_conntrack_init_init_net(void)
{
int max_factor = 8;
- int ret;
+ int ret, cpu;
/* Idea from tcp.c: use 1/16384 of memory. On i386: 32MB
* machine has 512 buckets. >= 1GB machines have 16384 buckets. */
@@ -1369,10 +1383,12 @@ static int nf_conntrack_init_init_net(void)
goto err_extend;
#endif
/* Set up fake conntrack: to never be deleted, not in any hashes */
-#ifdef CONFIG_NET_NS
- nf_conntrack_untracked.ct_net = &init_net;
-#endif
- atomic_set(&nf_conntrack_untracked.ct_general.use, 1);
+ for_each_possible_cpu(cpu) {
+ struct nf_conn *ct = &per_cpu(nf_conntrack_untracked, cpu);
+
+ write_pnet(&ct->ct_net, &init_net);
+ atomic_set(&ct->ct_general.use, 1);
+ }
/* - and look it like as a confirmed connection */
nf_ct_untracked_status_or(IPS_CONFIRMED | IPS_UNTRACKED);
return 0;
^ permalink raw reply related
* Re: [v5 Patch 1/3] netpoll: add generic support for bridge and bonding devices
From: Andy Gospodarek @ 2010-06-04 19:18 UTC (permalink / raw)
To: Cong Wang
Cc: Jay Vosburgh, Flavio Leitner, linux-kernel, Matt Mackall, netdev,
bridge, Andy Gospodarek, Neil Horman, Jeff Moyer,
Stephen Hemminger, bonding-devel, David Miller
In-Reply-To: <4C062CBD.7090906@redhat.com>
On Wed, Jun 02, 2010 at 06:04:45PM +0800, Cong Wang wrote:
> On 06/02/10 02:42, Jay Vosburgh wrote:
>> Cong Wang<amwang@redhat.com> wrote:
>>
>>> On 06/01/10 03:08, Flavio Leitner wrote:
>>>> On Mon, May 31, 2010 at 01:56:52PM +0800, Cong Wang wrote:
>>>>> Hi, Flavio,
>>>>>
>>>>> Please use the attached patch instead, try to see if it solves
>>>>> all your problems.
>>>>
>>>> I tried and it hangs. No backtraces this time.
>>>> The bond_change_active_slave() prints before NETDEV_BONDING_FAILOVER
>>>> notification, so I think it won't work.
>>>
>>> Ah, I thought the same.
>>>
>>>>
>>>> Please, correct if I'm wrong, but when a failover happens with your
>>>> patch applied, the netconsole would be disabled forever even with
>>>> another healthy slave, right?
>>>>
>>>
>>> Yes, this is an easy solution, because bonding has several modes,
>>> it is complex to make netpoll work in different modes.
>>
>> If I understand correctly, the root cause of the problem with
>> netconsole and bonding is that bonding is, ultimately, performing
>> printks with a write lock held, and when netconsole recursively calls
>> into bonding to send the printk over the netconsole, there is a deadlock
>> (when the bonding xmit function attempts to acquire the same lock for
>> read).
>
>
> Yes.
>
>>
>> You're trying to avoid the deadlock by shutting off netconsole
>> (permanently, it looks like) for one problem case: a failover, which
>> does some printks with a write lock held.
>>
>> This doesn't look to me like a complete solution, there are
>> other cases in bonding that will do printk with write locks held. I
>> suspect those will also hang netconsole as things exist today, and won't
>> be affected by your patch below.
>
>
> I can expect that, bonding modes are complex.
>
>>
>> For example:
>>
>> The sysfs functions to set the primary (bonding_store_primary)
>> or active (bonding_store_active_slave) options: a pr_info is called to
>> provide a log message of the results. These could be tested by setting
>> the primary or active options via sysfs, e.g.,
>>
>> echo eth0> /sys/class/net/bond0/bonding/primary
>> echo eth0> /sys/class/net/bond0/bonding/active
>>
>> If the kernel is defined with DEBUG, there are a few pr_debug
>> calls within write_locks (bond_del_vlan, for example).
>>
>> If the slave's underlying device driver's ndo_vlan_rx_register
>> or ndo_vlan_rx_kill_vid functions call printk (and it looks like some do
>> for error cases, e.g., igbvf, ehea, enic), those would also presumably
>> deadlock (because bonding holds its write_lock when calling the ndo_
>> vlan functions).
>>
>> It also appears that (with the patch below) some nominally
>> normal usage patterns will immediately disable netconsole. The one that
>> comes to mind is if the primary= option is set (to "eth1" for this
>> example), but that slave not enslaved first (the slaves are added, say,
>> eth0 then eth1). In that situation, when the primary slave (eth1 here)
>> is added, the first thing that will happen is a failover, and that will
>> disable netconsole.
>>
>
> Thanks for your detailed explanation!
>
> This is why I said bonding is complex. I guess we would have to adjust
> netpoll code for different bonding cases, one solution seems not fix all.
> I am not sure how much work to do, since I am not familiar with bonding
> code. Maybe Andy can help?
>
Sorry I've been silent until now. This does seem quite similar to a
problem I've previously encountered when dealing with bonding+netpoll on
some old 2.6.9-based kernels. There is no guarantee the methods used
there will apply here, but I'll talk about them anyway.
As Flavio noticed, recursive calls into the bond transmit routines were
not a good idea. I discovered the same and worked around this issue by
checking to see if we could take the bond->lock for writing before
continuing. If we could not get, I wanted to signal that this should be
queued for transmission later. Based on the flow of netpoll_send_skb
(or possibly for another reason that is escaping me right now) I added
one of these checks in bond_poll_controller too. These aren't the
prettiest fixes, but seemed to work well for me when I did this work in
the past. I realize the differences are not that great compared to some
of the patches posted by Flavio, but I think they are worth trying.
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index ef60244..d7b9b99 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1290,6 +1290,12 @@ static bool slaves_support_netpoll(struct net_device *bond_dev)
static void bond_poll_controller(struct net_device *bond_dev)
{
struct net_device *dev = bond_dev->npinfo->netpoll->real_dev;
+ struct bonding *bond = netdev_priv(bond_dev);
+
+ if (!write_trylock(&bond->lock))
+ return;
+ write_unlock(&bond->lock);
+
if (dev != bond_dev)
netpoll_poll_dev(dev);
}
@@ -4418,7 +4424,11 @@ static void bond_set_xmit_hash_policy(struct bonding *bond)
static netdev_tx_t bond_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
- const struct bonding *bond = netdev_priv(dev);
+ struct bonding *bond = netdev_priv(dev);
+
+ if (!write_trylock(&bond->lock))
+ return NETDEV_TX_BUSY;
+ write_unlock(&bond->lock);
switch (bond->params.mode) {
case BOND_MODE_ROUNDROBIN:
The other key to all of this is to make sure that queuing is done
correctly now that we expect to queue these frames and have them sent at
some point when there is a member of the bond that is actually capable
of sending them out.
The new style of sending queued skbs in a workqueue is much better than
what was done in the 2.6.9 timeframe, but careful attention should still
be paid to txq lock and which processor is the owner. Returning
something other than NETDEV_TX_OK from bond_start_xmit and checking for
locks being held there should also help with any deadlocks that show up
while running in queue_process (though they would not be recursive).
I'm not in a good spot to test this right now, but I can take a look at
next week and we can try and track down any of the other deadlocks that
currently exist as I suspect this will not resolve all of the issues.
^ permalink raw reply related
* Re: [PATCH 1/2] net: Enable 64-bit net device statistics on 32-bit architectures
From: Ben Hutchings @ 2010-06-04 18:15 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: David Miller, Arnd Bergmann, netdev, linux-net-drivers
In-Reply-To: <20100604102852.08ce3cd1@nehalam>
On Fri, 2010-06-04 at 10:28 -0700, Stephen Hemminger wrote:
> On Thu, 03 Jun 2010 20:11:38 +0100
> Ben Hutchings <bhutchings@solarflare.com> wrote:
>
> > static inline u64 rtnl_link_stats64_read(const u64 *field)
> > {
> > return ACCESS_ONCE(*field);
> > }
> > static inline u32 rtnl_link_stats64_read32(const u64 *field)
> > {
> > return ACCESS_ONCE(*field);
> > }
>
> Do we really care if compiler reorders access. I think not.
> There was no order guarantee in the past.
Since these reads are potentially racing with writes, we want to ensure
that they are atomic. Without the volatile-qualification, the compiler
can legitimately split or repeat the reads, though I don't see any
particular reason why this is a likely optimisation.
Ben.
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply
* Re: still having r8169 woes with XID 18000000
From: Timo Teräs @ 2010-06-04 17:31 UTC (permalink / raw)
To: Phil Sutter; +Cc: françois romieu, netdev
In-Reply-To: <20100604134351.7981F4CD45@orbit.nwl.cc>
On 06/04/2010 04:43 PM, Phil Sutter wrote:
> On Fri, Jun 04, 2010 at 04:02:11PM +0300, Timo Teräs wrote:
>>> Comparing r8169-6.013 with it's predecessor 6.012, you'll find a newly
>>> enabled function rtl8169_phy_power_up() as well as some more invocations
>>> of rtl8169_phy_power_down().
>>>
>>> This is probably the solution to these (at least in our case) very
>>> sporadic, but highly annoying, problems. In fact, when our NIC didn't
>>> detect any link, it needed a full power-cycle (no success with
>>> reset-button), so almost not workaroundable.
>>
>> Sounds very similar to the problem I have. Thanks for the pointers!
>>
>> It looks like the r8169 driver does have phy power up code in it, but
>> it's only executed for specific versions of the chip. Realtek driver
>> seems to do it unconditionally.
>
> Hmm. I actually never looked at the corresponding parts of the
> in-tree-driver, but that would have definitely been the next step in
> order to fix it.
>
>> The check seems to be:
>> if ((tp->mac_version == RTL_GIGA_MAC_VER_11) ||
>> (tp->mac_version == RTL_GIGA_MAC_VER_12) ||
>> (tp->mac_version >= RTL_GIGA_MAC_VER_17)) {
>>
>> I wonder if I should just add my mac version there (_VER_05) and test if
>> it'll make it better.
>
> Surely worth a try. On the other hand, looking at the sheer mass of
> problem reports regarding this driver, making it worse is rather hard to
> do I guess. :)
Ok. The issue is semi-reliably producible with just removing the
kernel driver and reloading it. The problem occurs maybe with 10-20% chance.
So far, it looks like the phy wakeup does not really help. Adding the
_VER_05 check did not help.
However, removing the specific phy config code
(rtl8169scd_hw_phy_config) which was introduced by commit 2e955856ff
seems to solve it. At least I was not able to reproduce the failure with
20-30 module reloads.
One more curiosity: if i do a hard power reset, the NIC has green link
indicator led after power up. When loading the kernel module it goes to
orange/red. I wonder why the difference.
- Timo
^ permalink raw reply
* Re: [PATCH 1/2] net: Enable 64-bit net device statistics on 32-bit architectures
From: Stephen Hemminger @ 2010-06-04 17:28 UTC (permalink / raw)
To: Ben Hutchings; +Cc: David Miller, Arnd Bergmann, netdev, linux-net-drivers
In-Reply-To: <1275592298.2106.36.camel@achroite.uk.solarflarecom.com>
On Thu, 03 Jun 2010 20:11:38 +0100
Ben Hutchings <bhutchings@solarflare.com> wrote:
> static inline u64 rtnl_link_stats64_read(const u64 *field)
> {
> return ACCESS_ONCE(*field);
> }
> static inline u32 rtnl_link_stats64_read32(const u64 *field)
> {
> return ACCESS_ONCE(*field);
> }
Do we really care if compiler reorders access. I think not.
There was no order guarantee in the past.
--
^ permalink raw reply
* [PATCH nf-next-2.6] conntrack: IPS_UNTRACKED bit
From: Eric Dumazet @ 2010-06-04 16:25 UTC (permalink / raw)
To: Patrick McHardy; +Cc: Changli Gao, Netfilter Developers, netdev
In-Reply-To: <1275654964.2482.150.camel@edumazet-laptop>
Le vendredi 04 juin 2010 à 14:36 +0200, Eric Dumazet a écrit :
> Le vendredi 04 juin 2010 à 14:29 +0200, Patrick McHardy a écrit :
> > Changli Gao wrote:
> > > On Fri, Jun 4, 2010 at 7:40 PM, Patrick McHardy <kaber@trash.net> wrote:
> > >> Eric Dumazet wrote:
> > >>> Obviously, an IPS_UNTRACKED bit would be much easier to implement.
> > >>> Would it be acceptable ?
> > >> That also would be fine. However the main idea behind using a nfctinfo
> > >> bit was that we wouldn't need the untracked conntrack anymore at all.
> > >> But I guess a per-cpu untrack conntrack would already be an improvement
> > >> over the current situation.
> > >
> > > I think Eric didn't mean ip_conntrack_info but ip_conntrack_status
> > > bit. Since we have had a IPS_TEMPLATE bit, I think another
> > > IPS_UNTRACKED bit is also acceptable.
> >
> > Yes, of course. But using one of these bits implies that we'd still
> > have the untracked conntrack.
>
> Yes, it was my idea, with a per_cpu untracked conntrack.
>
> I'll submit a patch, thanks.
>
>
Here is first part, introducing IPS_UNTRACKED bit and various helpers to
abstract nf_conntrack_untracked access.
I'll cook second patch in a couple of hours for per_cpu conversion.
Thanks !
[PATCH nf-next-2.6] conntrack: IPS_UNTRACKED bit
NOTRACK makes all cpus share a cache line on nf_conntrack_untracked
twice per packet. This is bad for performance.
__read_mostly annotation is also a bad choice.
This patch introduces IPS_UNTRACKED bit so that we can use later a
per_cpu untrack structure more easily.
A new helper, nf_ct_untracked_get() returns a pointer to
nf_conntrack_untracked.
Another one, nf_ct_untracked_status_or() is used by nf_nat_init() to add
IPS_NAT_DONE_MASK bits to untracked status.
nf_ct_is_untracked() prototype is changed to work on a nf_conn pointer.
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
include/linux/netfilter/nf_conntrack_common.h | 4 ++++
include/net/netfilter/nf_conntrack.h | 12 +++++++++---
include/net/netfilter/nf_conntrack_core.h | 2 +-
net/ipv4/netfilter/nf_nat_core.c | 2 +-
net/ipv4/netfilter/nf_nat_standalone.c | 2 +-
net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c | 2 +-
net/netfilter/nf_conntrack_core.c | 11 ++++++++---
net/netfilter/nf_conntrack_netlink.c | 2 +-
net/netfilter/xt_CT.c | 4 ++--
net/netfilter/xt_NOTRACK.c | 2 +-
net/netfilter/xt_TEE.c | 4 ++--
net/netfilter/xt_cluster.c | 2 +-
net/netfilter/xt_conntrack.c | 11 ++++++-----
net/netfilter/xt_socket.c | 2 +-
net/netfilter/xt_state.c | 14 ++++++++------
15 files changed, 47 insertions(+), 29 deletions(-)
diff --git a/include/linux/netfilter/nf_conntrack_common.h b/include/linux/netfilter/nf_conntrack_common.h
index 14e6d32..1afd18c 100644
--- a/include/linux/netfilter/nf_conntrack_common.h
+++ b/include/linux/netfilter/nf_conntrack_common.h
@@ -76,6 +76,10 @@ enum ip_conntrack_status {
/* Conntrack is a template */
IPS_TEMPLATE_BIT = 11,
IPS_TEMPLATE = (1 << IPS_TEMPLATE_BIT),
+
+ /* Conntrack is a fake untracked entry */
+ IPS_UNTRACKED_BIT = 12,
+ IPS_UNTRACKED = (1 << IPS_UNTRACKED_BIT),
};
/* Connection tracking event types */
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
index bde095f..3bc38c7 100644
--- a/include/net/netfilter/nf_conntrack.h
+++ b/include/net/netfilter/nf_conntrack.h
@@ -261,7 +261,13 @@ extern s16 (*nf_ct_nat_offset)(const struct nf_conn *ct,
u32 seq);
/* Fake conntrack entry for untracked connections */
-extern struct nf_conn nf_conntrack_untracked;
+static inline struct nf_conn *nf_ct_untracked_get(void)
+{
+ extern struct nf_conn nf_conntrack_untracked;
+
+ return &nf_conntrack_untracked;
+}
+extern void nf_ct_untracked_status_or(unsigned long bits);
/* Iterate over all conntracks: if iter returns true, it's deleted. */
extern void
@@ -289,9 +295,9 @@ static inline int nf_ct_is_dying(struct nf_conn *ct)
return test_bit(IPS_DYING_BIT, &ct->status);
}
-static inline int nf_ct_is_untracked(const struct sk_buff *skb)
+static inline int nf_ct_is_untracked(const struct nf_conn *ct)
{
- return (skb->nfct == &nf_conntrack_untracked.ct_general);
+ return test_bit(IPS_UNTRACKED_BIT, &ct->status);
}
extern int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp);
diff --git a/include/net/netfilter/nf_conntrack_core.h b/include/net/netfilter/nf_conntrack_core.h
index 3d7524f..aced085 100644
--- a/include/net/netfilter/nf_conntrack_core.h
+++ b/include/net/netfilter/nf_conntrack_core.h
@@ -60,7 +60,7 @@ static inline int nf_conntrack_confirm(struct sk_buff *skb)
struct nf_conn *ct = (struct nf_conn *)skb->nfct;
int ret = NF_ACCEPT;
- if (ct && ct != &nf_conntrack_untracked) {
+ if (ct && !nf_ct_is_untracked(ct)) {
if (!nf_ct_is_confirmed(ct))
ret = __nf_conntrack_confirm(skb);
if (likely(ret == NF_ACCEPT))
diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c
index 4f8bddb..c7719b2 100644
--- a/net/ipv4/netfilter/nf_nat_core.c
+++ b/net/ipv4/netfilter/nf_nat_core.c
@@ -742,7 +742,7 @@ static int __init nf_nat_init(void)
spin_unlock_bh(&nf_nat_lock);
/* Initialize fake conntrack so that NAT will skip it */
- nf_conntrack_untracked.status |= IPS_NAT_DONE_MASK;
+ nf_ct_untracked_status_or(IPS_NAT_DONE_MASK);
l3proto = nf_ct_l3proto_find_get((u_int16_t)AF_INET);
diff --git a/net/ipv4/netfilter/nf_nat_standalone.c b/net/ipv4/netfilter/nf_nat_standalone.c
index beb2581..6723c68 100644
--- a/net/ipv4/netfilter/nf_nat_standalone.c
+++ b/net/ipv4/netfilter/nf_nat_standalone.c
@@ -98,7 +98,7 @@ nf_nat_fn(unsigned int hooknum,
return NF_ACCEPT;
/* Don't try to NAT if this packet is not conntracked */
- if (ct == &nf_conntrack_untracked)
+ if (nf_ct_is_untracked(ct))
return NF_ACCEPT;
nat = nfct_nat(ct);
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
index 9be8177..1df3c8b 100644
--- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
@@ -208,7 +208,7 @@ icmpv6_error(struct net *net, struct nf_conn *tmpl,
type = icmp6h->icmp6_type - 130;
if (type >= 0 && type < sizeof(noct_valid_new) &&
noct_valid_new[type]) {
- skb->nfct = &nf_conntrack_untracked.ct_general;
+ skb->nfct = &nf_ct_untracked_get()->ct_general;
skb->nfctinfo = IP_CT_NEW;
nf_conntrack_get(skb->nfct);
return NF_ACCEPT;
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index eeeb8bc..6c1da21 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -62,7 +62,7 @@ EXPORT_SYMBOL_GPL(nf_conntrack_htable_size);
unsigned int nf_conntrack_max __read_mostly;
EXPORT_SYMBOL_GPL(nf_conntrack_max);
-struct nf_conn nf_conntrack_untracked __read_mostly;
+struct nf_conn nf_conntrack_untracked;
EXPORT_SYMBOL_GPL(nf_conntrack_untracked);
static int nf_conntrack_hash_rnd_initted;
@@ -1321,6 +1321,12 @@ EXPORT_SYMBOL_GPL(nf_conntrack_set_hashsize);
module_param_call(hashsize, nf_conntrack_set_hashsize, param_get_uint,
&nf_conntrack_htable_size, 0600);
+void nf_ct_untracked_status_or(unsigned long bits)
+{
+ nf_conntrack_untracked.status |= bits;
+}
+EXPORT_SYMBOL_GPL(nf_ct_untracked_status_or);
+
static int nf_conntrack_init_init_net(void)
{
int max_factor = 8;
@@ -1368,8 +1374,7 @@ static int nf_conntrack_init_init_net(void)
#endif
atomic_set(&nf_conntrack_untracked.ct_general.use, 1);
/* - and look it like as a confirmed connection */
- set_bit(IPS_CONFIRMED_BIT, &nf_conntrack_untracked.status);
-
+ nf_ct_untracked_status_or(IPS_CONFIRMED | IPS_UNTRACKED);
return 0;
#ifdef CONFIG_NF_CONNTRACK_ZONES
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index c42ff6a..5bae1cd 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -480,7 +480,7 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item)
int err;
/* ignore our fake conntrack entry */
- if (ct == &nf_conntrack_untracked)
+ if (nf_ct_is_untracked(ct))
return 0;
if (events & (1 << IPCT_DESTROY)) {
diff --git a/net/netfilter/xt_CT.c b/net/netfilter/xt_CT.c
index 562bf32..0cb6053 100644
--- a/net/netfilter/xt_CT.c
+++ b/net/netfilter/xt_CT.c
@@ -67,7 +67,7 @@ static int xt_ct_tg_check(const struct xt_tgchk_param *par)
return -EINVAL;
if (info->flags & XT_CT_NOTRACK) {
- ct = &nf_conntrack_untracked;
+ ct = nf_ct_untracked_get();
atomic_inc(&ct->ct_general.use);
goto out;
}
@@ -132,7 +132,7 @@ static void xt_ct_tg_destroy(const struct xt_tgdtor_param *par)
struct nf_conn *ct = info->ct;
struct nf_conn_help *help;
- if (ct != &nf_conntrack_untracked) {
+ if (!nf_ct_is_untracked(ct)) {
help = nfct_help(ct);
if (help)
module_put(help->helper->me);
diff --git a/net/netfilter/xt_NOTRACK.c b/net/netfilter/xt_NOTRACK.c
index 512b912..9d78218 100644
--- a/net/netfilter/xt_NOTRACK.c
+++ b/net/netfilter/xt_NOTRACK.c
@@ -23,7 +23,7 @@ notrack_tg(struct sk_buff *skb, const struct xt_action_param *par)
If there is a real ct entry correspondig to this packet,
it'll hang aroun till timing out. We don't deal with it
for performance reasons. JK */
- skb->nfct = &nf_conntrack_untracked.ct_general;
+ skb->nfct = &nf_ct_untracked_get()->ct_general;
skb->nfctinfo = IP_CT_NEW;
nf_conntrack_get(skb->nfct);
diff --git a/net/netfilter/xt_TEE.c b/net/netfilter/xt_TEE.c
index 859d9fd..7a11826 100644
--- a/net/netfilter/xt_TEE.c
+++ b/net/netfilter/xt_TEE.c
@@ -104,7 +104,7 @@ tee_tg4(struct sk_buff *skb, const struct xt_action_param *par)
#ifdef WITH_CONNTRACK
/* Avoid counting cloned packets towards the original connection. */
nf_conntrack_put(skb->nfct);
- skb->nfct = &nf_conntrack_untracked.ct_general;
+ skb->nfct = &nf_ct_untracked_get()->ct_general;
skb->nfctinfo = IP_CT_NEW;
nf_conntrack_get(skb->nfct);
#endif
@@ -177,7 +177,7 @@ tee_tg6(struct sk_buff *skb, const struct xt_action_param *par)
#ifdef WITH_CONNTRACK
nf_conntrack_put(skb->nfct);
- skb->nfct = &nf_conntrack_untracked.ct_general;
+ skb->nfct = &nf_ct_untracked_get()->ct_general;
skb->nfctinfo = IP_CT_NEW;
nf_conntrack_get(skb->nfct);
#endif
diff --git a/net/netfilter/xt_cluster.c b/net/netfilter/xt_cluster.c
index 30b95a1..f4af1bf 100644
--- a/net/netfilter/xt_cluster.c
+++ b/net/netfilter/xt_cluster.c
@@ -120,7 +120,7 @@ xt_cluster_mt(const struct sk_buff *skb, struct xt_action_param *par)
if (ct == NULL)
return false;
- if (ct == &nf_conntrack_untracked)
+ if (nf_ct_is_untracked(ct))
return false;
if (ct->master)
diff --git a/net/netfilter/xt_conntrack.c b/net/netfilter/xt_conntrack.c
index 39681f1..e536710 100644
--- a/net/netfilter/xt_conntrack.c
+++ b/net/netfilter/xt_conntrack.c
@@ -123,11 +123,12 @@ conntrack_mt(const struct sk_buff *skb, struct xt_action_param *par,
ct = nf_ct_get(skb, &ctinfo);
- if (ct == &nf_conntrack_untracked)
- statebit = XT_CONNTRACK_STATE_UNTRACKED;
- else if (ct != NULL)
- statebit = XT_CONNTRACK_STATE_BIT(ctinfo);
- else
+ if (ct) {
+ if (nf_ct_is_untracked(ct))
+ statebit = XT_CONNTRACK_STATE_UNTRACKED;
+ else
+ statebit = XT_CONNTRACK_STATE_BIT(ctinfo);
+ } else
statebit = XT_CONNTRACK_STATE_INVALID;
if (info->match_flags & XT_CONNTRACK_STATE) {
diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c
index 3d54c23..1ca8990 100644
--- a/net/netfilter/xt_socket.c
+++ b/net/netfilter/xt_socket.c
@@ -127,7 +127,7 @@ socket_match(const struct sk_buff *skb, struct xt_action_param *par,
* reply packet of an established SNAT-ted connection. */
ct = nf_ct_get(skb, &ctinfo);
- if (ct && (ct != &nf_conntrack_untracked) &&
+ if (ct && !nf_ct_is_untracked(ct) &&
((iph->protocol != IPPROTO_ICMP &&
ctinfo == IP_CT_IS_REPLY + IP_CT_ESTABLISHED) ||
(iph->protocol == IPPROTO_ICMP &&
diff --git a/net/netfilter/xt_state.c b/net/netfilter/xt_state.c
index e12e053..a507922 100644
--- a/net/netfilter/xt_state.c
+++ b/net/netfilter/xt_state.c
@@ -26,14 +26,16 @@ state_mt(const struct sk_buff *skb, struct xt_action_param *par)
const struct xt_state_info *sinfo = par->matchinfo;
enum ip_conntrack_info ctinfo;
unsigned int statebit;
+ struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
- if (nf_ct_is_untracked(skb))
- statebit = XT_STATE_UNTRACKED;
- else if (!nf_ct_get(skb, &ctinfo))
+ if (!ct)
statebit = XT_STATE_INVALID;
- else
- statebit = XT_STATE_BIT(ctinfo);
-
+ else {
+ if (nf_ct_is_untracked(ct))
+ statebit = XT_STATE_UNTRACKED;
+ else
+ statebit = XT_STATE_BIT(ctinfo);
+ }
return (sinfo->statemask & statebit);
}
^ permalink raw reply related
* Re: [PATCH] [ath5k][leds] Ability to disable leds support. If leds support enabled do not force mac802.11 leds layer selection.
From: Pavel Roskin @ 2010-06-04 16:22 UTC (permalink / raw)
To: Dmytro Milinevskyy
Cc: ath5k-devel, Jiri Slaby, Nick Kossifidis, Luis R. Rodriguez,
Bob Copeland, John W. Linville, GeunSik Lim, Greg Kroah-Hartman,
Lukas Turek, Mark Hindley, Johannes Berg, Jiri Kosina, Kalle Valo,
Keng-Yu Lin, Luca Verdesca, Shahar Or, linux-wireless, netdev,
linux-kernel
In-Reply-To: <4c0902ef.0a41df0a.6c86.2df0@mx.google.com>
On Fri, 2010-06-04 at 16:43 +0300, Dmytro Milinevskyy wrote:
> Hi!
>
> Here is the patch to disable ath5k leds support on build stage.
> However if the leds support was enabled do not force selection of 802.11 leds layer.
> Depency on LEDS_CLASS is kept.
>
> Suggestion given by Pavel Roskin and Bob Copeland applied.
It's great that you did it. The patch is much clearer now. That makes
smaller issues visible. Please don't be discouraged by the criticism,
you are on the right track.
First of all, your patch doesn't apply cleanly to the current
wireless-testing because of formatting changes in Makefile. Please
update.
> +config ATH5K_LEDS
> + tristate "Atheros 5xxx wireless cards LEDs support"
> + depends on ATH5K
> + select NEW_LEDS
> + select LEDS_CLASS
> + ---help---
> + Atheros 5xxx LED support.
"tristate" is wrong here. "tristate" would allow users select "m",
which is wrong, since LED support is not a separate module. I think you
want "bool" here.
> +#ifdef CONFIG_ATH5K_LEDS
> /*
> * State for LED triggers
> */
> @@ -95,6 +96,7 @@ struct ath5k_led
> struct ath5k_softc *sc; /* driver state */
> struct led_classdev led_dev; /* led classdev */
> };
> +#endif
This shouldn't be needed. I'll rather see a structure that is not used
in some cases than an extra pair of preprocessor conditionals.
> diff --git a/drivers/net/wireless/ath/ath5k/gpio.c b/drivers/net/wireless/ath/ath5k/gpio.c
> index 64a27e7..9e757b3 100644
> --- a/drivers/net/wireless/ath/ath5k/gpio.c
> +++ b/drivers/net/wireless/ath/ath5k/gpio.c
> @@ -25,6 +25,7 @@
> #include "debug.h"
> #include "base.h"
>
> +#ifdef CONFIG_ATH5K_LEDS
> /*
> * Set led state
> */
> @@ -76,6 +77,7 @@ void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state)
> else
> AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, led_5210);
> }
> +#endif
I would just move that function to led.c (and don't forget to include
reg.h). The Makefile should take care of the rest.
--
Regards,
Pavel Roskin
^ permalink raw reply
* Re: [2.6.35-rc1] page alloc failure order:1, mode:0x4020
From: Michael Guntsche @ 2010-06-04 16:16 UTC (permalink / raw)
To: Eric Dumazet; +Cc: linux-kernel, netdev
In-Reply-To: <1275656014.2482.169.camel@edumazet-laptop>
On 2010.06.04 14:53:34 , Eric Dumazet wrote:
> order-1 allocations are unfortunate, since this hardware should use
> order-0 ones if possible, and it seems it was its goal.
>
> 3872 (0xF20) comes from
<snip>
>
> 1) Maybe rx_bufsize should not include the roundup() since
> ath_rxbuf_alloc() also do an alignment adjustment ?
>
> 2) We should try to reduce skb_shared_info by four bytes.
>
> Could you try this patch ?
>
>
> We make sure rx_bufsize + various overhead <= PAGE_SIZE
> But I am not sure its legal for the hardware...
I applied the patch recompiled and run it on the routerboard, trying
to trigger the bug again.
Kind regards,
Michael
^ permalink raw reply
* Re: [stable] [PATCH] virtio_net: indicate oom when addbuf returns failure
From: Greg KH @ 2010-06-04 16:05 UTC (permalink / raw)
To: Rusty Russell
Cc: stable, Herbert Xu, Michael S. Tsirkin, netdev, Bruce Rogers
In-Reply-To: <201006041028.56798.rusty@rustcorp.com.au>
On Fri, Jun 04, 2010 at 10:28:56AM +0930, Rusty Russell wrote:
> This patch is a subset of an already upstream patch, but this portion
> is useful in earlier releases.
What is the git commit id of that upstream patch?
thanks,
greg k-h
^ permalink raw reply
* Re: [Patch] infiniband: check local reserved ports
From: Roland Dreier @ 2010-06-04 16:04 UTC (permalink / raw)
To: Cong Wang
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA, Tetsuo Handa,
davem-fT/PcQaiUtIeIZ0/mPfg9Q, linux-rdma-u79uwXL29TY76Z2rM5mHXA,
sean.hefty-ral2JQCrhuEAvxtiuMwx3w
In-Reply-To: <4C085C9A.30506-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
> > Should this inet_is_reserved_local_port() test apply to all the "port
> > spaces" that this code is handling? I honestly am ignorant of the
> > intended semantics of the new local_reserved_ports stuff, hence my question.
> Yes, but I only found this case, is there any else?
My question was more in the other direction: should this test apply to
all the "port spaces" handled here? From looking at the code, it
appears the answer is yes -- it seems that putting a port in
local_reserved_ports reserves that port for IPv4 and IPv6, UDP, TCP,
SCTP, DCCP, everything, so we should probably reserve all RDMA CM ports too.
--
Roland Dreier <rolandd-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org> || For corporate legal information go to:
http://www.cisco.com/web/about/doing_business/legal/cri/index.html
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" 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
* [PATCH] act_mirred: don't clone skb when skb isn't shared
From: Changli Gao @ 2010-06-04 13:43 UTC (permalink / raw)
To: Jamal Hadi Salim; +Cc: David S. Miller, netdev, Changli Gao
don't clone skb when skb isn't shared
When the tcf_action is TC_ACT_STOLEN, and the skb isn't shared, we don't need
to clone a new skb. As the skb will be freed after this function returns, we
can use it freely once we get a reference to it.
Signed-off-by: Changli Gao <xiaosuo@gmail.com>
----
net/sched/act_mirred.c | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c
index c0b6863..79d4318 100644
--- a/net/sched/act_mirred.c
+++ b/net/sched/act_mirred.c
@@ -169,13 +169,20 @@ static int tcf_mirred(struct sk_buff *skb, struct tc_action *a,
goto out;
}
- skb2 = skb_act_clone(skb, GFP_ATOMIC);
- if (skb2 == NULL)
- goto out;
+ at = G_TC_AT(skb->tc_verd);
+ if (m->tcf_action == TC_ACT_STOLEN && !skb_shared(skb)) {
+ skb2 = skb_get(skb);
+ skb2->tc_verd = SET_TC_VERD(skb2->tc_verd, 0);
+ skb2->tc_verd = CLR_TC_OK2MUNGE(skb2->tc_verd);
+ skb2->tc_verd = CLR_TC_MUNGED(skb2->tc_verd);
+ } else {
+ skb2 = skb_act_clone(skb, GFP_ATOMIC);
+ if (skb2 == NULL)
+ goto out;
+ }
m->tcf_bstats.bytes += qdisc_pkt_len(skb2);
m->tcf_bstats.packets++;
- at = G_TC_AT(skb->tc_verd);
if (!(at & AT_EGRESS)) {
if (m->tcfm_ok_push)
skb_push(skb2, skb2->dev->hard_header_len);
@@ -185,8 +192,8 @@ static int tcf_mirred(struct sk_buff *skb, struct tc_action *a,
if (m->tcfm_eaction != TCA_EGRESS_MIRROR)
skb2->tc_verd = SET_TC_FROM(skb2->tc_verd, at);
- skb2->dev = dev;
skb2->skb_iif = skb->dev->ifindex;
+ skb2->dev = dev;
dev_queue_xmit(skb2);
err = 0;
^ permalink raw reply related
* Re: [PATCH] rps: tcp: fix rps_sock_flow_table table updates
From: Tom Herbert @ 2010-06-04 15:15 UTC (permalink / raw)
To: David Miller; +Cc: eric.dumazet, netdev
In-Reply-To: <20100603.200721.59663365.davem@davemloft.net>
Looks good to me. Thanks Eric.
Tom
On Thu, Jun 3, 2010 at 8:07 PM, David Miller <davem@davemloft.net> wrote:
>
> From: Eric Dumazet <eric.dumazet@gmail.com>
> Date: Thu, 03 Jun 2010 21:03:58 +0200
>
> > I believe a moderate SYN flood attack can corrupt RFS flow table
> > (rps_sock_flow_table), making RPS/RFS much less effective.
> ...
> > This patch moves sock_rps_save_rxhash() to a sock locked section,
> > and only for non LISTEN sockets.
>
> This looks good to me.
>
> Tom, please review.
^ permalink raw reply
* Re: 200 millisecond timeouts in TCP
From: Satoru SATOH @ 2010-06-04 15:02 UTC (permalink / raw)
To: Ryousei Takano; +Cc: Ivan Novick, netdev
In-Reply-To: <AANLkTilsYS8P2VqATmasXjjdhjPMMZznIHBByXc1i8cU@mail.gmail.com>
It's possible to tune the RTO min value (rto_min) per route since
2.6.23+. (see also the manual of iproute2, ip(8) )
- satoru
On Fri, Jun 04, 2010 at 03:58:57PM +0900, Ryousei Takano wrote:
> On Fri, Jun 4, 2010 at 7:37 AM, Ivan Novick <novickivan@gmail.com> wrote:
> > Hello,
> >
> > Using tcpdump and systemtap I am seeing that sometimes retransmission
> > of data is sent after waiting 200 milliseconds. However sometimes
> > retransmissions happen quicker.
> >
> > Is there a specifc event that causes these 200 milisec delays to kick
> > in? Are those events identifiable in netstat -s output?
> >
> > Also do you know if the timeout numbers for TCP are configurable parameters?
> >
> The minimum RTO value is fixed to 200 ms. It is useful to make the min/max
> RTO values tunable. For example, reducing the minimum RTO value is effective
> for TCP incast problem [1]. Of course, it may occur spurious retransmissions.
>
> [1] Vijay Vasudevan, et al, Safe and Effective Fine-grained TCP Retransmissions
> for Datacenter Communication, SIGCOMM2009
>
> In Solaris, there are two tunable parameters: tcp_rexmit_interval_min/max.
>
> Do you have plan to introduce sysctl parameters like these to the Linux.
>
> Thanks,
> Ryousei
^ permalink raw reply
* Re: [Patch 2/2] mlx4: add dynamic LRO disable support
From: Ben Hutchings @ 2010-06-04 14:25 UTC (permalink / raw)
To: Cong Wang; +Cc: netdev, herbert.xu, nhorman, sgruszka, davem
In-Reply-To: <4C085D45.6040001@redhat.com>
On Fri, 2010-06-04 at 09:56 +0800, Cong Wang wrote:
> On 06/03/10 20:37, Ben Hutchings wrote:
> > On Wed, 2010-06-02 at 23:39 -0400, Amerigo Wang wrote:
> >> This patch adds dynamic LRO diable support for mlx4 net driver.
> >> It also fixes a bug of mlx4, which checks NETIF_F_LRO flag in rx
> >> path without rtnl lock.
> > [...]
> >
> > Is that flag test actually unsafe - and if so, how is testing num_lro
> > any better? Perhaps access to net_device::features should be wrapped
> > with ACCESS_ONCE() to ensure that reads and writes are atomic.
> >
>
> At least, I don't find there is any race with 'num_lro', thus
> no lock is needed.
In both cases there is a race condition but it is harmless so long as
the read and the write are atomic. There is a general assumption in
networking code that this is the case for int and long. Personally I
would prefer to see this made explicit using ACCESS_ONCE(), but I don't
see any specific problem in mlx4 (not that I'm familiar with this driver
either).
Now that I look at the patch again, I see you're using a static (i.e.
global) variable to 'back up' the non-zero (enabled) value of num_lro.
This is introducing a bug! The correct value is apparently set in
mlx4_en_get_profile(); you would need to replicate that.
Ben.
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply
* Is CONFIG_IP_VS_IPV6 still/really dangerous?
From: Ferenc Wagner @ 2010-06-04 13:56 UTC (permalink / raw)
To: Julius Volz; +Cc: netdev
Hi,
In commit fab0de02fb0da83b90cec7fce4294747d86d5c6f CONFIG_IP_VS_IPV6 is
described as:
Add IPv6 support to IPVS. This is incomplete and might be dangerous.
I agree its implementation is incomplete. But I wonder if it's really
dangerous in the sense that generic distribution kernels shouldn't
enable it, because it can break unrelated (eg. IPv4 IPVS) functionality.
What does that warning mean today? Isn't it out of date?
--
Thanks,
Feri.
^ permalink raw reply
* Re: [PATCH] [ath5k][leds] Ability to disable leds support. If leds support enabled do not force mac802.11 leds layer selection.
From: John W. Linville @ 2010-06-04 14:09 UTC (permalink / raw)
To: Dmytro Milinevskyy
Cc: Jiri Slaby, Nick Kossifidis, Luis R. Rodriguez, Bob Copeland,
GeunSik Lim, Greg Kroah-Hartman, Lukas Turek, Mark Hindley,
Johannes Berg, Jiri Kosina, Kalle Valo, Keng-Yu Lin,
Luca Verdesca, Shahar Or, linux-wireless, netdev, linux-kernel
In-Reply-To: <4c0804e2.0c3ddf0a.2771.10f7@mx.google.com>
On Thu, Jun 03, 2010 at 10:39:30PM +0300, Dmytro Milinevskyy wrote:
> Hi!
>
> Here is the patch to disable ath5k leds support on build stage.
> However if the leds support was enabled do not force selection of 802.11 leds layer.
> Depency on LEDS_CLASS is kept.
>
> Suggestion given by Pavel Roskin and Bob Copeland applied.
>
> Regards,
>
> --Dima
Needs at least a Signed-off-by line, and preferrably a changelog that
explains what the patch is doing and (especially) why it is necessary.
John
--
John W. Linville Someday the world will need a hero, and you
linville@tuxdriver.com might be all we have. Be ready.
^ permalink raw reply
* Re: Is CONFIG_IP_VS_IPV6 still/really dangerous?
From: Julius Volz @ 2010-06-04 14:14 UTC (permalink / raw)
To: Ferenc Wagner; +Cc: netdev, robert.gallagher
In-Reply-To: <87631y3nr3.fsf@tac.ki.iif.hu>
Hi Ferenc,
On Fri, Jun 4, 2010 at 3:56 PM, Ferenc Wagner <wferi@niif.hu> wrote:
> Hi,
>
> In commit fab0de02fb0da83b90cec7fce4294747d86d5c6f CONFIG_IP_VS_IPV6 is
> described as:
>
> Add IPv6 support to IPVS. This is incomplete and might be dangerous.
>
> I agree its implementation is incomplete. But I wonder if it's really
> dangerous in the sense that generic distribution kernels shouldn't
> enable it, because it can break unrelated (eg. IPv4 IPVS) functionality.
>
> What does that warning mean today? Isn't it out of date?
I wrote the IPv6 support back in the day, but never used it
large-scale. Rob Gallagher from HEAnet was doing some bigger
experiments with it, but I'm not sure how far it went. CCing him.
There are probably some other people out there that have tested it
extensively. Maybe try the lvs-users and lvs-devel mailing lists?
http://www.linuxvirtualserver.org/mailing.html
Julius
--
Julius Volz - Site Reliability Engineer
Google Switzerland GmbH - Identification No.: CH-020.4.028.116-1
^ permalink raw reply
* Re: still having r8169 woes with XID 18000000
From: Phil Sutter @ 2010-06-04 13:43 UTC (permalink / raw)
To: Timo Teräs; +Cc: netdev, françois romieu
In-Reply-To: <4C08F953.1050800@iki.fi>
Hi,
On Fri, Jun 04, 2010 at 04:02:11PM +0300, Timo Teräs wrote:
> > Comparing r8169-6.013 with it's predecessor 6.012, you'll find a newly
> > enabled function rtl8169_phy_power_up() as well as some more invocations
> > of rtl8169_phy_power_down().
> >
> > This is probably the solution to these (at least in our case) very
> > sporadic, but highly annoying, problems. In fact, when our NIC didn't
> > detect any link, it needed a full power-cycle (no success with
> > reset-button), so almost not workaroundable.
>
> Sounds very similar to the problem I have. Thanks for the pointers!
>
> It looks like the r8169 driver does have phy power up code in it, but
> it's only executed for specific versions of the chip. Realtek driver
> seems to do it unconditionally.
Hmm. I actually never looked at the corresponding parts of the
in-tree-driver, but that would have definitely been the next step in
order to fix it.
> The check seems to be:
> if ((tp->mac_version == RTL_GIGA_MAC_VER_11) ||
> (tp->mac_version == RTL_GIGA_MAC_VER_12) ||
> (tp->mac_version >= RTL_GIGA_MAC_VER_17)) {
>
> I wonder if I should just add my mac version there (_VER_05) and test if
> it'll make it better.
Surely worth a try. On the other hand, looking at the sheer mass of
problem reports regarding this driver, making it worse is rather hard to
do I guess. :)
(Good night and) good luck, Phil
^ permalink raw reply
* [PATCH] [ath5k][leds] Ability to disable leds support. If leds support enabled do not force mac802.11 leds layer selection.
From: Dmytro Milinevskyy @ 2010-06-04 13:43 UTC (permalink / raw)
To: ath5k-devel
Cc: Jiri Slaby, Nick Kossifidis, Luis R. Rodriguez, Bob Copeland,
John W. Linville, GeunSik Lim, Greg Kroah-Hartman, Lukas Turek,
Mark Hindley, Johannes Berg, Jiri Kosina, Kalle Valo, Keng-Yu Lin,
Luca Verdesca, Shahar Or, linux-wireless, netdev, linux-kernel
Hi!
Here is the patch to disable ath5k leds support on build stage.
However if the leds support was enabled do not force selection of 802.11 leds layer.
Depency on LEDS_CLASS is kept.
Suggestion given by Pavel Roskin and Bob Copeland applied.
Regards,
--Dima
---
drivers/net/wireless/ath/ath5k/Kconfig | 12 +++++++++---
drivers/net/wireless/ath/ath5k/Makefile | 2 +-
drivers/net/wireless/ath/ath5k/ath5k.h | 22 ++++++++++++++++++++++
drivers/net/wireless/ath/ath5k/base.h | 13 +++++++++----
drivers/net/wireless/ath/ath5k/gpio.c | 2 ++
5 files changed, 43 insertions(+), 8 deletions(-)
diff --git a/drivers/net/wireless/ath/ath5k/Kconfig b/drivers/net/wireless/ath/ath5k/Kconfig
index eb83b7b..29f4572 100644
--- a/drivers/net/wireless/ath/ath5k/Kconfig
+++ b/drivers/net/wireless/ath/ath5k/Kconfig
@@ -1,9 +1,6 @@
config ATH5K
tristate "Atheros 5xxx wireless cards support"
depends on PCI && MAC80211
- select MAC80211_LEDS
- select LEDS_CLASS
- select NEW_LEDS
---help---
This module adds support for wireless adapters based on
Atheros 5xxx chipset.
@@ -18,6 +15,15 @@ config ATH5K
If you choose to build a module, it'll be called ath5k. Say M if
unsure.
+
+config ATH5K_LEDS
+ tristate "Atheros 5xxx wireless cards LEDs support"
+ depends on ATH5K
+ select NEW_LEDS
+ select LEDS_CLASS
+ ---help---
+ Atheros 5xxx LED support.
+
config ATH5K_DEBUG
bool "Atheros 5xxx debugging"
depends on ATH5K
diff --git a/drivers/net/wireless/ath/ath5k/Makefile b/drivers/net/wireless/ath/ath5k/Makefile
index cc09595..6d552dd 100644
--- a/drivers/net/wireless/ath/ath5k/Makefile
+++ b/drivers/net/wireless/ath/ath5k/Makefile
@@ -10,8 +10,8 @@ ath5k-y += phy.o
ath5k-y += reset.o
ath5k-y += attach.o
ath5k-y += base.o
-ath5k-y += led.o
ath5k-y += rfkill.o
ath5k-y += ani.o
ath5k-$(CONFIG_ATH5K_DEBUG) += debug.o
+ath5k-$(CONFIG_ATH5K_LEDS) += led.o
obj-$(CONFIG_ATH5K) += ath5k.o
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h
index 2785946..bb7e09a 100644
--- a/drivers/net/wireless/ath/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath/ath5k/ath5k.h
@@ -1148,11 +1148,27 @@ struct ath5k_hw {
int ath5k_hw_attach(struct ath5k_softc *sc);
void ath5k_hw_detach(struct ath5k_hw *ah);
+#ifdef CONFIG_ATH5K_LEDS
/* LED functions */
int ath5k_init_leds(struct ath5k_softc *sc);
void ath5k_led_enable(struct ath5k_softc *sc);
void ath5k_led_off(struct ath5k_softc *sc);
void ath5k_unregister_leds(struct ath5k_softc *sc);
+#else
+static inline int ath5k_init_leds(struct ath5k_softc *sc)
+{
+ return 0;
+}
+static inline void ath5k_led_enable(struct ath5k_softc *sc)
+{
+}
+static inline void ath5k_led_off(struct ath5k_softc *sc)
+{
+}
+static inline void ath5k_unregister_leds(struct ath5k_softc *sc)
+{
+}
+#endif
/* Reset Functions */
int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial);
@@ -1233,7 +1249,13 @@ int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time);
int ath5k_hw_init_desc_functions(struct ath5k_hw *ah);
/* GPIO Functions */
+#ifdef CONFIG_ATH5K_LEDS
void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state);
+#else
+static inline void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state)
+{
+}
+#endif
int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio);
int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio);
u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio);
diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h
index 56221bc..97b26c1 100644
--- a/drivers/net/wireless/ath/ath5k/base.h
+++ b/drivers/net/wireless/ath/ath5k/base.h
@@ -86,6 +86,7 @@ struct ath5k_txq {
#define ATH5K_LED_MAX_NAME_LEN 31
+#ifdef CONFIG_ATH5K_LEDS
/*
* State for LED triggers
*/
@@ -95,6 +96,7 @@ struct ath5k_led
struct ath5k_softc *sc; /* driver state */
struct led_classdev led_dev; /* led classdev */
};
+#endif
/* Rfkill */
struct ath5k_rfkill {
@@ -186,9 +188,6 @@ struct ath5k_softc {
u8 bssidmask[ETH_ALEN];
- unsigned int led_pin, /* GPIO pin for driving LED */
- led_on; /* pin setting for LED on */
-
struct tasklet_struct restq; /* reset tasklet */
unsigned int rxbufsize; /* rx size based on mtu */
@@ -196,7 +195,6 @@ struct ath5k_softc {
spinlock_t rxbuflock;
u32 *rxlink; /* link ptr in last RX desc */
struct tasklet_struct rxtq; /* rx intr tasklet */
- struct ath5k_led rx_led; /* rx led */
struct list_head txbuf; /* transmit buffer */
spinlock_t txbuflock;
@@ -204,7 +202,14 @@ struct ath5k_softc {
struct ath5k_txq txqs[AR5K_NUM_TX_QUEUES]; /* tx queues */
struct ath5k_txq *txq; /* main tx queue */
struct tasklet_struct txtq; /* tx intr tasklet */
+
+
+#ifdef CONFIG_ATH5K_LEDS
+ unsigned int led_pin, /* GPIO pin for driving LED */
+ led_on; /* pin setting for LED on */
+ struct ath5k_led rx_led; /* rx led */
struct ath5k_led tx_led; /* tx led */
+#endif
struct ath5k_rfkill rf_kill;
diff --git a/drivers/net/wireless/ath/ath5k/gpio.c b/drivers/net/wireless/ath/ath5k/gpio.c
index 64a27e7..9e757b3 100644
--- a/drivers/net/wireless/ath/ath5k/gpio.c
+++ b/drivers/net/wireless/ath/ath5k/gpio.c
@@ -25,6 +25,7 @@
#include "debug.h"
#include "base.h"
+#ifdef CONFIG_ATH5K_LEDS
/*
* Set led state
*/
@@ -76,6 +77,7 @@ void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state)
else
AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, led_5210);
}
+#endif
/*
* Set GPIO inputs
--
1.7.1
^ permalink raw reply related
* [PATCH] htb: remove two unnecessary assignments
From: Changli Gao @ 2010-06-04 11:33 UTC (permalink / raw)
To: Jamal Hadi Salim; +Cc: David S. Miller, netdev, Changli Gao
remove two unnecessary assignments
we don't need to assign NULL when initialize structure objects.
Signed-off-by: Changli Gao <xiaosuo@gmail.com>
----
net/sched/sch_htb.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index 0b52b8d..4be8d04 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -1550,7 +1550,6 @@ static const struct Qdisc_class_ops htb_class_ops = {
};
static struct Qdisc_ops htb_qdisc_ops __read_mostly = {
- .next = NULL,
.cl_ops = &htb_class_ops,
.id = "htb",
.priv_size = sizeof(struct htb_sched),
@@ -1561,7 +1560,6 @@ static struct Qdisc_ops htb_qdisc_ops __read_mostly = {
.init = htb_init,
.reset = htb_reset,
.destroy = htb_destroy,
- .change = NULL /* htb_change */,
.dump = htb_dump,
.owner = THIS_MODULE,
};
^ permalink raw reply related
* Re: net-next Build error in qlogic driver from randconfig.
From: andrew hendry @ 2010-06-04 13:23 UTC (permalink / raw)
To: netdev; +Cc: Amit Kumar Salecha, Anirban Chakraborty
In-Reply-To: <1275657622.8635.13.camel@jaunty>
sorry ignore, i see it just got fixed.
On Fri, Jun 4, 2010 at 11:20 PM, Andrew Hendry <andrew.hendry@gmail.com> wrote:
>
> net-next currently gives a build error from a randconfig.
> # CONFIG_INET is not set
> CONFIG_QLCNIC=m
>
> ERROR: "qlcnicvf_set_ilb_mode" [drivers/net/qlcnic/qlcnic.ko] undefined!
> ERROR: "qlcnicvf_config_bridged_mode" [drivers/net/qlcnic/qlcnic.ko] undefined!
> ERROR: "qlcnicvf_config_led" [drivers/net/qlcnic/qlcnic.ko] undefined!
> ERROR: "qlcnicvf_clear_ilb_mode" [drivers/net/qlcnic/qlcnic.ko] undefined!
> ERROR: "qlcnicvf_start_firmware" [drivers/net/qlcnic/qlcnic.ko] undefined!
> make[1]: *** [__modpost] Error 1
> make: *** [modules] Error 2
> make: *** Waiting for unfinished jobs....
>
>
>
^ permalink raw reply
* net-next Build error in qlogic driver from randconfig.
From: Andrew Hendry @ 2010-06-04 13:20 UTC (permalink / raw)
To: netdev; +Cc: Amit Kumar Salecha, Anirban Chakraborty
net-next currently gives a build error from a randconfig.
# CONFIG_INET is not set
CONFIG_QLCNIC=m
ERROR: "qlcnicvf_set_ilb_mode" [drivers/net/qlcnic/qlcnic.ko] undefined!
ERROR: "qlcnicvf_config_bridged_mode" [drivers/net/qlcnic/qlcnic.ko] undefined!
ERROR: "qlcnicvf_config_led" [drivers/net/qlcnic/qlcnic.ko] undefined!
ERROR: "qlcnicvf_clear_ilb_mode" [drivers/net/qlcnic/qlcnic.ko] undefined!
ERROR: "qlcnicvf_start_firmware" [drivers/net/qlcnic/qlcnic.ko] undefined!
make[1]: *** [__modpost] Error 1
make: *** [modules] Error 2
make: *** Waiting for unfinished jobs....
^ permalink raw reply
* Re: [PATCH net-next-2.6] net sched: make pedit check for clones instead
From: Herbert Xu @ 2010-06-04 13:05 UTC (permalink / raw)
To: jamal; +Cc: davem, Jiri Pirko, netdev
In-Reply-To: <1275655386.3445.62.camel@bigi>
On Fri, Jun 04, 2010 at 08:43:06AM -0400, jamal wrote:
> And here's the second one. I noticed Changli's changes are not yet in
> net-next. I will wait for that change to propagate and then send the
> fix to pedit that i discussed with Herbert.
Thanks Jamal!
BTW, I think this patch should go in first (before the one that
removes the OK2MUNGE setting) to be on the safe side.
Cheers,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ 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