aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-26 11:41:30 -0800
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-26 11:41:30 -0800
commita7538a7f87826fb5cacc6959f00dfa9fba6f4b15 (patch)
treea0fef9252200a78634f0fa4eaa714c7a40e802b9
parent92320cec611d4ed44a9bd635727d61f6caa669a7 (diff)
parentdfff0a0671baf4e69fc676bf8150635407548288 (diff)
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: Revert "Driver core: let request_module() send a /sys/modules/kmod/-uevent" Driver core: fix error by cleanup up symlinks properly make kernel/kmod.c:kmod_mk static power management: fix struct layout and docs power management: no valid states w/o pm_ops Driver core: more fallout from class_device changes for pcmcia sysfs: move struct sysfs_dirent to private header driver core: refcounting fix Driver core: remove class_device_rename
-rw-r--r--drivers/base/class.c42
-rw-r--r--drivers/base/core.c31
-rw-r--r--drivers/pcmcia/hd64465_ss.c2
-rw-r--r--drivers/pcmcia/m32r_cfc.c2
-rw-r--r--drivers/pcmcia/m8xx_pcmcia.c2
-rw-r--r--drivers/pcmcia/omap_cf.c2
-rw-r--r--drivers/pcmcia/rsrc_mgr.c2
-rw-r--r--drivers/pcmcia/vrc4171_card.c2
-rw-r--r--fs/sysfs/sysfs.h11
-rw-r--r--include/linux/device.h2
-rw-r--r--include/linux/kmod.h2
-rw-r--r--include/linux/pm.h37
-rw-r--r--include/linux/sysfs.h13
-rw-r--r--kernel/kmod.c120
-rw-r--r--kernel/module.c32
-rw-r--r--kernel/params.c1
-rw-r--r--kernel/power/main.c5
17 files changed, 103 insertions, 205 deletions
diff --git a/drivers/base/class.c b/drivers/base/class.c
index 1417e5cd4c6..d5968128be2 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -840,48 +840,6 @@ void class_device_destroy(struct class *cls, dev_t devt)
class_device_unregister(class_dev);
}
-int class_device_rename(struct class_device *class_dev, char *new_name)
-{
- int error = 0;
- char *old_class_name = NULL, *new_class_name = NULL;
-
- class_dev = class_device_get(class_dev);
- if (!class_dev)
- return -EINVAL;
-
- pr_debug("CLASS: renaming '%s' to '%s'\n", class_dev->class_id,
- new_name);
-
-#ifdef CONFIG_SYSFS_DEPRECATED
- if (class_dev->dev)
- old_class_name = make_class_name(class_dev->class->name,
- &class_dev->kobj);
-#endif
-
- strlcpy(class_dev->class_id, new_name, KOBJ_NAME_LEN);
-
- error = kobject_rename(&class_dev->kobj, new_name);
-
-#ifdef CONFIG_SYSFS_DEPRECATED
- if (class_dev->dev) {
- new_class_name = make_class_name(class_dev->class->name,
- &class_dev->kobj);
- if (new_class_name)
- sysfs_create_link(&class_dev->dev->kobj,
- &class_dev->kobj, new_class_name);
- if (old_class_name)
- sysfs_remove_link(&class_dev->dev->kobj,
- old_class_name);
- }
-#endif
- class_device_put(class_dev);
-
- kfree(old_class_name);
- kfree(new_class_name);
-
- return error;
-}
-
struct class_device * class_device_get(struct class_device *class_dev)
{
if (class_dev)
diff --git a/drivers/base/core.c b/drivers/base/core.c
index d04fd33dcd9..cf2a398aaaa 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -637,12 +637,41 @@ int device_add(struct device *dev)
BUS_NOTIFY_DEL_DEVICE, dev);
device_remove_groups(dev);
GroupError:
- device_remove_attrs(dev);
+ device_remove_attrs(dev);
AttrsError:
if (dev->devt_attr) {
device_remove_file(dev, dev->devt_attr);
kfree(dev->devt_attr);
}
+
+ if (dev->class) {
+ sysfs_remove_link(&dev->kobj, "subsystem");
+ /* If this is not a "fake" compatible device, remove the
+ * symlink from the class to the device. */
+ if (dev->kobj.parent != &dev->class->subsys.kset.kobj)
+ sysfs_remove_link(&dev->class->subsys.kset.kobj,
+ dev->bus_id);
+#ifdef CONFIG_SYSFS_DEPRECATED
+ if (parent) {
+ char *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");
+ }
+#endif
+
+ down(&dev->class->sem);
+ /* notify any interfaces that the device is now gone */
+ list_for_each_entry(class_intf, &dev->class->interfaces, node)
+ if (class_intf->remove_dev)
+ class_intf->remove_dev(dev, class_intf);
+ /* remove the device from the class list */
+ list_del_init(&dev->node);
+ up(&dev->class->sem);
+ }
ueventattrError:
device_remove_file(dev, &dev->uevent_attr);
attrError:
diff --git a/drivers/pcmcia/hd64465_ss.c b/drivers/pcmcia/hd64465_ss.c
index caca0dc9d30..f2e810f53c8 100644
--- a/drivers/pcmcia/hd64465_ss.c
+++ b/drivers/pcmcia/hd64465_ss.c
@@ -907,7 +907,7 @@ static int __init init_hs(void)
for (i=0; i<HS_MAX_SOCKETS; i++) {
unsigned int ret;
- hs_sockets[i].socket.dev.dev = &hd64465_device.dev;
+ hs_sockets[i].socket.dev.parent = &hd64465_device.dev;
hs_sockets[i].number = i;
ret = pcmcia_register_socket(&hs_sockets[i].socket);
if (ret && i)
diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c
index e4a94108aab..91da15b5a81 100644
--- a/drivers/pcmcia/m32r_cfc.c
+++ b/drivers/pcmcia/m32r_cfc.c
@@ -760,7 +760,7 @@ static int __init init_m32r_pcc(void)
/* Set up interrupt handler(s) */
for (i = 0 ; i < pcc_sockets ; i++) {
- socket[i].socket.dev.dev = &pcc_device.dev;
+ socket[i].socket.dev.parent = &pcc_device.dev;
socket[i].socket.ops = &pcc_operations;
socket[i].socket.resource_ops = &pccard_nonstatic_ops;
socket[i].socket.owner = THIS_MODULE;
diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c
index d059c919617..9721ed7bf50 100644
--- a/drivers/pcmcia/m8xx_pcmcia.c
+++ b/drivers/pcmcia/m8xx_pcmcia.c
@@ -1321,7 +1321,7 @@ static int __init m8xx_init(void)
socket[i].socket.ops = &m8xx_services;
socket[i].socket.resource_ops = &pccard_iodyn_ops;
socket[i].socket.cb_dev = NULL;
- socket[i].socket.dev.dev = &m8xx_device.dev;
+ socket[i].socket.dev.parent = &m8xx_device.dev;
}
for (i = 0; i < PCMCIA_SOCKETS_NO; i++)
diff --git a/drivers/pcmcia/omap_cf.c b/drivers/pcmcia/omap_cf.c
index 76f7cbc62a8..d77f75129f8 100644
--- a/drivers/pcmcia/omap_cf.c
+++ b/drivers/pcmcia/omap_cf.c
@@ -291,7 +291,7 @@ static int __devinit omap_cf_probe(struct device *dev)
omap_cf_present() ? "present" : "(not present)");
cf->socket.owner = THIS_MODULE;
- cf->socket.dev.dev = dev;
+ cf->socket.dev.parent = dev;
cf->socket.ops = &omap_cf_ops;
cf->socket.resource_ops = &pccard_static_ops;
cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP
diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c
index 81dfc2cac2b..ce2226273aa 100644
--- a/drivers/pcmcia/rsrc_mgr.c
+++ b/drivers/pcmcia/rsrc_mgr.c
@@ -232,7 +232,7 @@ static struct resource *iodyn_find_io_region(unsigned long base, int num,
unsigned long align, struct pcmcia_socket *s)
{
struct resource *res = make_resource(0, num, IORESOURCE_IO,
- s->dev.class_id);
+ s->dev.bus_id);
struct pcmcia_align_data data;
unsigned long min = base;
int ret;
diff --git a/drivers/pcmcia/vrc4171_card.c b/drivers/pcmcia/vrc4171_card.c
index 206e26c9180..eee2f1cb213 100644
--- a/drivers/pcmcia/vrc4171_card.c
+++ b/drivers/pcmcia/vrc4171_card.c
@@ -596,7 +596,7 @@ static int __devinit vrc4171_add_sockets(void)
}
sprintf(socket->name, "NEC VRC4171 Card Slot %1c", 'A' + slot);
- socket->pcmcia_socket.dev.dev = &vrc4171_card_device.dev;
+ socket->pcmcia_socket.dev.parent = &vrc4171_card_device.dev;
socket->pcmcia_socket.ops = &vrc4171_pccard_operations;
socket->pcmcia_socket.owner = THIS_MODULE;
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index d976b000554..a77c57e5a6d 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -1,3 +1,14 @@
+struct sysfs_dirent {
+ atomic_t s_count;
+ struct list_head s_sibling;
+ struct list_head s_children;
+ void * s_element;
+ int s_type;
+ umode_t s_mode;
+ struct dentry * s_dentry;
+ struct iattr * s_iattr;
+ atomic_t s_event;
+};
extern struct vfsmount * sysfs_mount;
extern struct kmem_cache *sysfs_dir_cachep;
diff --git a/include/linux/device.h b/include/linux/device.h
index d1a3a27c398..39a3199a826 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -294,8 +294,6 @@ extern void class_device_initialize(struct class_device *);
extern int __must_check class_device_add(struct class_device *);
extern void class_device_del(struct class_device *);
-extern int class_device_rename(struct class_device *, char *);
-
extern struct class_device * class_device_get(struct class_device *);
extern void class_device_put(struct class_device *);
diff --git a/include/linux/kmod.h b/include/linux/kmod.h
index cc8e674ae27..10f505c8431 100644
--- a/include/linux/kmod.h
+++ b/include/linux/kmod.h
@@ -28,10 +28,8 @@
#ifdef CONFIG_KMOD
/* modprobe exit status on success, -ve on error. Return value
* usually useless though. */
-extern void kmod_sysfs_init(void);
extern int request_module(const char * name, ...) __attribute__ ((format (printf, 1, 2)));
#else
-static inline void kmod_sysfs_init(void) {};
static inline int request_module(const char * name, ...) { return -ENOSYS; }
#endif
diff --git a/include/linux/pm.h b/include/linux/pm.h
index 070394e846d..21db05ac7c0 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -120,15 +120,48 @@ typedef int __bitwise suspend_disk_method_t;
#define PM_DISK_TESTPROC ((__force suspend_disk_method_t) 6)
#define PM_DISK_MAX ((__force suspend_disk_method_t) 7)
+/**
+ * struct pm_ops - Callbacks for managing platform dependent suspend states.
+ * @valid: Callback to determine whether the given state can be entered.
+ * If %CONFIG_SOFTWARE_SUSPEND is set then %PM_SUSPEND_DISK is
+ * always valid and never passed to this call.
+ * If not assigned, all suspend states are advertised as valid
+ * in /sys/power/state (but can still be rejected by prepare or enter.)
+ *
+ * @prepare: Prepare the platform for the given suspend state. Can return a
+ * negative error code if necessary.
+ *
+ * @enter: Enter the given suspend state, must be assigned. Can return a
+ * negative error code if necessary.
+ *
+ * @finish: Called when the system has left the given state and all devices
+ * are resumed. The return value is ignored.
+ *
+ * @pm_disk_mode: Set to the disk method that the user should be able to
+ * configure for suspend-to-disk. Since %PM_DISK_SHUTDOWN,
+ * %PM_DISK_REBOOT, %PM_DISK_TEST and %PM_DISK_TESTPROC
+ * are always allowed, currently only %PM_DISK_PLATFORM
+ * makes sense. If the user then choses %PM_DISK_PLATFORM,
+ * the @prepare call will be called before suspending to disk
+ * (if present), the @enter call should be present and will
+ * be called after all state has been saved and the machine
+ * is ready to be shut down/suspended/..., and the @finish
+ * callback is called after state has been restored. All
+ * these calls are called with %PM_SUSPEND_DISK as the state.
+ */
struct pm_ops {
- suspend_disk_method_t pm_disk_mode;
int (*valid)(suspend_state_t state);
int (*prepare)(suspend_state_t state);
int (*enter)(suspend_state_t state);
int (*finish)(suspend_state_t state);
+ suspend_disk_method_t pm_disk_mode;
};
-extern void pm_set_ops(struct pm_ops *);
+/**
+ * pm_set_ops - set platform dependent power management ops
+ * @pm_ops: The new power management operations to set.
+ */
+extern void pm_set_ops(struct pm_ops *pm_ops);
extern struct pm_ops *pm_ops;
extern int pm_suspend(suspend_state_t state);
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index f45450b295c..21805b500aa 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -17,6 +17,7 @@
struct kobject;
struct module;
struct nameidata;
+struct dentry;
struct attribute {
const char * name;
@@ -68,18 +69,6 @@ struct sysfs_ops {
ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t);
};
-struct sysfs_dirent {
- atomic_t s_count;
- struct list_head s_sibling;
- struct list_head s_children;
- void * s_element;
- int s_type;
- umode_t s_mode;
- struct dentry * s_dentry;
- struct iattr * s_iattr;
- atomic_t s_event;
-};
-
#define SYSFS_ROOT 0x0001
#define SYSFS_DIR 0x0002
#define SYSFS_KOBJ_ATTR 0x0004
diff --git a/kernel/kmod.c b/kernel/kmod.c
index 9f923f8ce6a..796276141e5 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -36,8 +36,6 @@
#include <linux/resource.h>
#include <asm/uaccess.h>
-extern int delete_module(const char *name, unsigned int flags);
-
extern int max_threads;
static struct workqueue_struct *khelper_wq;
@@ -48,7 +46,6 @@ static struct workqueue_struct *khelper_wq;
modprobe_path is set via /proc/sys.
*/
char modprobe_path[KMOD_PATH_LEN] = "/sbin/modprobe";
-struct module_kobject kmod_mk;
/**
* request_module - try to load a kernel module
@@ -78,11 +75,6 @@ int request_module(const char *fmt, ...)
static atomic_t kmod_concurrent = ATOMIC_INIT(0);
#define MAX_KMOD_CONCURRENT 50 /* Completely arbitrary value - KAO */
static int kmod_loop_msg;
- char modalias[16 + MODULE_NAME_LEN] = "MODALIAS=";
- char *uevent_envp[2] = {
- modalias,
- NULL
- };
va_start(args, fmt);
ret = vsnprintf(module_name, MODULE_NAME_LEN, fmt, args);
@@ -90,12 +82,6 @@ int request_module(const char *fmt, ...)
if (ret >= MODULE_NAME_LEN)
return -ENAMETOOLONG;
- strcpy(&modalias[strlen("MODALIAS=")], module_name);
- kobject_uevent_env(&kmod_mk.kobj, KOBJ_CHANGE, uevent_envp);
-
- if (modprobe_path[0] == '\0')
- goto out;
-
/* If modprobe needs a service that is in a module, we get a recursive
* loop. Limit the number of running kmod threads to max_threads/2 or
* MAX_KMOD_CONCURRENT, whichever is the smaller. A cleaner method
@@ -122,115 +108,9 @@ int request_module(const char *fmt, ...)
ret = call_usermodehelper(modprobe_path, argv, envp, 1);
atomic_dec(&kmod_concurrent);
-out:
return ret;
}
EXPORT_SYMBOL(request_module);
-
-static ssize_t store_mod_request(struct module_attribute *mattr,
- struct module *mod,
- const char *buffer, size_t count)
-{
- char name[MODULE_NAME_LEN];
- int ret;
-
- if (count < 1 || count+1 > MODULE_NAME_LEN)
- return -EINVAL;
- memcpy(name, buffer, count);
- name[count] = '\0';
- if (name[count-1] == '\n')
- name[count-1] = '\0';
-
- ret = request_module(name);
- if (ret < 0)
- return ret;
- return count;
-}
-
-static struct module_attribute mod_request = {
- .attr = { .name = "mod_request", .mode = S_IWUSR, .owner = THIS_MODULE },
- .store = store_mod_request,
-};
-
-#ifdef CONFIG_MODULE_UNLOAD
-static ssize_t store_mod_unload(struct module_attribute *mattr,
- struct module *mod,
- const char *buffer, size_t count)
-{
- char name[MODULE_NAME_LEN];
- int ret;
-
- if (count < 1 || count+1 > MODULE_NAME_LEN)
- return -EINVAL;
- memcpy(name, buffer, count);
- name[count] = '\0';
- if (name[count-1] == '\n')
- name[count-1] = '\0';
-
- ret = delete_module(name, O_NONBLOCK);
- if (ret < 0)
- return ret;
- return count;
-}
-
-static struct module_attribute mod_unload = {
- .attr = { .name = "mod_unload", .mode = S_IWUSR, .owner = THIS_MODULE },
- .store = store_mod_unload,
-};
-#endif
-
-static ssize_t show_mod_request_helper(struct module_attribute *mattr,
- struct module *mod,
- char *buffer)
-{
- return sprintf(buffer, "%s\n", modprobe_path);
-}
-
-static ssize_t store_mod_request_helper(struct module_attribute *mattr,
- struct module *mod,
- const char *buffer, size_t count)
-{
- if (count < 1 || count+1 > KMOD_PATH_LEN)
- return -EINVAL;
- memcpy(modprobe_path, buffer, count);
- modprobe_path[count] = '\0';
- if (modprobe_path[count-1] == '\n')
- modprobe_path[count-1] = '\0';
- return count;
-}
-
-static struct module_attribute mod_request_helper = {
- .attr = {
- .name = "mod_request_helper",
- .mode = S_IWUSR | S_IRUGO,
- .owner = THIS_MODULE
- },
- .show = show_mod_request_helper,
- .store = store_mod_request_helper,
-};
-
-void __init kmod_sysfs_init(void)
-{
- int ret;
-
- kmod_mk.mod = THIS_MODULE;
- kobj_set_kset_s(&kmod_mk, module_subsys);
- kobject_set_name(&kmod_mk.kobj, "kmod");
- kobject_init(&kmod_mk.kobj);
- ret = kobject_add(&kmod_mk.kobj);
- if (ret < 0)
- goto out;
-
- ret = sysfs_create_file(&kmod_mk.kobj, &mod_request_helper.attr);
- ret = sysfs_create_file(&kmod_mk.kobj, &mod_request.attr);
-#ifdef CONFIG_MODULE_UNLOAD
- ret = sysfs_create_file(&kmod_mk.kobj, &mod_unload.attr);
-#endif
-
- kobject_uevent(&kmod_mk.kobj, KOBJ_ADD);
-out:
- return;
-}
#endif /* CONFIG_KMOD */
struct subprocess_info {
diff --git a/kernel/module.c b/kernel/module.c
index 8c25b1a04fa..f77e893e462 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -653,11 +653,20 @@ static void wait_for_zero_refcount(struct module *mod)
mutex_lock(&module_mutex);
}
-int delete_module(const char *name, unsigned int flags)
+asmlinkage long
+sys_delete_module(const char __user *name_user, unsigned int flags)
{
struct module *mod;
+ char name[MODULE_NAME_LEN];
int ret, forced = 0;
+ if (!capable(CAP_SYS_MODULE))
+ return -EPERM;
+
+ if (strncpy_from_user(name, name_user, MODULE_NAME_LEN-1) < 0)
+ return -EFAULT;
+ name[MODULE_NAME_LEN-1] = '\0';
+
if (mutex_lock_interruptible(&module_mutex) != 0)
return -EINTR;
@@ -718,21 +727,6 @@ int delete_module(const char *name, unsigned int flags)
return ret;
}
-asmlinkage long
-sys_delete_module(const char __user *name_user, unsigned int flags)
-{
- char name[MODULE_NAME_LEN];
-
- if (!capable(CAP_SYS_MODULE))
- return -EPERM;
-
- if (strncpy_from_user(name, name_user, MODULE_NAME_LEN-1) < 0)
- return -EFAULT;
- name[MODULE_NAME_LEN-1] = '\0';
-
- return delete_module(name, flags);
-}
-
static void print_unload_info(struct seq_file *m, struct module *mod)
{
struct module_use *use;
@@ -2425,6 +2419,12 @@ void module_remove_driver(struct device_driver *drv)
kfree(driver_name);
}
}
+ /*
+ * Undo the additional reference we added in module_add_driver()
+ * via kset_find_obj()
+ */
+ if (drv->mod_name)
+ kobject_put(&drv->kobj);
}
EXPORT_SYMBOL(module_remove_driver);
#endif
diff --git a/kernel/params.c b/kernel/params.c
index 7a751570b56..e265b13195b 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -707,7 +707,6 @@ static int __init param_sysfs_init(void)
}
param_sysfs_builtin();
- kmod_sysfs_init();
return 0;
}
diff --git a/kernel/power/main.c b/kernel/power/main.c
index e1c41312046..a064dfd8877 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -167,7 +167,10 @@ static inline int valid_state(suspend_state_t state)
if (state == PM_SUSPEND_DISK)
return 1;
- if (pm_ops && pm_ops->valid && !pm_ops->valid(state))
+ /* all other states need lowlevel support and need to be
+ * valid to the lowlevel implementation, no valid callback
+ * implies that all are valid. */
+ if (!pm_ops || (pm_ops->valid && !pm_ops->valid(state)))
return 0;
return 1;
}