diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-22 19:36:42 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-22 19:36:42 -0700 |
commit | b9da0571050c09863e59f94d0b8594a290d61b88 (patch) | |
tree | 3632c4fee768db9a27a5c872bd42133692e2f3d0 | |
parent | f8cae0f03f75adb54b1d48ddbc90f84a1f5de186 (diff) | |
parent | 5abd935661e01289ba143c3b2c1ba300c65bcc5f (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core-2.6: (31 commits)
driver core: Display error codes when class suspend fails
Driver core: Add section count to memory_block struct
Driver core: Add mutex for adding/removing memory blocks
Driver core: Move find_memory_block routine
hpilo: Despecificate driver from iLO generation
driver core: Convert link_mem_sections to use find_memory_block_hinted.
driver core: Introduce find_memory_block_hinted which utilizes kset_find_obj_hinted.
kobject: Introduce kset_find_obj_hinted.
driver core: fix build for CONFIG_BLOCK not enabled
driver-core: base: change to new flag variable
sysfs: only access bin file vm_ops with the active lock
sysfs: Fail bin file mmap if vma close is implemented.
FW_LOADER: fix kconfig dependency warning on HOTPLUG
uio: Statically allocate uio_class and use class .dev_attrs.
uio: Support 2^MINOR_BITS minors
uio: Cleanup irq handling.
uio: Don't clear driver data
uio: Fix lack of locking in init_uio_class
SYSFS: Allow boot time switching between deprecated and modern sysfs layout
driver core: remove CONFIG_SYSFS_DEPRECATED_V2 but keep it for block devices
...
34 files changed, 1238 insertions, 516 deletions
diff --git a/Documentation/ABI/testing/sysfs-module b/Documentation/ABI/testing/sysfs-module new file mode 100644 index 00000000000..cfcec3bffc0 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-module @@ -0,0 +1,12 @@ +What: /sys/module/pch_phub/drivers/.../pch_mac +Date: August 2010 +KernelVersion: 2.6.35 +Contact: masa-korg@dsn.okisemi.com +Description: Write/read GbE MAC address. + +What: /sys/module/pch_phub/drivers/.../pch_firmware +Date: August 2010 +KernelVersion: 2.6.35 +Contact: masa-korg@dsn.okisemi.com +Description: Write/read Option ROM data. + diff --git a/Documentation/dynamic-debug-howto.txt b/Documentation/dynamic-debug-howto.txt index 674c5663d34..58ea64a9616 100644 --- a/Documentation/dynamic-debug-howto.txt +++ b/Documentation/dynamic-debug-howto.txt @@ -24,7 +24,7 @@ Dynamic debug has even more useful features: read to display the complete list of known debug statements, to help guide you Controlling dynamic debug Behaviour -=============================== +=================================== The behaviour of pr_debug()/dev_debug()s are controlled via writing to a control file in the 'debugfs' filesystem. Thus, you must first mount the debugfs @@ -212,6 +212,26 @@ Note the regexp ^[-+=][scp]+$ matches a flags specification. Note also that there is no convenient syntax to remove all the flags at once, you need to use "-psc". + +Debug messages during boot process +================================== + +To be able to activate debug messages during the boot process, +even before userspace and debugfs exists, use the boot parameter: +ddebug_query="QUERY" + +QUERY follows the syntax described above, but must not exceed 1023 +characters. The enablement of debug messages is done as an arch_initcall. +Thus you can enable debug messages in all code processed after this +arch_initcall via this boot parameter. +On an x86 system for example ACPI enablement is a subsys_initcall and +ddebug_query="file ec.c +p" +will show early Embedded Controller transactions during ACPI setup if +your machine (typically a laptop) has an Embedded Controller. +PCI (or other devices) initialization also is a hot candidate for using +this boot parameter for debugging purposes. + + Examples ======== diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 02f21d9220c..4cd8b86e00e 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -43,10 +43,11 @@ parameter is applicable: AVR32 AVR32 architecture is enabled. AX25 Appropriate AX.25 support is enabled. BLACKFIN Blackfin architecture is enabled. - DRM Direct Rendering Management support is enabled. EDD BIOS Enhanced Disk Drive Services (EDD) is enabled EFI EFI Partitioning (GPT) is enabled EIDE EIDE/ATAPI support is enabled. + DRM Direct Rendering Management support is enabled. + DYNAMIC_DEBUG Build in debug messages and enable them at runtime FB The frame buffer device is enabled. GCOV GCOV profiling is enabled. HW Appropriate hardware is enabled. @@ -570,6 +571,10 @@ and is between 256 and 4096 characters. It is defined in the file Format: <port#>,<type> See also Documentation/input/joystick-parport.txt + ddebug_query= [KNL,DYNAMIC_DEBUG] Enable debug messages at early boot + time. See Documentation/dynamic-debug-howto.txt for + details. + debug [KNL] Enable kernel debugging (events log level). debug_locks_verbose= @@ -2370,6 +2375,15 @@ and is between 256 and 4096 characters. It is defined in the file switches= [HW,M68k] + sysfs.deprecated=0|1 [KNL] + Enable/disable old style sysfs layout for old udev + on older distributions. When this option is enabled + very new udev will not work anymore. When this option + is disabled (or CONFIG_SYSFS_DEPRECATED not compiled) + in older udev will not work anymore. + Default depends on CONFIG_SYSFS_DEPRECATED_V2 set in + the kernel configuration. + sysrq_always_enabled [KNL] Ignore sysrq setting - this boot parameter will diff --git a/MAINTAINERS b/MAINTAINERS index b618b1e86c4..fd19b544a1b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2064,14 +2064,16 @@ F: drivers/block/drbd/ F: lib/lru_cache.c F: Documentation/blockdev/drbd/ -DRIVER CORE, KOBJECTS, AND SYSFS +DRIVER CORE, KOBJECTS, DEBUGFS AND SYSFS M: Greg Kroah-Hartman <gregkh@suse.de> T: quilt kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/ S: Supported F: Documentation/kobject.txt F: drivers/base/ F: fs/sysfs/ +F: fs/debugfs/ F: include/linux/kobj* +F: include/linux/debugfs.h F: lib/kobj* DRM DRIVERS diff --git a/block/genhd.c b/block/genhd.c index 8313834596d..a8adf96a4b4 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -22,9 +22,7 @@ #include "blk.h" static DEFINE_MUTEX(block_class_lock); -#ifndef CONFIG_SYSFS_DEPRECATED struct kobject *block_depr; -#endif /* for extended dynamic devt allocation, currently only one major is used */ #define MAX_EXT_DEVT (1 << MINORBITS) @@ -810,10 +808,9 @@ static int __init genhd_device_init(void) register_blkdev(BLOCK_EXT_MAJOR, "blkext"); -#ifndef CONFIG_SYSFS_DEPRECATED /* create top-level block dir */ - block_depr = kobject_create_and_add("block", NULL); -#endif + if (!sysfs_deprecated) + block_depr = kobject_create_and_add("block", NULL); return 0; } diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index ef38aff737e..fd96345bc35 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -71,7 +71,6 @@ config PREVENT_FIRMWARE_BUILD config FW_LOADER tristate "Userspace firmware loading support" if EMBEDDED - depends on HOTPLUG default y ---help--- This option is provided for the case where no in-kernel-tree modules diff --git a/drivers/base/Makefile b/drivers/base/Makefile index c12c7f2f2a6..5f51c3b4451 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile @@ -19,7 +19,5 @@ obj-$(CONFIG_MODULES) += module.o endif obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor.o -ifeq ($(CONFIG_DEBUG_DRIVER),y) -EXTRA_CFLAGS += -DDEBUG -endif +ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG diff --git a/drivers/base/bus.c b/drivers/base/bus.c index eb1b7fa20dc..33c270a64db 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -440,22 +440,6 @@ static void device_remove_attrs(struct bus_type *bus, struct device *dev) } } -#ifdef CONFIG_SYSFS_DEPRECATED -static int make_deprecated_bus_links(struct device *dev) -{ - return sysfs_create_link(&dev->kobj, - &dev->bus->p->subsys.kobj, "bus"); -} - -static void remove_deprecated_bus_links(struct device *dev) -{ - sysfs_remove_link(&dev->kobj, "bus"); -} -#else -static inline int make_deprecated_bus_links(struct device *dev) { return 0; } -static inline void remove_deprecated_bus_links(struct device *dev) { } -#endif - /** * bus_add_device - add device to bus * @dev: device being added @@ -482,15 +466,10 @@ int bus_add_device(struct device *dev) &dev->bus->p->subsys.kobj, "subsystem"); if (error) goto out_subsys; - error = make_deprecated_bus_links(dev); - if (error) - goto out_deprecated; klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices); } return 0; -out_deprecated: - sysfs_remove_link(&dev->kobj, "subsystem"); out_subsys: sysfs_remove_link(&bus->p->devices_kset->kobj, dev_name(dev)); out_id: @@ -530,7 +509,6 @@ void bus_remove_device(struct device *dev) { if (dev->bus) { sysfs_remove_link(&dev->kobj, "subsystem"); - remove_deprecated_bus_links(dev); sysfs_remove_link(&dev->bus->p->devices_kset->kobj, dev_name(dev)); device_remove_attrs(dev->bus, dev); diff --git a/drivers/base/class.c b/drivers/base/class.c index 8e231d05b40..9c63a5687d6 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -184,9 +184,9 @@ int __class_register(struct class *cls, struct lock_class_key *key) if (!cls->dev_kobj) cls->dev_kobj = sysfs_dev_char_kobj; -#if defined(CONFIG_SYSFS_DEPRECATED) && defined(CONFIG_BLOCK) +#if defined(CONFIG_BLOCK) /* let the block class directory show up in the root of sysfs */ - if (cls != &block_class) + if (!sysfs_deprecated || cls != &block_class) cp->class_subsys.kobj.kset = class_kset; #else cp->class_subsys.kobj.kset = class_kset; @@ -276,25 +276,6 @@ void class_destroy(struct class *cls) class_unregister(cls); } -#ifdef CONFIG_SYSFS_DEPRECATED -char *make_class_name(const char *name, struct kobject *kobj) -{ - char *class_name; - int size; - - size = strlen(name) + strlen(kobject_name(kobj)) + 2; - - class_name = kmalloc(size, GFP_KERNEL); - if (!class_name) - return NULL; - - strcpy(class_name, name); - strcat(class_name, ":"); - strcat(class_name, kobject_name(kobj)); - return class_name; -} -#endif - /** * class_dev_iter_init - initialize class device iterator * @iter: class iterator to initialize diff --git a/drivers/base/core.c b/drivers/base/core.c index d1b2c9adc27..2cb49a93b1e 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -26,6 +26,19 @@ #include "base.h" #include "power/power.h" +#ifdef CONFIG_SYSFS_DEPRECATED +#ifdef CONFIG_SYSFS_DEPRECATED_V2 +long sysfs_deprecated = 1; +#else +long sysfs_deprecated = 0; +#endif +static __init int sysfs_deprecated_setup(char *arg) +{ + return strict_strtol(arg, 10, &sysfs_deprecated); +} +early_param("sysfs.deprecated", sysfs_deprecated_setup); +#endif + int (*platform_notify)(struct device *dev) = NULL; int (*platform_notify_remove)(struct device *dev) = NULL; static struct kobject *dev_kobj; @@ -203,37 +216,6 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, if (dev->driver) add_uevent_var(env, "DRIVER=%s", dev->driver->name); -#ifdef CONFIG_SYSFS_DEPRECATED - if (dev->class) { - struct device *parent = dev->parent; - - /* find first bus device in parent chain */ - while (parent && !parent->bus) - parent = parent->parent; - if (parent && parent->bus) { - const char *path; - - path = kobject_get_path(&parent->kobj, GFP_KERNEL); - if (path) { - add_uevent_var(env, "PHYSDEVPATH=%s", path); - kfree(path); - } - - add_uevent_var(env, "PHYSDEVBUS=%s", parent->bus->name); - - if (parent->driver) - add_uevent_var(env, "PHYSDEVDRIVER=%s", - parent->driver->name); - } - } else if (dev->bus) { - add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name); - - if (dev->driver) - add_uevent_var(env, "PHYSDEVDRIVER=%s", - dev->driver->name); - } -#endif - /* have the bus specific function add its stuff */ if (dev->bus && dev->bus->uevent) { retval = dev->bus->uevent(dev, env); @@ -578,24 +560,6 @@ void device_initialize(struct device *dev) set_dev_node(dev, -1); } -#ifdef CONFIG_SYSFS_DEPRECATED -static struct kobject *get_device_parent(struct device *dev, - struct device *parent) -{ - /* class devices without a parent live in /sys/class/<classname>/ */ - if (dev->class && (!parent || parent->class != dev->class)) - return &dev->class->p->class_subsys.kobj; - /* all other devices keep their parent */ - else if (parent) - return &parent->kobj; - - return NULL; -} - -static inline void cleanup_device_parent(struct device *dev) {} -static inline void cleanup_glue_dir(struct device *dev, - struct kobject *glue_dir) {} -#else static struct kobject *virtual_device_parent(struct device *dev) { static struct kobject *virtual_dir = NULL; @@ -666,6 +630,15 @@ static struct kobject *get_device_parent(struct device *dev, struct kobject *parent_kobj; struct kobject *k; +#ifdef CONFIG_BLOCK + /* block disks show up in /sys/block */ + if (sysfs_deprecated && dev->class == &block_class) { + if (parent && parent->class == &block_class) + return &parent->kobj; + return &block_class.p->class_subsys.kobj; + } +#endif + /* * If we have no parent, we live in "virtual". * Class-devices with a non class-device as parent, live @@ -719,7 +692,6 @@ static void cleanup_device_parent(struct device *dev) { cleanup_glue_dir(dev, dev->kobj.parent); } -#endif static void setup_parent(struct device *dev, struct device *parent) { @@ -742,70 +714,29 @@ static int device_add_class_symlinks(struct device *dev) if (error) goto out; -#ifdef CONFIG_SYSFS_DEPRECATED - /* stacked class devices need a symlink in the class directory */ - if (dev->kobj.parent != &dev->class->p->class_subsys.kobj && - device_is_not_partition(dev)) { - error = sysfs_create_link(&dev->class->p->class_subsys.kobj, - &dev->kobj, dev_name(dev)); - if (error) - goto out_subsys; - } - if (dev->parent && device_is_not_partition(dev)) { - struct device *parent = dev->parent; - char *class_name; - - /* - * stacked class devices have the 'device' link - * pointing to the bus device instead of the parent - */ - while (parent->class && !parent->bus && parent->parent) - parent = parent->parent; - - error = sysfs_create_link(&dev->kobj, - &parent->kobj, + error = sysfs_create_link(&dev->kobj, &dev->parent->kobj, "device"); if (error) - goto out_busid; - - class_name = make_class_name(dev->class->name, - &dev->kobj); - if (class_name) - error = sysfs_create_link(&dev->parent->kobj, - &dev->kobj, class_name); - kfree(class_name); - if (error) - goto out_device; + goto out_subsys; } - return 0; -out_device: - if (dev->parent && device_is_not_partition(dev)) - sysfs_remove_link(&dev->kobj, "device"); -out_busid: - if (dev->kobj.parent != &dev->class->p->class_subsys.kobj && - device_is_not_partition(dev)) - sysfs_delete_link(&dev->class->p->class_subsys.kobj, &dev->kobj, - dev_name(dev)); -#else +#ifdef CONFIG_BLOCK + /* /sys/block has directories and does not need symlinks */ + if (sysfs_deprecated && dev->class == &block_class) + return 0; +#endif + /* link in the class directory pointing to the device */ error = sysfs_create_link(&dev->class->p->class_subsys.kobj, &dev->kobj, dev_name(dev)); if (error) - goto out_subsys; + goto out_device; - if (dev->parent && device_is_not_partition(dev)) { - error = sysfs_create_link(&dev->kobj, &dev->parent->kobj, - "device"); - if (error) - goto out_busid; - } return 0; -out_busid: - sysfs_delete_link(&dev->class->p->class_subsys.kobj, &dev->kobj, dev_name(dev)); -#endif +out_device: + sysfs_remove_link(&dev->kobj, "device"); out_subsys: sysfs_remove_link(&dev->kobj, "subsystem"); @@ -818,30 +749,14 @@ static void device_remove_class_symlinks(struct device *dev) if (!dev->class) return; -#ifdef CONFIG_SYSFS_DEPRECATED - if (dev->parent && device_is_not_partition(dev)) { - char *class_name; - - class_name = make_class_name(dev->class->name, &dev->kobj); - if (class_name) { - sysfs_remove_link(&dev->parent->kobj, class_name); - kfree(class_name); - } - sysfs_remove_link(&dev->kobj, "device"); - } - - if (dev->kobj.parent != &dev->class->p->class_subsys.kobj && - device_is_not_partition(dev)) - sysfs_delete_link(&dev->class->p->class_subsys.kobj, &dev->kobj, - dev_name(dev)); -#else if (dev->parent && device_is_not_partition(dev)) sysfs_remove_link(&dev->kobj, "device"); - - sysfs_delete_link(&dev->class->p->class_subsys.kobj, &dev->kobj, dev_name(dev)); -#endif - sysfs_remove_link(&dev->kobj, "subsystem"); +#ifdef CONFIG_BLOCK + if (sysfs_deprecated && dev->class == &block_class) + return; +#endif + sysfs_delete_link(&dev->class->p->class_subsys.kobj, &dev->kobj, dev_name(dev)); } /** @@ -1613,41 +1528,23 @@ int device_rename(struct device *dev, const char *new_name) pr_debug("device: '%s': %s: renaming to '%s'\n", dev_name(dev), __func__, new_name); -#ifdef CONFIG_SYSFS_DEPRECATED - if ((dev->class) && (dev->parent)) - old_class_name = make_class_name(dev->class->name, &dev->kobj); -#endif - old_device_name = kstrdup(dev_name(dev), GFP_KERNEL); if (!old_device_name) { error = -ENOMEM; goto out; } -#ifndef CONFIG_SYSFS_DEPRECATED if (dev->class) { error = sysfs_rename_link(&dev->class->p->class_subsys.kobj, &dev->kobj, old_device_name, new_name); if (error) goto out; } -#endif + error = kobject_rename(&dev->kobj, new_name); if (error) goto out; -#ifdef CONFIG_SYSFS_DEPRECATED - if (old_class_name) { - new_class_name = make_class_name(dev->class->name, &dev->kobj); - if (new_class_name) { - error = sysfs_rename_link(&dev->parent->kobj, - &dev->kobj, - old_class_name, - new_class_name); - } - } -#endif - out: put_device(dev); @@ -1664,40 +1561,13 @@ static int device_move_class_links(struct device *dev, struct device *new_parent) { int error = 0; -#ifdef CONFIG_SYSFS_DEPRECATED - char *class_name; - class_name = make_class_name(dev->class->name, &dev->kobj); - if (!class_name) { - error = -ENOMEM; - goto out; - } - if (old_parent) { - sysfs_remove_link(&dev->kobj, "device"); - sysfs_remove_link(&old_parent->kobj, class_name); - } - if (new_parent) { - error = sysfs_create_link(&dev->kobj, &new_parent->kobj, - "device"); - if (error) - goto out; - error = sysfs_create_link(&new_parent->kobj, &dev->kobj, - class_name); - if (error) - sysfs_remove_link(&dev->kobj, "device"); - } else - error = 0; -out: - kfree(class_name); - return error; -#else if (old_parent) sysfs_remove_link(&dev->kobj, "device"); if (new_parent) error = sysfs_create_link(&dev->kobj, &new_parent->kobj, "device"); return error; -#endif } /** diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 933442f4032..cafeaaf0428 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -27,6 +27,8 @@ #include <asm/atomic.h> #include <asm/uaccess.h> +static DEFINE_MUTEX(mem_sysfs_mutex); + #define MEMORY_CLASS_NAME "memory" static struct sysdev_class memory_sysdev_class = { @@ -435,6 +437,45 @@ int __weak arch_get_memory_phys_device(unsigned long start_pfn) return 0; } +struct memory_block *find_memory_block_hinted(struct mem_section *section, + struct memory_block *hint) +{ + struct kobject *kobj; + struct sys_device *sysdev; + struct memory_block *mem; + char name[sizeof(MEMORY_CLASS_NAME) + 9 + 1]; + + kobj = hint ? &hint->sysdev.kobj : NULL; + + /* + * This only works because we know that section == sysdev->id + * slightly redundant with sysdev_register() + */ + sprintf(&name[0], "%s%d", MEMORY_CLASS_NAME, __section_nr(section)); + + kobj = kset_find_obj_hinted(&memory_sysdev_class.kset, name, kobj); + if (!kobj) + return NULL; + + sysdev = container_of(kobj, struct sys_device, kobj); + mem = container_of(sysdev, struct memory_block, sysdev); + + return mem; +} + +/* + * For now, we have a linear search to go find the appropriate + * memory_block corresponding to a particular phys_index. If + * this gets to be a real problem, we can always use a radix + * tree or something here. + * + * This could be made generic for all sysdev classes. + */ +struct memory_block *find_memory_block(struct mem_section *section) +{ + return find_memory_block_hinted(section, NULL); +} + static int add_memory_block(int nid, struct mem_section *section, unsigned long state, enum mem_add_context context) { @@ -445,8 +486,11 @@ static int add_memory_block(int nid, struct mem_section *section, if (!mem) return -ENOMEM; + mutex_lock(&mem_sysfs_mutex); + mem->phys_index = __section_nr(section); mem->state = state; + mem->section_count++; mutex_init(&mem->state_mutex); start_pfn = section_nr_to_pfn(mem->phys_index); mem->phys_device = arch_get_memory_phys_device(start_pfn); @@ -465,53 +509,29 @@ static int add_memory_block(int nid, struct mem_section *section, ret = register_mem_sect_under_node(mem, nid); } + mutex_unlock(&mem_sysfs_mutex); return ret; } -/* - * For now, we have a linear search to go find the appropriate - * memory_block corresponding to a particular phys_index. If - * this gets to be a real problem, we can always use a radix - * tree or something here. - * - * This could be made generic for all sysdev classes. - */ -struct memory_block *find_memory_block(struct mem_section *section) -{ - struct kobject *kobj; - struct sys_device *sysdev; - struct memory_block *mem; - char name[sizeof(MEMORY_CLASS_NAME) + 9 + 1]; - - /* - * This only works because we know that section == sysdev->id - * slightly redundant with sysdev_register() - */ - sprintf(&name[0], "%s%d", MEMORY_CLASS_NAME, __section_nr(section)); - - kobj = kset_find_obj(&memory_sysdev_class.kset, name); - if (!kobj) - return NULL; - - sysdev = container_of(kobj, struct sys_device, kobj); - mem = container_of(sysdev, struct memory_block, sysdev); - - return mem; -} - int remove_memory_block(unsigned long node_id, struct mem_section *section, int phys_device) { struct memory_block *mem; + mutex_lock(&mem_sysfs_mutex); mem = find_memory_block(section); - unregister_mem_sect_under_nodes(mem); - mem_remove_simple_file(mem, phys_index); - mem_remove_simple_file(mem, state); - mem_remove_simple_file(mem, phys_device); - mem_remove_simple_file(mem, removable); - unregister_memory(mem, section); + mem->section_count--; + if (mem->section_count == 0) { + unregister_mem_sect_under_nodes(mem); + mem_remove_simple_file(mem, phys_index); + mem_remove_simple_file(mem, state); + mem_remove_simple_file(mem, phys_device); + mem_remove_simple_file(mem, removable); + unregister_memory(mem, section); + } + + mutex_unlock(&mem_sysfs_mutex); return 0; } diff --git a/drivers/base/node.c b/drivers/base/node.c index 2872e86837b..ee53558b452 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -409,25 +409,27 @@ static int link_mem_sections(int nid) unsigned long start_pfn = NODE_DATA(nid)->node_start_pfn; unsigned long end_pfn = start_pfn + NODE_DATA(nid)->node_spanned_pages; unsigned long pfn; + struct memory_block *mem_blk = NULL; int err = 0; for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) { unsigned long section_nr = pfn_to_section_nr(pfn); struct mem_section *mem_sect; - struct memory_block *mem_blk; int ret; if (!present_section_nr(section_nr)) continue; mem_sect = __nr_to_section(section_nr); - mem_blk = find_memory_block(mem_sect); + mem_blk = find_memory_block_hinted(mem_sect, mem_blk); ret = register_mem_sect_under_node(mem_blk, nid); if (!err) err = ret; /* discard ref obtained in find_memory_block() */ - kobject_put(&mem_blk->sysdev.kobj); } + + if (mem_blk) + kobject_put(&mem_blk->sysdev.kobj); return err; } diff --git a/drivers/base/platform.c b/drivers/base/platform.c index c6c933f5810..3966e62ad01 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -192,6 +192,9 @@ int platform_device_add_resources(struct platform_device *pdev, { struct resource *r; + if (!res) + return 0; + r = kmemdup(res, sizeof(struct resource) * num, GFP_KERNEL); if (r) { pdev->resource = r; @@ -215,8 +218,12 @@ EXPORT_SYMBOL_GPL(platform_device_add_resources); int platform_device_add_data(struct platform_device *pdev, const void *data, size_t size) { - void *d = kmemdup(data, size, GFP_KERNEL); + void *d; + + if (!data) + return 0; + d = kmemdup(data, size, GFP_KERNEL); if (d) { pdev->dev.platform_data = d; return 0; @@ -373,17 +380,13 @@ struct platform_device *__init_or_module platform_device_register_resndata( pdev->dev.parent = parent; - if (res) { - ret = platform_device_add_resources(pdev, res, num); - if (ret) - goto err; - } + ret = platform_device_add_resources(pdev, res, num); + if (ret) + goto err; - if (data) { - ret = platform_device_add_data(pdev, data, size); - if (ret) - goto err; - } |