提交 08a4ecee 编写于 作者: L Linus Torvalds

Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/driver-2.6

* master.kernel.org:/pub/scm/linux/kernel/git/gregkh/driver-2.6: (23 commits)
  [PATCH] sysfs: fix a kobject leak in sysfs_add_link on the error path
  [PATCH] sysfs: don't export dir symbols
  [PATCH] get_cpu_sysdev() signedness fix
  [PATCH] kobject_add_dir
  [PATCH] debugfs: Add debugfs_create_blob() helper for exporting binary data
  [PATCH] sysfs: fix problem with duplicate sysfs directories and files
  [PATCH] Kobject: kobject.h: fix a typo
  [PATCH] Kobject: provide better warning messages when people do stupid things
  [PATCH] Driver core: add macros notice(), dev_notice()
  [PATCH] firmware: fix BUG: in fw_realloc_buffer
  [PATCH] sysfs: kzalloc conversion
  [PATCH] fix module sysfs files reference counting
  [PATCH] add EXPORT_SYMBOL_GPL_FUTURE() to USB subsystem
  [PATCH] add EXPORT_SYMBOL_GPL_FUTURE() to RCU subsystem
  [PATCH] add EXPORT_SYMBOL_GPL_FUTURE()
  [PATCH] Clean up module.c symbol searching logic
  [PATCH] kobj_map semaphore to mutex conversion
  [PATCH] kref: avoid an atomic operation in kref_put()
  [PATCH] handle errors returned by platform_get_irq*()
  [PATCH] driver core: platform_get_irq*(): return -ENXIO on error
  ...
