Here is the driver core patchset for the 2.6.31 merge window
It consists of a variety of different things:
- devtmpfs. This has been discussed a lot, is tiny,
self-contained, and has been acked by all of the major distros
as something they will use, and it has been used in the SuSE
kernels for quite some time now.
- driver core cleanups
- debugfs documentation updates
- uio drivers
- hplio driver updates (for some reason they came in through
this tree due to procedural issues, they are self-contained).
- other minor stuff.
Please pull from:
master.kernel.org:/pub/scm/linux/kernel/git/gregkh/driver-core-2.6.git/
All of these patches have been in the linux-next and mm trees for a
long time.
The patches will be sent as a follow-on to this message to lkml for people
to see.
thanks,
greg k-h
------------
Documentation/DocBook/uio-howto.tmpl | 163 ++++++++++++
Documentation/trace/events.txt | 24 +-
MAINTAINERS | 7 +
block/genhd.c | 2 +-
drivers/base/Kconfig | 25 ++
drivers/base/Makefile | 2 +
drivers/base/base.h | 13 +-
drivers/base/bus.c | 23 +-
drivers/base/class.c | 87 +++++++
drivers/base/core.c | 29 ++-
drivers/base/dd.c | 31 +++-
drivers/base/devtmpfs.c | 367 ++++++++++++++++++++++++++++
{kernel => drivers/base}/dma-coherent.c | 0
drivers/base/driver.c | 4 +-
drivers/base/init.c | 1 +
drivers/base/platform.c | 8 +-
drivers/block/cciss.c | 2 +-
drivers/block/pktcdvd.c | 2 +-
drivers/char/mem.c | 82 +++----
drivers/firewire/core-device.c | 2 +-
drivers/firmware/dmi-id.c | 2 +-
drivers/infiniband/hw/ehca/ehca_main.c | 2 +-
drivers/infiniband/hw/ipath/ipath_kernel.h | 2 +-
drivers/infiniband/hw/ipath/ipath_sysfs.c | 2 +-
drivers/input/input.c | 2 +-
drivers/misc/enclosure.c | 4 +-
drivers/misc/hpilo.c | 290 +++++++++++++++-------
drivers/misc/hpilo.h | 8 +-
drivers/mmc/core/mmc.c | 2 +-
drivers/mmc/core/sd.c | 2 +-
drivers/mtd/mtdcore.c | 2 +-
drivers/net/wireless/iwmc3200wifi/Kconfig | 6 +-
drivers/s390/cio/css.c | 2 +-
drivers/s390/cio/device.c | 2 +-
drivers/s390/net/netiucv.c | 2 +-
drivers/scsi/scsi_priv.h | 2 +-
drivers/scsi/scsi_sysfs.c | 4 +-
drivers/uio/Kconfig | 15 +-
drivers/uio/Makefile | 1 +
drivers/uio/uio_pci_generic.c | 207 ++++++++++++++++
drivers/usb/core/endpoint.c | 2 +-
drivers/usb/core/sysfs.c | 4 +-
drivers/usb/core/usb.h | 4 +-
drivers/usb/host/uhci-hcd.c | 2 +-
drivers/uwb/lc-dev.c | 2 +-
fs/partitions/check.c | 2 +-
include/linux/attribute_container.h | 2 +-
include/linux/device.h | 45 +++--
include/linux/netdevice.h | 2 +-
include/linux/pci_regs.h | 1 +
include/linux/shmem_fs.h | 3 +
include/linux/transport_class.h | 2 +-
init/do_mounts.c | 2 +-
init/main.c | 2 +
kernel/Makefile | 1 -
mm/shmem.c | 9 +-
net/bluetooth/hci_sysfs.c | 4 +-
net/core/net-sysfs.c | 2 +-
samples/trace_events/trace-events-sample.h | 2 +-
59 files changed, 1287 insertions(+), 239 deletions(-)
create mode 100644 drivers/base/devtmpfs.c
rename {kernel => drivers/base}/dma-coherent.c (100%)
create mode 100644 drivers/uio/uio_pci_generic.c
---------------
Alan Stern (1):
Driver core: add new device to bus's list before probing
Andrew Morton (1):
driver core: platform_device_add_data(): use kmemdup()
Daniel Mack (1):
UIO: remove 'default n' from Kconfig
David Altobelli (3):
hpilo: staging for interrupt handling
hpilo: add interrupt handler
hpilo: add poll f_op
David Brownell (1):
driver model: constify attribute groups
GeunSik Lim (5):
debugfs: Fix mount directory of debugfs by default in events.txt
debugfs: Change debuhgfs directory of trace-events-sample.h
debugfs: Change debugfs directory of IWMC3200
debugfs: Modified default dir of debugfs for debugging UHCI.
debugfs: Modify default debugfs directory for debugging pktcdvd.
Greg Kroah-Hartman (1):
Driver core: move dev_get/set_drvdata to drivers/base/dd.c
Jean Delvare (1):
Driver core: Add support for compatibility classes
Jin Dongming (1):
mem_class: fix bug
Kay Sievers (2):
mem_class: use minor as index instead of searching the array
Driver Core: devtmpfs - kernel-maintained tmpfs-based /dev
Mark Brown (1):
Driver core: Add accessor for device platform data
Michael S. Tsirkin (1):
uio: add generic driver for PCI 2.3 devices
Ming Lei (1):
driver-core: move dma-coherent.c from kernel to driver/base
From: Alan Stern <[email protected]>
This patch (as1271) affects when new devices get linked into their
bus's list of devices. Currently this happens after probing, and it
doesn't happen at all if probing fails. Clearly this is wrong,
because at that point quite a few symbolic links have already been
created in sysfs. We are committed to adding the device, so it should
be linked into the bus's list regardless.
In addition, this needs to happen before the uevent announcing the new
device gets issued. Otherwise user programs might try to access the
device before it has been added to the bus.
To fix both these problems, the patch moves the call to
klist_add_tail() forward from bus_attach_device() to bus_add_device().
Since bus_attach_device() now does nothing but probe for drivers, it
has been renamed to bus_probe_device(). And lastly, the kerneldoc is
updated.
Signed-off-by: Alan Stern <[email protected]>
CC: Kay Sievers <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
drivers/base/base.h | 2 +-
drivers/base/bus.c | 23 ++++++++++-------------
drivers/base/core.c | 2 +-
3 files changed, 12 insertions(+), 15 deletions(-)
diff --git a/drivers/base/base.h b/drivers/base/base.h
index b528145..1e52c12 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -104,7 +104,7 @@ extern int system_bus_init(void);
extern int cpu_dev_init(void);
extern int bus_add_device(struct device *dev);
-extern void bus_attach_device(struct device *dev);
+extern void bus_probe_device(struct device *dev);
extern void bus_remove_device(struct device *dev);
extern int bus_add_driver(struct device_driver *drv);
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 4b04a15..973bf2a 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -459,8 +459,9 @@ static inline void remove_deprecated_bus_links(struct device *dev) { }
* bus_add_device - add device to bus
* @dev: device being added
*
+ * - Add device's bus attributes.
+ * - Create links to device's bus.
* - Add the device to its bus's list of devices.
- * - Create link to device's bus.
*/
int bus_add_device(struct device *dev)
{
@@ -483,6 +484,7 @@ int bus_add_device(struct device *dev)
error = make_deprecated_bus_links(dev);
if (error)
goto out_deprecated;
+ klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices);
}
return 0;
@@ -498,24 +500,19 @@ out_put:
}
/**
- * bus_attach_device - add device to bus
- * @dev: device tried to attach to a driver
+ * bus_probe_device - probe drivers for a new device
+ * @dev: device to probe
*
- * - Add device to bus's list of devices.
- * - Try to attach to driver.
+ * - Automatically probe for a driver if the bus allows it.
*/
-void bus_attach_device(struct device *dev)
+void bus_probe_device(struct device *dev)
{
struct bus_type *bus = dev->bus;
- int ret = 0;
+ int ret;
- if (bus) {
- if (bus->p->drivers_autoprobe)
- ret = device_attach(dev);
+ if (bus && bus->p->drivers_autoprobe) {
+ ret = device_attach(dev);
WARN_ON(ret < 0);
- if (ret >= 0)
- klist_add_tail(&dev->p->knode_bus,
- &bus->p->klist_devices);
}
}
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 7ecb193..c34774d 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -945,7 +945,7 @@ int device_add(struct device *dev)
BUS_NOTIFY_ADD_DEVICE, dev);
kobject_uevent(&dev->kobj, KOBJ_ADD);
- bus_attach_device(dev);
+ bus_probe_device(dev);
if (parent)
klist_add_tail(&dev->p->knode_parent,
&parent->p->klist_children);
--
1.6.4.2
No one should directly access the driver_data field, so remove the field
and make it private. We dynamically create the private field now if it
is needed, to handle drivers that call get/set before they are
registered with the driver core.
Also update the copyright notices on these files while we are there.
Cc: Kay Sievers <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
drivers/base/base.h | 5 +++++
drivers/base/core.c | 20 ++++++++++++++------
drivers/base/dd.c | 31 +++++++++++++++++++++++++++++--
include/linux/device.h | 16 ++++------------
4 files changed, 52 insertions(+), 20 deletions(-)
diff --git a/drivers/base/base.h b/drivers/base/base.h
index 1e52c12..503d59c 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -70,6 +70,8 @@ struct class_private {
* @knode_parent - node in sibling list
* @knode_driver - node in driver list
* @knode_bus - node in bus list
+ * @driver_data - private pointer for driver specific info. Will turn into a
+ * list soon.
* @device - pointer back to the struct class that this structure is
* associated with.
*
@@ -80,6 +82,7 @@ struct device_private {
struct klist_node knode_parent;
struct klist_node knode_driver;
struct klist_node knode_bus;
+ void *driver_data;
struct device *device;
};
#define to_device_private_parent(obj) \
@@ -89,6 +92,8 @@ struct device_private {
#define to_device_private_bus(obj) \
container_of(obj, struct device_private, knode_bus)
+extern int device_private_init(struct device *dev);
+
/* initialisation functions */
extern int devices_init(void);
extern int buses_init(void);
diff --git a/drivers/base/core.c b/drivers/base/core.c
index c34774d..99dfe96 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -843,6 +843,17 @@ static void device_remove_sys_dev_entry(struct device *dev)
}
}
+int device_private_init(struct device *dev)
+{
+ dev->p = kzalloc(sizeof(*dev->p), GFP_KERNEL);
+ if (!dev->p)
+ return -ENOMEM;
+ dev->p->device = dev;
+ klist_init(&dev->p->klist_children, klist_children_get,
+ klist_children_put);
+ return 0;
+}
+
/**
* device_add - add device to device hierarchy.
* @dev: device.
@@ -868,14 +879,11 @@ int device_add(struct device *dev)
if (!dev)
goto done;
- dev->p = kzalloc(sizeof(*dev->p), GFP_KERNEL);
if (!dev->p) {
- error = -ENOMEM;
- goto done;
+ error = device_private_init(dev);
+ if (error)
+ goto done;
}
- dev->p->device = dev;
- klist_init(&dev->p->klist_children, klist_children_get,
- klist_children_put);
/*
* for statically allocated devices, which should all be converted
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 7b34b3a..979d159 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -11,8 +11,8 @@
*
* Copyright (c) 2002-5 Patrick Mochel
* Copyright (c) 2002-3 Open Source Development Labs
- * Copyright (c) 2007 Greg Kroah-Hartman <[email protected]>
- * Copyright (c) 2007 Novell Inc.
+ * Copyright (c) 2007-2009 Greg Kroah-Hartman <[email protected]>
+ * Copyright (c) 2007-2009 Novell Inc.
*
* This file is released under the GPLv2
*/
@@ -391,3 +391,30 @@ void driver_detach(struct device_driver *drv)
put_device(dev);
}
}
+
+/*
+ * These exports can't be _GPL due to .h files using this within them, and it
+ * might break something that was previously working...
+ */
+void *dev_get_drvdata(const struct device *dev)
+{
+ if (dev && dev->p)
+ return dev->p->driver_data;
+ return NULL;
+}
+EXPORT_SYMBOL(dev_get_drvdata);
+
+void dev_set_drvdata(struct device *dev, void *data)
+{
+ int error;
+
+ if (!dev)
+ return;
+ if (!dev->p) {
+ error = device_private_init(dev);
+ if (error)
+ return;
+ }
+ dev->p->driver_data = data;
+}
+EXPORT_SYMBOL(dev_set_drvdata);
diff --git a/include/linux/device.h b/include/linux/device.h
index a286429..c0bd230 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -2,7 +2,8 @@
* device.h - generic, centralized driver model
*
* Copyright (c) 2001-2003 Patrick Mochel <[email protected]>
- * Copyright (c) 2004-2007 Greg Kroah-Hartman <[email protected]>
+ * Copyright (c) 2004-2009 Greg Kroah-Hartman <[email protected]>
+ * Copyright (c) 2008-2009 Novell Inc.
*
* This file is released under the GPLv2
*
@@ -381,7 +382,6 @@ struct device {
struct bus_type *bus; /* type of bus device is on */
struct device_driver *driver; /* which driver has allocated this
device */
- void *driver_data; /* data private to the driver */
void *platform_data; /* Platform specific data, device
core doesn't touch it */
struct dev_pm_info power;
@@ -447,16 +447,6 @@ static inline void set_dev_node(struct device *dev, int node)
}
#endif
-static inline void *dev_get_drvdata(const struct device *dev)
-{
- return dev->driver_data;
-}
-
-static inline void dev_set_drvdata(struct device *dev, void *data)
-{
- dev->driver_data = data;
-}
-
static inline unsigned int dev_get_uevent_suppress(const struct device *dev)
{
return dev->kobj.uevent_suppress;
@@ -490,6 +480,8 @@ extern int device_rename(struct device *dev, char *new_name);
extern int device_move(struct device *dev, struct device *new_parent,
enum dpm_order dpm_order);
extern const char *device_get_nodename(struct device *dev, const char **tmp);
+extern void *dev_get_drvdata(const struct device *dev);
+extern void dev_set_drvdata(struct device *dev, void *data);
/*
* Root device objects for grouping under /sys/devices
--
1.6.4.2
From: Mark Brown <[email protected]>
For consistency with driver data provide a dev_get_platdata() accessor
for reading the platform data from a device.
Signed-off-by: Mark Brown <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
include/linux/device.h | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/include/linux/device.h b/include/linux/device.h
index c0bd230..3f33f17 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -494,6 +494,11 @@ static inline struct device *root_device_register(const char *name)
}
extern void root_device_unregister(struct device *root);
+static inline void *dev_get_platdata(const struct device *dev)
+{
+ return dev->platform_data;
+}
+
/*
* Manual binding of a device to driver. See drivers/base/bus.c
* for information on use.
--
1.6.4.2
From: Daniel Mack <[email protected]>
'default n' is the default, there is no need for these lines.
Signed-off-by: Daniel Mack <[email protected]>
Cc: Hans J. Koch <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
drivers/uio/Kconfig | 5 -----
1 files changed, 0 insertions(+), 5 deletions(-)
diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig
index 7f86534..45200fd 100644
--- a/drivers/uio/Kconfig
+++ b/drivers/uio/Kconfig
@@ -1,7 +1,6 @@
menuconfig UIO
tristate "Userspace I/O drivers"
depends on !S390
- default n
help
Enable this to allow the userspace driver core code to be
built. This code allows userspace programs easy access to
@@ -16,7 +15,6 @@ if UIO
config UIO_CIF
tristate "generic Hilscher CIF Card driver"
depends on PCI
- default n
help
Driver for Hilscher CIF DeviceNet and Profibus cards. This
driver requires a userspace component that handles all of the
@@ -48,7 +46,6 @@ config UIO_PDRV_GENIRQ
config UIO_SMX
tristate "SMX cryptengine UIO interface"
- default n
help
Userspace IO interface to the Cryptography engine found on the
Nias Digital SMX boards. These will be available from Q4 2008
@@ -61,7 +58,6 @@ config UIO_SMX
config UIO_AEC
tristate "AEC video timestamp device"
depends on PCI
- default n
help
UIO driver for the Adrienne Electronics Corporation PCI time
@@ -78,7 +74,6 @@ config UIO_AEC
config UIO_SERCOS3
tristate "Automata Sercos III PCI card driver"
- default n
help
Userspace I/O interface for the Sercos III PCI card from
Automata GmbH. The userspace part of this driver will be
--
1.6.4.2
From: David Brownell <[email protected]>
Let attribute group vectors be declared "const". We'd
like to let most attribute metadata live in read-only
sections... this is a start.
Signed-off-by: David Brownell <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
block/genhd.c | 2 +-
drivers/base/core.c | 4 ++--
drivers/base/driver.c | 4 ++--
drivers/block/cciss.c | 2 +-
drivers/firewire/core-device.c | 2 +-
drivers/firmware/dmi-id.c | 2 +-
drivers/infiniband/hw/ehca/ehca_main.c | 2 +-
drivers/infiniband/hw/ipath/ipath_kernel.h | 2 +-
drivers/infiniband/hw/ipath/ipath_sysfs.c | 2 +-
drivers/input/input.c | 2 +-
drivers/misc/enclosure.c | 4 ++--
drivers/mmc/core/mmc.c | 2 +-
drivers/mmc/core/sd.c | 2 +-
drivers/mtd/mtdcore.c | 2 +-
drivers/s390/cio/css.c | 2 +-
drivers/s390/cio/device.c | 2 +-
drivers/s390/net/netiucv.c | 2 +-
drivers/scsi/scsi_priv.h | 2 +-
drivers/scsi/scsi_sysfs.c | 4 ++--
drivers/usb/core/endpoint.c | 2 +-
drivers/usb/core/sysfs.c | 4 ++--
drivers/usb/core/usb.h | 4 ++--
drivers/uwb/lc-dev.c | 2 +-
fs/partitions/check.c | 2 +-
include/linux/attribute_container.h | 2 +-
include/linux/device.h | 6 +++---
include/linux/netdevice.h | 2 +-
include/linux/transport_class.h | 2 +-
net/bluetooth/hci_sysfs.c | 4 ++--
net/core/net-sysfs.c | 2 +-
30 files changed, 39 insertions(+), 39 deletions(-)
diff --git a/block/genhd.c b/block/genhd.c
index 5b76bf5..2ad91dd 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -903,7 +903,7 @@ static struct attribute_group disk_attr_group = {
.attrs = disk_attrs,
};
-static struct attribute_group *disk_attr_groups[] = {
+static const struct attribute_group *disk_attr_groups[] = {
&disk_attr_group,
NULL
};
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 99dfe96..a992985 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -341,7 +341,7 @@ static void device_remove_attributes(struct device *dev,
}
static int device_add_groups(struct device *dev,
- struct attribute_group **groups)
+ const struct attribute_group **groups)
{
int error = 0;
int i;
@@ -361,7 +361,7 @@ static int device_add_groups(struct device *dev,
}
static void device_remove_groups(struct device *dev,
- struct attribute_group **groups)
+ const struct attribute_group **groups)
{
int i;
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index 8ae0f63..ed2ebd3 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -181,7 +181,7 @@ void put_driver(struct device_driver *drv)
EXPORT_SYMBOL_GPL(put_driver);
static int driver_add_groups(struct device_driver *drv,
- struct attribute_group **groups)
+ const struct attribute_group **groups)
{
int error = 0;
int i;
@@ -201,7 +201,7 @@ static int driver_add_groups(struct device_driver *drv,
}
static void driver_remove_groups(struct device_driver *drv,
- struct attribute_group **groups)
+ const struct attribute_group **groups)
{
int i;
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 0589dfb..d8372b4 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -572,7 +572,7 @@ static struct attribute_group cciss_dev_attr_group = {
.attrs = cciss_dev_attrs,
};
-static struct attribute_group *cciss_dev_attr_groups[] = {
+static const struct attribute_group *cciss_dev_attr_groups[] = {
&cciss_dev_attr_group,
NULL
};
diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c
index 97e656a..9d0dfcb 100644
--- a/drivers/firewire/core-device.c
+++ b/drivers/firewire/core-device.c
@@ -312,7 +312,7 @@ static void init_fw_attribute_group(struct device *dev,
group->groups[0] = &group->group;
group->groups[1] = NULL;
group->group.attrs = group->attrs;
- dev->groups = group->groups;
+ dev->groups = (const struct attribute_group **) group->groups;
}
static ssize_t modalias_show(struct device *dev,
diff --git a/drivers/firmware/dmi-id.c b/drivers/firmware/dmi-id.c
index 5a76d05..dbdf6fa 100644
--- a/drivers/firmware/dmi-id.c
+++ b/drivers/firmware/dmi-id.c
@@ -139,7 +139,7 @@ static struct attribute_group sys_dmi_attribute_group = {
.attrs = sys_dmi_attributes,
};
-static struct attribute_group* sys_dmi_attribute_groups[] = {
+static const struct attribute_group* sys_dmi_attribute_groups[] = {
&sys_dmi_attribute_group,
NULL
};
diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c
index 5b635aa..fb2d83c 100644
--- a/drivers/infiniband/hw/ehca/ehca_main.c
+++ b/drivers/infiniband/hw/ehca/ehca_main.c
@@ -623,7 +623,7 @@ static struct attribute_group ehca_drv_attr_grp = {
.attrs = ehca_drv_attrs
};
-static struct attribute_group *ehca_drv_attr_groups[] = {
+static const struct attribute_group *ehca_drv_attr_groups[] = {
&ehca_drv_attr_grp,
NULL,
};
diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h
index 6ba4861..b3d7efc 100644
--- a/drivers/infiniband/hw/ipath/ipath_kernel.h
+++ b/drivers/infiniband/hw/ipath/ipath_kernel.h
@@ -1286,7 +1286,7 @@ struct device_driver;
extern const char ib_ipath_version[];
-extern struct attribute_group *ipath_driver_attr_groups[];
+extern const struct attribute_group *ipath_driver_attr_groups[];
int ipath_device_create_group(struct device *, struct ipath_devdata *);
void ipath_device_remove_group(struct device *, struct ipath_devdata *);
diff --git a/drivers/infiniband/hw/ipath/ipath_sysfs.c b/drivers/infiniband/hw/ipath/ipath_sysfs.c
index a6c8efb..b8cb2f1 100644
--- a/drivers/infiniband/hw/ipath/ipath_sysfs.c
+++ b/drivers/infiniband/hw/ipath/ipath_sysfs.c
@@ -1069,7 +1069,7 @@ static ssize_t show_tempsense(struct device *dev,
return ret;
}
-struct attribute_group *ipath_driver_attr_groups[] = {
+const struct attribute_group *ipath_driver_attr_groups[] = {
&driver_attr_group,
NULL,
};
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 7c237e6..851791d 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -1144,7 +1144,7 @@ static struct attribute_group input_dev_caps_attr_group = {
.attrs = input_dev_caps_attrs,
};
-static struct attribute_group *input_dev_attr_groups[] = {
+static const struct attribute_group *input_dev_attr_groups[] = {
&input_dev_attr_group,
&input_dev_id_attr_group,
&input_dev_caps_attr_group,
diff --git a/drivers/misc/enclosure.c b/drivers/misc/enclosure.c
index 7b03930..e9eae4a 100644
--- a/drivers/misc/enclosure.c
+++ b/drivers/misc/enclosure.c
@@ -238,7 +238,7 @@ static void enclosure_component_release(struct device *dev)
put_device(dev->parent);
}
-static struct attribute_group *enclosure_groups[];
+static const struct attribute_group *enclosure_groups[];
/**
* enclosure_component_register - add a particular component to an enclosure
@@ -536,7 +536,7 @@ static struct attribute_group enclosure_group = {
.attrs = enclosure_component_attrs,
};
-static struct attribute_group *enclosure_groups[] = {
+static const struct attribute_group *enclosure_groups[] = {
&enclosure_group,
NULL
};
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 06084db..2fb9d5f 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -276,7 +276,7 @@ static struct attribute_group mmc_std_attr_group = {
.attrs = mmc_std_attrs,
};
-static struct attribute_group *mmc_attr_groups[] = {
+static const struct attribute_group *mmc_attr_groups[] = {
&mmc_std_attr_group,
NULL,
};
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index cd81c39..7ad646f 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -314,7 +314,7 @@ static struct attribute_group sd_std_attr_group = {
.attrs = sd_std_attrs,
};
-static struct attribute_group *sd_attr_groups[] = {
+static const struct attribute_group *sd_attr_groups[] = {
&sd_std_attr_group,
NULL,
};
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 00ebf7a..69007a6 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -217,7 +217,7 @@ struct attribute_group mtd_group = {
.attrs = mtd_attrs,
};
-struct attribute_group *mtd_groups[] = {
+const struct attribute_group *mtd_groups[] = {
&mtd_group,
NULL,
};
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index e995123..393c73c 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -266,7 +266,7 @@ static struct attribute_group subch_attr_group = {
.attrs = subch_attrs,
};
-static struct attribute_group *default_subch_attr_groups[] = {
+static const struct attribute_group *default_subch_attr_groups[] = {
&subch_attr_group,
NULL,
};
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 0f95405..6527f3f 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -656,7 +656,7 @@ static struct attribute_group ccwdev_attr_group = {
.attrs = ccwdev_attrs,
};
-static struct attribute_group *ccwdev_attr_groups[] = {
+static const struct attribute_group *ccwdev_attr_groups[] = {
&ccwdev_attr_group,
NULL,
};
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c
index 9215fbb..a4b2c57 100644
--- a/drivers/s390/net/netiucv.c
+++ b/drivers/s390/net/netiucv.c
@@ -2159,7 +2159,7 @@ static struct attribute_group netiucv_drv_attr_group = {
.attrs = netiucv_drv_attrs,
};
-static struct attribute_group *netiucv_drv_attr_groups[] = {
+static const struct attribute_group *netiucv_drv_attr_groups[] = {
&netiucv_drv_attr_group,
NULL,
};
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index 021e503..1fbf7c7 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -132,7 +132,7 @@ extern struct scsi_transport_template blank_transport_template;
extern void __scsi_remove_device(struct scsi_device *);
extern struct bus_type scsi_bus_type;
-extern struct attribute_group *scsi_sysfs_shost_attr_groups[];
+extern const struct attribute_group *scsi_sysfs_shost_attr_groups[];
/* scsi_netlink.c */
#ifdef CONFIG_SCSI_NETLINK
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 91482f2..fde5453 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -275,7 +275,7 @@ struct attribute_group scsi_shost_attr_group = {
.attrs = scsi_sysfs_shost_attrs,
};
-struct attribute_group *scsi_sysfs_shost_attr_groups[] = {
+const struct attribute_group *scsi_sysfs_shost_attr_groups[] = {
&scsi_shost_attr_group,
NULL
};
@@ -745,7 +745,7 @@ static struct attribute_group scsi_sdev_attr_group = {
.attrs = scsi_sdev_attrs,
};
-static struct attribute_group *scsi_sdev_attr_groups[] = {
+static const struct attribute_group *scsi_sdev_attr_groups[] = {
&scsi_sdev_attr_group,
NULL
};
diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c
index bc39fc4..fdfaa78 100644
--- a/drivers/usb/core/endpoint.c
+++ b/drivers/usb/core/endpoint.c
@@ -154,7 +154,7 @@ static struct attribute *ep_dev_attrs[] = {
static struct attribute_group ep_dev_attr_grp = {
.attrs = ep_dev_attrs,
};
-static struct attribute_group *ep_dev_groups[] = {
+static const struct attribute_group *ep_dev_groups[] = {
&ep_dev_attr_grp,
NULL
};
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index b5c72e4..7ec3041 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -573,7 +573,7 @@ static struct attribute_group dev_string_attr_grp = {
.is_visible = dev_string_attrs_are_visible,
};
-struct attribute_group *usb_device_groups[] = {
+const struct attribute_group *usb_device_groups[] = {
&dev_attr_grp,
&dev_string_attr_grp,
NULL
@@ -799,7 +799,7 @@ static struct attribute_group intf_assoc_attr_grp = {
.is_visible = intf_assoc_attrs_are_visible,
};
-struct attribute_group *usb_interface_groups[] = {
+const struct attribute_group *usb_interface_groups[] = {
&intf_attr_grp,
&intf_assoc_attr_grp,
NULL
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index e2a8cfa..c0e0ae2 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -152,8 +152,8 @@ static inline int is_active(const struct usb_interface *f)
extern const char *usbcore_name;
/* sysfs stuff */
-extern struct attribute_group *usb_device_groups[];
-extern struct attribute_group *usb_interface_groups[];
+extern const struct attribute_group *usb_device_groups[];
+extern const struct attribute_group *usb_interface_groups[];
/* usbfs stuff */
extern struct mutex usbfs_mutex;
diff --git a/drivers/uwb/lc-dev.c b/drivers/uwb/lc-dev.c
index e9fe1bb..1097e81 100644
--- a/drivers/uwb/lc-dev.c
+++ b/drivers/uwb/lc-dev.c
@@ -255,7 +255,7 @@ static struct attribute_group dev_attr_group = {
.attrs = dev_attrs,
};
-static struct attribute_group *groups[] = {
+static const struct attribute_group *groups[] = {
&dev_attr_group,
NULL,
};
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index 619ba99..fbeaddf 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -312,7 +312,7 @@ static struct attribute_group part_attr_group = {
.attrs = part_attrs,
};
-static struct attribute_group *part_attr_groups[] = {
+static const struct attribute_group *part_attr_groups[] = {
&part_attr_group,
#ifdef CONFIG_BLK_DEV_IO_TRACE
&blk_trace_attr_group,
diff --git a/include/linux/attribute_container.h b/include/linux/attribute_container.h
index 794ad74..c3ab814 100644
--- a/include/linux/attribute_container.h
+++ b/include/linux/attribute_container.h
@@ -17,7 +17,7 @@ struct attribute_container {
struct list_head node;
struct klist containers;
struct class *class;
- struct attribute_group *grp;
+ const struct attribute_group *grp;
struct device_attribute **attrs;
int (*match)(struct attribute_container *, struct device *);
#define ATTRIBUTE_CONTAINER_NO_CLASSDEVS 0x01
diff --git a/include/linux/device.h b/include/linux/device.h
index 3f33f17..e19e40a 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -131,7 +131,7 @@ struct device_driver {
void (*shutdown) (struct device *dev);
int (*suspend) (struct device *dev, pm_message_t state);
int (*resume) (struct device *dev);
- struct attribute_group **groups;
+ const struct attribute_group **groups;
const struct dev_pm_ops *pm;
@@ -288,7 +288,7 @@ extern void class_destroy(struct class *cls);
*/
struct device_type {
const char *name;
- struct attribute_group **groups;
+ const struct attribute_group **groups;
int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
char *(*nodename)(struct device *dev);
void (*release)(struct device *dev);
@@ -412,7 +412,7 @@ struct device {
struct klist_node knode_class;
struct class *class;
- struct attribute_group **groups; /* optional groups */
+ const struct attribute_group **groups; /* optional groups */
void (*release)(struct device *dev);
};
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 65ee192..a9aa4b5 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -895,7 +895,7 @@ struct net_device
/* class/net/name entry */
struct device dev;
/* space for optional statistics and wireless sysfs groups */
- struct attribute_group *sysfs_groups[3];
+ const struct attribute_group *sysfs_groups[3];
/* rtnetlink link ops */
const struct rtnl_link_ops *rtnl_link_ops;
diff --git a/include/linux/transport_class.h b/include/linux/transport_class.h
index eaec1ea..9ae8da3 100644
--- a/include/linux/transport_class.h
+++ b/include/linux/transport_class.h
@@ -55,7 +55,7 @@ struct anon_transport_class cls = { \
struct transport_container {
struct attribute_container ac;
- struct attribute_group *statistics;
+ const struct attribute_group *statistics;
};
#define attribute_container_to_transport_container(x) \
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index 95f7a7a..7f939ce 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -68,7 +68,7 @@ static struct attribute_group bt_link_group = {
.attrs = bt_link_attrs,
};
-static struct attribute_group *bt_link_groups[] = {
+static const struct attribute_group *bt_link_groups[] = {
&bt_link_group,
NULL
};
@@ -392,7 +392,7 @@ static struct attribute_group bt_host_group = {
.attrs = bt_host_attrs,
};
-static struct attribute_group *bt_host_groups[] = {
+static const struct attribute_group *bt_host_groups[] = {
&bt_host_group,
NULL
};
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index ad91e9e..7d4c575 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -493,7 +493,7 @@ void netdev_unregister_kobject(struct net_device * net)
int netdev_register_kobject(struct net_device *net)
{
struct device *dev = &(net->dev);
- struct attribute_group **groups = net->sysfs_groups;
+ const struct attribute_group **groups = net->sysfs_groups;
dev->class = &net_class;
dev->platform_data = net;
--
1.6.4.2
From: Kay Sievers <[email protected]>
Declare the device list with the minor numbers as the index, which saves us from
searching for a matching list entry. Remove old devfs permissions declaration.
Signed-off-by: Kay Sievers <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
drivers/char/mem.c | 82 +++++++++++++++++++++++++--------------------------
1 files changed, 40 insertions(+), 42 deletions(-)
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 645237b..bed3503 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -864,71 +864,67 @@ static const struct file_operations kmsg_fops = {
.write = kmsg_write,
};
-static const struct {
- unsigned int minor;
- char *name;
- umode_t mode;
- const struct file_operations *fops;
- struct backing_dev_info *dev_info;
-} devlist[] = { /* list of minor devices */
- {1, "mem", S_IRUSR | S_IWUSR | S_IRGRP, &mem_fops,
- &directly_mappable_cdev_bdi},
+static const struct memdev {
+ const char *name;
+ const struct file_operations *fops;
+ struct backing_dev_info *dev_info;
+} devlist[] = {
+ [ 1] = { "mem", &mem_fops, &directly_mappable_cdev_bdi },
#ifdef CONFIG_DEVKMEM
- {2, "kmem", S_IRUSR | S_IWUSR | S_IRGRP, &kmem_fops,
- &directly_mappable_cdev_bdi},
+ [ 2] = { "kmem", &kmem_fops, &directly_mappable_cdev_bdi },
#endif
- {3, "null", S_IRUGO | S_IWUGO, &null_fops, NULL},
+ [ 3] = {"null", &null_fops, NULL },
#ifdef CONFIG_DEVPORT
- {4, "port", S_IRUSR | S_IWUSR | S_IRGRP, &port_fops, NULL},
+ [ 4] = { "port", &port_fops, NULL },
#endif
- {5, "zero", S_IRUGO | S_IWUGO, &zero_fops, &zero_bdi},
- {7, "full", S_IRUGO | S_IWUGO, &full_fops, NULL},
- {8, "random", S_IRUGO | S_IWUSR, &random_fops, NULL},
- {9, "urandom", S_IRUGO | S_IWUSR, &urandom_fops, NULL},
- {11,"kmsg", S_IRUGO | S_IWUSR, &kmsg_fops, NULL},
+ [ 5] = { "zero", &zero_fops, &zero_bdi },
+ [ 6] = { "full", &full_fops, NULL },
+ [ 7] = { "random", &random_fops, NULL },
+ [ 9] = { "urandom", &urandom_fops, NULL },
+ [11] = { "kmsg", &kmsg_fops, NULL },
#ifdef CONFIG_CRASH_DUMP
- {12,"oldmem", S_IRUSR | S_IWUSR | S_IRGRP, &oldmem_fops, NULL},
+ [12] = { "oldmem", &oldmem_fops, NULL },
#endif
};
static int memory_open(struct inode *inode, struct file *filp)
{
- int ret = 0;
- int i;
+ int minor;
+ const struct memdev *dev;
+ int ret = -ENXIO;
lock_kernel();
- for (i = 0; i < ARRAY_SIZE(devlist); i++) {
- if (devlist[i].minor == iminor(inode)) {
- filp->f_op = devlist[i].fops;
- if (devlist[i].dev_info) {
- filp->f_mapping->backing_dev_info =
- devlist[i].dev_info;
- }
+ minor = iminor(inode);
+ if (minor >= ARRAY_SIZE(devlist))
+ goto out;
- break;
- }
- }
+ dev = &devlist[minor];
+ if (!dev->fops)
+ goto out;
- if (i == ARRAY_SIZE(devlist))
- ret = -ENXIO;
- else
- if (filp->f_op && filp->f_op->open)
- ret = filp->f_op->open(inode, filp);
+ filp->f_op = dev->fops;
+ if (dev->dev_info)
+ filp->f_mapping->backing_dev_info = dev->dev_info;
+ if (dev->fops->open)
+ ret = dev->fops->open(inode, filp);
+ else
+ ret = 0;
+out:
unlock_kernel();
return ret;
}
static const struct file_operations memory_fops = {
- .open = memory_open, /* just a selector for the real open */
+ .open = memory_open,
};
static struct class *mem_class;
static int __init chr_dev_init(void)
{
- int i;
+ int minor;
int err;
err = bdi_init(&zero_bdi);
@@ -939,10 +935,12 @@ static int __init chr_dev_init(void)
printk("unable to get major %d for memory devs\n", MEM_MAJOR);
mem_class = class_create(THIS_MODULE, "mem");
- for (i = 0; i < ARRAY_SIZE(devlist); i++)
- device_create(mem_class, NULL,
- MKDEV(MEM_MAJOR, devlist[i].minor), NULL,
- devlist[i].name);
+ for (minor = 1; minor < ARRAY_SIZE(devlist); minor++) {
+ if (!devlist[minor].name)
+ continue;
+ device_create(mem_class, NULL, MKDEV(MEM_MAJOR, minor),
+ NULL, devlist[minor].name);
+ }
return 0;
}
--
1.6.4.2
From: Jin Dongming <[email protected]>
When I build and boot -next on fedora 10, I can not login anymore.
When I input the user name and password, the system does not output
any message and requires user to input the user name and password
again and again.
I find the patch which caused this problem with "GIT BISECT" command.
And the patch is
commit 7c4b7daa1878972ed0137c95f23569124bd6e2b1
"mem_class: use minor as index instead of searching the array".
Though I don't know the real reason why user could not login, I
confirmed the patch I made as following could resolve the problem on
fedora 10.
Signed-off-by: Jin Dongming <[email protected]>
Acked-by: Kay Sievers <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
drivers/char/mem.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index bed3503..0491cdf 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -878,8 +878,8 @@ static const struct memdev {
[ 4] = { "port", &port_fops, NULL },
#endif
[ 5] = { "zero", &zero_fops, &zero_bdi },
- [ 6] = { "full", &full_fops, NULL },
- [ 7] = { "random", &random_fops, NULL },
+ [ 7] = { "full", &full_fops, NULL },
+ [ 8] = { "random", &random_fops, NULL },
[ 9] = { "urandom", &urandom_fops, NULL },
[11] = { "kmsg", &kmsg_fops, NULL },
#ifdef CONFIG_CRASH_DUMP
--
1.6.4.2
From: Ming Lei <[email protected]>
Placing dma-coherent.c in driver/base is better than in kernel,
since it contains code to do per-device coherent dma memory
handling.
Signed-off-by: Ming Lei <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
drivers/base/Makefile | 1 +
{kernel => drivers/base}/dma-coherent.c | 0
kernel/Makefile | 1 -
3 files changed, 1 insertions(+), 1 deletions(-)
rename {kernel => drivers/base}/dma-coherent.c (100%)
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index b5b8ba5..1b2640c 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -6,6 +6,7 @@ obj-y := core.o sys.o bus.o dd.o \
attribute_container.o transport_class.o
obj-y += power/
obj-$(CONFIG_HAS_DMA) += dma-mapping.o
+obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o
obj-$(CONFIG_ISA) += isa.o
obj-$(CONFIG_FW_LOADER) += firmware_class.o
obj-$(CONFIG_NUMA) += node.o
diff --git a/kernel/dma-coherent.c b/drivers/base/dma-coherent.c
similarity index 100%
rename from kernel/dma-coherent.c
rename to drivers/base/dma-coherent.c
diff --git a/kernel/Makefile b/kernel/Makefile
index 961379c..3d9c7e2 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -90,7 +90,6 @@ obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o
obj-$(CONFIG_MARKERS) += marker.o
obj-$(CONFIG_TRACEPOINTS) += tracepoint.o
obj-$(CONFIG_LATENCYTOP) += latencytop.o
-obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o
obj-$(CONFIG_FUNCTION_TRACER) += trace/
obj-$(CONFIG_TRACING) += trace/
obj-$(CONFIG_X86_DS) += trace/
--
1.6.4.2
From: Michael S. Tsirkin <[email protected]>
This adds a generic uio driver that can bind to any PCI device. First
user will be virtualization where a qemu userspace process needs to give
guest OS access to the device.
Interrupts are handled using the Interrupt Disable bit in the PCI
command register and Interrupt Status bit in the PCI status register.
All devices compliant to PCI 2.3 (circa 2002) and all compliant PCI
Express devices should support these bits. Driver detects this support,
and won't bind to devices which do not support the Interrupt Disable Bit
in the command register.
It's expected that more features of interest to virtualization will be
added to this driver in the future. Possibilities are: mmap for device
resources, MSI/MSI-X, eventfd (to interface with kvm), iommu.
Signed-off-by: Michael S. Tsirkin <[email protected]>
Acked-by: Chris Wright <[email protected]>
Signed-off-by: Hans J. Koch <[email protected]>
Acked-by: Jesse Barnes <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
Documentation/DocBook/uio-howto.tmpl | 163 ++++++++++++++++++++++++++
MAINTAINERS | 7 +
drivers/uio/Kconfig | 10 ++
drivers/uio/Makefile | 1 +
drivers/uio/uio_pci_generic.c | 207 ++++++++++++++++++++++++++++++++++
include/linux/pci_regs.h | 1 +
6 files changed, 389 insertions(+), 0 deletions(-)
create mode 100644 drivers/uio/uio_pci_generic.c
diff --git a/Documentation/DocBook/uio-howto.tmpl b/Documentation/DocBook/uio-howto.tmpl
index 8f6e3b2..4d4ce0e 100644
--- a/Documentation/DocBook/uio-howto.tmpl
+++ b/Documentation/DocBook/uio-howto.tmpl
@@ -25,6 +25,10 @@
<year>2006-2008</year>
<holder>Hans-Jürgen Koch.</holder>
</copyright>
+<copyright>
+ <year>2009</year>
+ <holder>Red Hat Inc, Michael S. Tsirkin ([email protected])</holder>
+</copyright>
<legalnotice>
<para>
@@ -42,6 +46,13 @@ GPL version 2.
<revhistory>
<revision>
+ <revnumber>0.9</revnumber>
+ <date>2009-07-16</date>
+ <authorinitials>mst</authorinitials>
+ <revremark>Added generic pci driver
+ </revremark>
+ </revision>
+ <revision>
<revnumber>0.8</revnumber>
<date>2008-12-24</date>
<authorinitials>hjk</authorinitials>
@@ -809,6 +820,158 @@ framework to set up sysfs files for this region. Simply leave it alone.
</chapter>
+<chapter id="uio_pci_generic" xreflabel="Using Generic driver for PCI cards">
+<?dbhtml filename="uio_pci_generic.html"?>
+<title>Generic PCI UIO driver</title>
+ <para>
+ The generic driver is a kernel module named uio_pci_generic.
+ It can work with any device compliant to PCI 2.3 (circa 2002) and
+ any compliant PCI Express device. Using this, you only need to
+ write the userspace driver, removing the need to write
+ a hardware-specific kernel module.
+ </para>
+
+<sect1 id="uio_pci_generic_binding">
+<title>Making the driver recognize the device</title>
+ <para>
+Since the driver does not declare any device ids, it will not get loaded
+automatically and will not automatically bind to any devices, you must load it
+and allocate id to the driver yourself. For example:
+ <programlisting>
+ modprobe uio_pci_generic
+ echo "8086 10f5" > /sys/bus/pci/drivers/uio_pci_generic/new_id
+ </programlisting>
+ </para>
+ <para>
+If there already is a hardware specific kernel driver for your device, the
+generic driver still won't bind to it, in this case if you want to use the
+generic driver (why would you?) you'll have to manually unbind the hardware
+specific driver and bind the generic driver, like this:
+ <programlisting>
+ echo -n 0000:00:19.0 > /sys/bus/pci/drivers/e1000e/unbind
+ echo -n 0000:00:19.0 > /sys/bus/pci/drivers/uio_pci_generic/bind
+ </programlisting>
+ </para>
+ <para>
+You can verify that the device has been bound to the driver
+by looking for it in sysfs, for example like the following:
+ <programlisting>
+ ls -l /sys/bus/pci/devices/0000:00:19.0/driver
+ </programlisting>
+Which if successful should print
+ <programlisting>
+ .../0000:00:19.0/driver -> ../../../bus/pci/drivers/uio_pci_generic
+ </programlisting>
+Note that the generic driver will not bind to old PCI 2.2 devices.
+If binding the device failed, run the following command:
+ <programlisting>
+ dmesg
+ </programlisting>
+and look in the output for failure reasons
+ </para>
+</sect1>
+
+<sect1 id="uio_pci_generic_internals">
+<title>Things to know about uio_pci_generic</title>
+ <para>
+Interrupts are handled using the Interrupt Disable bit in the PCI command
+register and Interrupt Status bit in the PCI status register. All devices
+compliant to PCI 2.3 (circa 2002) and all compliant PCI Express devices should
+support these bits. uio_pci_generic detects this support, and won't bind to
+devices which do not support the Interrupt Disable Bit in the command register.
+ </para>
+ <para>
+On each interrupt, uio_pci_generic sets the Interrupt Disable bit.
+This prevents the device from generating further interrupts
+until the bit is cleared. The userspace driver should clear this
+bit before blocking and waiting for more interrupts.
+ </para>
+</sect1>
+<sect1 id="uio_pci_generic_userspace">
+<title>Writing userspace driver using uio_pci_generic</title>
+ <para>
+Userspace driver can use pci sysfs interface, or the
+libpci libray that wraps it, to talk to the device and to
+re-enable interrupts by writing to the command register.
+ </para>
+</sect1>
+<sect1 id="uio_pci_generic_example">
+<title>Example code using uio_pci_generic</title>
+ <para>
+Here is some sample userspace driver code using uio_pci_generic:
+<programlisting>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+int main()
+{
+ int uiofd;
+ int configfd;
+ int err;
+ int i;
+ unsigned icount;
+ unsigned char command_high;
+
+ uiofd = open("/dev/uio0", O_RDONLY);
+ if (uiofd < 0) {
+ perror("uio open:");
+ return errno;
+ }
+ configfd = open("/sys/class/uio/uio0/device/config", O_RDWR);
+ if (uiofd < 0) {
+ perror("config open:");
+ return errno;
+ }
+
+ /* Read and cache command value */
+ err = pread(configfd, &command_high, 1, 5);
+ if (err != 1) {
+ perror("command config read:");
+ return errno;
+ }
+ command_high &= ~0x4;
+
+ for(i = 0;; ++i) {
+ /* Print out a message, for debugging. */
+ if (i == 0)
+ fprintf(stderr, "Started uio test driver.\n");
+ else
+ fprintf(stderr, "Interrupts: %d\n", icount);
+
+ /****************************************/
+ /* Here we got an interrupt from the
+ device. Do something to it. */
+ /****************************************/
+
+ /* Re-enable interrupts. */
+ err = pwrite(configfd, &command_high, 1, 5);
+ if (err != 1) {
+ perror("config write:");
+ break;
+ }
+
+ /* Wait for next interrupt. */
+ err = read(uiofd, &icount, 4);
+ if (err != 4) {
+ perror("uio read:");
+ break;
+ }
+
+ }
+ return errno;
+}
+
+</programlisting>
+ </para>
+</sect1>
+
+</chapter>
+
<appendix id="app1">
<title>Further information</title>
<itemizedlist>
diff --git a/MAINTAINERS b/MAINTAINERS
index 837b598..01193a4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2218,6 +2218,13 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/arnd/asm-generic.git
S: Maintained
F: include/asm-generic
+GENERIC UIO DRIVER FOR PCI DEVICES
+M: Michael S. Tsirkin <[email protected]>
+L: [email protected]
+L: [email protected]
+S: Supported
+F: drivers/uio/uio_pci_generic.c
+
GFS2 FILE SYSTEM
M: Steven Whitehouse <[email protected]>
L: [email protected]
diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig
index 45200fd..8aa1955 100644
--- a/drivers/uio/Kconfig
+++ b/drivers/uio/Kconfig
@@ -84,4 +84,14 @@ config UIO_SERCOS3
If you compile this as a module, it will be called uio_sercos3.
+config UIO_PCI_GENERIC
+ tristate "Generic driver for PCI 2.3 and PCI Express cards"
+ depends on PCI
+ default n
+ help
+ Generic driver that you can bind, dynamically, to any
+ PCI 2.3 compliant and PCI Express card. It is useful,
+ primarily, for virtualization scenarios.
+ If you compile this as a module, it will be called uio_pci_generic.
+
endif
diff --git a/drivers/uio/Makefile b/drivers/uio/Makefile
index 5c2586d..73b2e75 100644
--- a/drivers/uio/Makefile
+++ b/drivers/uio/Makefile
@@ -5,3 +5,4 @@ obj-$(CONFIG_UIO_PDRV_GENIRQ) += uio_pdrv_genirq.o
obj-$(CONFIG_UIO_SMX) += uio_smx.o
obj-$(CONFIG_UIO_AEC) += uio_aec.o
obj-$(CONFIG_UIO_SERCOS3) += uio_sercos3.o
+obj-$(CONFIG_UIO_PCI_GENERIC) += uio_pci_generic.o
diff --git a/drivers/uio/uio_pci_generic.c b/drivers/uio/uio_pci_generic.c
new file mode 100644
index 0000000..313da35
--- /dev/null
+++ b/drivers/uio/uio_pci_generic.c
@@ -0,0 +1,207 @@
+/* uio_pci_generic - generic UIO driver for PCI 2.3 devices
+ *
+ * Copyright (C) 2009 Red Hat, Inc.
+ * Author: Michael S. Tsirkin <[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ *
+ * Since the driver does not declare any device ids, you must allocate
+ * id and bind the device to the driver yourself. For example:
+ *
+ * # echo "8086 10f5" > /sys/bus/pci/drivers/uio_pci_generic/new_id
+ * # echo -n 0000:00:19.0 > /sys/bus/pci/drivers/e1000e/unbind
+ * # echo -n 0000:00:19.0 > /sys/bus/pci/drivers/uio_pci_generic/bind
+ * # ls -l /sys/bus/pci/devices/0000:00:19.0/driver
+ * .../0000:00:19.0/driver -> ../../../bus/pci/drivers/uio_pci_generic
+ *
+ * Driver won't bind to devices which do not support the Interrupt Disable Bit
+ * in the command register. All devices compliant to PCI 2.3 (circa 2002) and
+ * all compliant PCI Express devices should support this bit.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/uio_driver.h>
+#include <linux/spinlock.h>
+
+#define DRIVER_VERSION "0.01.0"
+#define DRIVER_AUTHOR "Michael S. Tsirkin <[email protected]>"
+#define DRIVER_DESC "Generic UIO driver for PCI 2.3 devices"
+
+struct uio_pci_generic_dev {
+ struct uio_info info;
+ struct pci_dev *pdev;
+ spinlock_t lock; /* guards command register accesses */
+};
+
+static inline struct uio_pci_generic_dev *
+to_uio_pci_generic_dev(struct uio_info *info)
+{
+ return container_of(info, struct uio_pci_generic_dev, info);
+}
+
+/* Interrupt handler. Read/modify/write the command register to disable
+ * the interrupt. */
+static irqreturn_t irqhandler(int irq, struct uio_info *info)
+{
+ struct uio_pci_generic_dev *gdev = to_uio_pci_generic_dev(info);
+ struct pci_dev *pdev = gdev->pdev;
+ irqreturn_t ret = IRQ_NONE;
+ u32 cmd_status_dword;
+ u16 origcmd, newcmd, status;
+
+ /* We do a single dword read to retrieve both command and status.
+ * Document assumptions that make this possible. */
+ BUILD_BUG_ON(PCI_COMMAND % 4);
+ BUILD_BUG_ON(PCI_COMMAND + 2 != PCI_STATUS);
+
+ spin_lock_irq(&gdev->lock);
+ pci_block_user_cfg_access(pdev);
+
+ /* Read both command and status registers in a single 32-bit operation.
+ * Note: we could cache the value for command and move the status read
+ * out of the lock if there was a way to get notified of user changes
+ * to command register through sysfs. Should be good for shared irqs. */
+ pci_read_config_dword(pdev, PCI_COMMAND, &cmd_status_dword);
+ origcmd = cmd_status_dword;
+ status = cmd_status_dword >> 16;
+
+ /* Check interrupt status register to see whether our device
+ * triggered the interrupt. */
+ if (!(status & PCI_STATUS_INTERRUPT))
+ goto done;
+
+ /* We triggered the interrupt, disable it. */
+ newcmd = origcmd | PCI_COMMAND_INTX_DISABLE;
+ if (newcmd != origcmd)
+ pci_write_config_word(pdev, PCI_COMMAND, newcmd);
+
+ /* UIO core will signal the user process. */
+ ret = IRQ_HANDLED;
+done:
+
+ pci_unblock_user_cfg_access(pdev);
+ spin_unlock_irq(&gdev->lock);
+ return ret;
+}
+
+/* Verify that the device supports Interrupt Disable bit in command register,
+ * per PCI 2.3, by flipping this bit and reading it back: this bit was readonly
+ * in PCI 2.2. */
+static int __devinit verify_pci_2_3(struct pci_dev *pdev)
+{
+ u16 orig, new;
+ int err = 0;
+
+ pci_block_user_cfg_access(pdev);
+ pci_read_config_word(pdev, PCI_COMMAND, &orig);
+ pci_write_config_word(pdev, PCI_COMMAND,
+ orig ^ PCI_COMMAND_INTX_DISABLE);
+ pci_read_config_word(pdev, PCI_COMMAND, &new);
+ /* There's no way to protect against
+ * hardware bugs or detect them reliably, but as long as we know
+ * what the value should be, let's go ahead and check it. */
+ if ((new ^ orig) & ~PCI_COMMAND_INTX_DISABLE) {
+ err = -EBUSY;
+ dev_err(&pdev->dev, "Command changed from 0x%x to 0x%x: "
+ "driver or HW bug?\n", orig, new);
+ goto err;
+ }
+ if (!((new ^ orig) & PCI_COMMAND_INTX_DISABLE)) {
+ dev_warn(&pdev->dev, "Device does not support "
+ "disabling interrupts: unable to bind.\n");
+ err = -ENODEV;
+ goto err;
+ }
+ /* Now restore the original value. */
+ pci_write_config_word(pdev, PCI_COMMAND, orig);
+err:
+ pci_unblock_user_cfg_access(pdev);
+ return err;
+}
+
+static int __devinit probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ struct uio_pci_generic_dev *gdev;
+ int err;
+
+ if (!pdev->irq) {
+ dev_warn(&pdev->dev, "No IRQ assigned to device: "
+ "no support for interrupts?\n");
+ return -ENODEV;
+ }
+
+ err = pci_enable_device(pdev);
+ if (err) {
+ dev_err(&pdev->dev, "%s: pci_enable_device failed: %d\n",
+ __func__, err);
+ return err;
+ }
+
+ err = verify_pci_2_3(pdev);
+ if (err)
+ goto err_verify;
+
+ gdev = kzalloc(sizeof(struct uio_pci_generic_dev), GFP_KERNEL);
+ if (!gdev) {
+ err = -ENOMEM;
+ goto err_alloc;
+ }
+
+ gdev->info.name = "uio_pci_generic";
+ gdev->info.version = DRIVER_VERSION;
+ gdev->info.irq = pdev->irq;
+ gdev->info.irq_flags = IRQF_SHARED;
+ gdev->info.handler = irqhandler;
+ gdev->pdev = pdev;
+ spin_lock_init(&gdev->lock);
+
+ if (uio_register_device(&pdev->dev, &gdev->info))
+ goto err_register;
+ pci_set_drvdata(pdev, gdev);
+
+ return 0;
+err_register:
+ kfree(gdev);
+err_alloc:
+err_verify:
+ pci_disable_device(pdev);
+ return err;
+}
+
+static void remove(struct pci_dev *pdev)
+{
+ struct uio_pci_generic_dev *gdev = pci_get_drvdata(pdev);
+
+ uio_unregister_device(&gdev->info);
+ pci_disable_device(pdev);
+ kfree(gdev);
+}
+
+static struct pci_driver driver = {
+ .name = "uio_pci_generic",
+ .id_table = NULL, /* only dynamic id's */
+ .probe = probe,
+ .remove = remove,
+};
+
+static int __init init(void)
+{
+ pr_info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
+ return pci_register_driver(&driver);
+}
+
+static void __exit cleanup(void)
+{
+ pci_unregister_driver(&driver);
+}
+
+module_init(init);
+module_exit(cleanup);
+
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h
index fcaee42..dd0bed4 100644
--- a/include/linux/pci_regs.h
+++ b/include/linux/pci_regs.h
@@ -42,6 +42,7 @@
#define PCI_COMMAND_INTX_DISABLE 0x400 /* INTx Emulation Disable */
#define PCI_STATUS 0x06 /* 16 bits */
+#define PCI_STATUS_INTERRUPT 0x08 /* Interrupt status */
#define PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */
#define PCI_STATUS_66MHZ 0x20 /* Support 66 Mhz PCI 2.1 bus */
#define PCI_STATUS_UDF 0x40 /* Support User Definable Features [obsolete] */
--
1.6.4.2
From: Jean Delvare <[email protected]>
When turning class devices into bus devices, we may need to
temporarily add links in sysfs so that user-space applications
are not confused. This is done by adding the following API:
* Functions to register and unregister compatibility classes.
These appear in sysfs at the same location as regular classes, but
instead of class devices, they contain links to bus devices.
* Functions to create and delete such links. Additionally, the caller
can optionally pass a target device to which a "device" link should
point (typically that would be the device's parent), to fully emulate
the original class device.
The i2c subsystem will be the first user of this API, as i2c adapters
are being converted from class devices to bus devices.
Signed-off-by: Jean Delvare <[email protected]>
Signed-off-by: Kay Sievers <[email protected]>
---
drivers/base/class.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/device.h | 8 ++++
2 files changed, 95 insertions(+), 0 deletions(-)
diff --git a/drivers/base/class.c b/drivers/base/class.c
index eb85e43..161746d 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -488,6 +488,93 @@ void class_interface_unregister(struct class_interface *class_intf)
class_put(parent);
}
+struct class_compat {
+ struct kobject *kobj;
+};
+
+/**
+ * class_compat_register - register a compatibility class
+ * @name: the name of the class
+ *
+ * Compatibility class are meant as a temporary user-space compatibility
+ * workaround when converting a family of class devices to a bus devices.
+ */
+struct class_compat *class_compat_register(const char *name)
+{
+ struct class_compat *cls;
+
+ cls = kmalloc(sizeof(struct class_compat), GFP_KERNEL);
+ if (!cls)
+ return NULL;
+ cls->kobj = kobject_create_and_add(name, &class_kset->kobj);
+ if (!cls->kobj) {
+ kfree(cls);
+ return NULL;
+ }
+ return cls;
+}
+EXPORT_SYMBOL_GPL(class_compat_register);
+
+/**
+ * class_compat_unregister - unregister a compatibility class
+ * @cls: the class to unregister
+ */
+void class_compat_unregister(struct class_compat *cls)
+{
+ kobject_put(cls->kobj);
+ kfree(cls);
+}
+EXPORT_SYMBOL_GPL(class_compat_unregister);
+
+/**
+ * class_compat_create_link - create a compatibility class device link to
+ * a bus device
+ * @cls: the compatibility class
+ * @dev: the target bus device
+ * @device_link: an optional device to which a "device" link should be created
+ */
+int class_compat_create_link(struct class_compat *cls, struct device *dev,
+ struct device *device_link)
+{
+ int error;
+
+ error = sysfs_create_link(cls->kobj, &dev->kobj, dev_name(dev));
+ if (error)
+ return error;
+
+ /*
+ * Optionally add a "device" link (typically to the parent), as a
+ * class device would have one and we want to provide as much
+ * backwards compatibility as possible.
+ */
+ if (device_link) {
+ error = sysfs_create_link(&dev->kobj, &device_link->kobj,
+ "device");
+ if (error)
+ sysfs_remove_link(cls->kobj, dev_name(dev));
+ }
+
+ return error;
+}
+EXPORT_SYMBOL_GPL(class_compat_create_link);
+
+/**
+ * class_compat_remove_link - remove a compatibility class device link to
+ * a bus device
+ * @cls: the compatibility class
+ * @dev: the target bus device
+ * @device_link: an optional device to which a "device" link was previously
+ * created
+ */
+void class_compat_remove_link(struct class_compat *cls, struct device *dev,
+ struct device *device_link)
+{
+ if (device_link)
+ sysfs_remove_link(&dev->kobj, "device");
+ sysfs_remove_link(cls->kobj, dev_name(dev));
+}
+EXPORT_SYMBOL_GPL(class_compat_remove_link);
+
int __init classes_init(void)
{
class_kset = kset_create_and_add("class", NULL, NULL);
diff --git a/include/linux/device.h b/include/linux/device.h
index e19e40a..62ff53a 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -225,6 +225,14 @@ extern void class_unregister(struct class *class);
__class_register(class, &__key); \
})
+struct class_compat;
+struct class_compat *class_compat_register(const char *name);
+void class_compat_unregister(struct class_compat *cls);
+int class_compat_create_link(struct class_compat *cls, struct device *dev,
+ struct device *device_link);
+void class_compat_remove_link(struct class_compat *cls, struct device *dev,
+ struct device *device_link);
+
extern void class_dev_iter_init(struct class_dev_iter *iter,
struct class *class,
struct device *start,
--
1.6.4.2
From: Andrew Morton <[email protected]>
Instead of open-coding it.
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
drivers/base/platform.c | 8 ++++----
1 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 0f7d434..ed156a1 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -10,6 +10,7 @@
* information.
*/
+#include <linux/string.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -213,14 +214,13 @@ EXPORT_SYMBOL_GPL(platform_device_add_resources);
int platform_device_add_data(struct platform_device *pdev, const void *data,
size_t size)
{
- void *d;
+ void *d = kmemdup(data, size, GFP_KERNEL);
- d = kmalloc(size, GFP_KERNEL);
if (d) {
- memcpy(d, data, size);
pdev->dev.platform_data = d;
+ return 0;
}
- return d ? 0 : -ENOMEM;
+ return -ENOMEM;
}
EXPORT_SYMBOL_GPL(platform_device_add_data);
--
1.6.4.2
From: David Altobelli <[email protected]>
Refactor some hpilo routines in order to allow for locking changes in
interrupt handling. Should not be functionally different.
Signed-off-by: David Altobelli <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
drivers/misc/hpilo.c | 120 ++++++++++++++++++++++++++++++-------------------
1 files changed, 73 insertions(+), 47 deletions(-)
diff --git a/drivers/misc/hpilo.c b/drivers/misc/hpilo.c
index 880ccf3..35ed123 100644
--- a/drivers/misc/hpilo.c
+++ b/drivers/misc/hpilo.c
@@ -151,6 +151,7 @@ static inline void doorbell_clr(struct ccb *ccb)
{
iowrite8(2, ccb->ccb_u5.db_base);
}
+
static inline int ctrl_set(int l2sz, int idxmask, int desclim)
{
int active = 0, go = 1;
@@ -160,6 +161,7 @@ static inline int ctrl_set(int l2sz, int idxmask, int desclim)
active << CTRL_BITPOS_A |
go << CTRL_BITPOS_G;
}
+
static void ctrl_setup(struct ccb *ccb, int nr_desc, int l2desc_sz)
{
/* for simplicity, use the same parameters for send and recv ctrls */
@@ -192,13 +194,10 @@ static void fifo_setup(void *base_addr, int nr_entry)
static void ilo_ccb_close(struct pci_dev *pdev, struct ccb_data *data)
{
- struct ccb *driver_ccb;
- struct ccb __iomem *device_ccb;
+ struct ccb *driver_ccb = &data->driver_ccb;
+ struct ccb __iomem *device_ccb = data->mapped_ccb;
int retries;
- driver_ccb = &data->driver_ccb;
- device_ccb = data->mapped_ccb;
-
/* complicated dance to tell the hw we are stopping */
doorbell_clr(driver_ccb);
iowrite32(ioread32(&device_ccb->send_ctrl) & ~(1 << CTRL_BITPOS_G),
@@ -225,26 +224,22 @@ static void ilo_ccb_close(struct pci_dev *pdev, struct ccb_data *data)
pci_free_consistent(pdev, data->dma_size, data->dma_va, data->dma_pa);
}
-static int ilo_ccb_open(struct ilo_hwinfo *hw, struct ccb_data *data, int slot)
+static int ilo_ccb_setup(struct ilo_hwinfo *hw, struct ccb_data *data, int slot)
{
char *dma_va, *dma_pa;
- int pkt_id, pkt_sz, i, error;
struct ccb *driver_ccb, *ilo_ccb;
- struct pci_dev *pdev;
driver_ccb = &data->driver_ccb;
ilo_ccb = &data->ilo_ccb;
- pdev = hw->ilo_dev;
data->dma_size = 2 * fifo_sz(NR_QENTRY) +
2 * desc_mem_sz(NR_QENTRY) +
ILO_START_ALIGN + ILO_CACHE_SZ;
- error = -ENOMEM;
- data->dma_va = pci_alloc_consistent(pdev, data->dma_size,
+ data->dma_va = pci_alloc_consistent(hw->ilo_dev, data->dma_size,
&data->dma_pa);
if (!data->dma_va)
- goto out;
+ return -ENOMEM;
dma_va = (char *)data->dma_va;
dma_pa = (char *)data->dma_pa;
@@ -290,10 +285,18 @@ static int ilo_ccb_open(struct ilo_hwinfo *hw, struct ccb_data *data, int slot)
driver_ccb->ccb_u5.db_base = hw->db_vaddr + (slot << L2_DB_SIZE);
ilo_ccb->ccb_u5.db_base = NULL; /* hw ccb's doorbell is not used */
+ return 0;
+}
+
+static void ilo_ccb_open(struct ilo_hwinfo *hw, struct ccb_data *data, int slot)
+{
+ int pkt_id, pkt_sz;
+ struct ccb *driver_ccb = &data->driver_ccb;
+
/* copy the ccb with physical addrs to device memory */
data->mapped_ccb = (struct ccb __iomem *)
(hw->ram_vaddr + (slot * ILOHW_CCB_SZ));
- memcpy_toio(data->mapped_ccb, ilo_ccb, sizeof(struct ccb));
+ memcpy_toio(data->mapped_ccb, &data->ilo_ccb, sizeof(struct ccb));
/* put packets on the send and receive queues */
pkt_sz = 0;
@@ -306,7 +309,14 @@ static int ilo_ccb_open(struct ilo_hwinfo *hw, struct ccb_data *data, int slot)
for (pkt_id = 0; pkt_id < NR_QENTRY; pkt_id++)
ilo_pkt_enqueue(hw, driver_ccb, RECVQ, pkt_id, pkt_sz);
+ /* the ccb is ready to use */
doorbell_clr(driver_ccb);
+}
+
+static int ilo_ccb_verify(struct ilo_hwinfo *hw, struct ccb_data *data)
+{
+ int pkt_id, i;
+ struct ccb *driver_ccb = &data->driver_ccb;
/* make sure iLO is really handling requests */
for (i = MAX_WAIT; i > 0; i--) {
@@ -315,20 +325,14 @@ static int ilo_ccb_open(struct ilo_hwinfo *hw, struct ccb_data *data, int slot)
udelay(WAIT_TIME);
}
- if (i) {
- ilo_pkt_enqueue(hw, driver_ccb, SENDQ, pkt_id, 0);
- doorbell_set(driver_ccb);
- } else {
- dev_err(&pdev->dev, "Open could not dequeue a packet\n");
- error = -EBUSY;
- goto free;
+ if (i == 0) {
+ dev_err(&hw->ilo_dev->dev, "Open could not dequeue a packet\n");
+ return -EBUSY;
}
+ ilo_pkt_enqueue(hw, driver_ccb, SENDQ, pkt_id, 0);
+ doorbell_set(driver_ccb);
return 0;
-free:
- ilo_ccb_close(pdev, data);
-out:
- return error;
}
static inline int is_channel_reset(struct ccb *ccb)
@@ -343,16 +347,31 @@ static inline void set_channel_reset(struct ccb *ccb)
FIFOBARTOHANDLE(ccb->ccb_u1.send_fifobar)->reset = 1;
}
+static inline int get_device_outbound(struct ilo_hwinfo *hw)
+{
+ return ioread32(&hw->mmio_vaddr[DB_OUT]);
+}
+
+static inline int is_db_reset(int db_out)
+{
+ return db_out & (1 << DB_RESET);
+}
+
static inline int is_device_reset(struct ilo_hwinfo *hw)
{
/* check for global reset condition */
- return ioread32(&hw->mmio_vaddr[DB_OUT]) & (1 << DB_RESET);
+ return is_db_reset(get_device_outbound(hw));
+}
+
+static inline void clear_pending_db(struct ilo_hwinfo *hw, int clr)
+{
+ iowrite32(clr, &hw->mmio_vaddr[DB_OUT]);
}
static inline void clear_device(struct ilo_hwinfo *hw)
{
/* clear the device (reset bits, pending channel entries) */
- iowrite32(-1, &hw->mmio_vaddr[DB_OUT]);
+ clear_pending_db(hw, -1);
}
static void ilo_locked_reset(struct ilo_hwinfo *hw)
@@ -387,15 +406,11 @@ static ssize_t ilo_read(struct file *fp, char __user *buf,
size_t len, loff_t *off)
{
int err, found, cnt, pkt_id, pkt_len;
- struct ccb_data *data;
- struct ccb *driver_ccb;
- struct ilo_hwinfo *hw;
+ struct ccb_data *data = fp->private_data;
+ struct ccb *driver_ccb = &data->driver_ccb;
+ struct ilo_hwinfo *hw = data->ilo_hw;
void *pkt;
- data = fp->private_data;
- driver_ccb = &data->driver_ccb;
- hw = data->ilo_hw;
-
if (is_device_reset(hw) || is_channel_reset(driver_ccb)) {
/*
* If the device has been reset, applications
@@ -442,15 +457,11 @@ static ssize_t ilo_write(struct file *fp, const char __user *buf,
size_t len, loff_t *off)
{
int err, pkt_id, pkt_len;
- struct ccb_data *data;
- struct ccb *driver_ccb;
- struct ilo_hwinfo *hw;
+ struct ccb_data *data = fp->private_data;
+ struct ccb *driver_ccb = &data->driver_ccb;
+ struct ilo_hwinfo *hw = data->ilo_hw;
void *pkt;
- data = fp->private_data;
- driver_ccb = &data->driver_ccb;
- hw = data->ilo_hw;
-
if (is_device_reset(hw) || is_channel_reset(driver_ccb)) {
/*
* If the device has been reset, applications
@@ -532,14 +543,28 @@ static int ilo_open(struct inode *ip, struct file *fp)
/* each fd private_data holds sw/hw view of ccb */
if (hw->ccb_alloc[slot] == NULL) {
/* create a channel control block for this minor */
- error = ilo_ccb_open(hw, data, slot);
- if (!error) {
- hw->ccb_alloc[slot] = data;
- hw->ccb_alloc[slot]->ccb_cnt = 1;
- hw->ccb_alloc[slot]->ccb_excl = fp->f_flags & O_EXCL;
- hw->ccb_alloc[slot]->ilo_hw = hw;
- } else
+ error = ilo_ccb_setup(hw, data, slot);
+ if (error) {
+ kfree(data);
+ goto out;
+ }
+
+ /* write the ccb to hw */
+ ilo_ccb_open(hw, data, slot);
+
+ /* make sure the channel is functional */
+ error = ilo_ccb_verify(hw, data);
+ if (error) {
+ ilo_ccb_close(hw->ilo_dev, data);
kfree(data);
+ goto out;
+ }
+
+ data->ccb_cnt = 1;
+ data->ccb_excl = fp->f_flags & O_EXCL;
+ data->ilo_hw = hw;
+ hw->ccb_alloc[slot] = data;
+
} else {
kfree(data);
if (fp->f_flags & O_EXCL || hw->ccb_alloc[slot]->ccb_excl) {
@@ -554,6 +579,7 @@ static int ilo_open(struct inode *ip, struct file *fp)
error = 0;
}
}
+out:
spin_unlock(&hw->alloc_lock);
if (!error)
--
1.6.4.2
From: David Altobelli <[email protected]>
Add interrupt handler to hpilo. This is enablement for poll handler,
and it also simplifies the logic for handling an iLO reset, because now
only the interrupt handler needs to look for reset, the file system
interfaces only need to return failure when a reset has happened.
Signed-off-by: David Altobelli <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
drivers/misc/hpilo.c | 138 ++++++++++++++++++++++++++++++++++----------------
drivers/misc/hpilo.h | 8 +++-
2 files changed, 101 insertions(+), 45 deletions(-)
diff --git a/drivers/misc/hpilo.c b/drivers/misc/hpilo.c
index 35ed123..9a370d5 100644
--- a/drivers/misc/hpilo.c
+++ b/drivers/misc/hpilo.c
@@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/pci.h>
+#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/device.h>
#include <linux/file.h>
@@ -21,6 +22,7 @@
#include <linux/delay.h>
#include <linux/uaccess.h>
#include <linux/io.h>
+#include <linux/wait.h>
#include "hpilo.h"
static struct class *ilo_class;
@@ -61,9 +63,10 @@ static inline int desc_mem_sz(int nr_entry)
static int fifo_enqueue(struct ilo_hwinfo *hw, char *fifobar, int entry)
{
struct fifo *fifo_q = FIFOBARTOHANDLE(fifobar);
+ unsigned long flags;
int ret = 0;
- spin_lock(&hw->fifo_lock);
+ spin_lock_irqsave(&hw->fifo_lock, flags);
if (!(fifo_q->fifobar[(fifo_q->tail + 1) & fifo_q->imask]
& ENTRY_MASK_O)) {
fifo_q->fifobar[fifo_q->tail & fifo_q->imask] |=
@@ -71,7 +74,7 @@ static int fifo_enqueue(struct ilo_hwinfo *hw, char *fifobar, int entry)
fifo_q->tail += 1;
ret = 1;
}
- spin_unlock(&hw->fifo_lock);
+ spin_unlock_irqrestore(&hw->fifo_lock, flags);
return ret;
}
@@ -79,10 +82,11 @@ static int fifo_enqueue(struct ilo_hwinfo *hw, char *fifobar, int entry)
static int fifo_dequeue(struct ilo_hwinfo *hw, char *fifobar, int *entry)
{
struct fifo *fifo_q = FIFOBARTOHANDLE(fifobar);
+ unsigned long flags;
int ret = 0;
u64 c;
- spin_lock(&hw->fifo_lock);
+ spin_lock_irqsave(&hw->fifo_lock, flags);
c = fifo_q->fifobar[fifo_q->head & fifo_q->imask];
if (c & ENTRY_MASK_C) {
if (entry)
@@ -93,7 +97,7 @@ static int fifo_dequeue(struct ilo_hwinfo *hw, char *fifobar, int *entry)
fifo_q->head += 1;
ret = 1;
}
- spin_unlock(&hw->fifo_lock);
+ spin_unlock_irqrestore(&hw->fifo_lock, flags);
return ret;
}
@@ -374,7 +378,18 @@ static inline void clear_device(struct ilo_hwinfo *hw)
clear_pending_db(hw, -1);
}
-static void ilo_locked_reset(struct ilo_hwinfo *hw)
+static inline void ilo_enable_interrupts(struct ilo_hwinfo *hw)
+{
+ iowrite8(ioread8(&hw->mmio_vaddr[DB_IRQ]) | 1, &hw->mmio_vaddr[DB_IRQ]);
+}
+
+static inline void ilo_disable_interrupts(struct ilo_hwinfo *hw)
+{
+ iowrite8(ioread8(&hw->mmio_vaddr[DB_IRQ]) & ~1,
+ &hw->mmio_vaddr[DB_IRQ]);
+}
+
+static void ilo_set_reset(struct ilo_hwinfo *hw)
{
int slot;
@@ -387,19 +402,6 @@ static void ilo_locked_reset(struct ilo_hwinfo *hw)
continue;
set_channel_reset(&hw->ccb_alloc[slot]->driver_ccb);
}
-
- clear_device(hw);
-}
-
-static void ilo_reset(struct ilo_hwinfo *hw)
-{
- spin_lock(&hw->alloc_lock);
-
- /* reset might have been handled after lock was taken */
- if (is_device_reset(hw))
- ilo_locked_reset(hw);
-
- spin_unlock(&hw->alloc_lock);
}
static ssize_t ilo_read(struct file *fp, char __user *buf,
@@ -411,12 +413,11 @@ static ssize_t ilo_read(struct file *fp, char __user *buf,
struct ilo_hwinfo *hw = data->ilo_hw;
void *pkt;
- if (is_device_reset(hw) || is_channel_reset(driver_ccb)) {
+ if (is_channel_reset(driver_ccb)) {
/*
* If the device has been reset, applications
* need to close and reopen all ccbs.
*/
- ilo_reset(hw);
return -ENODEV;
}
@@ -462,14 +463,8 @@ static ssize_t ilo_write(struct file *fp, const char __user *buf,
struct ilo_hwinfo *hw = data->ilo_hw;
void *pkt;
- if (is_device_reset(hw) || is_channel_reset(driver_ccb)) {
- /*
- * If the device has been reset, applications
- * need to close and reopen all ccbs.
- */
- ilo_reset(hw);
+ if (is_channel_reset(driver_ccb))
return -ENODEV;
- }
/* get a packet to send the user command */
if (!ilo_pkt_dequeue(hw, driver_ccb, SENDQ, &pkt_id, &pkt_len, &pkt))
@@ -496,27 +491,28 @@ static int ilo_close(struct inode *ip, struct file *fp)
int slot;
struct ccb_data *data;
struct ilo_hwinfo *hw;
+ unsigned long flags;
slot = iminor(ip) % MAX_CCB;
hw = container_of(ip->i_cdev, struct ilo_hwinfo, cdev);
- spin_lock(&hw->alloc_lock);
-
- if (is_device_reset(hw))
- ilo_locked_reset(hw);
+ spin_lock(&hw->open_lock);
if (hw->ccb_alloc[slot]->ccb_cnt == 1) {
data = fp->private_data;
+ spin_lock_irqsave(&hw->alloc_lock, flags);
+ hw->ccb_alloc[slot] = NULL;
+ spin_unlock_irqrestore(&hw->alloc_lock, flags);
+
ilo_ccb_close(hw->ilo_dev, data);
kfree(data);
- hw->ccb_alloc[slot] = NULL;
} else
hw->ccb_alloc[slot]->ccb_cnt--;
- spin_unlock(&hw->alloc_lock);
+ spin_unlock(&hw->open_lock);
return 0;
}
@@ -526,6 +522,7 @@ static int ilo_open(struct inode *ip, struct file *fp)
int slot, error;
struct ccb_data *data;
struct ilo_hwinfo *hw;
+ unsigned long flags;
slot = iminor(ip) % MAX_CCB;
hw = container_of(ip->i_cdev, struct ilo_hwinfo, cdev);
@@ -535,10 +532,7 @@ static int ilo_open(struct inode *ip, struct file *fp)
if (!data)
return -ENOMEM;
- spin_lock(&hw->alloc_lock);
-
- if (is_device_reset(hw))
- ilo_locked_reset(hw);
+ spin_lock(&hw->open_lock);
/* each fd private_data holds sw/hw view of ccb */
if (hw->ccb_alloc[slot] == NULL) {
@@ -549,22 +543,31 @@ static int ilo_open(struct inode *ip, struct file *fp)
goto out;
}
+ data->ccb_cnt = 1;
+ data->ccb_excl = fp->f_flags & O_EXCL;
+ data->ilo_hw = hw;
+ init_waitqueue_head(&data->ccb_waitq);
+
/* write the ccb to hw */
+ spin_lock_irqsave(&hw->alloc_lock, flags);
ilo_ccb_open(hw, data, slot);
+ hw->ccb_alloc[slot] = data;
+ spin_unlock_irqrestore(&hw->alloc_lock, flags);
/* make sure the channel is functional */
error = ilo_ccb_verify(hw, data);
if (error) {
+
+ spin_lock_irqsave(&hw->alloc_lock, flags);
+ hw->ccb_alloc[slot] = NULL;
+ spin_unlock_irqrestore(&hw->alloc_lock, flags);
+
ilo_ccb_close(hw->ilo_dev, data);
+
kfree(data);
goto out;
}
- data->ccb_cnt = 1;
- data->ccb_excl = fp->f_flags & O_EXCL;
- data->ilo_hw = hw;
- hw->ccb_alloc[slot] = data;
-
} else {
kfree(data);
if (fp->f_flags & O_EXCL || hw->ccb_alloc[slot]->ccb_excl) {
@@ -580,7 +583,7 @@ static int ilo_open(struct inode *ip, struct file *fp)
}
}
out:
- spin_unlock(&hw->alloc_lock);
+ spin_unlock(&hw->open_lock);
if (!error)
fp->private_data = hw->ccb_alloc[slot];
@@ -596,6 +599,41 @@ static const struct file_operations ilo_fops = {
.release = ilo_close,
};
+static irqreturn_t ilo_isr(int irq, void *data)
+{
+ struct ilo_hwinfo *hw = data;
+ int pending, i;
+
+ spin_lock(&hw->alloc_lock);
+
+ /* check for ccbs which have data */
+ pending = get_device_outbound(hw);
+ if (!pending) {
+ spin_unlock(&hw->alloc_lock);
+ return IRQ_NONE;
+ }
+
+ if (is_db_reset(pending)) {
+ /* wake up all ccbs if the device was reset */
+ pending = -1;
+ ilo_set_reset(hw);
+ }
+
+ for (i = 0; i < MAX_CCB; i++) {
+ if (!hw->ccb_alloc[i])
+ continue;
+ if (pending & (1 << i))
+ wake_up_interruptible(&hw->ccb_alloc[i]->ccb_waitq);
+ }
+
+ /* clear the device of the channels that have been handled */
+ clear_pending_db(hw, pending);
+
+ spin_unlock(&hw->alloc_lock);
+
+ return IRQ_HANDLED;
+}
+
static void ilo_unmap_device(struct pci_dev *pdev, struct ilo_hwinfo *hw)
{
pci_iounmap(pdev, hw->db_vaddr);
@@ -649,6 +687,8 @@ static void ilo_remove(struct pci_dev *pdev)
device_destroy(ilo_class, MKDEV(ilo_major, i));
cdev_del(&ilo_hw->cdev);
+ ilo_disable_interrupts(ilo_hw);
+ free_irq(pdev->irq, ilo_hw);
ilo_unmap_device(pdev, ilo_hw);
pci_release_regions(pdev);
pci_disable_device(pdev);
@@ -684,6 +724,7 @@ static int __devinit ilo_probe(struct pci_dev *pdev,
ilo_hw->ilo_dev = pdev;
spin_lock_init(&ilo_hw->alloc_lock);
spin_lock_init(&ilo_hw->fifo_lock);
+ spin_lock_init(&ilo_hw->open_lock);
error = pci_enable_device(pdev);
if (error)
@@ -702,13 +743,19 @@ static int __devinit ilo_probe(struct pci_dev *pdev,
pci_set_drvdata(pdev, ilo_hw);
clear_device(ilo_hw);
+ error = request_irq(pdev->irq, ilo_isr, IRQF_SHARED, "hpilo", ilo_hw);
+ if (error)
+ goto unmap;
+
+ ilo_enable_interrupts(ilo_hw);
+
cdev_init(&ilo_hw->cdev, &ilo_fops);
ilo_hw->cdev.owner = THIS_MODULE;
start = devnum * MAX_CCB;
error = cdev_add(&ilo_hw->cdev, MKDEV(ilo_major, start), MAX_CCB);
if (error) {
dev_err(&pdev->dev, "Could not add cdev\n");
- goto unmap;
+ goto remove_isr;
}
for (minor = 0 ; minor < MAX_CCB; minor++) {
@@ -721,6 +768,9 @@ static int __devinit ilo_probe(struct pci_dev *pdev,
}
return 0;
+remove_isr:
+ ilo_disable_interrupts(ilo_hw);
+ free_irq(pdev->irq, ilo_hw);
unmap:
ilo_unmap_device(pdev, ilo_hw);
free_regions:
diff --git a/drivers/misc/hpilo.h b/drivers/misc/hpilo.h
index 03a14c8..3857605 100644
--- a/drivers/misc/hpilo.h
+++ b/drivers/misc/hpilo.h
@@ -46,11 +46,14 @@ struct ilo_hwinfo {
spinlock_t alloc_lock;
spinlock_t fifo_lock;
+ spinlock_t open_lock;
struct cdev cdev;
};
-/* offset from mmio_vaddr */
+/* offset from mmio_vaddr for enabling doorbell interrupts */
+#define DB_IRQ 0xB2
+/* offset from mmio_vaddr for outbound communications */
#define DB_OUT 0xD4
/* DB_OUT reset bit */
#define DB_RESET 26
@@ -131,6 +134,9 @@ struct ccb_data {
/* pointer to hardware device info */
struct ilo_hwinfo *ilo_hw;
+ /* queue for this ccb to wait for recv data */
+ wait_queue_head_t ccb_waitq;
+
/* usage count, to allow for shared ccb's */
int ccb_cnt;
--
1.6.4.2
From: David Altobelli <[email protected]>
Add poll handler to hpilo, to allow applications a low overhead method
of waiting for data.
Signed-off-by: David Altobelli <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
drivers/misc/hpilo.c | 42 +++++++++++++++++++++++++++++++++++++++++-
1 files changed, 41 insertions(+), 1 deletions(-)
diff --git a/drivers/misc/hpilo.c b/drivers/misc/hpilo.c
index 9a370d5..1ad27c6 100644
--- a/drivers/misc/hpilo.c
+++ b/drivers/misc/hpilo.c
@@ -23,6 +23,7 @@
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/wait.h>
+#include <linux/poll.h>
#include "hpilo.h"
static struct class *ilo_class;
@@ -102,6 +103,22 @@ static int fifo_dequeue(struct ilo_hwinfo *hw, char *fifobar, int *entry)
return ret;
}
+static int fifo_check_recv(struct ilo_hwinfo *hw, char *fifobar)
+{
+ struct fifo *fifo_q = FIFOBARTOHANDLE(fifobar);
+ unsigned long flags;
+ int ret = 0;
+ u64 c;
+
+ spin_lock_irqsave(&hw->fifo_lock, flags);
+ c = fifo_q->fifobar[fifo_q->head & fifo_q->imask];
+ if (c & ENTRY_MASK_C)
+ ret = 1;
+ spin_unlock_irqrestore(&hw->fifo_lock, flags);
+
+ return ret;
+}
+
static int ilo_pkt_enqueue(struct ilo_hwinfo *hw, struct ccb *ccb,
int dir, int id, int len)
{
@@ -146,6 +163,13 @@ static int ilo_pkt_dequeue(struct ilo_hwinfo *hw, struct ccb *ccb,
return ret;
}
+static int ilo_pkt_recv(struct ilo_hwinfo *hw, struct ccb *ccb)
+{
+ char *fifobar = ccb->ccb_u3.recv_fifobar;
+
+ return fifo_check_recv(hw, fifobar);
+}
+
static inline void doorbell_set(struct ccb *ccb)
{
iowrite8(1, ccb->ccb_u5.db_base);
@@ -486,6 +510,21 @@ static ssize_t ilo_write(struct file *fp, const char __user *buf,
return err ? -EFAULT : len;
}
+static unsigned int ilo_poll(struct file *fp, poll_table *wait)
+{
+ struct ccb_data *data = fp->private_data;
+ struct ccb *driver_ccb = &data->driver_ccb;
+
+ poll_wait(fp, &data->ccb_waitq, wait);
+
+ if (is_channel_reset(driver_ccb))
+ return POLLERR;
+ else if (ilo_pkt_recv(data->ilo_hw, driver_ccb))
+ return POLLIN | POLLRDNORM;
+
+ return 0;
+}
+
static int ilo_close(struct inode *ip, struct file *fp)
{
int slot;
@@ -595,6 +634,7 @@ static const struct file_operations ilo_fops = {
.owner = THIS_MODULE,
.read = ilo_read,
.write = ilo_write,
+ .poll = ilo_poll,
.open = ilo_open,
.release = ilo_close,
};
@@ -835,7 +875,7 @@ static void __exit ilo_exit(void)
class_destroy(ilo_class);
}
-MODULE_VERSION("1.1");
+MODULE_VERSION("1.2");
MODULE_ALIAS(ILO_NAME);
MODULE_DESCRIPTION(ILO_NAME);
MODULE_AUTHOR("David Altobelli <[email protected]>");
--
1.6.4.2
From: GeunSik Lim <[email protected]>
We need common default directory of denbugfs for consistency.
(debugfs's default directory is /sys/kernel/debug/ by debugfs.)
Signed-off-by: GeunSik Lim <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
Documentation/trace/events.txt | 24 ++++++++++++------------
1 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/Documentation/trace/events.txt b/Documentation/trace/events.txt
index 2bcc8d4..90e8b33 100644
--- a/Documentation/trace/events.txt
+++ b/Documentation/trace/events.txt
@@ -22,12 +22,12 @@ tracing information should be printed.
---------------------------------
The events which are available for tracing can be found in the file
-/debug/tracing/available_events.
+/sys/kernel/debug/tracing/available_events.
To enable a particular event, such as 'sched_wakeup', simply echo it
-to /debug/tracing/set_event. For example:
+to /sys/kernel/debug/tracing/set_event. For example:
- # echo sched_wakeup >> /debug/tracing/set_event
+ # echo sched_wakeup >> /sys/kernel/debug/tracing/set_event
[ Note: '>>' is necessary, otherwise it will firstly disable
all the events. ]
@@ -35,15 +35,15 @@ to /debug/tracing/set_event. For example:
To disable an event, echo the event name to the set_event file prefixed
with an exclamation point:
- # echo '!sched_wakeup' >> /debug/tracing/set_event
+ # echo '!sched_wakeup' >> /sys/kernel/debug/tracing/set_event
To disable all events, echo an empty line to the set_event file:
- # echo > /debug/tracing/set_event
+ # echo > /sys/kernel/debug/tracing/set_event
To enable all events, echo '*:*' or '*:' to the set_event file:
- # echo *:* > /debug/tracing/set_event
+ # echo *:* > /sys/kernel/debug/tracing/set_event
The events are organized into subsystems, such as ext4, irq, sched,
etc., and a full event name looks like this: <subsystem>:<event>. The
@@ -52,29 +52,29 @@ file. All of the events in a subsystem can be specified via the syntax
"<subsystem>:*"; for example, to enable all irq events, you can use the
command:
- # echo 'irq:*' > /debug/tracing/set_event
+ # echo 'irq:*' > /sys/kernel/debug/tracing/set_event
2.2 Via the 'enable' toggle
---------------------------
-The events available are also listed in /debug/tracing/events/ hierarchy
+The events available are also listed in /sys/kernel/debug/tracing/events/ hierarchy
of directories.
To enable event 'sched_wakeup':
- # echo 1 > /debug/tracing/events/sched/sched_wakeup/enable
+ # echo 1 > /sys/kernel/debug/tracing/events/sched/sched_wakeup/enable
To disable it:
- # echo 0 > /debug/tracing/events/sched/sched_wakeup/enable
+ # echo 0 > /sys/kernel/debug/tracing/events/sched/sched_wakeup/enable
To enable all events in sched subsystem:
- # echo 1 > /debug/tracing/events/sched/enable
+ # echo 1 > /sys/kernel/debug/tracing/events/sched/enable
To eanble all events:
- # echo 1 > /debug/tracing/events/enable
+ # echo 1 > /sys/kernel/debug/tracing/events/enable
When reading one of these enable files, there are four results:
--
1.6.4.2
From: GeunSik Lim <[email protected]>
Default directory of debug filesystem for ftrace is /sys/kernel/debug/.
Signed-off-by: GeunSik Lim <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
samples/trace_events/trace-events-sample.h | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/samples/trace_events/trace-events-sample.h b/samples/trace_events/trace-events-sample.h
index f24ae37..6af3732 100644
--- a/samples/trace_events/trace-events-sample.h
+++ b/samples/trace_events/trace-events-sample.h
@@ -1,6 +1,6 @@
/*
* If TRACE_SYSTEM is defined, that will be the directory created
- * in the ftrace directory under /debugfs/tracing/events/<system>
+ * in the ftrace directory under /sys/kernel/debug/tracing/events/<system>
*
* The define_trace.h below will also look for a file name of
* TRACE_SYSTEM.h where TRACE_SYSTEM is what is defined here.
--
1.6.4.2
From: GeunSik Lim <[email protected]>
Change default debugfs directory that mount for debugging
IWMC3200(Intel Wireless Multicomm 3200 WiFi driver).
As we all know, We need change default directory for consistency of
debugfs by Greg.K.H
Signed-off-by: GeunSik Lim <[email protected]>
Acked-by: Zhu Yi <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
drivers/net/wireless/iwmc3200wifi/Kconfig | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/iwmc3200wifi/Kconfig b/drivers/net/wireless/iwmc3200wifi/Kconfig
index c62da43..c25a043 100644
--- a/drivers/net/wireless/iwmc3200wifi/Kconfig
+++ b/drivers/net/wireless/iwmc3200wifi/Kconfig
@@ -24,8 +24,8 @@ config IWM_DEBUG
To see the list of debug modules and levels, see iwm/debug.h
For example, if you want the full MLME debug output:
- echo 0xff > /debug/iwm/phyN/debug/mlme
+ echo 0xff > /sys/kernel/debug/iwm/phyN/debug/mlme
Or, if you want the full debug, for all modules:
- echo 0xff > /debug/iwm/phyN/debug/level
- echo 0xff > /debug/iwm/phyN/debug/modules
+ echo 0xff > /sys/kernel/debug/iwm/phyN/debug/level
+ echo 0xff > /sys/kernel/debug/iwm/phyN/debug/modules
--
1.6.4.2
From: GeunSik Lim <[email protected]>
Change default debugfs directory as mounting point for debugging
UHCI(Universal Host Controller Interface driver) for USB.
As we all know, We need change default directory for consistency of
debugfs by Greg K-H
Signed-off-by: GeunSik Lim <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
drivers/usb/host/uhci-hcd.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index 274751b..5cd0e48 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -67,7 +67,7 @@ MODULE_PARM_DESC(ignore_oc, "ignore hardware overcurrent indications");
* debug = 0, no debugging messages
* debug = 1, dump failed URBs except for stalls
* debug = 2, dump all failed URBs (including stalls)
- * show all queues in /debug/uhci/[pci_addr]
+ * show all queues in /sys/kernel/debug/uhci/[pci_addr]
* debug = 3, show all TDs in URBs when dumping
*/
#ifdef DEBUG
--
1.6.4.2
From: GeunSik Lim <[email protected]>
As we all know, We need change default directory for consistency of
debugfs by Greg K-H
Signed-off-by: GeunSik Lim <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
drivers/block/pktcdvd.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index 99a506f..95f11cd 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -92,7 +92,7 @@ static struct mutex ctl_mutex; /* Serialize open/close/setup/teardown */
static mempool_t *psd_pool;
static struct class *class_pktcdvd = NULL; /* /sys/class/pktcdvd */
-static struct dentry *pkt_debugfs_root = NULL; /* /debug/pktcdvd */
+static struct dentry *pkt_debugfs_root = NULL; /* /sys/kernel/debug/pktcdvd */
/* forward declaration */
static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev);
--
1.6.4.2
From: Kay Sievers <[email protected]>
Devtmpfs lets the kernel create a tmpfs instance called devtmpfs
very early at kernel initialization, before any driver-core device
is registered. Every device with a major/minor will provide a
device node in devtmpfs.
Devtmpfs can be changed and altered by userspace at any time,
and in any way needed - just like today's udev-mounted tmpfs.
Unmodified udev versions will run just fine on top of it, and will
recognize an already existing kernel-created device node and use it.
The default node permissions are root:root 0600. Proper permissions
and user/group ownership, meaningful symlinks, all other policy still
needs to be applied by userspace.
If a node is created by devtmps, devtmpfs will remove the device node
when the device goes away. If the device node was created by
userspace, or the devtmpfs created node was replaced by userspace, it
will no longer be removed by devtmpfs.
If it is requested to auto-mount it, it makes init=/bin/sh work
without any further userspace support. /dev will be fully populated
and dynamic, and always reflect the current device state of the kernel.
With the commonly used dynamic device numbers, it solves the problem
where static devices nodes may point to the wrong devices.
It is intended to make the initial bootup logic simpler and more robust,
by de-coupling the creation of the inital environment, to reliably run
userspace processes, from a complex userspace bootstrap logic to provide
a working /dev.
Signed-off-by: Kay Sievers <[email protected]>
Signed-off-by: Jan Blunck <[email protected]>
Tested-By: Harald Hoyer <[email protected]>
Tested-By: Scott James Remnant <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
drivers/base/Kconfig | 25 +++
drivers/base/Makefile | 1 +
drivers/base/base.h | 6 +
drivers/base/core.c | 3 +
drivers/base/devtmpfs.c | 367 ++++++++++++++++++++++++++++++++++++++++++++++
drivers/base/init.c | 1 +
include/linux/device.h | 10 ++
include/linux/shmem_fs.h | 3 +
init/do_mounts.c | 2 +-
init/main.c | 2 +
mm/shmem.c | 9 +-
11 files changed, 422 insertions(+), 7 deletions(-)
create mode 100644 drivers/base/devtmpfs.c
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index 8f006f9..ee37727 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -8,6 +8,31 @@ config UEVENT_HELPER_PATH
Path to uevent helper program forked by the kernel for
every uevent.
+config DEVTMPFS
+ bool "Create a kernel maintained /dev tmpfs (EXPERIMENTAL)"
+ depends on HOTPLUG && SHMEM && TMPFS
+ help
+ This creates a tmpfs filesystem, and mounts it at bootup
+ and mounts it at /dev. The kernel driver core creates device
+ nodes for all registered devices in that filesystem. All device
+ nodes are owned by root and have the default mode of 0600.
+ Userspace can add and delete the nodes as needed. This is
+ intended to simplify bootup, and make it possible to delay
+ the initial coldplug at bootup done by udev in userspace.
+ It should also provide a simpler way for rescue systems
+ to bring up a kernel with dynamic major/minor numbers.
+ Meaningful symlinks, permissions and device ownership must
+ still be handled by userspace.
+ If unsure, say N here.
+
+config DEVTMPFS_MOUNT
+ bool "Automount devtmpfs at /dev"
+ depends on DEVTMPFS
+ help
+ This will mount devtmpfs at /dev if the kernel mounts the root
+ filesystem. It will not affect initramfs based mounting.
+ If unsure, say N here.
+
config STANDALONE
bool "Select only drivers that don't need compile-time external firmware" if EXPERIMENTAL
default y
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 1b2640c..c12c7f2 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -4,6 +4,7 @@ obj-y := core.o sys.o bus.o dd.o \
driver.o class.o platform.o \
cpu.o firmware.o init.o map.o devres.o \
attribute_container.o transport_class.o
+obj-$(CONFIG_DEVTMPFS) += devtmpfs.o
obj-y += power/
obj-$(CONFIG_HAS_DMA) += dma-mapping.o
obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o
diff --git a/drivers/base/base.h b/drivers/base/base.h
index 503d59c..2ca7f5b 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -139,3 +139,9 @@ static inline void module_add_driver(struct module *mod,
struct device_driver *drv) { }
static inline void module_remove_driver(struct device_driver *drv) { }
#endif
+
+#ifdef CONFIG_DEVTMPFS
+extern int devtmpfs_init(void);
+#else
+static inline int devtmpfs_init(void) { return 0; }
+#endif
diff --git a/drivers/base/core.c b/drivers/base/core.c
index a992985..390e664 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -929,6 +929,8 @@ int device_add(struct device *dev)
error = device_create_sys_dev_entry(dev);
if (error)
goto devtattrError;
+
+ devtmpfs_create_node(dev);
}
error = device_add_class_symlinks(dev);
@@ -1075,6 +1077,7 @@ void device_del(struct device *dev)
if (parent)
klist_del(&dev->p->knode_parent);
if (MAJOR(dev->devt)) {
+ devtmpfs_delete_node(dev);
device_remove_sys_dev_entry(dev);
device_remove_file(dev, &devt_attr);
}
diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c
new file mode 100644
index 0000000..fd488ad
--- /dev/null
+++ b/drivers/base/devtmpfs.c
@@ -0,0 +1,367 @@
+/*
+ * devtmpfs - kernel-maintained tmpfs-based /dev
+ *
+ * Copyright (C) 2009, Kay Sievers <[email protected]>
+ *
+ * During bootup, before any driver core device is registered,
+ * devtmpfs, a tmpfs-based filesystem is created. Every driver-core
+ * device which requests a device node, will add a node in this
+ * filesystem. The node is named after the the name of the device,
+ * or the susbsytem can provide a custom name. All devices are
+ * owned by root and have a mode of 0600.
+ */
+
+#include <linux/kernel.h>
+#include <linux/syscalls.h>
+#include <linux/mount.h>
+#include <linux/device.h>
+#include <linux/genhd.h>
+#include <linux/namei.h>
+#include <linux/fs.h>
+#include <linux/shmem_fs.h>
+#include <linux/cred.h>
+#include <linux/init_task.h>
+
+static struct vfsmount *dev_mnt;
+
+#if defined CONFIG_DEVTMPFS_MOUNT
+static int dev_mount = 1;
+#else
+static int dev_mount;
+#endif
+
+static int __init mount_param(char *str)
+{
+ dev_mount = simple_strtoul(str, NULL, 0);
+ return 1;
+}
+__setup("devtmpfs.mount=", mount_param);
+
+static int dev_get_sb(struct file_system_type *fs_type, int flags,
+ const char *dev_name, void *data, struct vfsmount *mnt)
+{
+ return get_sb_single(fs_type, flags, data, shmem_fill_super, mnt);
+}
+
+static struct file_system_type dev_fs_type = {
+ .name = "devtmpfs",
+ .get_sb = dev_get_sb,
+ .kill_sb = kill_litter_super,
+};
+
+#ifdef CONFIG_BLOCK
+static inline int is_blockdev(struct device *dev)
+{
+ return dev->class == &block_class;
+}
+#else
+static inline int is_blockdev(struct device *dev) { return 0; }
+#endif
+
+static int dev_mkdir(const char *name, mode_t mode)
+{
+ struct nameidata nd;
+ struct dentry *dentry;
+ int err;
+
+ err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
+ name, LOOKUP_PARENT, &nd);
+ if (err)
+ return err;
+
+ dentry = lookup_create(&nd, 1);
+ if (!IS_ERR(dentry)) {
+ err = vfs_mkdir(nd.path.dentry->d_inode, dentry, mode);
+ dput(dentry);
+ } else {
+ err = PTR_ERR(dentry);
+ }
+ mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
+
+ path_put(&nd.path);
+ return err;
+}
+
+static int create_path(const char *nodepath)
+{
+ char *path;
+ struct nameidata nd;
+ int err = 0;
+
+ path = kstrdup(nodepath, GFP_KERNEL);
+ if (!path)
+ return -ENOMEM;
+
+ err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
+ path, LOOKUP_PARENT, &nd);
+ if (err == 0) {
+ struct dentry *dentry;
+
+ /* create directory right away */
+ dentry = lookup_create(&nd, 1);
+ if (!IS_ERR(dentry)) {
+ err = vfs_mkdir(nd.path.dentry->d_inode,
+ dentry, 0755);
+ dput(dentry);
+ }
+ mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
+
+ path_put(&nd.path);
+ } else if (err == -ENOENT) {
+ char *s;
+
+ /* parent directories do not exist, create them */
+ s = path;
+ while (1) {
+ s = strchr(s, '/');
+ if (!s)
+ break;
+ s[0] = '\0';
+ err = dev_mkdir(path, 0755);
+ if (err && err != -EEXIST)
+ break;
+ s[0] = '/';
+ s++;
+ }
+ }
+
+ kfree(path);
+ return err;
+}
+
+int devtmpfs_create_node(struct device *dev)
+{
+ const char *tmp = NULL;
+ const char *nodename;
+ const struct cred *curr_cred;
+ mode_t mode;
+ struct nameidata nd;
+ struct dentry *dentry;
+ int err;
+
+ if (!dev_mnt)
+ return 0;
+
+ nodename = device_get_nodename(dev, &tmp);
+ if (!nodename)
+ return -ENOMEM;
+
+ if (is_blockdev(dev))
+ mode = S_IFBLK|0600;
+ else
+ mode = S_IFCHR|0600;
+
+ curr_cred = override_creds(&init_cred);
+ err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
+ nodename, LOOKUP_PARENT, &nd);
+ if (err == -ENOENT) {
+ /* create missing parent directories */
+ create_path(nodename);
+ err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
+ nodename, LOOKUP_PARENT, &nd);
+ if (err)
+ goto out;
+ }
+
+ dentry = lookup_create(&nd, 0);
+ if (!IS_ERR(dentry)) {
+ err = vfs_mknod(nd.path.dentry->d_inode,
+ dentry, mode, dev->devt);
+ /* mark as kernel created inode */
+ if (!err)
+ dentry->d_inode->i_private = &dev_mnt;
+ dput(dentry);
+ } else {
+ err = PTR_ERR(dentry);
+ }
+ mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
+
+ path_put(&nd.path);
+out:
+ kfree(tmp);
+ revert_creds(curr_cred);
+ return err;
+}
+
+static int dev_rmdir(const char *name)
+{
+ struct nameidata nd;
+ struct dentry *dentry;
+ int err;
+
+ err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
+ name, LOOKUP_PARENT, &nd);
+ if (err)
+ return err;
+
+ mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
+ dentry = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len);
+ if (!IS_ERR(dentry)) {
+ if (dentry->d_inode)
+ err = vfs_rmdir(nd.path.dentry->d_inode, dentry);
+ else
+ err = -ENOENT;
+ dput(dentry);
+ } else {
+ err = PTR_ERR(dentry);
+ }
+ mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
+
+ path_put(&nd.path);
+ return err;
+}
+
+static int delete_path(const char *nodepath)
+{
+ const char *path;
+ int err = 0;
+
+ path = kstrdup(nodepath, GFP_KERNEL);
+ if (!path)
+ return -ENOMEM;
+
+ while (1) {
+ char *base;
+
+ base = strrchr(path, '/');
+ if (!base)
+ break;
+ base[0] = '\0';
+ err = dev_rmdir(path);
+ if (err)
+ break;
+ }
+
+ kfree(path);
+ return err;
+}
+
+static int dev_mynode(struct device *dev, struct inode *inode, struct kstat *stat)
+{
+ /* did we create it */
+ if (inode->i_private != &dev_mnt)
+ return 0;
+
+ /* does the dev_t match */
+ if (is_blockdev(dev)) {
+ if (!S_ISBLK(stat->mode))
+ return 0;
+ } else {
+ if (!S_ISCHR(stat->mode))
+ return 0;
+ }
+ if (stat->rdev != dev->devt)
+ return 0;
+
+ /* ours */
+ return 1;
+}
+
+int devtmpfs_delete_node(struct device *dev)
+{
+ const char *tmp = NULL;
+ const char *nodename;
+ const struct cred *curr_cred;
+ struct nameidata nd;
+ struct dentry *dentry;
+ struct kstat stat;
+ int deleted = 1;
+ int err;
+
+ if (!dev_mnt)
+ return 0;
+
+ nodename = device_get_nodename(dev, &tmp);
+ if (!nodename)
+ return -ENOMEM;
+
+ curr_cred = override_creds(&init_cred);
+ err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
+ nodename, LOOKUP_PARENT, &nd);
+ if (err)
+ goto out;
+
+ mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
+ dentry = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len);
+ if (!IS_ERR(dentry)) {
+ if (dentry->d_inode) {
+ err = vfs_getattr(nd.path.mnt, dentry, &stat);
+ if (!err && dev_mynode(dev, dentry->d_inode, &stat)) {
+ err = vfs_unlink(nd.path.dentry->d_inode,
+ dentry);
+ if (!err || err == -ENOENT)
+ deleted = 1;
+ }
+ } else {
+ err = -ENOENT;
+ }
+ dput(dentry);
+ } else {
+ err = PTR_ERR(dentry);
+ }
+ mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
+
+ path_put(&nd.path);
+ if (deleted && strchr(nodename, '/'))
+ delete_path(nodename);
+out:
+ kfree(tmp);
+ revert_creds(curr_cred);
+ return err;
+}
+
+/*
+ * If configured, or requested by the commandline, devtmpfs will be
+ * auto-mounted after the kernel mounted the root filesystem.
+ */
+int devtmpfs_mount(const char *mountpoint)
+{
+ struct path path;
+ int err;
+
+ if (!dev_mount)
+ return 0;
+
+ if (!dev_mnt)
+ return 0;
+
+ err = kern_path(mountpoint, LOOKUP_FOLLOW, &path);
+ if (err)
+ return err;
+ err = do_add_mount(dev_mnt, &path, 0, NULL);
+ if (err)
+ printk(KERN_INFO "devtmpfs: error mounting %i\n", err);
+ else
+ printk(KERN_INFO "devtmpfs: mounted\n");
+ path_put(&path);
+ return err;
+}
+
+/*
+ * Create devtmpfs instance, driver-core devices will add their device
+ * nodes here.
+ */
+int __init devtmpfs_init(void)
+{
+ int err;
+ struct vfsmount *mnt;
+
+ err = register_filesystem(&dev_fs_type);
+ if (err) {
+ printk(KERN_ERR "devtmpfs: unable to register devtmpfs "
+ "type %i\n", err);
+ return err;
+ }
+
+ mnt = kern_mount(&dev_fs_type);
+ if (IS_ERR(mnt)) {
+ err = PTR_ERR(mnt);
+ printk(KERN_ERR "devtmpfs: unable to create devtmpfs %i\n", err);
+ unregister_filesystem(&dev_fs_type);
+ return err;
+ }
+ dev_mnt = mnt;
+
+ printk(KERN_INFO "devtmpfs: initialized\n");
+ return 0;
+}
diff --git a/drivers/base/init.c b/drivers/base/init.c
index 7bd9b6a..c8a934e 100644
--- a/drivers/base/init.c
+++ b/drivers/base/init.c
@@ -20,6 +20,7 @@
void __init driver_init(void)
{
/* These are the core pieces */
+ devtmpfs_init();
devices_init();
buses_init();
classes_init();
diff --git a/include/linux/device.h b/include/linux/device.h
index 62ff53a..847b763 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -552,6 +552,16 @@ extern void put_device(struct device *dev);
extern void wait_for_device_probe(void);
+#ifdef CONFIG_DEVTMPFS
+extern int devtmpfs_create_node(struct device *dev);
+extern int devtmpfs_delete_node(struct device *dev);
+extern int devtmpfs_mount(const char *mountpoint);
+#else
+static inline int devtmpfs_create_node(struct device *dev) { return 0; }
+static inline int devtmpfs_delete_node(struct device *dev) { return 0; }
+static inline int devtmpfs_mount(const char *mountpoint) { return 0; }
+#endif
+
/* drivers/base/power/shutdown.c */
extern void device_shutdown(void);
diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h
index 6d3f2f4..deee7af 100644
--- a/include/linux/shmem_fs.h
+++ b/include/linux/shmem_fs.h
@@ -38,6 +38,9 @@ static inline struct shmem_inode_info *SHMEM_I(struct inode *inode)
return container_of(inode, struct shmem_inode_info, vfs_inode);
}
+extern int init_tmpfs(void);
+extern int shmem_fill_super(struct super_block *sb, void *data, int silent);
+
#ifdef CONFIG_TMPFS_POSIX_ACL
int shmem_check_acl(struct inode *, int);
int shmem_acl_init(struct inode *, struct inode *);
diff --git a/init/do_mounts.c b/init/do_mounts.c
index 093f659..bb008d0 100644
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -415,7 +415,7 @@ void __init prepare_namespace(void)
mount_root();
out:
+ devtmpfs_mount("dev");
sys_mount(".", "/", NULL, MS_MOVE, NULL);
sys_chroot(".");
}
-
diff --git a/init/main.c b/init/main.c
index b34fd8e..8e6a784 100644
--- a/init/main.c
+++ b/init/main.c
@@ -68,6 +68,7 @@
#include <linux/async.h>
#include <linux/kmemcheck.h>
#include <linux/kmemtrace.h>
+#include <linux/shmem_fs.h>
#include <trace/boot.h>
#include <asm/io.h>
@@ -809,6 +810,7 @@ static void __init do_basic_setup(void)
init_workqueues();
cpuset_init_smp();
usermodehelper_init();
+ init_tmpfs();
driver_init();
init_irq_proc();
do_ctors();
diff --git a/mm/shmem.c b/mm/shmem.c
index 5a0b3d4..bd20f8b 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -2298,8 +2298,7 @@ static void shmem_put_super(struct super_block *sb)
sb->s_fs_info = NULL;
}
-static int shmem_fill_super(struct super_block *sb,
- void *data, int silent)
+int shmem_fill_super(struct super_block *sb, void *data, int silent)
{
struct inode *inode;
struct dentry *root;
@@ -2519,7 +2518,7 @@ static struct file_system_type tmpfs_fs_type = {
.kill_sb = kill_litter_super,
};
-static int __init init_tmpfs(void)
+int __init init_tmpfs(void)
{
int error;
@@ -2576,7 +2575,7 @@ static struct file_system_type tmpfs_fs_type = {
.kill_sb = kill_litter_super,
};
-static int __init init_tmpfs(void)
+int __init init_tmpfs(void)
{
BUG_ON(register_filesystem(&tmpfs_fs_type) != 0);
@@ -2687,5 +2686,3 @@ int shmem_zero_setup(struct vm_area_struct *vma)
vma->vm_ops = &shmem_vm_ops;
return 0;
}
-
-module_init(init_tmpfs)
--
1.6.4.2
On Tue, Sep 15, 2009 at 12:12:40PM -0700, Greg Kroah-Hartman wrote:
> From: Daniel Mack <[email protected]>
>
> 'default n' is the default, there is no need for these lines.
That's quite true.
I must have forgotten to sign-off this one, you can add my signed-off-by,
if you like.
Thanks,
Hans
>
> Signed-off-by: Daniel Mack <[email protected]>
> Cc: Hans J. Koch <[email protected]>
> Signed-off-by: Greg Kroah-Hartman <[email protected]>
Signed-off-by: Hans J. Koch <[email protected]>
> ---
> drivers/uio/Kconfig | 5 -----
> 1 files changed, 0 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig
> index 7f86534..45200fd 100644
> --- a/drivers/uio/Kconfig
> +++ b/drivers/uio/Kconfig
> @@ -1,7 +1,6 @@
> menuconfig UIO
> tristate "Userspace I/O drivers"
> depends on !S390
> - default n
> help
> Enable this to allow the userspace driver core code to be
> built. This code allows userspace programs easy access to
> @@ -16,7 +15,6 @@ if UIO
> config UIO_CIF
> tristate "generic Hilscher CIF Card driver"
> depends on PCI
> - default n
> help
> Driver for Hilscher CIF DeviceNet and Profibus cards. This
> driver requires a userspace component that handles all of the
> @@ -48,7 +46,6 @@ config UIO_PDRV_GENIRQ
>
> config UIO_SMX
> tristate "SMX cryptengine UIO interface"
> - default n
> help
> Userspace IO interface to the Cryptography engine found on the
> Nias Digital SMX boards. These will be available from Q4 2008
> @@ -61,7 +58,6 @@ config UIO_SMX
> config UIO_AEC
> tristate "AEC video timestamp device"
> depends on PCI
> - default n
> help
>
> UIO driver for the Adrienne Electronics Corporation PCI time
> @@ -78,7 +74,6 @@ config UIO_AEC
>
> config UIO_SERCOS3
> tristate "Automata Sercos III PCI card driver"
> - default n
> help
> Userspace I/O interface for the Sercos III PCI card from
> Automata GmbH. The userspace part of this driver will be
> --
> 1.6.4.2
On Tue, 2009-09-15 at 12:12 -0700, Greg Kroah-Hartman wrote:
> +static const struct memdev {
> + const char *name;
> + const struct file_operations *fops;
> + struct backing_dev_info *dev_info;
> +} devlist[] = {
> + [ 1] = { "mem", &mem_fops, &directly_mappable_cdev_bdi },
This patch has several checkpatch errors wrt. the spacing used in the
array index..
Kay, can you send a follow up patch to correct them?
Daniel
On Tue, Sep 15, 2009 at 21:42, Daniel Walker <[email protected]> wrote:
> On Tue, 2009-09-15 at 12:12 -0700, Greg Kroah-Hartman wrote:
>> +static const struct memdev {
>> + const char *name;
>> + const struct file_operations *fops;
>> + struct backing_dev_info *dev_info;
>> +} devlist[] = {
>> + [ 1] = { "mem", &mem_fops, &directly_mappable_cdev_bdi },
>
> This patch has several checkpatch errors wrt. the spacing used in the
> array index..
>
> Kay, can you send a follow up patch to correct them?
I think they are fine, and properly aligned to be best readable.
Thanks,
Kay
On Tue, 2009-09-15 at 21:46 +0200, Kay Sievers wrote:
> On Tue, Sep 15, 2009 at 21:42, Daniel Walker <[email protected]> wrote:
> > On Tue, 2009-09-15 at 12:12 -0700, Greg Kroah-Hartman wrote:
> >> +static const struct memdev {
> >> + const char *name;
> >> + const struct file_operations *fops;
> >> + struct backing_dev_info *dev_info;
> >> +} devlist[] = {
> >> + [ 1] = { "mem", &mem_fops, &directly_mappable_cdev_bdi },
> >
> > This patch has several checkpatch errors wrt. the spacing used in the
> > array index..
> >
> > Kay, can you send a follow up patch to correct them?
>
> I think they are fine, and properly aligned to be best readable.
We already have a coding style in Linux which doesn't allow this type of
alignment .. If we allowed everyone to pick their own coding style we
would have a pretty ugly looking kernel.. That's why the checkpatch tool
was create to test for style conformance.. If you feel strongly about
this alignment you could change checkpatch not to warn on this , but I
don't think it's likely a change like that would be accepted..
Daniel
On Tue, Sep 15, 2009 at 01:07:09PM -0700, Daniel Walker wrote:
> On Tue, 2009-09-15 at 21:46 +0200, Kay Sievers wrote:
> > On Tue, Sep 15, 2009 at 21:42, Daniel Walker <[email protected]> wrote:
> > > On Tue, 2009-09-15 at 12:12 -0700, Greg Kroah-Hartman wrote:
> > >> +static const struct memdev {
> > >> + const char *name;
> > >> + const struct file_operations *fops;
> > >> + struct backing_dev_info *dev_info;
> > >> +} devlist[] = {
> > >> + [ 1] = { "mem", &mem_fops, &directly_mappable_cdev_bdi },
> > >
> > > This patch has several checkpatch errors wrt. the spacing used in the
> > > array index..
> > >
> > > Kay, can you send a follow up patch to correct them?
> >
> > I think they are fine, and properly aligned to be best readable.
>
> We already have a coding style in Linux which doesn't allow this type of
> alignment .. If we allowed everyone to pick their own coding style we
> would have a pretty ugly looking kernel.. That's why the checkpatch tool
> was create to test for style conformance.. If you feel strongly about
> this alignment you could change checkpatch not to warn on this , but I
> don't think it's likely a change like that would be accepted..
I explicitly ignored the checkpatch warnings here, as Kay is right, it
does look better and is more sane with the way he wrote it.
Remember, checkpatch.pl is a _guide_ not a
hard-and-fast-rule-or-else-puppies-will-get-hurt type of a thing.
The whole reason for having a consistant coding style is so your brain
gets used to patterns and you can see the context of the code instead.
It's a proven thing. Arguing that removing that space makes it easier
to understand and maintain over time is illogical.
thanks,
greg k-h
On Tue, 2009-09-15 at 13:24 -0700, Greg KH wrote:
> On Tue, Sep 15, 2009 at 01:07:09PM -0700, Daniel Walker wrote:
> > On Tue, 2009-09-15 at 21:46 +0200, Kay Sievers wrote:
> > > On Tue, Sep 15, 2009 at 21:42, Daniel Walker <[email protected]> wrote:
> > > > On Tue, 2009-09-15 at 12:12 -0700, Greg Kroah-Hartman wrote:
> > > >> +static const struct memdev {
> > > >> + const char *name;
> > > >> + const struct file_operations *fops;
> > > >> + struct backing_dev_info *dev_info;
> > > >> +} devlist[] = {
> > > >> + [ 1] = { "mem", &mem_fops, &directly_mappable_cdev_bdi },
> > > >
> > > > This patch has several checkpatch errors wrt. the spacing used in the
> > > > array index..
> > > >
> > > > Kay, can you send a follow up patch to correct them?
> > >
> > > I think they are fine, and properly aligned to be best readable.
> >
> > We already have a coding style in Linux which doesn't allow this type of
> > alignment .. If we allowed everyone to pick their own coding style we
> > would have a pretty ugly looking kernel.. That's why the checkpatch tool
> > was create to test for style conformance.. If you feel strongly about
> > this alignment you could change checkpatch not to warn on this , but I
> > don't think it's likely a change like that would be accepted..
>
> I explicitly ignored the checkpatch warnings here, as Kay is right, it
> does look better and is more sane with the way he wrote it.
>
> Remember, checkpatch.pl is a _guide_ not a
> hard-and-fast-rule-or-else-puppies-will-get-hurt type of a thing.
>
> The whole reason for having a consistant coding style is so your brain
> gets used to patterns and you can see the context of the code instead.
> It's a proven thing. Arguing that removing that space makes it easier
> to understand and maintain over time is illogical.
I agree It can depend on context , but I don't agree that it's needed
here..
In this case space or no space it really doesn't matter, since half the
lines are spaced with ifdefs ..
So it boils down to just these lines,
+ [ 5] = { "zero", &zero_fops, &zero_bdi },
+ [ 6] = { "full", &full_fops, NULL },
+ [ 7] = { "random", &random_fops, NULL },
+ [ 9] = { "urandom", &urandom_fops, NULL },
+ [11] = { "kmsg", &kmsg_fops, NULL },
or properly formatted like this,
+ [5] = { "zero", &zero_fops, &zero_bdi },
+ [6] = { "full", &full_fops, NULL },
+ [7] = { "random", &random_fops, NULL },
+ [9] = { "urandom", &urandom_fops, NULL },
+ [11] = { "kmsg", &kmsg_fops, NULL },
I don't see a stark difference. Now you have to contend with the fact
that checkpatch spews errors on these lines .. If your going to allow
errors you better be getting your moneys worth since you'll have to
defend them , and ignore patches to clean them up.
In terms of maintaining these actual lines of code, I don't think it
matters either.. However, the more style errors you allow into a tree
the more clean up patches you will have to ignore, or explain away..
Which is all just wasted work either by you or others that could be
better spent doing other stuff .. In general I think everything should
be style clean unless there is a concrete reason not to be..
Daniel
On Tue, Sep 15, 2009 at 02:18:11PM -0700, Daniel Walker wrote:
> On Tue, 2009-09-15 at 13:24 -0700, Greg KH wrote:
> > On Tue, Sep 15, 2009 at 01:07:09PM -0700, Daniel Walker wrote:
> > > On Tue, 2009-09-15 at 21:46 +0200, Kay Sievers wrote:
> > > > On Tue, Sep 15, 2009 at 21:42, Daniel Walker <[email protected]> wrote:
> > > > > On Tue, 2009-09-15 at 12:12 -0700, Greg Kroah-Hartman wrote:
> > > > >> +static const struct memdev {
> > > > >> + const char *name;
> > > > >> + const struct file_operations *fops;
> > > > >> + struct backing_dev_info *dev_info;
> > > > >> +} devlist[] = {
> > > > >> + [ 1] = { "mem", &mem_fops, &directly_mappable_cdev_bdi },
> > > > >
> > > > > This patch has several checkpatch errors wrt. the spacing used in the
> > > > > array index..
> > > > >
> > > > > Kay, can you send a follow up patch to correct them?
> > > >
> > > > I think they are fine, and properly aligned to be best readable.
> > >
> > > We already have a coding style in Linux which doesn't allow this type of
> > > alignment .. If we allowed everyone to pick their own coding style we
> > > would have a pretty ugly looking kernel.. That's why the checkpatch tool
> > > was create to test for style conformance.. If you feel strongly about
> > > this alignment you could change checkpatch not to warn on this , but I
> > > don't think it's likely a change like that would be accepted..
> >
> > I explicitly ignored the checkpatch warnings here, as Kay is right, it
> > does look better and is more sane with the way he wrote it.
> >
> > Remember, checkpatch.pl is a _guide_ not a
> > hard-and-fast-rule-or-else-puppies-will-get-hurt type of a thing.
> >
> > The whole reason for having a consistant coding style is so your brain
> > gets used to patterns and you can see the context of the code instead.
> > It's a proven thing. Arguing that removing that space makes it easier
> > to understand and maintain over time is illogical.
>
> I agree It can depend on context , but I don't agree that it's needed
> here..
>
> In this case space or no space it really doesn't matter, since half the
> lines are spaced with ifdefs ..
>
> So it boils down to just these lines,
>
> + [ 5] = { "zero", &zero_fops, &zero_bdi },
> + [ 6] = { "full", &full_fops, NULL },
> + [ 7] = { "random", &random_fops, NULL },
> + [ 9] = { "urandom", &urandom_fops, NULL },
> + [11] = { "kmsg", &kmsg_fops, NULL },
>
> or properly formatted like this,
>
> + [5] = { "zero", &zero_fops, &zero_bdi },
> + [6] = { "full", &full_fops, NULL },
> + [7] = { "random", &random_fops, NULL },
> + [9] = { "urandom", &urandom_fops, NULL },
> + [11] = { "kmsg", &kmsg_fops, NULL },
>
> I don't see a stark difference. Now you have to contend with the fact
> that checkpatch spews errors on these lines .. If your going to allow
> errors you better be getting your moneys worth since you'll have to
> defend them , and ignore patches to clean them up.
I'll gladly do that, it's trival for me to do so.
thanks,
greg k-h
On Tue, 2009-09-15 at 14:20 -0700, Greg KH wrote:
> I'll gladly do that, it's trival for me to do so.
>
What about the other side ? The people who are sending the clean ups,
there time is valuable too..
I hope you don't ignore these errors very often ..
Daniel
On Tue, Sep 15, 2009 at 02:26:46PM -0700, Daniel Walker wrote:
> On Tue, 2009-09-15 at 14:20 -0700, Greg KH wrote:
>
> > I'll gladly do that, it's trival for me to do so.
> >
>
> What about the other side ? The people who are sending the clean ups,
> there time is valuable too..
Don't you mean "their"? (hey, I can be nit-picky too...)
And yes, but the engineering model of the kernel development cycle is
that engineer hours are wasted and thrown away all the time. They are
surplus, sorry. That's how life works here.
> I hope you don't ignore these errors very often ..
More often then you want to know, I have real issues to deal with :)
thanks,
greg "it's a _guide_ dammit!" k-h
On Tue, 2009-09-15 at 14:32 -0700, Greg KH wrote:
> On Tue, Sep 15, 2009 at 02:26:46PM -0700, Daniel Walker wrote:
> > On Tue, 2009-09-15 at 14:20 -0700, Greg KH wrote:
> >
> > > I'll gladly do that, it's trival for me to do so.
> > >
> >
> > What about the other side ? The people who are sending the clean ups,
> > there time is valuable too..
>
> Don't you mean "their"? (hey, I can be nit-picky too...)
Yeah, I'll send you a clean up email for that tomorrow ;)
> And yes, but the engineering model of the kernel development cycle is
> that engineer hours are wasted and thrown away all the time. They are
> surplus, sorry. That's how life works here.
It's like we're driving the SUVs that run on engineering hours ? Just
imagine the electrical power savings you would get if you had 1000 less
emails send to you daily .. But seriously, why waste people time if it
can be prevented ..
Less checkpatch errors, less wasted time, better for the environment..
> > I hope you don't ignore these errors very often ..
>
> More often then you want to know, I have real issues to deal with :)
I'm sure I have no idea..
Daniel
NACK, this touches init code to mount stuff inside the namespace fro ma
filesystem driver which is a big no-go. I also can't see any ACK or
similar from VFS people for that crap (obviously)
On Tue, Sep 15, 2009 at 07:21:04PM -0400, Christoph Hellwig wrote:
> NACK, this touches init code to mount stuff inside the namespace fro ma
> filesystem driver which is a big no-go.
It does? What code is that, the following line in prepare_namespace():
devtmpfs_mount("dev");
?
What is the problem with that?
> I also can't see any ACK or similar from VFS people for that crap
> (obviously)
For that one line? If this call is not the correct way to do this, or
it should be done somewhere else, please let us know.
The patch has been posted for review many times and has been in the
-next and -mm releases for over 2 merge windows, which has gotten it a
lot of exposure and testing and review. This is the first time I recall
this issue being raised.
thanks,
greg k-h
On Tue, Sep 15, 2009 at 11:12:47AM -0700, Greg KH wrote:
> Here is the driver core patchset for the 2.6.31 merge window
>
> It consists of a variety of different things:
> - devtmpfs. This has been discussed a lot, is tiny,
> self-contained, and has been acked by all of the major distros
> as something they will use, and it has been used in the SuSE
> kernels for quite some time now.
Grr, as Greg didn't Cc the actual patches to Linus here's the objection
again:
- it mounts a filesystem into the init (aka global) namespace on mount
for no good reason
- it then manipulates it using the high-level VFS functions which it
could just do on any filesystem if it really wanted
These lots of dicussions were basically people telling Greg that he
should come up wit ha real problem instead of just pushing it for it's
own sake. Arjan And Eric have very well refuted the spped claim.
NACK from me from the VFS point of view - this is devfs 2.0, just worse
than the last version of devfs 1. I would really really like to head
what the udev folks actually want instead of pushing in this crap.
On Wed, Sep 16, 2009 at 08:45:33AM -0400, Christoph Hellwig wrote:
> On Tue, Sep 15, 2009 at 11:12:47AM -0700, Greg KH wrote:
> > Here is the driver core patchset for the 2.6.31 merge window
> >
> > It consists of a variety of different things:
> > - devtmpfs. This has been discussed a lot, is tiny,
> > self-contained, and has been acked by all of the major distros
> > as something they will use, and it has been used in the SuSE
> > kernels for quite some time now.
>
> Grr, as Greg didn't Cc the actual patches to Linus here's the objection
> again:
I will attach it below for transparency.
> - it mounts a filesystem into the init (aka global) namespace on mount
> for no good reason
Huh? It only does this if you ask it to, that is a separate config
option.
And I have never heard this complaint, in the 6 or so months that this
has been discussed.
> - it then manipulates it using the high-level VFS functions which it
> could just do on any filesystem if it really wanted
I don't understand what you are trying to object to here. What is wrong
with that?
> These lots of dicussions were basically people telling Greg that he
> should come up wit ha real problem instead of just pushing it for it's
> own sake. Arjan And Eric have very well refuted the spped claim.
And Kay and I and many others have refuted the "it's only about speed"
claim :)
And yes, it is about speed, and using single, simple tools instead of
having to write another version of udev again (which is what Arjan had
to do). And it's also about simplicity, which is what the distro kernel
maintainers like about it and why they agreed to sign-off on the patch
after testing it in their boot environments and configurations.
> NACK from me from the VFS point of view - this is devfs 2.0, just worse
> than the last version of devfs 1.
Hey, as one who actually remembers, and read the devfs 1 code, that's
really harsh :(
This looks, and works, and interacts with the kernel in a _totally_
different way than devfs used to. The races that were in devfs are not
there, and the naming scheme and intrusiveness are also not there.
In fact, everything that was objected to in the original devfs is not
there as well.
> I would really really like to head what the udev folks actually want
> instead of pushing in this crap.
I don't understand this sentence.
I understand that some people do not like the idea of this code. But
others do. It's completly self-contained, tiny, and easy to handle.
All of the major distros want it, one of them is already shipping it to
customers, and the embedded developers and distros are jumping up in joy
over it.
Think of it as a filesystem or a driver that you don't want to use. If
you don't configure it into your kernel, you _never_ have to deal with
it or even read the code. Others will maintain it over time, you do not
have to.
thanks,
greg k-h
------------
From: Kay Sievers <[email protected]>
Date: Thu, 30 Apr 2009 15:23:42 +0200
Subject: Driver Core: devtmpfs - kernel-maintained tmpfs-based /dev
Cc: Greg KH <[email protected]>, Jan Blunck <[email protected]>
Message-ID: <1241097822.2516.3.camel@poy>
From: Kay Sievers <[email protected]>
Devtmpfs lets the kernel create a tmpfs instance called devtmpfs
very early at kernel initialization, before any driver-core device
is registered. Every device with a major/minor will provide a
device node in devtmpfs.
Devtmpfs can be changed and altered by userspace at any time,
and in any way needed - just like today's udev-mounted tmpfs.
Unmodified udev versions will run just fine on top of it, and will
recognize an already existing kernel-created device node and use it.
The default node permissions are root:root 0600. Proper permissions
and user/group ownership, meaningful symlinks, all other policy still
needs to be applied by userspace.
If a node is created by devtmps, devtmpfs will remove the device node
when the device goes away. If the device node was created by
userspace, or the devtmpfs created node was replaced by userspace, it
will no longer be removed by devtmpfs.
If it is requested to auto-mount it, it makes init=/bin/sh work
without any further userspace support. /dev will be fully populated
and dynamic, and always reflect the current device state of the kernel.
With the commonly used dynamic device numbers, it solves the problem
where static devices nodes may point to the wrong devices.
It is intended to make the initial bootup logic simpler and more robust,
by de-coupling the creation of the inital environment, to reliably run
userspace processes, from a complex userspace bootstrap logic to provide
a working /dev.
Signed-off-by: Kay Sievers <[email protected]>
Signed-off-by: Jan Blunck <[email protected]>
Tested-By: Harald Hoyer <[email protected]>
Tested-By: Scott James Remnant <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
drivers/base/Kconfig | 25 +++
drivers/base/Makefile | 1
drivers/base/base.h | 6
drivers/base/core.c | 3
drivers/base/devtmpfs.c | 367 +++++++++++++++++++++++++++++++++++++++++++++++
drivers/base/init.c | 1
include/linux/device.h | 10 +
include/linux/shmem_fs.h | 3
init/do_mounts.c | 2
init/main.c | 2
mm/shmem.c | 9 -
11 files changed, 422 insertions(+), 7 deletions(-)
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -139,3 +139,9 @@ static inline void module_add_driver(str
struct device_driver *drv) { }
static inline void module_remove_driver(struct device_driver *drv) { }
#endif
+
+#ifdef CONFIG_DEVTMPFS
+extern int devtmpfs_init(void);
+#else
+static inline int devtmpfs_init(void) { return 0; }
+#endif
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -929,6 +929,8 @@ int device_add(struct device *dev)
error = device_create_sys_dev_entry(dev);
if (error)
goto devtattrError;
+
+ devtmpfs_create_node(dev);
}
error = device_add_class_symlinks(dev);
@@ -1075,6 +1077,7 @@ void device_del(struct device *dev)
if (parent)
klist_del(&dev->p->knode_parent);
if (MAJOR(dev->devt)) {
+ devtmpfs_delete_node(dev);
device_remove_sys_dev_entry(dev);
device_remove_file(dev, &devt_attr);
}
--- /dev/null
+++ b/drivers/base/devtmpfs.c
@@ -0,0 +1,367 @@
+/*
+ * devtmpfs - kernel-maintained tmpfs-based /dev
+ *
+ * Copyright (C) 2009, Kay Sievers <[email protected]>
+ *
+ * During bootup, before any driver core device is registered,
+ * devtmpfs, a tmpfs-based filesystem is created. Every driver-core
+ * device which requests a device node, will add a node in this
+ * filesystem. The node is named after the the name of the device,
+ * or the susbsytem can provide a custom name. All devices are
+ * owned by root and have a mode of 0600.
+ */
+
+#include <linux/kernel.h>
+#include <linux/syscalls.h>
+#include <linux/mount.h>
+#include <linux/device.h>
+#include <linux/genhd.h>
+#include <linux/namei.h>
+#include <linux/fs.h>
+#include <linux/shmem_fs.h>
+#include <linux/cred.h>
+#include <linux/init_task.h>
+
+static struct vfsmount *dev_mnt;
+
+#if defined CONFIG_DEVTMPFS_MOUNT
+static int dev_mount = 1;
+#else
+static int dev_mount;
+#endif
+
+static int __init mount_param(char *str)
+{
+ dev_mount = simple_strtoul(str, NULL, 0);
+ return 1;
+}
+__setup("devtmpfs.mount=", mount_param);
+
+static int dev_get_sb(struct file_system_type *fs_type, int flags,
+ const char *dev_name, void *data, struct vfsmount *mnt)
+{
+ return get_sb_single(fs_type, flags, data, shmem_fill_super, mnt);
+}
+
+static struct file_system_type dev_fs_type = {
+ .name = "devtmpfs",
+ .get_sb = dev_get_sb,
+ .kill_sb = kill_litter_super,
+};
+
+#ifdef CONFIG_BLOCK
+static inline int is_blockdev(struct device *dev)
+{
+ return dev->class == &block_class;
+}
+#else
+static inline int is_blockdev(struct device *dev) { return 0; }
+#endif
+
+static int dev_mkdir(const char *name, mode_t mode)
+{
+ struct nameidata nd;
+ struct dentry *dentry;
+ int err;
+
+ err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
+ name, LOOKUP_PARENT, &nd);
+ if (err)
+ return err;
+
+ dentry = lookup_create(&nd, 1);
+ if (!IS_ERR(dentry)) {
+ err = vfs_mkdir(nd.path.dentry->d_inode, dentry, mode);
+ dput(dentry);
+ } else {
+ err = PTR_ERR(dentry);
+ }
+ mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
+
+ path_put(&nd.path);
+ return err;
+}
+
+static int create_path(const char *nodepath)
+{
+ char *path;
+ struct nameidata nd;
+ int err = 0;
+
+ path = kstrdup(nodepath, GFP_KERNEL);
+ if (!path)
+ return -ENOMEM;
+
+ err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
+ path, LOOKUP_PARENT, &nd);
+ if (err == 0) {
+ struct dentry *dentry;
+
+ /* create directory right away */
+ dentry = lookup_create(&nd, 1);
+ if (!IS_ERR(dentry)) {
+ err = vfs_mkdir(nd.path.dentry->d_inode,
+ dentry, 0755);
+ dput(dentry);
+ }
+ mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
+
+ path_put(&nd.path);
+ } else if (err == -ENOENT) {
+ char *s;
+
+ /* parent directories do not exist, create them */
+ s = path;
+ while (1) {
+ s = strchr(s, '/');
+ if (!s)
+ break;
+ s[0] = '\0';
+ err = dev_mkdir(path, 0755);
+ if (err && err != -EEXIST)
+ break;
+ s[0] = '/';
+ s++;
+ }
+ }
+
+ kfree(path);
+ return err;
+}
+
+int devtmpfs_create_node(struct device *dev)
+{
+ const char *tmp = NULL;
+ const char *nodename;
+ const struct cred *curr_cred;
+ mode_t mode;
+ struct nameidata nd;
+ struct dentry *dentry;
+ int err;
+
+ if (!dev_mnt)
+ return 0;
+
+ nodename = device_get_nodename(dev, &tmp);
+ if (!nodename)
+ return -ENOMEM;
+
+ if (is_blockdev(dev))
+ mode = S_IFBLK|0600;
+ else
+ mode = S_IFCHR|0600;
+
+ curr_cred = override_creds(&init_cred);
+ err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
+ nodename, LOOKUP_PARENT, &nd);
+ if (err == -ENOENT) {
+ /* create missing parent directories */
+ create_path(nodename);
+ err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
+ nodename, LOOKUP_PARENT, &nd);
+ if (err)
+ goto out;
+ }
+
+ dentry = lookup_create(&nd, 0);
+ if (!IS_ERR(dentry)) {
+ err = vfs_mknod(nd.path.dentry->d_inode,
+ dentry, mode, dev->devt);
+ /* mark as kernel created inode */
+ if (!err)
+ dentry->d_inode->i_private = &dev_mnt;
+ dput(dentry);
+ } else {
+ err = PTR_ERR(dentry);
+ }
+ mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
+
+ path_put(&nd.path);
+out:
+ kfree(tmp);
+ revert_creds(curr_cred);
+ return err;
+}
+
+static int dev_rmdir(const char *name)
+{
+ struct nameidata nd;
+ struct dentry *dentry;
+ int err;
+
+ err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
+ name, LOOKUP_PARENT, &nd);
+ if (err)
+ return err;
+
+ mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
+ dentry = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len);
+ if (!IS_ERR(dentry)) {
+ if (dentry->d_inode)
+ err = vfs_rmdir(nd.path.dentry->d_inode, dentry);
+ else
+ err = -ENOENT;
+ dput(dentry);
+ } else {
+ err = PTR_ERR(dentry);
+ }
+ mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
+
+ path_put(&nd.path);
+ return err;
+}
+
+static int delete_path(const char *nodepath)
+{
+ const char *path;
+ int err = 0;
+
+ path = kstrdup(nodepath, GFP_KERNEL);
+ if (!path)
+ return -ENOMEM;
+
+ while (1) {
+ char *base;
+
+ base = strrchr(path, '/');
+ if (!base)
+ break;
+ base[0] = '\0';
+ err = dev_rmdir(path);
+ if (err)
+ break;
+ }
+
+ kfree(path);
+ return err;
+}
+
+static int dev_mynode(struct device *dev, struct inode *inode, struct kstat *stat)
+{
+ /* did we create it */
+ if (inode->i_private != &dev_mnt)
+ return 0;
+
+ /* does the dev_t match */
+ if (is_blockdev(dev)) {
+ if (!S_ISBLK(stat->mode))
+ return 0;
+ } else {
+ if (!S_ISCHR(stat->mode))
+ return 0;
+ }
+ if (stat->rdev != dev->devt)
+ return 0;
+
+ /* ours */
+ return 1;
+}
+
+int devtmpfs_delete_node(struct device *dev)
+{
+ const char *tmp = NULL;
+ const char *nodename;
+ const struct cred *curr_cred;
+ struct nameidata nd;
+ struct dentry *dentry;
+ struct kstat stat;
+ int deleted = 1;
+ int err;
+
+ if (!dev_mnt)
+ return 0;
+
+ nodename = device_get_nodename(dev, &tmp);
+ if (!nodename)
+ return -ENOMEM;
+
+ curr_cred = override_creds(&init_cred);
+ err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
+ nodename, LOOKUP_PARENT, &nd);
+ if (err)
+ goto out;
+
+ mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
+ dentry = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len);
+ if (!IS_ERR(dentry)) {
+ if (dentry->d_inode) {
+ err = vfs_getattr(nd.path.mnt, dentry, &stat);
+ if (!err && dev_mynode(dev, dentry->d_inode, &stat)) {
+ err = vfs_unlink(nd.path.dentry->d_inode,
+ dentry);
+ if (!err || err == -ENOENT)
+ deleted = 1;
+ }
+ } else {
+ err = -ENOENT;
+ }
+ dput(dentry);
+ } else {
+ err = PTR_ERR(dentry);
+ }
+ mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
+
+ path_put(&nd.path);
+ if (deleted && strchr(nodename, '/'))
+ delete_path(nodename);
+out:
+ kfree(tmp);
+ revert_creds(curr_cred);
+ return err;
+}
+
+/*
+ * If configured, or requested by the commandline, devtmpfs will be
+ * auto-mounted after the kernel mounted the root filesystem.
+ */
+int devtmpfs_mount(const char *mountpoint)
+{
+ struct path path;
+ int err;
+
+ if (!dev_mount)
+ return 0;
+
+ if (!dev_mnt)
+ return 0;
+
+ err = kern_path(mountpoint, LOOKUP_FOLLOW, &path);
+ if (err)
+ return err;
+ err = do_add_mount(dev_mnt, &path, 0, NULL);
+ if (err)
+ printk(KERN_INFO "devtmpfs: error mounting %i\n", err);
+ else
+ printk(KERN_INFO "devtmpfs: mounted\n");
+ path_put(&path);
+ return err;
+}
+
+/*
+ * Create devtmpfs instance, driver-core devices will add their device
+ * nodes here.
+ */
+int __init devtmpfs_init(void)
+{
+ int err;
+ struct vfsmount *mnt;
+
+ err = register_filesystem(&dev_fs_type);
+ if (err) {
+ printk(KERN_ERR "devtmpfs: unable to register devtmpfs "
+ "type %i\n", err);
+ return err;
+ }
+
+ mnt = kern_mount(&dev_fs_type);
+ if (IS_ERR(mnt)) {
+ err = PTR_ERR(mnt);
+ printk(KERN_ERR "devtmpfs: unable to create devtmpfs %i\n", err);
+ unregister_filesystem(&dev_fs_type);
+ return err;
+ }
+ dev_mnt = mnt;
+
+ printk(KERN_INFO "devtmpfs: initialized\n");
+ return 0;
+}
--- a/drivers/base/init.c
+++ b/drivers/base/init.c
@@ -20,6 +20,7 @@
void __init driver_init(void)
{
/* These are the core pieces */
+ devtmpfs_init();
devices_init();
buses_init();
classes_init();
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -8,6 +8,31 @@ config UEVENT_HELPER_PATH
Path to uevent helper program forked by the kernel for
every uevent.
+config DEVTMPFS
+ bool "Create a kernel maintained /dev tmpfs (EXPERIMENTAL)"
+ depends on HOTPLUG && SHMEM && TMPFS
+ help
+ This creates a tmpfs filesystem, and mounts it at bootup
+ and mounts it at /dev. The kernel driver core creates device
+ nodes for all registered devices in that filesystem. All device
+ nodes are owned by root and have the default mode of 0600.
+ Userspace can add and delete the nodes as needed. This is
+ intended to simplify bootup, and make it possible to delay
+ the initial coldplug at bootup done by udev in userspace.
+ It should also provide a simpler way for rescue systems
+ to bring up a kernel with dynamic major/minor numbers.
+ Meaningful symlinks, permissions and device ownership must
+ still be handled by userspace.
+ If unsure, say N here.
+
+config DEVTMPFS_MOUNT
+ bool "Automount devtmpfs at /dev"
+ depends on DEVTMPFS
+ help
+ This will mount devtmpfs at /dev if the kernel mounts the root
+ filesystem. It will not affect initramfs based mounting.
+ If unsure, say N here.
+
config STANDALONE
bool "Select only drivers that don't need compile-time external firmware" if EXPERIMENTAL
default y
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -4,6 +4,7 @@ obj-y := core.o sys.o bus.o dd.o \
driver.o class.o platform.o \
cpu.o firmware.o init.o map.o devres.o \
attribute_container.o transport_class.o
+obj-$(CONFIG_DEVTMPFS) += devtmpfs.o
obj-y += power/
obj-$(CONFIG_HAS_DMA) += dma-mapping.o
obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -552,6 +552,16 @@ extern void put_device(struct device *de
extern void wait_for_device_probe(void);
+#ifdef CONFIG_DEVTMPFS
+extern int devtmpfs_create_node(struct device *dev);
+extern int devtmpfs_delete_node(struct device *dev);
+extern int devtmpfs_mount(const char *mountpoint);
+#else
+static inline int devtmpfs_create_node(struct device *dev) { return 0; }
+static inline int devtmpfs_delete_node(struct device *dev) { return 0; }
+static inline int devtmpfs_mount(const char *mountpoint) { return 0; }
+#endif
+
/* drivers/base/power/shutdown.c */
extern void device_shutdown(void);
--- a/include/linux/shmem_fs.h
+++ b/include/linux/shmem_fs.h
@@ -38,6 +38,9 @@ static inline struct shmem_inode_info *S
return container_of(inode, struct shmem_inode_info, vfs_inode);
}
+extern int init_tmpfs(void);
+extern int shmem_fill_super(struct super_block *sb, void *data, int silent);
+
#ifdef CONFIG_TMPFS_POSIX_ACL
int shmem_check_acl(struct inode *, int);
int shmem_acl_init(struct inode *, struct inode *);
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -415,7 +415,7 @@ void __init prepare_namespace(void)
mount_root();
out:
+ devtmpfs_mount("dev");
sys_mount(".", "/", NULL, MS_MOVE, NULL);
sys_chroot(".");
}
-
--- a/init/main.c
+++ b/init/main.c
@@ -68,6 +68,7 @@
#include <linux/async.h>
#include <linux/kmemcheck.h>
#include <linux/kmemtrace.h>
+#include <linux/shmem_fs.h>
#include <trace/boot.h>
#include <asm/io.h>
@@ -785,6 +786,7 @@ static void __init do_basic_setup(void)
init_workqueues();
cpuset_init_smp();
usermodehelper_init();
+ init_tmpfs();
driver_init();
init_irq_proc();
do_ctors();
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -2298,8 +2298,7 @@ static void shmem_put_super(struct super
sb->s_fs_info = NULL;
}
-static int shmem_fill_super(struct super_block *sb,
- void *data, int silent)
+int shmem_fill_super(struct super_block *sb, void *data, int silent)
{
struct inode *inode;
struct dentry *root;
@@ -2519,7 +2518,7 @@ static struct file_system_type tmpfs_fs_
.kill_sb = kill_litter_super,
};
-static int __init init_tmpfs(void)
+int __init init_tmpfs(void)
{
int error;
@@ -2576,7 +2575,7 @@ static struct file_system_type tmpfs_fs_
.kill_sb = kill_litter_super,
};
-static int __init init_tmpfs(void)
+int __init init_tmpfs(void)
{
BUG_ON(register_filesystem(&tmpfs_fs_type) != 0);
@@ -2687,5 +2686,3 @@ int shmem_zero_setup(struct vm_area_stru
vma->vm_ops = &shmem_vm_ops;
return 0;
}
-
-module_init(init_tmpfs)
On Wed, Sep 16, 2009 at 05:59:19AM -0700, Greg KH wrote:
> And I have never heard this complaint, in the 6 or so months that this
> has been discussed.
I've mentioned it before, as have others.
> > - it then manipulates it using the high-level VFS functions which it
> > could just do on any filesystem if it really wanted
>
> I don't understand what you are trying to object to here. What is wrong
> with that?
It's a very bad way to expose kernel state, and the same problem the
original devfs had. A good kernel state filesystem is immutable to
changes from userspace, that is fully controlled by the kernel. The
problem with devfs and your new devfstmpfs is that you have both
userspace and the kernel manipulating the same object. Which for
example makes life time management impossible.
> > These lots of dicussions were basically people telling Greg that he
> > should come up wit ha real problem instead of just pushing it for it's
> > own sake. Arjan And Eric have very well refuted the spped claim.
>
> And Kay and I and many others have refuted the "it's only about speed"
> claim :)
As many people have asked you already then come up with a description
of what you actually want. You ealize you're acting exactly like those
"But we need feature $FOO because we have it inhose / on windows / on
solaris" people everyone is upset at on lkml?
> > NACK from me from the VFS point of view - this is devfs 2.0, just worse
> > than the last version of devfs 1.
>
> Hey, as one who actually remembers, and read the devfs 1 code, that's
> really harsh :(
It's not. The last version we had in -mm for a while was the rewrite
from Adam richter that did exactly what devtmpfs does - use ramfs
(insteaf of tmpfs now) and use the vfs path helpers to work on it.
I also know who gladly killed it just to re-introduce the same thing
years later, not actually solving any of the problems in it. The only
major-ish difference is that old devfs had explicit calls to create the
node names (and stupid choicses from Good times) while version 2.0 hides
the naming inside the driver core.
On Wed, Sep 16, 2009 at 15:15, Christoph Hellwig <[email protected]> wrote:
> On Wed, Sep 16, 2009 at 05:59:19AM -0700, Greg KH wrote:
> It's a very bad way to expose kernel state, and the same problem the
> original devfs had. A good kernel state filesystem is immutable to
> changes from userspace, that is fully controlled by the kernel. The
> problem with devfs and your new devfstmpfs is that you have both
> userspace and the kernel manipulating the same object. Which for
> example makes life time management impossible.
It's well defined. When the device goes away, the node is removed, in
the same way the sysfs device is removed, and if userspace has
created/replaced the node, it has control over it and the kernel does
not touch it anymore. There is no known problem with that and no
difference how udev works today on all common systems.
If wanted, at the time you guys come up with a working union-mount, we
can make the kernel-maintained dev-filesystem read-only and mount a
tmpfs on-top of it. But we are not there at the moment.
> I also know who gladly killed it
And for good reason. The naming scheme was as wrong as it could be. We
have a completely different situation today.
> just to re-introduce the same thing years later,
It's not the same at all. There is udev today, and a well-defined way
to work with /dev, synchronized across all distros. Nothing really
changes with devtpmfs, it just gets simpler, has less races, and is a
lot more reliable.
It's a logical extension to sysfs, not much more. We create all the
things in /sys, why shouldn't we create the few nodes too, and make
many things much easier?
Kay
Am 15.09.2009 23:26 schrieb Daniel Walker:
> On Tue, 2009-09-15 at 14:20 -0700, Greg KH wrote:
>
>> I'll gladly do that, it's trival for me to do so.
>>
>
> What about the other side ? The people who are sending the clean ups,
> there time is valuable too..
Do such people really exist? Nobody ever sent a cleanup patch for any
of the numerous checkpatch errors in drivers/isdn/gigaset. I only get
complaints about them when I submit a patch that touches one of the
affected lines.
SCNR
T.
--
Tilman Schmidt E-Mail: [email protected]
Bonn, Germany
Diese Nachricht besteht zu 100% aus wiederverwerteten Bits.
Unge?ffnet mindestens haltbar bis: (siehe R?ckseite)
On Sat, 2009-09-19 at 17:17 +0200, Tilman Schmidt wrote:
> Am 15.09.2009 23:26 schrieb Daniel Walker:
> > On Tue, 2009-09-15 at 14:20 -0700, Greg KH wrote:
> >
> >> I'll gladly do that, it's trival for me to do so.
> >>
> >
> > What about the other side ? The people who are sending the clean ups,
> > there time is valuable too..
>
> Do such people really exist? Nobody ever sent a cleanup patch for any
> of the numerous checkpatch errors in drivers/isdn/gigaset. I only get
> complaints about them when I submit a patch that touches one of the
> affected lines.
Yeah, they do exist .. I've sent numerous checkpatch clean ups.
Daniel