......@@ -196,3 +196,21 @@ Why: Board specific code doesn't build anymore since ~2.6.0 and no
users have complained indicating there is no more need for these
boards. This should really be considered a last call.
Who: Ralf Baechle <ralf@linux-mips.org>
---------------------------
What: USB driver API moves to EXPORT_SYMBOL_GPL
When: Febuary 2008
Files: include/linux/usb.h, drivers/usb/core/driver.c
Why: The USB subsystem has changed a lot over time, and it has been
possible to create userspace USB drivers using usbfs/libusb/gadgetfs
that operate as fast as the USB bus allows. Because of this, the USB
subsystem will not be allowing closed source kernel drivers to
register with it, after this grace period is over. If anyone needs
any help in converting their closed source drivers over to use the
userspace filesystems, please contact the
linux-usb-devel@lists.sourceforge.net mailing list, and the developers
there will be glad to help you out.
Who: Greg Kroah-Hartman <gregkh@suse.de>
---------------------------
......@@ -788,6 +788,8 @@ static int locomo_probe(struct platform_device *dev)
if (!mem)
return -EINVAL;
irq = platform_get_irq(dev, 0);
if (irq < 0)
return -ENXIO;
return __locomo_probe(&dev->dev, mem, irq);
}
......
......@@ -943,6 +943,8 @@ static int sa1111_probe(struct platform_device *pdev)
if (!mem)
return -EINVAL;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return -ENXIO;
return __sa1111_probe(&pdev->dev, mem, irq);
}
......
......@@ -269,6 +269,11 @@ SECTIONS {
*(__ksymtab_gpl)
__stop___ksymtab_gpl = .;
/* Kernel symbol table: GPL-future symbols */
__start___ksymtab_gpl_future = .;
*(__ksymtab_gpl_future)
__stop___ksymtab_gpl_future = .;
/* Kernel symbol table: Normal symbols */
__start___kcrctab = .;
*(__kcrctab)
......@@ -279,6 +284,11 @@ SECTIONS {
*(__kcrctab_gpl)
__stop___kcrctab_gpl = .;
/* Kernel symbol table: GPL-future symbols */
__start___kcrctab_gpl_future = .;
*(__kcrctab_gpl_future)
__stop___kcrctab_gpl_future = .;
/* Kernel symbol table: strings */
*(__ksymtab_strings)
......
......@@ -64,6 +64,10 @@
___start___ksymtab_gpl = .; \
*(__ksymtab_gpl) \
___stop___ksymtab_gpl = .; \
/* Kernel symbol table: GPL-future symbols */ \
___start___ksymtab_gpl_future = .; \
*(__ksymtab_gpl_future) \
___stop___ksymtab_gpl_future = .; \
/* Kernel symbol table: strings */ \
*(__ksymtab_strings) \
/* Kernel symbol table: Normal symbols */ \
......@@ -74,6 +78,10 @@
___start___kcrctab_gpl = .; \
*(__kcrctab_gpl) \
___stop___kcrctab_gpl = .; \
/* Kernel symbol table: GPL-future symbols */ \
___start___kcrctab_gpl_future = .; \
*(__kcrctab_gpl_future) \
___stop___kcrctab_gpl_future = .; \
/* Built-in module parameters */ \
. = ALIGN (4) ; \
___start___param = .; \
......
......@@ -15,12 +15,13 @@
#include <linux/kmod.h>
#include <linux/kobj_map.h>
#include <linux/buffer_head.h>
#include <linux/mutex.h>
#define MAX_PROBE_HASH 255 /* random */
static struct subsystem block_subsys;
static DECLARE_MUTEX(block_subsys_sem);
static DEFINE_MUTEX(block_subsys_lock);
/*
* Can be deleted altogether. Later.
......@@ -46,7 +47,7 @@ struct blkdev_info {
/*
* iterate over a list of blkdev_info structures. allows
* the major_names array to be iterated over from outside this file
* must be called with the block_subsys_sem held
* must be called with the block_subsys_lock held
*/
void *get_next_blkdev(void *dev)
{
......@@ -85,20 +86,20 @@ void *get_next_blkdev(void *dev)
void *acquire_blkdev_list(void)
{
down(&block_subsys_sem);
mutex_lock(&block_subsys_lock);
return get_next_blkdev(NULL);
}
void release_blkdev_list(void *dev)
{
up(&block_subsys_sem);
mutex_unlock(&block_subsys_lock);
kfree(dev);
}
/*
* Count the number of records in the blkdev_list.
* must be called with the block_subsys_sem held
* must be called with the block_subsys_lock held
*/
int count_blkdev_list(void)
{
......@@ -118,7 +119,7 @@ int count_blkdev_list(void)
/*
* extract the major and name values from a blkdev_info struct
* passed in as a void to *dev. Must be called with
* block_subsys_sem held
* block_subsys_lock held
*/
int get_blkdev_info(void *dev, int *major, char **name)
{
......@@ -138,7 +139,7 @@ int register_blkdev(unsigned int major, const char *name)
struct blk_major_name **n, *p;
int index, ret = 0;
down(&block_subsys_sem);
mutex_lock(&block_subsys_lock);
/* temporary */
if (major == 0) {
......@@ -183,7 +184,7 @@ int register_blkdev(unsigned int major, const char *name)
kfree(p);
}
out:
up(&block_subsys_sem);
mutex_unlock(&block_subsys_lock);
return ret;
}
......@@ -197,7 +198,7 @@ int unregister_blkdev(unsigned int major, const char *name)
int index = major_to_index(major);
int ret = 0;
down(&block_subsys_sem);
mutex_lock(&block_subsys_lock);
for (n = &major_names[index]; *n; n = &(*n)->next)
if ((*n)->major == major)
break;
......@@ -207,7 +208,7 @@ int unregister_blkdev(unsigned int major, const char *name)
p = *n;
*n = p->next;
}
up(&block_subsys_sem);
mutex_unlock(&block_subsys_lock);
kfree(p);
return ret;
......@@ -301,7 +302,7 @@ static void *part_start(struct seq_file *part, loff_t *pos)
struct list_head *p;
loff_t l = *pos;
down(&block_subsys_sem);
mutex_lock(&block_subsys_lock);
list_for_each(p, &block_subsys.kset.list)
if (!l--)
return list_entry(p, struct gendisk, kobj.entry);
......@@ -318,7 +319,7 @@ static void *part_next(struct seq_file *part, void *v, loff_t *pos)
static void part_stop(struct seq_file *part, void *v)
{
up(&block_subsys_sem);
mutex_unlock(&block_subsys_lock);
}
static int show_partition(struct seq_file *part, void *v)
......@@ -377,7 +378,7 @@ static struct kobject *base_probe(dev_t dev, int *part, void *data)
static int __init genhd_device_init(void)
{
bdev_map = kobj_map_init(base_probe, &block_subsys_sem);
bdev_map = kobj_map_init(base_probe, &block_subsys_lock);
blk_dev_init();
subsystem_register(&block_subsys);
return 0;
......@@ -611,7 +612,7 @@ static void *diskstats_start(struct seq_file *part, loff_t *pos)
loff_t k = *pos;
struct list_head *p;
down(&block_subsys_sem);
mutex_lock(&block_subsys_lock);
list_for_each(p, &block_subsys.kset.list)
if (!k--)
return list_entry(p, struct gendisk, kobj.entry);
......@@ -628,7 +629,7 @@ static void *diskstats_next(struct seq_file *part, void *v, loff_t *pos)
static void diskstats_stop(struct seq_file *part, void *v)
{
up(&block_subsys_sem);
mutex_unlock(&block_subsys_lock);
}
static int diskstats_show(struct seq_file *s, void *v)
......
......@@ -141,7 +141,7 @@ int __devinit register_cpu(struct cpu *cpu, int num, struct node *root)
return error;
}
struct sys_device *get_cpu_sysdev(int cpu)
struct sys_device *get_cpu_sysdev(unsigned cpu)
{
if (cpu < NR_CPUS)
return cpu_sys_devices[cpu];
......
......@@ -211,18 +211,20 @@ static int
fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size)
{
u8 *new_data;
int new_size = fw_priv->alloc_size;
if (min_size <= fw_priv->alloc_size)
return 0;
new_data = vmalloc(fw_priv->alloc_size + PAGE_SIZE);
new_size = ALIGN(min_size, PAGE_SIZE);
new_data = vmalloc(new_size);
if (!new_data) {
printk(KERN_ERR "%s: unable to alloc buffer\n", __FUNCTION__);
/* Make sure that we don't keep incomplete data */
fw_load_abort(fw_priv);
return -ENOMEM;
}
fw_priv->alloc_size += PAGE_SIZE;
fw_priv->alloc_size = new_size;
if (fw_priv->fw->data) {
memcpy(new_data, fw_priv->fw->data, fw_priv->fw->size);
vfree(fw_priv->fw->data);
......
......@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/kdev_t.h>
#include <linux/kobject.h>
#include <linux/kobj_map.h>
......@@ -25,7 +26,7 @@ struct kobj_map {
int (*lock)(dev_t, void *);
void *data;
} *probes[255];
struct semaphore *sem;
struct mutex *lock;
};
int kobj_map(struct kobj_map *domain, dev_t dev, unsigned long range,
......@@ -53,7 +54,7 @@ int kobj_map(struct kobj_map *domain, dev_t dev, unsigned long range,
p->range = range;
p->data = data;
}
down(domain->sem);
mutex_lock(domain->lock);
for (i = 0, p -= n; i < n; i++, p++, index++) {
struct probe **s = &domain->probes[index % 255];
while (*s && (*s)->range < range)
......@@ -61,7 +62,7 @@ int kobj_map(struct kobj_map *domain, dev_t dev, unsigned long range,
p->next = *s;
*s = p;
}
up(domain->sem);
mutex_unlock(domain->lock);
return 0;
}
......@@ -75,7 +76,7 @@ void kobj_unmap(struct kobj_map *domain, dev_t dev, unsigned long range)
if (n > 255)
n = 255;
down(domain->sem);
mutex_lock(domain->lock);
for (i = 0; i < n; i++, index++) {
struct probe **s;
for (s = &domain->probes[index % 255]; *s; s = &(*s)->next) {
......@@ -88,7 +89,7 @@ void kobj_unmap(struct kobj_map *domain, dev_t dev, unsigned long range)
}
}
}
up(domain->sem);
mutex_unlock(domain->lock);
kfree(found);
}
......@@ -99,7 +100,7 @@ struct kobject *kobj_lookup(struct kobj_map *domain, dev_t dev, int *index)
unsigned long best = ~0UL;
retry:
down(domain->sem);
mutex_lock(domain->lock);
for (p = domain->probes[MAJOR(dev) % 255]; p; p = p->next) {
struct kobject *(*probe)(dev_t, int *, void *);
struct module *owner;
......@@ -120,7 +121,7 @@ struct kobject *kobj_lookup(struct kobj_map *domain, dev_t dev, int *index)
module_put(owner);
continue;
}
up(domain->sem);
mutex_unlock(domain->lock);
kobj = probe(dev, index, data);
/* Currently ->owner protects _only_ ->probe() itself. */
module_put(owner);
......@@ -128,11 +129,11 @@ struct kobject *kobj_lookup(struct kobj_map *domain, dev_t dev, int *index)
return kobj;
goto retry;
}
up(domain->sem);
mutex_unlock(domain->lock);
return NULL;
}
struct kobj_map *kobj_map_init(kobj_probe_t *base_probe, struct semaphore *sem)
struct kobj_map *kobj_map_init(kobj_probe_t *base_probe, struct mutex *lock)
{
struct kobj_map *p = kmalloc(sizeof(struct kobj_map), GFP_KERNEL);
struct probe *base = kzalloc(sizeof(*base), GFP_KERNEL);
......@@ -149,6 +150,6 @@ struct kobj_map *kobj_map_init(kobj_probe_t *base_probe, struct semaphore *sem)
base->get = base_probe;
for (i = 0; i < 255; i++)
p->probes[i] = base;
p->sem = sem;
p->lock = lock;
return p;
}
......@@ -61,7 +61,7 @@ int platform_get_irq(struct platform_device *dev, unsigned int num)
{
struct resource *r = platform_get_resource(dev, IORESOURCE_IRQ, num);
return r ? r->start : 0;
return r ? r->start : -ENXIO;
}
EXPORT_SYMBOL_GPL(platform_get_irq);
......@@ -98,7 +98,7 @@ int platform_get_irq_byname(struct platform_device *dev, char *name)
{
struct resource *r = platform_get_resource_byname(dev, IORESOURCE_IRQ, name);
return r ? r->start : 0;
return r ? r->start : -ENXIO;
}
EXPORT_SYMBOL_GPL(platform_get_irq_byname);
......
......@@ -448,13 +448,13 @@ static int s3c2410_rtc_probe(struct platform_device *pdev)
/* find the IRQs */
s3c2410_rtc_tickno = platform_get_irq(pdev, 1);
if (s3c2410_rtc_tickno <= 0) {
if (s3c2410_rtc_tickno < 0) {
dev_err(&pdev->dev, "no irq for rtc tick\n");
return -ENOENT;
}
s3c2410_rtc_alarmno = platform_get_irq(pdev, 0);
if (s3c2410_rtc_alarmno <= 0) {
if (s3c2410_rtc_alarmno < 0) {
dev_err(&pdev->dev, "no irq for alarm\n");
return -ENOENT;
}
......
......@@ -338,6 +338,10 @@ static int __devinit mpcore_wdt_probe(struct platform_device *dev)
wdt->dev = &dev->dev;
wdt->irq = platform_get_irq(dev, 0);
if (wdt->irq < 0) {
ret = -ENXIO;
goto err_free;
}
wdt->base = ioremap(res->start, res->end - res->start + 1);
if (!wdt->base) {
ret = -ENOMEM;
......
......@@ -434,7 +434,7 @@ static int
iop3xx_i2c_probe(struct platform_device *pdev)
{
struct resource *res;
int ret;
int ret, irq;
struct i2c_adapter *new_adapter;
struct i2c_algo_iop3xx_data *adapter_data;
......@@ -470,7 +470,12 @@ iop3xx_i2c_probe(struct platform_device *pdev)
goto release_region;
}
ret = request_irq(platform_get_irq(pdev, 0), iop3xx_i2c_irq_handler, 0,
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
ret = -ENXIO;
goto unmap;
}
ret = request_irq(irq, iop3xx_i2c_irq_handler, 0,
pdev->name, adapter_data);
if (ret) {
......
......@@ -302,6 +302,10 @@ static int fsl_i2c_probe(struct platform_device *pdev)
}
i2c->irq = platform_get_irq(pdev, 0);
if (i2c->irq < 0) {
result = -ENXIO;
goto fail_get_irq;
}
i2c->flags = pdata->device_flags;
init_waitqueue_head(&i2c->queue);
......@@ -340,6 +344,7 @@ static int fsl_i2c_probe(struct platform_device *pdev)
fail_irq:
iounmap(i2c->base);
fail_map:
fail_get_irq:
kfree(i2c);
return result;
};
......
......@@ -516,6 +516,10 @@ mv64xxx_i2c_probe(struct platform_device *pd)
drv_data->freq_m = pdata->freq_m;
drv_data->freq_n = pdata->freq_n;
drv_data->irq = platform_get_irq(pd, 0);
if (drv_data->irq < 0) {
rc = -ENXIO;
goto exit_unmap_regs;
}
drv_data->adapter.id = I2C_HW_MV64XXX;
drv_data->adapter.algo = &mv64xxx_i2c_algo;
drv_data->adapter.owner = THIS_MODULE;
......
......@@ -674,6 +674,11 @@ static int au_ide_probe(struct device *dev)
ret = -ENODEV;
goto out;
}
if (ahwif->irq < 0) {
pr_debug("%s %d: no IRQ\n", DRV_NAME, pdev->id);
ret = -ENODEV;
goto out;
}
if (!request_mem_region (res->start, res->end-res->start, pdev->name)) {
pr_debug("%s: request_mem_region failed\n", DRV_NAME);
......
......@@ -438,7 +438,7 @@ static int pxamci_probe(struct platform_device *pdev)
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
if (!r || irq == NO_IRQ)
if (!r || irq < 0)
return -ENXIO;
r = request_mem_region(r->start, SZ_4K, DRIVER_NAME);
......
......@@ -696,7 +696,9 @@ static int __init am79c961_probe(struct platform_device *pdev)
dev->base_addr = res->start;
dev->irq = platform_get_irq(pdev, 0);
ret = -ENODEV;
ret = -ENODEV;
if (dev->irq < 0)
goto nodev;
if (!request_region(dev->base_addr, 0x18, dev->name))
goto nodev;
......
......@@ -118,6 +118,8 @@ static int do_pd_setup(struct fs_enet_private *fep)
/* Fill out IRQ field */
fep->interrupt = platform_get_irq(pdev, 0);
if (fep->interrupt < 0)
return -EINVAL;
/* Attach the memory for the FCC Parameter RAM */
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_pram");
......
......@@ -144,6 +144,8 @@ static int do_pd_setup(struct fs_enet_private *fep)
/* Fill out IRQ field */
fep->interrupt = platform_get_irq_byname(pdev,"interrupt");
if (fep->interrupt < 0)
return -EINVAL;
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
fep->fec.fecp =(void*)r->start;
......
......@@ -118,6 +118,8 @@ static int do_pd_setup(struct fs_enet_private *fep)
/* Fill out IRQ field */
fep->interrupt = platform_get_irq_byname(pdev, "interrupt");
if (fep->interrupt < 0)
return -EINVAL;
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
fep->scc.sccp = (void *)r->start;
......
......@@ -193,8 +193,12 @@ static int gfar_probe(struct platform_device *pdev)
priv->interruptTransmit = platform_get_irq_byname(pdev, "tx");
priv->interruptReceive = platform_get_irq_byname(pdev, "rx");
priv->interruptError = platform_get_irq_byname(pdev, "error");
if (priv->interruptTransmit < 0 || priv->interruptReceive < 0 || priv->interruptError < 0)
goto regs_fail;
} else {
priv->interruptTransmit = platform_get_irq(pdev, 0);
if (priv->interruptTransmit < 0)
goto regs_fail;
}
/* get a pointer to the register memory */
......
......@@ -2221,6 +2221,10 @@ static int smc_drv_probe(struct platform_device *pdev)
ndev->dma = (unsigned char)-1;
ndev->irq = platform_get_irq(pdev, 0);
if (ndev->irq < 0) {
ret = -ENODEV;
goto out_free_netdev;
}
ret = smc_request_attrib(pdev);
if (ret)
......
......@@ -218,7 +218,7 @@ static int __init omap_cf_probe(struct device *dev)
/* either CFLASH.IREQ (INT_1610_CF) or some GPIO */
irq = platform_get_irq(pdev, 0);
if (!irq)
if (irq < 0)
return -EINVAL;
cf = kcalloc(1, sizeof *cf, GFP_KERNEL);
......
......@@ -1066,6 +1066,8 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
port->mapbase = res->start;
port->membase = S3C24XX_VA_UART + (res->start - S3C24XX_PA_UART);
port->irq = platform_get_irq(platdev, 0);
if (port->irq < 0)
port->irq = 0;
ourport->clk = clk_get(&platdev->dev, "uart");
......
......@@ -378,7 +378,7 @@ const struct usb_device_id *usb_match_id(struct usb_interface *interface,
return NULL;
}
EXPORT_SYMBOL(usb_match_id);
EXPORT_SYMBOL_GPL_FUTURE(usb_match_id);
int usb_device_match(struct device *dev, struct device_driver *drv)
{
......@@ -446,7 +446,7 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner)
return retval;
}
EXPORT_SYMBOL(usb_register_driver);
EXPORT_SYMBOL_GPL_FUTURE(usb_register_driver);
/**
* usb_deregister - unregister a USB driver
......@@ -469,4 +469,4 @@ void usb_deregister(struct usb_driver *driver)
usbfs_update_special();
}
EXPORT_SYMBOL(usb_deregister);
EXPORT_SYMBOL_GPL_FUTURE(usb_deregister);
......@@ -286,7 +286,7 @@ void usb_hcd_omap_remove (struct usb_hcd *, struct platform_device *);
int usb_hcd_omap_probe (const struct hc_driver *driver,
struct platform_device *pdev)
{
int retval;
int retval, irq;
struct usb_hcd *hcd = 0;
struct ohci_hcd *ohci;
......@@ -329,7 +329,12 @@ int usb_hcd_omap_probe (const struct hc_driver *driver,
if (retval < 0)
goto err2;
retval = usb_add_hcd(hcd, platform_get_irq(pdev, 0), SA_INTERRUPT);
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
retval = -ENXIO;
goto err2;
}
retval = usb_add_hcd(hcd, irq, SA_INTERRUPT);
if (retval == 0)
return retval;
......
......@@ -607,6 +607,7 @@ static void clearfb16(struct fb_info *info)
static void epson1355fb_platform_release(struct device *device)
{
dev_err(device, "This driver is broken, please bug the authors so they will fix it.\n");
}
static int epson1355fb_remove(struct platform_device *dev)
......
......@@ -1457,7 +1457,7 @@ static int __init sa1100fb_probe(struct platform_device *pdev)
int ret, irq;
irq = platform_get_irq(pdev, 0);
if (irq <= 0)
if (irq < 0)
return -EINVAL;
if (!request_mem_region(0xb0100000, 0x10000, "LCD"))
......
......@@ -401,6 +401,7 @@ static int __init vfb_setup(char *options)
static void vfb_platform_release(struct device *device)
{
// This is called when the reference count goes to zero.
dev_err(device, "This driver is broken, please bug the authors so they will fix it.\n");
}
static int __init vfb_probe(struct platform_device *dev)
......
......@@ -19,6 +19,7 @@
#include <linux/kobject.h>
#include <linux/kobj_map.h>
#include <linux/cdev.h>
#include <linux/mutex.h>
#ifdef CONFIG_KMOD
#include <linux/kmod.h>
......@@ -28,7 +29,7 @@ static struct kobj_map *cdev_map;
#define MAX_PROBE_HASH 255 /* random */
static DECLARE_MUTEX(chrdevs_lock);
static DEFINE_MUTEX(chrdevs_lock);
static struct char_device_struct {
struct char_device_struct *next;
......@@ -88,13 +89,13 @@ void *get_next_chrdev(void *dev)
void *acquire_chrdev_list(void)
{
down(&chrdevs_lock);
mutex_lock(&chrdevs_lock);
return get_next_chrdev(NULL);
}
void release_chrdev_list(void *dev)
{
up(&chrdevs_lock);
mutex_unlock(&chrdevs_lock);
kfree(dev);
}
......@@ -151,7 +152,7 @@ __register_chrdev_region(unsigned int major, unsigned int baseminor,
memset(cd, 0, sizeof(struct char_device_struct));
down(&chrdevs_lock);
mutex_lock(&chrdevs_lock);
/* temporary */
if (major == 0) {
......@@ -186,10 +187,10 @@ __register_chrdev_region(unsigned int major, unsigned int baseminor,
}
cd->next = *cp;
*cp = cd;
up(&chrdevs_lock);
mutex_unlock(&chrdevs_lock);
return cd;
out:
up(&chrdevs_lock);
mutex_unlock(&chrdevs_lock);
kfree(cd);
return ERR_PTR(ret);
}
......@@ -200,7 +201,7 @@ __unregister_chrdev_region(unsigned major, unsigned baseminor, int minorct)
struct char_device_struct *cd = NULL, **cp;
int i = major_to_index(major);
down(&chrdevs_lock);
mutex_lock(&chrdevs_lock);
for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)
if ((*cp)->major == major &&
(*cp)->baseminor == baseminor &&
......@@ -210,7 +211,7 @@ __unregister_chrdev_region(unsigned major, unsigned baseminor, int minorct)
cd = *cp;
*cp = cd->next;
}
up(&chrdevs_lock);
mutex_unlock(&chrdevs_lock);
return cd;
}
......
......@@ -251,3 +251,49 @@ struct dentry *debugfs_create_bool(const char *name, mode_t mode,
}
EXPORT_SYMBOL_GPL(debugfs_create_bool);
static ssize_t read_file_blob(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct debugfs_blob_wrapper *blob = file->private_data;
return simple_read_from_buffer(user_buf, count, ppos, blob->data,
blob->size);
}
static struct file_operations fops_blob = {
.read = read_file_blob,
.open = default_open,
};
/**
* debugfs_create_blob - create a file in the debugfs filesystem that is
* used to read and write a binary blob.
*
* @name: a pointer to a string containing the name of the file to create.
* @mode: the permission that the file should have
* @parent: a pointer to the parent dentry for this file. This should be a
* directory dentry if set. If this paramater is NULL, then the
* file will be created in the root of the debugfs filesystem.
* @blob: a pointer to a struct debugfs_blob_wrapper which contains a pointer
* to the blob data and the size of the data.
*
* This function creates a file in debugfs with the given name that exports
* @blob->data as a binary blob. If the @mode variable is so set it can be
* read from. Writing is not supported.
*
* This function will return a pointer to a dentry if it succeeds. This
* pointer must be passed to the debugfs_remove() function when the file is
* to be removed (no automatic cleanup happens if your module is unloaded,
* you are responsible here.) If an error occurs, NULL will be returned.
*
* If debugfs is not enabled in the kernel, the value -ENODEV will be
* returned. It is not wise to check for this value, but rather, check for
* NULL or !NULL instead as to eliminate the need for #ifdef in the calling
* code.
*/
struct dentry *debugfs_create_blob(const char *name, mode_t mode,
struct dentry *parent,
struct debugfs_blob_wrapper *blob)
{
return debugfs_create_file(name, mode, parent, blob, &fops_blob);
}
EXPORT_SYMBOL_GPL(debugfs_create_blob);
......@@ -50,6 +50,32 @@ static struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent * parent_sd,
return sd;
}
/**
*
* Return -EEXIST if there is already a sysfs element with the same name for
* the same parent.
*
* called with parent inode's i_mutex held
*/
int sysfs_dirent_exist(struct sysfs_dirent *parent_sd,
const unsigned char *new)
{
struct sysfs_dirent * sd;
list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
if (sd->s_element) {
const unsigned char *existing = sysfs_get_name(sd);
if (strcmp(existing, new))
continue;
else
return -EEXIST;
}
}
return 0;
}
int sysfs_make_dirent(struct sysfs_dirent * parent_sd, struct dentry * dentry,
void * element, umode_t mode, int type)
{
......@@ -102,7 +128,11 @@ static int create_dir(struct kobject * k, struct dentry * p,
mutex_lock(&p->d_inode->i_mutex);
*d = lookup_one_len(n, p, strlen(n));
if (!IS_ERR(*d)) {
error = sysfs_make_dirent(p->d_fsdata, *d, k, mode, SYSFS_DIR);
if (sysfs_dirent_exist(p->d_fsdata, n))
error = -EEXIST;
else
error = sysfs_make_dirent(p->d_fsdata, *d, k, mode,
SYSFS_DIR);
if (!error) {
error = sysfs_create(*d, mode, init_dir);
if (!error) {
......@@ -302,6 +332,7 @@ void sysfs_remove_dir(struct kobject * kobj)
* Drop reference from dget() on entrance.
*/
dput(dentry);
kobj->dentry = NULL;
}
int sysfs_rename_dir(struct kobject * kobj, const char *new_name)
......@@ -479,7 +510,3 @@ struct file_operations sysfs_dir_operations = {
.read = generic_read_dir,
.readdir = sysfs_readdir,
};
EXPORT_SYMBOL_GPL(sysfs_create_dir);
EXPORT_SYMBOL_GPL(sysfs_remove_dir);
EXPORT_SYMBOL_GPL(sysfs_rename_dir);
......@@ -301,9 +301,8 @@ static int check_perm(struct inode * inode, struct file * file)
/* No error? Great, allocate a buffer for the file, and store it
* it in file->private_data for easy access.
*/
buffer = kmalloc(sizeof(struct sysfs_buffer),GFP_KERNEL);
buffer = kzalloc(sizeof(struct sysfs_buffer), GFP_KERNEL);
if (buffer) {
memset(buffer,0,sizeof(struct sysfs_buffer));
init_MUTEX(&buffer->sem);
buffer->needs_read_fill = 1;
buffer->ops = ops;
......@@ -362,10 +361,12 @@ int sysfs_add_file(struct dentry * dir, const struct attribute * attr, int type)
{
struct sysfs_dirent * parent_sd = dir->d_fsdata;
umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG;
int error = 0;
int error = -EEXIST;
mutex_lock(&dir->d_inode->i_mutex);
error = sysfs_make_dirent(parent_sd, NULL, (void *) attr, mode, type);
if (!sysfs_dirent_exist(parent_sd, attr->name))
error = sysfs_make_dirent(parent_sd, NULL, (void *)attr,
mode, type);
mutex_unlock(&dir->d_inode->i_mutex);
return error;
......
......@@ -54,11 +54,10 @@ int sysfs_setattr(struct dentry * dentry, struct iattr * iattr)
if (!sd_iattr) {
/* setting attributes for the first time, allocate now */
sd_iattr = kmalloc(sizeof(struct iattr), GFP_KERNEL);
sd_iattr = kzalloc(sizeof(struct iattr), GFP_KERNEL);
if (!sd_iattr)
return -ENOMEM;
/* assign default attributes */
memset(sd_iattr, 0, sizeof(struct iattr));
sd_iattr->ia_mode = sd->s_mode;
sd_iattr->ia_uid = 0;
sd_iattr->ia_gid = 0;
......@@ -227,12 +226,16 @@ void sysfs_drop_dentry(struct sysfs_dirent * sd, struct dentry * parent)
void sysfs_hash_and_remove(struct dentry * dir, const char * name)
{
struct sysfs_dirent * sd;
struct sysfs_dirent * parent_sd = dir->d_fsdata;
struct sysfs_dirent * parent_sd;
if (!dir)
return;
if (dir->d_inode == NULL)
/* no inode means this hasn't been made visible yet */
return;
parent_sd = dir->d_fsdata;
mutex_lock(&dir->d_inode->i_mutex);
list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
if (!sd->s_element)
......
......@@ -66,6 +66,7 @@ static int sysfs_add_link(struct dentry * parent, const char * name, struct kobj
if (!error)
return 0;
kobject_put(target);
kfree(sl->link_name);
exit2:
kfree(sl);
......@@ -82,12 +83,13 @@ static int sysfs_add_link(struct dentry * parent, const char * name, struct kobj
int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char * name)
{
struct dentry * dentry = kobj->dentry;
int error = 0;
int error = -EEXIST;
BUG_ON(!kobj || !kobj->dentry || !name);
mutex_lock(&dentry->d_inode->i_mutex);
error = sysfs_add_link(dentry, name, target);
if (!sysfs_dirent_exist(dentry->d_fsdata, name))
error = sysfs_add_link(dentry, name, target);
mutex_unlock(&dentry->d_inode->i_mutex);
return error;
}
......
......@@ -5,6 +5,7 @@ extern kmem_cache_t *sysfs_dir_cachep;
extern struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent *);
extern int sysfs_create(struct dentry *, int mode, int (*init)(struct inode *));
extern int sysfs_dirent_exist(struct sysfs_dirent *, const unsigned char *);
extern int sysfs_make_dirent(struct sysfs_dirent *, struct dentry *, void *,
umode_t, int);
......
......@@ -58,6 +58,13 @@
VMLINUX_SYMBOL(__stop___ksymtab_gpl) = .; \
} \
\
/* Kernel symbol table: GPL-future-only symbols */ \
__ksymtab_gpl_future : AT(ADDR(__ksymtab_gpl_future) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___ksymtab_gpl_future) = .; \
*(__ksymtab_gpl_future) \
VMLINUX_SYMBOL(__stop___ksymtab_gpl_future) = .; \
} \
\
/* Kernel symbol table: Normal symbols */ \
__kcrctab : AT(ADDR(__kcrctab) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___kcrctab) = .; \
......@@ -72,6 +79,13 @@
VMLINUX_SYMBOL(__stop___kcrctab_gpl) = .; \
} \
\
/* Kernel symbol table: GPL-future-only symbols */ \
__kcrctab_gpl_future : AT(ADDR(__kcrctab_gpl_future) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___kcrctab_gpl_future) = .; \
*(__kcrctab_gpl_future) \
VMLINUX_SYMBOL(__stop___kcrctab_gpl_future) = .; \
} \
\
/* Kernel symbol table: strings */ \
__ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) { \
*(__ksymtab_strings) \
......
......@@ -32,7 +32,7 @@ struct cpu {
};
extern int register_cpu(struct cpu *, int, struct node *);
extern struct sys_device *get_cpu_sysdev(int cpu);
extern struct sys_device *get_cpu_sysdev(unsigned cpu);
#ifdef CONFIG_HOTPLUG_CPU
extern void unregister_cpu(struct cpu *, struct node *);
#endif
......
......@@ -21,6 +21,11 @@
struct file_operations;
struct debugfs_blob_wrapper {
void *data;
unsigned long size;
};
#if defined(CONFIG_DEBUG_FS)
struct dentry *debugfs_create_file(const char *name, mode_t mode,
struct dentry *parent, void *data,
......@@ -39,6 +44,9 @@ struct dentry *debugfs_create_u32(const char *name, mode_t mode,
struct dentry *debugfs_create_bool(const char *name, mode_t mode,
struct dentry *parent, u32 *value);
struct dentry *debugfs_create_blob(const char *name, mode_t mode,
struct dentry *parent,
struct debugfs_blob_wrapper *blob);
#else
#include <linux/err.h>
......@@ -94,6 +102,13 @@ static inline struct dentry *debugfs_create_bool(const char *name, mode_t mode,
return ERR_PTR(-ENODEV);
}
static inline struct dentry *debugfs_create_blob(const char *name, mode_t mode,
struct dentry *parent,
struct debugfs_blob_wrapper *blob)
{
return ERR_PTR(-ENODEV);
}
#endif
#endif
......@@ -424,6 +424,8 @@ extern void firmware_unregister(struct subsystem *);
dev_printk(KERN_INFO , dev , format , ## arg)
#define dev_warn(dev, format, arg...) \
dev_printk(KERN_WARNING , dev , format , ## arg)
#define dev_notice(dev, format, arg...) \
dev_printk(KERN_NOTICE , dev , format , ## arg)
/* Create alias, so I can be autoloaded. */
#define MODULE_ALIAS_CHARDEV(major,minor) \
......
#ifdef __KERNEL__
#include <asm/semaphore.h>
#include <linux/mutex.h>
typedef struct kobject *kobj_probe_t(dev_t, int *, void *);
struct kobj_map;
......@@ -9,6 +9,6 @@ int kobj_map(struct kobj_map *, dev_t, unsigned long, struct module *,
kobj_probe_t *, int (*)(dev_t, void *), void *);
void kobj_unmap(struct kobj_map *, dev_t, unsigned long);
struct kobject *kobj_lookup(struct kobj_map *, dev_t, int *);
struct kobj_map *kobj_map_init(kobj_probe_t *, struct semaphore *);
struct kobj_map *kobj_map_init(kobj_probe_t *, struct mutex *);
#endif
......@@ -80,6 +80,8 @@ extern void kobject_unregister(struct kobject *);
extern struct kobject * kobject_get(struct kobject *);
extern void kobject_put(struct kobject *);
extern struct kobject *kobject_add_dir(struct kobject *, const char *);
extern char * kobject_get_path(struct kobject *, gfp_t);
struct kobj_type {
......@@ -255,7 +257,7 @@ struct subsys_attribute {
extern int subsys_create_file(struct subsystem * , struct subsys_attribute *);
extern void subsys_remove_file(struct subsystem * , struct subsys_attribute *);
#if defined(CONFIG_HOTPLUG) & defined(CONFIG_NET)
#if defined(CONFIG_HOTPLUG) && defined(CONFIG_NET)
void kobject_uevent(struct kobject *kobj, enum kobject_action action);
int add_uevent_var(char **envp, int num_envp, int *cur_index,
......
......@@ -198,6 +198,9 @@ void *__symbol_get_gpl(const char *symbol);
#define EXPORT_SYMBOL_GPL(sym) \
__EXPORT_SYMBOL(sym, "_gpl")
#define EXPORT_SYMBOL_GPL_FUTURE(sym) \
__EXPORT_SYMBOL(sym, "_gpl_future")
#endif
struct module_ref
......@@ -242,6 +245,7 @@ struct module
/* Sysfs stuff. */
struct module_kobject mkobj;
struct module_param_attrs *param_attrs;
struct module_attribute *modinfo_attrs;
const char *version;
const char *srcversion;
......@@ -255,6 +259,11 @@ struct module
unsigned int num_gpl_syms;
const unsigned long *gpl_crcs;
/* symbols that will be GPL-only in the near future. */
const struct kernel_symbol *gpl_future_syms;
unsigned int num_gpl_future_syms;
const unsigned long *gpl_future_crcs;
/* Exception table */
unsigned int num_exentries;
const struct exception_table_entry *extable;
......@@ -441,6 +450,7 @@ void module_remove_driver(struct device_driver *);
#else /* !CONFIG_MODULES... */
#define EXPORT_SYMBOL(sym)
#define EXPORT_SYMBOL_GPL(sym)
#define EXPORT_SYMBOL_GPL_FUTURE(sym)
/* Given an address, look for it in the exception tables. */
static inline const struct exception_table_entry *
......
......@@ -15,9 +15,6 @@
#include <linux/module.h>
#include <linux/init.h>
u64 uevent_seqnum;
char uevent_helper[UEVENT_HELPER_PATH_LEN] = "/sbin/hotplug";
#define KERNEL_ATTR_RO(_name) \
static struct subsys_attribute _name##_attr = __ATTR_RO(_name)
......
......@@ -126,8 +126,11 @@ extern const struct kernel_symbol __start___ksymtab[];
extern const struct kernel_symbol __stop___ksymtab[];
extern const struct kernel_symbol __start___ksymtab_gpl[];
extern const struct kernel_symbol __stop___ksymtab_gpl[];
extern const struct kernel_symbol __start___ksymtab_gpl_future[];
extern const struct kernel_symbol __stop___ksymtab_gpl_future[];
extern const unsigned long __start___kcrctab[];
extern const unsigned long __start___kcrctab_gpl[];
extern const unsigned long __start___kcrctab_gpl_future[];
#ifndef CONFIG_MODVERSIONS
#define symversion(base, idx) NULL
......@@ -135,6 +138,18 @@ extern const unsigned long __start___kcrctab_gpl[];
#define symversion(base, idx) ((base) ? ((base) + (idx)) : NULL)
#endif
/* lookup symbol in given range of kernel_symbols */
static const struct kernel_symbol *lookup_symbol(const char *name,
const struct kernel_symbol *start,
const struct kernel_symbol *stop)
{
const struct kernel_symbol *ks = start;
for (; ks < stop; ks++)
if (strcmp(ks->name, name) == 0)
return ks;
return NULL;
}
/* Find a symbol, return value, crc and module which owns it */
static unsigned long __find_symbol(const char *name,
struct module **owner,
......@@ -142,40 +157,75 @@ static unsigned long __find_symbol(const char *name,
int gplok)
{
struct module *mod;
unsigned int i;
const struct kernel_symbol *ks;
/* Core kernel first. */
*owner = NULL;
for (i = 0; __start___ksymtab+i < __stop___ksymtab; i++) {
if (strcmp(__start___ksymtab[i].name, name) == 0) {
*crc = symversion(__start___kcrctab, i);
return __start___ksymtab[i].value;
}
ks = lookup_symbol(name, __start___ksymtab, __stop___ksymtab);
if (ks) {
*crc = symversion(__start___kcrctab, (ks - __start___ksymtab));
return ks->value;
}
if (gplok) {
for (i = 0; __start___ksymtab_gpl+i<__stop___ksymtab_gpl; i++)
if (strcmp(__start___ksymtab_gpl[i].name, name) == 0) {
*crc = symversion(__start___kcrctab_gpl, i);
return __start___ksymtab_gpl[i].value;
}
ks = lookup_symbol(name, __start___ksymtab_gpl,
__stop___ksymtab_gpl);
if (ks) {
*crc = symversion(__start___kcrctab_gpl,
(ks - __start___ksymtab_gpl));
return ks->value;
}
}
ks = lookup_symbol(name, __start___ksymtab_gpl_future,
__stop___ksymtab_gpl_future);
if (ks) {
if (!gplok) {
printk(KERN_WARNING "Symbol %s is being used "
"by a non-GPL module, which will not "
"be allowed in the future\n", name);
printk(KERN_WARNING "Please see the file "
"Documentation/feature-removal-schedule.txt "
"in the kernel source tree for more "
"details.\n");
}
*crc = symversion(__start___kcrctab_gpl_future,
(ks - __start___ksymtab_gpl_future));
return ks->value;
}
/* Now try modules. */
list_for_each_entry(mod, &modules, list) {
*owner = mod;
for (i = 0; i < mod->num_syms; i++)
if (strcmp(mod->syms[i].name, name) == 0) {
*crc = symversion(mod->crcs, i);
return mod->syms[i].value;
}
ks = lookup_symbol(name, mod->syms, mod->syms + mod->num_syms);
if (ks) {
*crc = symversion(mod->crcs, (ks - mod->syms));
return ks->value;
}
if (gplok) {
for (i = 0; i < mod->num_gpl_syms; i++) {
if (strcmp(mod->gpl_syms[i].name, name) == 0) {
*crc = symversion(mod->gpl_crcs, i);
return mod->gpl_syms[i].value;
}
ks = lookup_symbol(name, mod->gpl_syms,
mod->gpl_syms + mod->num_gpl_syms);
if (ks) {
*crc = symversion(mod->gpl_crcs,
(ks - mod->gpl_syms));
return ks->value;
}
}
ks = lookup_symbol(name, mod->gpl_future_syms,
(mod->gpl_future_syms +
mod->num_gpl_future_syms));
if (ks) {
if (!gplok) {
printk(KERN_WARNING "Symbol %s is being used "
"by a non-GPL module, which will not "
"be allowed in the future\n", name);
printk(KERN_WARNING "Please see the file "
"Documentation/feature-removal-schedule.txt "
"in the kernel source tree for more "
"details.\n");
}
*crc = symversion(mod->gpl_future_crcs,
(ks - mod->gpl_future_syms));
return ks->value;
}
}
DEBUGP("Failed to find symbol %s\n", name);
......@@ -379,7 +429,6 @@ static inline void percpu_modcopy(void *pcpudst, const void *src,
}
#endif /* CONFIG_SMP */
#ifdef CONFIG_MODULE_UNLOAD
#define MODINFO_ATTR(field) \
static void setup_modinfo_##field(struct module *mod, const char *s) \
{ \
......@@ -411,12 +460,7 @@ static struct module_attribute modinfo_##field = { \
MODINFO_ATTR(version);
MODINFO_ATTR(srcversion);
static struct module_attribute *modinfo_attrs[] = {
&modinfo_version,
&modinfo_srcversion,
NULL,
};
#ifdef CONFIG_MODULE_UNLOAD
/* Init the unload section of the module. */
static void module_unload_init(struct module *mod)
{
......@@ -731,6 +775,15 @@ static inline void module_unload_init(struct module *mod)
}
#endif /* CONFIG_MODULE_UNLOAD */
static struct module_attribute *modinfo_attrs[] = {
&modinfo_version,
&modinfo_srcversion,
#ifdef CONFIG_MODULE_UNLOAD
&refcnt,
#endif
NULL,
};
#ifdef CONFIG_OBSOLETE_MODPARM
/* Bounds checking done below */
static int obsparm_copy_string(const char *val, struct kernel_param *kp)
......@@ -1056,37 +1109,28 @@ static inline void remove_sect_attrs(struct module *mod)
}
#endif /* CONFIG_KALLSYMS */
#ifdef CONFIG_MODULE_UNLOAD
static inline int module_add_refcnt_attr(struct module *mod)
{
return sysfs_create_file(&mod->mkobj.kobj, &refcnt.attr);
}
static void module_remove_refcnt_attr(struct module *mod)
{
return sysfs_remove_file(&mod->mkobj.kobj, &refcnt.attr);
}
#else
static inline int module_add_refcnt_attr(struct module *mod)
{
return 0;
}
static void module_remove_refcnt_attr(struct module *mod)
{
}
#endif
#ifdef CONFIG_MODULE_UNLOAD
static int module_add_modinfo_attrs(struct module *mod)
{
struct module_attribute *attr;
struct module_attribute *temp_attr;
int error = 0;
int i;
mod->modinfo_attrs = kzalloc((sizeof(struct module_attribute) *
(ARRAY_SIZE(modinfo_attrs) + 1)),
GFP_KERNEL);
if (!mod->modinfo_attrs)
return -ENOMEM;
temp_attr = mod->modinfo_attrs;
for (i = 0; (attr = modinfo_attrs[i]) && !error; i++) {
if (!attr->test ||
(attr->test && attr->test(mod)))
error = sysfs_create_file(&mod->mkobj.kobj,&attr->attr);
(attr->test && attr->test(mod))) {
memcpy(temp_attr, attr, sizeof(*temp_attr));
temp_attr->attr.owner = mod;
error = sysfs_create_file(&mod->mkobj.kobj,&temp_attr->attr);
++temp_attr;
}
}
return error;
}
......@@ -1096,12 +1140,16 @@ static void module_remove_modinfo_attrs(struct module *mod)
struct module_attribute *attr;
int i;
for (i = 0; (attr = modinfo_attrs[i]); i++) {
for (i = 0; (attr = &mod->modinfo_attrs[i]); i++) {
/* pick a field to test for end of list */
if (!attr->attr.name)
break;
sysfs_remove_file(&mod->mkobj.kobj,&attr->attr);
attr->free(mod);
if (attr->free)
attr->free(mod);
}
kfree(mod->modinfo_attrs);
}
#endif
static int mod_sysfs_setup(struct module *mod,
struct kernel_param *kparam,
......@@ -1119,19 +1167,13 @@ static int mod_sysfs_setup(struct module *mod,
if (err)
goto out;
err = module_add_refcnt_attr(mod);
if (err)
goto out_unreg;
err = module_param_sysfs_setup(mod, kparam, num_params);
if (err)
goto out_unreg;
#ifdef CONFIG_MODULE_UNLOAD
err = module_add_modinfo_attrs(mod);
if (err)
goto out_unreg;
#endif
return 0;
......@@ -1143,10 +1185,7 @@ static int mod_sysfs_setup(struct module *mod,
static void mod_kobject_remove(struct module *mod)
{
#ifdef CONFIG_MODULE_UNLOAD
module_remove_modinfo_attrs(mod);
#endif
module_remove_refcnt_attr(mod);
module_param_sysfs_remove(mod);
kobject_unregister(&mod->mkobj.kobj);
......@@ -1424,7 +1463,6 @@ static char *get_modinfo(Elf_Shdr *sechdrs,
return NULL;
}
#ifdef CONFIG_MODULE_UNLOAD
static void setup_modinfo(struct module *mod, Elf_Shdr *sechdrs,
unsigned int infoindex)
{
......@@ -1439,23 +1477,17 @@ static void setup_modinfo(struct module *mod, Elf_Shdr *sechdrs,
attr->attr.name));
}
}
#endif
#ifdef CONFIG_KALLSYMS
int is_exported(const char *name, const struct module *mod)
{
unsigned int i;
if (!mod) {
for (i = 0; __start___ksymtab+i < __stop___ksymtab; i++)
if (strcmp(__start___ksymtab[i].name, name) == 0)
return 1;
return 0;
}
for (i = 0; i < mod->num_syms; i++)
if (strcmp(mod->syms[i].name, name) == 0)
if (!mod && lookup_symbol(name, __start___ksymtab, __stop___ksymtab))
return 1;
else
if (lookup_symbol(name, mod->syms, mod->syms + mod->num_syms))
return 1;
return 0;
else
return 0;
}
/* As per nm */
......@@ -1537,7 +1569,8 @@ static struct module *load_module(void __user *umod,
char *secstrings, *args, *modmagic, *strtab = NULL;
unsigned int i, symindex = 0, strindex = 0, setupindex, exindex,
exportindex, modindex, obsparmindex, infoindex, gplindex,
crcindex, gplcrcindex, versindex, pcpuindex;
crcindex, gplcrcindex, versindex, pcpuindex, gplfutureindex,
gplfuturecrcindex;
long arglen;
struct module *mod;
long err = 0;
......@@ -1618,8 +1651,10 @@ static struct module *load_module(void __user *umod,
/* Optional sections */
exportindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab");
gplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl");
gplfutureindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl_future");
crcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab");
gplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl");
gplfuturecrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl_future");
setupindex = find_sec(hdr, sechdrs, secstrings, "__param");
exindex = find_sec(hdr, sechdrs, secstrings, "__ex_table");
obsparmindex = find_sec(hdr, sechdrs, secstrings, "__obsparm");
......@@ -1755,10 +1790,8 @@ static struct module *load_module(void __user *umod,
if (strcmp(mod->name, "driverloader") == 0)
add_taint(TAINT_PROPRIETARY_MODULE);
#ifdef CONFIG_MODULE_UNLOAD
/* Set up MODINFO_ATTR fields */
setup_modinfo(mod, sechdrs, infoindex);
#endif
/* Fix up syms, so that st_value is a pointer to location. */
err = simplify_symbols(sechdrs, symindex, strtab, versindex, pcpuindex,
......@@ -1775,10 +1808,16 @@ static struct module *load_module(void __user *umod,
mod->gpl_syms = (void *)sechdrs[gplindex].sh_addr;
if (gplcrcindex)
mod->gpl_crcs = (void *)sechdrs[gplcrcindex].sh_addr;
mod->num_gpl_future_syms = sechdrs[gplfutureindex].sh_size /
sizeof(*mod->gpl_future_syms);
mod->gpl_future_syms = (void *)sechdrs[gplfutureindex].sh_addr;
if (gplfuturecrcindex)
mod->gpl_future_crcs = (void *)sechdrs[gplfuturecrcindex].sh_addr;
#ifdef CONFIG_MODVERSIONS
if ((mod->num_syms && !crcindex) ||
(mod->num_gpl_syms && !gplcrcindex)) {
(mod->num_gpl_syms && !gplcrcindex) ||
(mod->num_gpl_future_syms && !gplfuturecrcindex)) {
printk(KERN_WARNING "%s: No versions for exported symbols."
" Tainting kernel.\n", mod->name);
add_taint(TAINT_FORCED_MODULE);
......
......@@ -638,13 +638,8 @@ static ssize_t module_attr_show(struct kobject *kobj,
if (!attribute->show)
return -EIO;
if (!try_module_get(mk->mod))
return -ENODEV;
ret = attribute->show(attribute, mk->mod, buf);
module_put(mk->mod);
return ret;
}
......@@ -662,13 +657,8 @@ static ssize_t module_attr_store(struct kobject *kobj,
if (!attribute->store)
return -EIO;
if (!try_module_get(mk->mod))
return -ENODEV;
ret = attribute->store(attribute, mk->mod, buf, len);
module_put(mk->mod);
return ret;
}
......
......@@ -609,7 +609,7 @@ module_param(qlowmark, int, 0);
module_param(rsinterval, int, 0);
#endif
EXPORT_SYMBOL_GPL(rcu_batches_completed);
EXPORT_SYMBOL(call_rcu); /* WARNING: GPL-only in April 2006. */
EXPORT_SYMBOL(call_rcu_bh); /* WARNING: GPL-only in April 2006. */
EXPORT_SYMBOL_GPL_FUTURE(call_rcu); /* WARNING: GPL-only in April 2006. */
EXPORT_SYMBOL_GPL_FUTURE(call_rcu_bh); /* WARNING: GPL-only in April 2006. */
EXPORT_SYMBOL_GPL(synchronize_rcu);
EXPORT_SYMBOL(synchronize_kernel); /* WARNING: GPL-only in April 2006. */
EXPORT_SYMBOL_GPL_FUTURE(synchronize_kernel); /* WARNING: GPL-only in April 2006. */
......@@ -194,6 +194,17 @@ int kobject_add(struct kobject * kobj)
unlink(kobj);
if (parent)
kobject_put(parent);
/* be noisy on error issues */
if (error == -EEXIST)
printk("kobject_add failed for %s with -EEXIST, "
"don't try to register things with the "
"same name in the same directory.\n",
kobject_name(kobj));
else
printk("kobject_add failed for %s (%d)\n",
kobject_name(kobj), error);
dump_stack();
}
return error;
......@@ -207,18 +218,13 @@ int kobject_add(struct kobject * kobj)
int kobject_register(struct kobject * kobj)
{
int error = 0;
int error = -EINVAL;
if (kobj) {
kobject_init(kobj);
error = kobject_add(kobj);
if (error) {
printk("kobject_register failed for %s (%d)\n",
kobject_name(kobj),error);
dump_stack();
} else
if (!error)
kobject_uevent(kobj, KOBJ_ADD);
} else
error = -EINVAL;
}
return error;
}
......@@ -379,6 +385,44 @@ void kobject_put(struct kobject * kobj)
}
static void dir_release(struct kobject *kobj)
{
kfree(kobj);
}
static struct kobj_type dir_ktype = {
.release = dir_release,
.sysfs_ops = NULL,
.default_attrs = NULL,
};
/**
* kobject_add_dir - add sub directory of object.
* @parent: object in which a directory is created.
* @name: directory name.
*
* Add a plain directory object as child of given object.
*/
struct kobject *kobject_add_dir(struct kobject *parent, const char *name)
{
struct kobject *k;
if (!parent)
return NULL;
k = kzalloc(sizeof(*k), GFP_KERNEL);
if (!k)
return NULL;
k->parent = parent;
k->ktype = &dir_ktype;
kobject_set_name(k, name);
kobject_register(k);
return k;
}
EXPORT_SYMBOL_GPL(kobject_add_dir);
/**
* kset_init - initialize a kset for use
* @k: kset
......
......@@ -26,6 +26,8 @@
#define NUM_ENVP 32 /* number of env pointers */
#if defined(CONFIG_HOTPLUG) && defined(CONFIG_NET)
u64 uevent_seqnum;
char uevent_helper[UEVENT_HELPER_PATH_LEN] = "/sbin/hotplug";
static DEFINE_SPINLOCK(sequence_lock);
static struct sock *uevent_sock;
......
......@@ -52,7 +52,12 @@ int kref_put(struct kref *kref, void (*release)(struct kref *kref))
WARN_ON(release == NULL);
WARN_ON(release == (void (*)(struct kref *))kfree);
if (atomic_dec_and_test(&kref->refcount)) {
/*
* if current count is one, we are the last user and can release object
* right now, avoiding an atomic operation on 'refcount'
*/
if ((atomic_read(&kref->refcount) == 1) ||
(atomic_dec_and_test(&kref->refcount))) {
release(kref);
return 1;
}
......
......@@ -52,9 +52,9 @@ is_reserved_hash (register const char *str, register unsigned int len)
71, 71, 71, 71, 71, 71, 71, 71, 71, 71,
71, 71, 71, 71, 71, 71, 71, 71, 71, 71,
71, 71, 71, 71, 71, 71, 71, 71, 71, 71,
71, 71, 71, 71, 71, 71, 71, 71, 71, 15,
71, 71, 71, 71, 71, 71, 15, 71, 71, 71,
10, 71, 71, 71, 71, 71, 71, 71, 71, 71,
71, 71, 71, 71, 71, 71, 71, 71, 71, 0,
71, 71, 71, 71, 71, 71, 35, 71, 71, 71,
5, 71, 71, 71, 71, 71, 71, 71, 71, 71,
71, 71, 71, 71, 71, 0, 71, 0, 71, 5,
5, 0, 10, 20, 71, 25, 71, 71, 20, 0,
20, 30, 25, 71, 10, 5, 0, 20, 15, 71,
......@@ -84,9 +84,9 @@ is_reserved_word (register const char *str, register unsigned int len)
{
enum
{
TOTAL_KEYWORDS = 41,
TOTAL_KEYWORDS = 42,
MIN_WORD_LENGTH = 3,
MAX_WORD_LENGTH = 17,
MAX_WORD_LENGTH = 24,
MIN_HASH_VALUE = 3,
MAX_HASH_VALUE = 70
};
......@@ -94,104 +94,105 @@ is_reserved_word (register const char *str, register unsigned int len)
static const struct resword wordlist[] =
{
{""}, {""}, {""},
#line 24 "scripts/genksyms/keywords.gperf"
#line 25 "scripts/genksyms/keywords.gperf"
{"asm", ASM_KEYW},
{""},
#line 7 "scripts/genksyms/keywords.gperf"
#line 8 "scripts/genksyms/keywords.gperf"
{"__asm", ASM_KEYW},
{""},
#line 8 "scripts/genksyms/keywords.gperf"
#line 9 "scripts/genksyms/keywords.gperf"
{"__asm__", ASM_KEYW},
{""},
#line 21 "scripts/genksyms/keywords.gperf"
#line 22 "scripts/genksyms/keywords.gperf"
{"_restrict", RESTRICT_KEYW},
#line 50 "scripts/genksyms/keywords.gperf"
#line 51 "scripts/genksyms/keywords.gperf"
{"__typeof__", TYPEOF_KEYW},
#line 9 "scripts/genksyms/keywords.gperf"
#line 10 "scripts/genksyms/keywords.gperf"
{"__attribute", ATTRIBUTE_KEYW},
#line 11 "scripts/genksyms/keywords.gperf"
#line 12 "scripts/genksyms/keywords.gperf"
{"__const", CONST_KEYW},
#line 10 "scripts/genksyms/keywords.gperf"
#line 11 "scripts/genksyms/keywords.gperf"
{"__attribute__", ATTRIBUTE_KEYW},
#line 12 "scripts/genksyms/keywords.gperf"
#line 13 "scripts/genksyms/keywords.gperf"
{"__const__", CONST_KEYW},
#line 16 "scripts/genksyms/keywords.gperf"
#line 17 "scripts/genksyms/keywords.gperf"
{"__signed__", SIGNED_KEYW},
#line 42 "scripts/genksyms/keywords.gperf"
#line 43 "scripts/genksyms/keywords.gperf"
{"static", STATIC_KEYW},
{""},
#line 15 "scripts/genksyms/keywords.gperf"
#line 16 "scripts/genksyms/keywords.gperf"
{"__signed", SIGNED_KEYW},
#line 30 "scripts/genksyms/keywords.gperf"
#line 31 "scripts/genksyms/keywords.gperf"
{"char", CHAR_KEYW},
{""},
#line 43 "scripts/genksyms/keywords.gperf"
#line 44 "scripts/genksyms/keywords.gperf"
{"struct", STRUCT_KEYW},
#line 22 "scripts/genksyms/keywords.gperf"
{"__restrict__", RESTRICT_KEYW},
#line 23 "scripts/genksyms/keywords.gperf"
{"__restrict__", RESTRICT_KEYW},
#line 24 "scripts/genksyms/keywords.gperf"
{"restrict", RESTRICT_KEYW},
#line 33 "scripts/genksyms/keywords.gperf"
#line 34 "scripts/genksyms/keywords.gperf"
{"enum", ENUM_KEYW},
#line 17 "scripts/genksyms/keywords.gperf"
#line 18 "scripts/genksyms/keywords.gperf"
{"__volatile", VOLATILE_KEYW},
#line 34 "scripts/genksyms/keywords.gperf"
#line 35 "scripts/genksyms/keywords.gperf"
{"extern", EXTERN_KEYW},
#line 18 "scripts/genksyms/keywords.gperf"
#line 19 "scripts/genksyms/keywords.gperf"
{"__volatile__", VOLATILE_KEYW},
#line 37 "scripts/genksyms/keywords.gperf"
#line 38 "scripts/genksyms/keywords.gperf"
{"int", INT_KEYW},
{""},
#line 31 "scripts/genksyms/keywords.gperf"
{"const", CONST_KEYW},
#line 7 "scripts/genksyms/keywords.gperf"
{"EXPORT_SYMBOL_GPL_FUTURE", EXPORT_SYMBOL_KEYW},
#line 32 "scripts/genksyms/keywords.gperf"
{"const", CONST_KEYW},
#line 33 "scripts/genksyms/keywords.gperf"
{"double", DOUBLE_KEYW},
{""},
#line 13 "scripts/genksyms/keywords.gperf"
#line 14 "scripts/genksyms/keywords.gperf"
{"__inline", INLINE_KEYW},
#line 29 "scripts/genksyms/keywords.gperf"
#line 30 "scripts/genksyms/keywords.gperf"
{"auto", AUTO_KEYW},
#line 14 "scripts/genksyms/keywords.gperf"
#line 15 "scripts/genksyms/keywords.gperf"
{"__inline__", INLINE_KEYW},
#line 41 "scripts/genksyms/keywords.gperf"
#line 42 "scripts/genksyms/keywords.gperf"
{"signed", SIGNED_KEYW},
{""},
#line 46 "scripts/genksyms/keywords.gperf"
#line 47 "scripts/genksyms/keywords.gperf"
{"unsigned", UNSIGNED_KEYW},
{""},
#line 40 "scripts/genksyms/keywords.gperf"
#line 41 "scripts/genksyms/keywords.gperf"
{"short", SHORT_KEYW},
#line 49 "scripts/genksyms/keywords.gperf"
#line 50 "scripts/genksyms/keywords.gperf"
{"typeof", TYPEOF_KEYW},
#line 44 "scripts/genksyms/keywords.gperf"
#line 45 "scripts/genksyms/keywords.gperf"
{"typedef", TYPEDEF_KEYW},
#line 48 "scripts/genksyms/keywords.gperf"
#line 49 "scripts/genksyms/keywords.gperf"
{"volatile", VOLATILE_KEYW},
{""},
#line 35 "scripts/genksyms/keywords.gperf"
#line 36 "scripts/genksyms/keywords.gperf"
{"float", FLOAT_KEYW},
{""}, {""},
#line 39 "scripts/genksyms/keywords.gperf"
#line 40 "scripts/genksyms/keywords.gperf"
{"register", REGISTER_KEYW},
#line 47 "scripts/genksyms/keywords.gperf"
#line 48 "scripts/genksyms/keywords.gperf"
{"void", VOID_KEYW},
{""},
#line 36 "scripts/genksyms/keywords.gperf"
#line 37 "scripts/genksyms/keywords.gperf"
{"inline", INLINE_KEYW},
{""},
#line 5 "scripts/genksyms/keywords.gperf"
{"EXPORT_SYMBOL", EXPORT_SYMBOL_KEYW},
{""},
#line 20 "scripts/genksyms/keywords.gperf"
#line 21 "scripts/genksyms/keywords.gperf"
{"_Bool", BOOL_KEYW},
{""},
#line 6 "scripts/genksyms/keywords.gperf"
{"EXPORT_SYMBOL_GPL", EXPORT_SYMBOL_KEYW},
{""}, {""}, {""}, {""}, {""}, {""},
#line 38 "scripts/genksyms/keywords.gperf"
#line 39 "scripts/genksyms/keywords.gperf"
{"long", LONG_KEYW},
{""}, {""}, {""}, {""}, {""},
#line 45 "scripts/genksyms/keywords.gperf"
#line 46 "scripts/genksyms/keywords.gperf"
{"union", UNION_KEYW}
};
......
......@@ -4,6 +4,7 @@ struct resword { const char *name; int token; }
%%
EXPORT_SYMBOL, EXPORT_SYMBOL_KEYW
EXPORT_SYMBOL_GPL, EXPORT_SYMBOL_KEYW
EXPORT_SYMBOL_GPL_FUTURE, EXPORT_SYMBOL_KEYW
__asm, ASM_KEYW
__asm__, ASM_KEYW
__attribute, ATTRIBUTE_KEYW
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册