Commit f58df54a authored by Linus Torvalds's avatar Linus Torvalds

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: (27 commits)
  Driver core: fix race in dev_driver_string
  Driver Core: Early platform driver buffer
  sysfs: sysfs_setattr remove unnecessary permission check.
  sysfs: Factor out sysfs_rename from sysfs_rename_dir and sysfs_move_dir
  sysfs: Propagate renames to the vfs on demand
  sysfs: Gut sysfs_addrm_start and sysfs_addrm_finish
  sysfs: In sysfs_chmod_file lazily propagate the mode change.
  sysfs: Implement sysfs_getattr & sysfs_permission
  sysfs: Nicely indent sysfs_symlink_inode_operations
  sysfs: Update s_iattr on link and unlink.
  sysfs: Fix locking and factor out sysfs_sd_setattr
  sysfs: Simplify iattr time assignments
  sysfs: Simplify sysfs_chmod_file semantics
  sysfs: Use dentry_ops instead of directly playing with the dcache
  sysfs: Rename sysfs_d_iput to sysfs_dentry_iput
  sysfs: Update sysfs_setxattr so it updates secdata under the sysfs_mutex
  debugfs: fix create mutex racy fops and private data
  Driver core: Don't remove kobjects in device_shutdown.
  firmware_class: make request_firmware_nowait more useful
  Driver-Core: devtmpfs - set root directory mode to 0755
  ...
parents 748e566b 3589972e
...@@ -56,7 +56,14 @@ static inline int device_is_not_partition(struct device *dev) ...@@ -56,7 +56,14 @@ static inline int device_is_not_partition(struct device *dev)
*/ */
const char *dev_driver_string(const struct device *dev) const char *dev_driver_string(const struct device *dev)
{ {
return dev->driver ? dev->driver->name : struct device_driver *drv;
/* dev->driver can change to NULL underneath us because of unbinding,
* so be careful about accessing it. dev->bus and dev->class should
* never change once they are set, so they don't need special care.
*/
drv = ACCESS_ONCE(dev->driver);
return drv ? drv->name :
(dev->bus ? dev->bus->name : (dev->bus ? dev->bus->name :
(dev->class ? dev->class->name : "")); (dev->class ? dev->class->name : ""));
} }
...@@ -986,6 +993,8 @@ int device_add(struct device *dev) ...@@ -986,6 +993,8 @@ int device_add(struct device *dev)
AttrsError: AttrsError:
device_remove_class_symlinks(dev); device_remove_class_symlinks(dev);
SymlinkError: SymlinkError:
if (MAJOR(dev->devt))
devtmpfs_delete_node(dev);
if (MAJOR(dev->devt)) if (MAJOR(dev->devt))
device_remove_sys_dev_entry(dev); device_remove_sys_dev_entry(dev);
devtattrError: devtattrError:
...@@ -1728,8 +1737,5 @@ void device_shutdown(void) ...@@ -1728,8 +1737,5 @@ void device_shutdown(void)
dev->driver->shutdown(dev); dev->driver->shutdown(dev);
} }
} }
kobject_put(sysfs_dev_char_kobj);
kobject_put(sysfs_dev_block_kobj);
kobject_put(dev_kobj);
async_synchronize_full(); async_synchronize_full();
} }
...@@ -32,6 +32,8 @@ static int dev_mount = 1; ...@@ -32,6 +32,8 @@ static int dev_mount = 1;
static int dev_mount; static int dev_mount;
#endif #endif
static rwlock_t dirlock;
static int __init mount_param(char *str) static int __init mount_param(char *str)
{ {
dev_mount = simple_strtoul(str, NULL, 0); dev_mount = simple_strtoul(str, NULL, 0);
...@@ -74,47 +76,35 @@ static int dev_mkdir(const char *name, mode_t mode) ...@@ -74,47 +76,35 @@ static int dev_mkdir(const char *name, mode_t mode)
dentry = lookup_create(&nd, 1); dentry = lookup_create(&nd, 1);
if (!IS_ERR(dentry)) { if (!IS_ERR(dentry)) {
err = vfs_mkdir(nd.path.dentry->d_inode, dentry, mode); err = vfs_mkdir(nd.path.dentry->d_inode, dentry, mode);
if (!err)
/* mark as kernel-created inode */
dentry->d_inode->i_private = &dev_mnt;
dput(dentry); dput(dentry);
} else { } else {
err = PTR_ERR(dentry); err = PTR_ERR(dentry);
} }
mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
path_put(&nd.path); path_put(&nd.path);
return err; return err;
} }
static int create_path(const char *nodepath) static int create_path(const char *nodepath)
{ {
char *path; int err;
struct nameidata nd;
int err = 0;
path = kstrdup(nodepath, GFP_KERNEL);
if (!path)
return -ENOMEM;
err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
path, LOOKUP_PARENT, &nd);
if (err == 0) {
struct dentry *dentry;
/* create directory right away */
dentry = lookup_create(&nd, 1);
if (!IS_ERR(dentry)) {
err = vfs_mkdir(nd.path.dentry->d_inode,
dentry, 0755);
dput(dentry);
}
mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
path_put(&nd.path); read_lock(&dirlock);
} else if (err == -ENOENT) { err = dev_mkdir(nodepath, 0755);
if (err == -ENOENT) {
char *path;
char *s; char *s;
/* parent directories do not exist, create them */ /* parent directories do not exist, create them */
path = kstrdup(nodepath, GFP_KERNEL);
if (!path)
return -ENOMEM;
s = path; s = path;
while (1) { for (;;) {
s = strchr(s, '/'); s = strchr(s, '/');
if (!s) if (!s)
break; break;
...@@ -125,9 +115,9 @@ static int create_path(const char *nodepath) ...@@ -125,9 +115,9 @@ static int create_path(const char *nodepath)
s[0] = '/'; s[0] = '/';
s++; s++;
} }
kfree(path);
} }
read_unlock(&dirlock);
kfree(path);
return err; return err;
} }
...@@ -156,34 +146,40 @@ int devtmpfs_create_node(struct device *dev) ...@@ -156,34 +146,40 @@ int devtmpfs_create_node(struct device *dev)
mode |= S_IFCHR; mode |= S_IFCHR;
curr_cred = override_creds(&init_cred); curr_cred = override_creds(&init_cred);
err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
nodename, LOOKUP_PARENT, &nd); nodename, LOOKUP_PARENT, &nd);
if (err == -ENOENT) { if (err == -ENOENT) {
/* create missing parent directories */
create_path(nodename); create_path(nodename);
err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
nodename, LOOKUP_PARENT, &nd); nodename, LOOKUP_PARENT, &nd);
if (err)
goto out;
} }
if (err)
goto out;
dentry = lookup_create(&nd, 0); dentry = lookup_create(&nd, 0);
if (!IS_ERR(dentry)) { if (!IS_ERR(dentry)) {
int umask;
umask = sys_umask(0000);
err = vfs_mknod(nd.path.dentry->d_inode, err = vfs_mknod(nd.path.dentry->d_inode,
dentry, mode, dev->devt); dentry, mode, dev->devt);
sys_umask(umask); if (!err) {
/* mark as kernel created inode */ struct iattr newattrs;
if (!err)
/* fixup possibly umasked mode */
newattrs.ia_mode = mode;
newattrs.ia_valid = ATTR_MODE;
mutex_lock(&dentry->d_inode->i_mutex);
notify_change(dentry, &newattrs);
mutex_unlock(&dentry->d_inode->i_mutex);
/* mark as kernel-created inode */
dentry->d_inode->i_private = &dev_mnt; dentry->d_inode->i_private = &dev_mnt;
}
dput(dentry); dput(dentry);
} else { } else {
err = PTR_ERR(dentry); err = PTR_ERR(dentry);
} }
mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
path_put(&nd.path); path_put(&nd.path);
out: out:
kfree(tmp); kfree(tmp);
...@@ -205,16 +201,21 @@ static int dev_rmdir(const char *name) ...@@ -205,16 +201,21 @@ static int dev_rmdir(const char *name)
mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT); mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
dentry = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len); dentry = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len);
if (!IS_ERR(dentry)) { if (!IS_ERR(dentry)) {
if (dentry->d_inode) if (dentry->d_inode) {
err = vfs_rmdir(nd.path.dentry->d_inode, dentry); if (dentry->d_inode->i_private == &dev_mnt)
else err = vfs_rmdir(nd.path.dentry->d_inode,
dentry);
else
err = -EPERM;
} else {
err = -ENOENT; err = -ENOENT;
}
dput(dentry); dput(dentry);
} else { } else {
err = PTR_ERR(dentry); err = PTR_ERR(dentry);
} }
mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
path_put(&nd.path); path_put(&nd.path);
return err; return err;
} }
...@@ -228,7 +229,8 @@ static int delete_path(const char *nodepath) ...@@ -228,7 +229,8 @@ static int delete_path(const char *nodepath)
if (!path) if (!path)
return -ENOMEM; return -ENOMEM;
while (1) { write_lock(&dirlock);
for (;;) {
char *base; char *base;
base = strrchr(path, '/'); base = strrchr(path, '/');
...@@ -239,6 +241,7 @@ static int delete_path(const char *nodepath) ...@@ -239,6 +241,7 @@ static int delete_path(const char *nodepath)
if (err) if (err)
break; break;
} }
write_unlock(&dirlock);
kfree(path); kfree(path);
return err; return err;
...@@ -322,9 +325,8 @@ int devtmpfs_delete_node(struct device *dev) ...@@ -322,9 +325,8 @@ int devtmpfs_delete_node(struct device *dev)
* If configured, or requested by the commandline, devtmpfs will be * If configured, or requested by the commandline, devtmpfs will be
* auto-mounted after the kernel mounted the root filesystem. * auto-mounted after the kernel mounted the root filesystem.
*/ */
int devtmpfs_mount(const char *mountpoint) int devtmpfs_mount(const char *mntdir)
{ {
struct path path;
int err; int err;
if (!dev_mount) if (!dev_mount)
...@@ -333,15 +335,11 @@ int devtmpfs_mount(const char *mountpoint) ...@@ -333,15 +335,11 @@ int devtmpfs_mount(const char *mountpoint)
if (!dev_mnt) if (!dev_mnt)
return 0; return 0;
err = kern_path(mountpoint, LOOKUP_FOLLOW, &path); err = sys_mount("devtmpfs", (char *)mntdir, "devtmpfs", MS_SILENT, NULL);
if (err)
return err;
err = do_add_mount(dev_mnt, &path, 0, NULL);
if (err) if (err)
printk(KERN_INFO "devtmpfs: error mounting %i\n", err); printk(KERN_INFO "devtmpfs: error mounting %i\n", err);
else else
printk(KERN_INFO "devtmpfs: mounted\n"); printk(KERN_INFO "devtmpfs: mounted\n");
path_put(&path);
return err; return err;
} }
...@@ -354,6 +352,8 @@ int __init devtmpfs_init(void) ...@@ -354,6 +352,8 @@ int __init devtmpfs_init(void)
int err; int err;
struct vfsmount *mnt; struct vfsmount *mnt;
rwlock_init(&dirlock);
err = register_filesystem(&dev_fs_type); err = register_filesystem(&dev_fs_type);
if (err) { if (err) {
printk(KERN_ERR "devtmpfs: unable to register devtmpfs " printk(KERN_ERR "devtmpfs: unable to register devtmpfs "
...@@ -361,7 +361,7 @@ int __init devtmpfs_init(void) ...@@ -361,7 +361,7 @@ int __init devtmpfs_init(void)
return err; return err;
} }
mnt = kern_mount(&dev_fs_type); mnt = kern_mount_data(&dev_fs_type, "mode=0755");
if (IS_ERR(mnt)) { if (IS_ERR(mnt)) {
err = PTR_ERR(mnt); err = PTR_ERR(mnt);
printk(KERN_ERR "devtmpfs: unable to create devtmpfs %i\n", err); printk(KERN_ERR "devtmpfs: unable to create devtmpfs %i\n", err);
......
...@@ -601,12 +601,9 @@ request_firmware_work_func(void *arg) ...@@ -601,12 +601,9 @@ request_firmware_work_func(void *arg)
} }
ret = _request_firmware(&fw, fw_work->name, fw_work->device, ret = _request_firmware(&fw, fw_work->name, fw_work->device,
fw_work->uevent); fw_work->uevent);
if (ret < 0)
fw_work->cont(NULL, fw_work->context); fw_work->cont(fw, fw_work->context);
else {
fw_work->cont(fw, fw_work->context);
release_firmware(fw);
}
module_put(fw_work->module); module_put(fw_work->module);
kfree(fw_work); kfree(fw_work);
return ret; return ret;
...@@ -619,6 +616,7 @@ request_firmware_work_func(void *arg) ...@@ -619,6 +616,7 @@ request_firmware_work_func(void *arg)
* is non-zero else the firmware copy must be done manually. * is non-zero else the firmware copy must be done manually.
* @name: name of firmware file * @name: name of firmware file
* @device: device for which firmware is being loaded * @device: device for which firmware is being loaded
* @gfp: allocation flags
* @context: will be passed over to @cont, and * @context: will be passed over to @cont, and
* @fw may be %NULL if firmware request fails. * @fw may be %NULL if firmware request fails.
* @cont: function will be called asynchronously when the firmware * @cont: function will be called asynchronously when the firmware
...@@ -631,12 +629,12 @@ request_firmware_work_func(void *arg) ...@@ -631,12 +629,12 @@ request_firmware_work_func(void *arg)
int int
request_firmware_nowait( request_firmware_nowait(
struct module *module, int uevent, struct module *module, int uevent,
const char *name, struct device *device, void *context, const char *name, struct device *device, gfp_t gfp, void *context,
void (*cont)(const struct firmware *fw, void *context)) void (*cont)(const struct firmware *fw, void *context))
{ {
struct task_struct *task; struct task_struct *task;
struct firmware_work *fw_work = kmalloc(sizeof (struct firmware_work), struct firmware_work *fw_work = kmalloc(sizeof (struct firmware_work),
GFP_ATOMIC); gfp);
if (!fw_work) if (!fw_work)
return -ENOMEM; return -ENOMEM;
......
...@@ -1000,7 +1000,7 @@ static __initdata LIST_HEAD(early_platform_device_list); ...@@ -1000,7 +1000,7 @@ static __initdata LIST_HEAD(early_platform_device_list);
int __init early_platform_driver_register(struct early_platform_driver *epdrv, int __init early_platform_driver_register(struct early_platform_driver *epdrv,
char *buf) char *buf)
{ {
unsigned long index; char *tmp;
int n; int n;
/* Simply add the driver to the end of the global list. /* Simply add the driver to the end of the global list.
...@@ -1019,13 +1019,28 @@ int __init early_platform_driver_register(struct early_platform_driver *epdrv, ...@@ -1019,13 +1019,28 @@ int __init early_platform_driver_register(struct early_platform_driver *epdrv,
if (buf && !strncmp(buf, epdrv->pdrv->driver.name, n)) { if (buf && !strncmp(buf, epdrv->pdrv->driver.name, n)) {
list_move(&epdrv->list, &early_platform_driver_list); list_move(&epdrv->list, &early_platform_driver_list);
if (!strcmp(buf, epdrv->pdrv->driver.name)) /* Allow passing parameters after device name */
if (buf[n] == '\0' || buf[n] == ',')
epdrv->requested_id = -1; epdrv->requested_id = -1;
else if (buf[n] == '.' && strict_strtoul(&buf[n + 1], 10, else {
&index) == 0) epdrv->requested_id = simple_strtoul(&buf[n + 1],
epdrv->requested_id = index; &tmp, 10);
else
epdrv->requested_id = EARLY_PLATFORM_ID_ERROR; if (buf[n] != '.' || (tmp == &buf[n + 1])) {
epdrv->requested_id = EARLY_PLATFORM_ID_ERROR;
n = 0;
} else
n += strcspn(&buf[n + 1], ",") + 1;
}
if (buf[n] == ',')
n++;
if (epdrv->bufsize) {
memcpy(epdrv->buffer, &buf[n],
min_t(int, epdrv->bufsize, strlen(&buf[n]) + 1));
epdrv->buffer[epdrv->bufsize - 1] = '\0';
}
} }
return 0; return 0;
......
...@@ -544,9 +544,12 @@ static void callbackfn_rbu(const struct firmware *fw, void *context) ...@@ -544,9 +544,12 @@ static void callbackfn_rbu(const struct firmware *fw, void *context)
{ {
rbu_data.entry_created = 0; rbu_data.entry_created = 0;
if (!fw || !fw->size) if (!fw)
return; return;
if (!fw->size)
goto out;
spin_lock(&rbu_data.lock); spin_lock(&rbu_data.lock);
if (!strcmp(image_type, "mono")) { if (!strcmp(image_type, "mono")) {
if (!img_update_realloc(fw->size)) if (!img_update_realloc(fw->size))
...@@ -568,6 +571,8 @@ static void callbackfn_rbu(const struct firmware *fw, void *context) ...@@ -568,6 +571,8 @@ static void callbackfn_rbu(const struct firmware *fw, void *context)
} else } else
pr_debug("invalid image type specified.\n"); pr_debug("invalid image type specified.\n");
spin_unlock(&rbu_data.lock); spin_unlock(&rbu_data.lock);
out:
release_firmware(fw);
} }
static ssize_t read_rbu_image_type(struct kobject *kobj, static ssize_t read_rbu_image_type(struct kobject *kobj,
...@@ -615,7 +620,7 @@ static ssize_t write_rbu_image_type(struct kobject *kobj, ...@@ -615,7 +620,7 @@ static ssize_t write_rbu_image_type(struct kobject *kobj,
spin_unlock(&rbu_data.lock); spin_unlock(&rbu_data.lock);
req_firm_rc = request_firmware_nowait(THIS_MODULE, req_firm_rc = request_firmware_nowait(THIS_MODULE,
FW_ACTION_NOHOTPLUG, "dell_rbu", FW_ACTION_NOHOTPLUG, "dell_rbu",
&rbu_device->dev, &context, &rbu_device->dev, GFP_KERNEL, &context,
callbackfn_rbu); callbackfn_rbu);
if (req_firm_rc) { if (req_firm_rc) {
printk(KERN_ERR printk(KERN_ERR
......
...@@ -44,9 +44,20 @@ struct ilo_hwinfo { ...@@ -44,9 +44,20 @@ struct ilo_hwinfo {
struct pci_dev *ilo_dev; struct pci_dev *ilo_dev;
/*
* open_lock serializes ccb_cnt during open and close
* [ irq disabled ]
* -> alloc_lock used when adding/removing/searching ccb_alloc,
* which represents all ccbs open on the device
* --> fifo_lock controls access to fifo queues shared with hw
*
* Locks must be taken in this order, but open_lock and alloc_lock
* are optional, they do not need to be held in order to take a
* lower level lock.
*/
spinlock_t open_lock;
spinlock_t alloc_lock; spinlock_t alloc_lock;
spinlock_t fifo_lock; spinlock_t fifo_lock;
spinlock_t open_lock;
struct cdev cdev; struct cdev cdev;
}; };
......
...@@ -1179,16 +1179,18 @@ static void uart_firmware_cont(const struct firmware *fw, void *context) ...@@ -1179,16 +1179,18 @@ static void uart_firmware_cont(const struct firmware *fw, void *context)
if (firmware->header.length != fw->size) { if (firmware->header.length != fw->size) {
dev_err(dev, "invalid firmware\n"); dev_err(dev, "invalid firmware\n");
return; goto out;
} }
ret = qe_upload_firmware(firmware); ret = qe_upload_firmware(firmware);
if (ret) { if (ret) {
dev_err(dev, "could not load firmware\n"); dev_err(dev, "could not load firmware\n");
return; goto out;
} }
firmware_loaded = 1; firmware_loaded = 1;
out:
release_firmware(fw);
} }
static int ucc_uart_probe(struct of_device *ofdev, static int ucc_uart_probe(struct of_device *ofdev,
...@@ -1247,7 +1249,7 @@ static int ucc_uart_probe(struct of_device *ofdev, ...@@ -1247,7 +1249,7 @@ static int ucc_uart_probe(struct of_device *ofdev,
*/ */
ret = request_firmware_nowait(THIS_MODULE, ret = request_firmware_nowait(THIS_MODULE,
FW_ACTION_HOTPLUG, filename, &ofdev->dev, FW_ACTION_HOTPLUG, filename, &ofdev->dev,
&ofdev->dev, uart_firmware_cont); GFP_KERNEL, &ofdev->dev, uart_firmware_cont);
if (ret) { if (ret) {
dev_err(&ofdev->dev, dev_err(&ofdev->dev,
"could not load firmware %s\n", "could not load firmware %s\n",
......
...@@ -2327,9 +2327,11 @@ static void usbdux_firmware_request_complete_handler(const struct firmware *fw, ...@@ -2327,9 +2327,11 @@ static void usbdux_firmware_request_complete_handler(const struct firmware *fw,
if (ret) { if (ret) {
dev_err(&usbdev->dev, dev_err(&usbdev->dev,
"Could not upload firmware (err=%d)\n", ret); "Could not upload firmware (err=%d)\n", ret);
return; goto out;
} }
comedi_usb_auto_config(usbdev, BOARDNAME); comedi_usb_auto_config(usbdev, BOARDNAME);
out:
release_firmware(fw);
} }
/* allocate memory for the urbs and initialise them */ /* allocate memory for the urbs and initialise them */
...@@ -2580,6 +2582,7 @@ static int usbduxsub_probe(struct usb_interface *uinterf, ...@@ -2580,6 +2582,7 @@ static int usbduxsub_probe(struct usb_interface *uinterf,
FW_ACTION_HOTPLUG, FW_ACTION_HOTPLUG,
"usbdux_firmware.bin", "usbdux_firmware.bin",
&udev->dev, &udev->dev,
GFP_KERNEL,
usbduxsub + index, usbduxsub + index,
usbdux_firmware_request_complete_handler); usbdux_firmware_request_complete_handler);
......
...@@ -1451,10 +1451,12 @@ static void usbduxfast_firmware_request_complete_handler(const struct firmware ...@@ -1451,10 +1451,12 @@ static void usbduxfast_firmware_request_complete_handler(const struct firmware
if (ret) { if (ret) {
dev_err(&usbdev->dev, dev_err(&usbdev->dev,
"Could not upload firmware (err=%d)\n", ret); "Could not upload firmware (err=%d)\n", ret);
return; goto out;
} }
comedi_usb_auto_config(usbdev, BOARDNAME); comedi_usb_auto_config(usbdev, BOARDNAME);
out:
release_firmware(fw);
} }
/* /*
...@@ -1569,6 +1571,7 @@ static int usbduxfastsub_probe(struct usb_interface *uinterf, ...@@ -1569,6 +1571,7 @@ static int usbduxfastsub_probe(struct usb_interface *uinterf,
FW_ACTION_HOTPLUG, FW_ACTION_HOTPLUG,
"usbduxfast_firmware.bin", "usbduxfast_firmware.bin",
&udev->dev, &udev->dev,
GFP_KERNEL,
usbduxfastsub + index, usbduxfastsub + index,
usbduxfast_firmware_request_complete_handler); usbduxfast_firmware_request_complete_handler);
......
...@@ -667,12 +667,12 @@ static void uea_upload_pre_firmware(const struct firmware *fw_entry, void *conte ...@@ -667,12 +667,12 @@ static void uea_upload_pre_firmware(const struct firmware *fw_entry, void *conte
else else
uea_info(usb, "firmware uploaded\n"); uea_info(usb, "firmware uploaded\n");
uea_leaves(usb); goto err;
return;
err_fw_corrupted: err_fw_corrupted:
uea_err(usb, "firmware is corrupted\n"); uea_err(usb, "firmware is corrupted\n");
err: err:
release_firmware(fw_entry);
uea_leaves(usb); uea_leaves(usb);
} }
...@@ -705,7 +705,8 @@ static int uea_load_firmware(struct usb_device *usb, unsigned int ver) ...@@ -705,7 +705,8 @@ static int uea_load_firmware(struct usb_device *usb, unsigned int ver)
break; break;
} }
ret = request_firmware_nowait(THIS_MODULE, 1, fw_name, &usb->dev, usb, uea_upload_pre_firmware); ret = request_firmware_nowait(THIS_MODULE, 1, fw_name, &usb->dev,
GFP_KERNEL, usb, uea_upload_pre_firmware);
if (ret) if (ret)
uea_err(usb, "firmware %s is not available\n", fw_name); uea_err(usb, "firmware %s is not available\n", fw_name);
else else
......
...@@ -32,7 +32,9 @@ static struct vfsmount *debugfs_mount; ...@@ -32,7 +32,9 @@ static struct vfsmount *debugfs_mount;
static int debugfs_mount_count; static int debugfs_mount_count;
static bool debugfs_registered; static bool debugfs_registered;
static struct inode *debugfs_get_inode(struct super_block *sb, int mode, dev_t dev) static struct inode *debugfs_get_inode(struct super_block *sb, int mode, dev_t dev,
void *data, const struct file_operations *fops)
{ {
struct inode *inode = new_inode(sb); struct inode *inode = new_inode(sb);
...@@ -44,14 +46,18 @@ static struct inode *debugfs_get_inode(struct super_block *sb, int mode, dev_t d ...@@ -44,14 +46,18 @@ static struct inode *debugfs_get_inode(struct super_block *sb, int mode, dev_t d
init_special_inode(inode, mode, dev); init_special_inode(inode, mode, dev);
break; break;
case S_IFREG: case S_IFREG:
inode->i_fop = &debugfs_file_operations; inode->i_fop = fops ? fops : &debugfs_file_operations;
inode->i_private = data;
break; break;
case S_IFLNK: case S_IFLNK:
inode->i_op = &debugfs_link_operations; inode->i_op = &debugfs_link_operations;
inode->i_fop = fops;
inode->i_private = data;
break; break;
case S_IFDIR: case S_IFDIR:
inode->i_op = &simple_dir_inode_operations; inode->i_op = &simple_dir_inode_operations;
inode->i_fop = &simple_dir_operations; inode->i_fop = fops ? fops : &simple_dir_operations;
inode->i_private = data;
/* directory inodes start off with i_nlink == 2 /* directory inodes start off with i_nlink == 2
* (for "." entry) */ * (for "." entry) */
...@@ -64,7 +70,8 @@ static struct inode *debugfs_get_inode(struct super_block *sb, int mode, dev_t d ...@@ -64,7 +70,8 @@ static struct inode *debugfs_get_inode(struct super_block *sb, int mode, dev_t d
/* SMP-safe */ /* SMP-safe */
static int debugfs_mknod(struct inode *dir, struct dentry *dentry, static int debugfs_mknod(struct inode *dir, struct dentry *dentry,
int mode, dev_t dev) int mode, dev_t dev, void *data,
const struct file_operations *fops)
{ {
struct inode *inode; struct inode *inode;
int error = -EPERM; int error = -EPERM;
...@@ -72,7 +79,7 @@ static int debugfs_mknod(struct inode *dir, struct dentry *dentry, ...@@ -72,7 +79,7 @@ static int debugfs_mknod(struct inode *dir, struct dentry *dentry,
if (dentry->d_inode) if (dentry->d_inode)
return -EEXIST; return -EEXIST;
inode = debugfs_get_inode(dir->i_sb, mode, dev); inode = debugfs_get_inode(dir->i_sb, mode, dev, data, fops);
if (inode) { if (inode) {
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
dget(dentry); dget(dentry);
...@@ -81,12 +88,13 @@ static int debugfs_mknod(struct inode *dir, struct dentry *dentry, ...@@ -81,12 +88,13 @@ static int debugfs_mknod(struct inode *dir, struct dentry *dentry,
return error; return error;
} }
static int debugfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) static int debugfs_mkdir(struct inode *dir, struct dentry *dentry, int mode,
void *data, const struct file_operations *fops)
{ {
int res; int res;
mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR; mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR;
res = debugfs_mknod(dir, dentry, mode, 0); res = debugfs_mknod(dir, dentry, mode, 0, data, fops);
if (!res) { if (!res) {
inc_nlink(dir); inc_nlink(dir);
fsnotify_mkdir(dir, dentry); fsnotify_mkdir(dir, dentry);
...@@ -94,18 +102,20 @@ static int debugfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) ...@@ -94,18 +102,20 @@ static int debugfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
return res; return res;
} }
static int debugfs_link(struct inode *dir, struct dentry *dentry, int mode) static int debugfs_link(struct inode *dir, struct dentry *dentry, int mode,
void *data, const struct file_operations *fops)
{ {
mode = (mode & S_IALLUGO) | S_IFLNK; mode = (mode & S_IALLUGO) | S_IFLNK;
return debugfs_mknod(dir, dentry, mode, 0); return debugfs_mknod(dir, dentry, mode, 0, data, fops);
} }
static int debugfs_create(struct inode *dir, struct dentry *dentry, int mode) static int debugfs_create(struct inode *dir, struct dentry *dentry, int mode,
void *data, const struct file_operations *fops)
{ {
int res; int res;
mode = (mode & S_IALLUGO) | S_IFREG; mode = (mode & S_IALLUGO) | S_IFREG;
res = debugfs_mknod(dir, dentry, mode, 0); res = debugfs_mknod(dir, dentry, mode, 0, data, fops);
if (!res) if (!res)
fsnotify_create(dir, dentry); fsnotify_create(dir, dentry);
return res; return res;
...@@ -139,7 +149,9 @@ static struct file_system_type debug_fs_type = { ...@@ -139,7 +149,9 @@ static struct file_system_type debug_fs_type = {
static int debugfs_create_by_name(const char *name, mode_t mode, static int debugfs_create_by_name(const char *name, mode_t mode,
struct dentry *parent, struct dentry *parent,
struct dentry **dentry) struct dentry **dentry,
void *data,
const struct file_operations *fops)
{ {
int error = 0; int error = 0;
...@@ -164,13 +176,16 @@ static int debugfs_create_by_name(const char *name, mode_t mode, ...@@ -164,13 +176,16 @@ static int debugfs_create_by_name(const char *name, mode_t mode,
if (!IS_ERR(*dentry)) { if (!IS_ERR(*dentry)) {
switch (mode & S_IFMT) { switch (mode & S_IFMT) {
case S_IFDIR: case S_IFDIR:
error = debugfs_mkdir(parent->d_inode, *dentry, mode); error = debugfs_mkdir(parent->d_inode, *dentry, mode,
data, fops);
break; break;
case S_IFLNK: case S_IFLNK:
error = debugfs_link(parent->d_inode, *dentry, mode); error = debugfs_link(parent->d_inode, *dentry, mode,
data, fops);
break; break;
default: default:
error = debugfs_create(parent->d_inode, *dentry, mode); error = debugfs_create(parent->d_inode, *dentry, mode,
data, fops);
break; break;
} }
dput(*dentry); dput(*dentry);
...@@ -221,19 +236,13 @@ struct dentry *debugfs_create_file(const char *name, mode_t mode, ...@@ -221,19 +236,13 @@ struct dentry *debugfs_create_file(const char *name, mode_t mode,
if (error) if (error)
goto exit; goto exit;
error = debugfs_create_by_name(name, mode, parent, &dentry); error = debugfs_create_by_name(name, mode, parent, &dentry,
data, fops);
if (error) { if (error) {
dentry = NULL; dentry = NULL;
simple_release_fs(&debugfs_mount, &debugfs_mount_count); simple_release_fs(&debugfs_mount, &debugfs_mount_count);
goto exit; goto exit;
} }
if (dentry->d_inode) {
if (data)
dentry->d_inode->i_private = data;
if (fops)
dentry->d_inode->i_fop = fops;
}
exit: exit:
return dentry; return dentry;
} }
......
...@@ -1279,28 +1279,6 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len) ...@@ -1279,28 +1279,6 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
return __lookup_hash(&this, base, NULL); return __lookup_hash(&this, base, NULL);
} }
/**
* lookup_one_noperm - bad hack for sysfs
* @name: pathname component to lookup
* @base: base directory to lookup from
*
* This is a variant of lookup_one_len that doesn't perform any permission
* checks. It's a horrible hack to work around the braindead sysfs
* architecture and should not be used anywhere else.
*
* DON'T USE THIS FUNCTION EVER, thanks.
*/
struct dentry *lookup_one_noperm(const char *name, struct dentry *base)
{
int err;
struct qstr this;
err = __lookup_one_len(name, &this, base, strlen(name));
if (err)
return ERR_PTR(err);
return __lookup_hash(&this, base, NULL);
}
int user_path_at(int dfd, const char __user *name, unsigned flags, int user_path_at(int dfd, const char __user *name, unsigned flags,
struct path *path) struct path *path)
{ {
......
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
#include "sysfs.h" #include "sysfs.h"
DEFINE_MUTEX(sysfs_mutex); DEFINE_MUTEX(sysfs_mutex);
DEFINE_MUTEX(sysfs_rename_mutex);
DEFINE_SPINLOCK(sysfs_assoc_lock); DEFINE_SPINLOCK(sysfs_assoc_lock);
static DEFINE_SPINLOCK(sysfs_ino_lock); static DEFINE_SPINLOCK(sysfs_ino_lock);
...@@ -84,46 +83,6 @@ static void sysfs_unlink_sibling(struct sysfs_dirent *sd) ...@@ -84,46 +83,6 @@ static void sysfs_unlink_sibling(struct sysfs_dirent *sd)
} }
} }
/**
* sysfs_get_dentry - get dentry for the given sysfs_dirent
* @sd: sysfs_dirent of interest
*
* Get dentry for @sd. Dentry is looked up if currently not
* present. This function descends from the root looking up
* dentry for each step.
*
* LOCKING:
* mutex_lock(sysfs_rename_mutex)
*
* RETURNS:
* Pointer to found dentry on success, ERR_PTR() value on error.
*/
struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd)
{
struct dentry *dentry = dget(sysfs_sb->s_root);
while (dentry->d_fsdata != sd) {
struct sysfs_dirent *cur;
struct dentry *parent;
/* find the first ancestor which hasn't been looked up */
cur = sd;
while (cur->s_parent != dentry->d_fsdata)
cur = cur->s_parent;
/* look it up */
parent = dentry;
mutex_lock(&parent->d_inode->i_mutex);
dentry = lookup_one_noperm(cur->s_name, parent);
mutex_unlock(&parent->d_inode->i_mutex);
dput(parent);
if (IS_ERR(dentry))
break;
}
return dentry;
}
/** /**
* sysfs_get_active - get an active reference to sysfs_dirent * sysfs_get_active - get an active reference to sysfs_dirent
* @sd: sysfs_dirent to get an active reference to * @sd: sysfs_dirent to get an active reference to
...@@ -298,7 +257,61 @@ void release_sysfs_dirent(struct sysfs_dirent * sd) ...@@ -298,7 +257,61 @@ void release_sysfs_dirent(struct sysfs_dirent * sd)
goto repeat; goto repeat;
} }
static void sysfs_d_iput(struct dentry * dentry, struct inode * inode) static int sysfs_dentry_delete(struct dentry *dentry)
{
struct sysfs_dirent *sd = dentry->d_fsdata;
return !!(sd->s_flags & SYSFS_FLAG_REMOVED);
}
static int sysfs_dentry_revalidate(struct dentry *dentry, struct nameidata *nd)
{
struct sysfs_dirent *sd = dentry->d_fsdata;
int is_dir;
mutex_lock(&sysfs_mutex);
/* The sysfs dirent has been deleted */
if (sd->s_flags & SYSFS_FLAG_REMOVED)
goto out_bad;
/* The sysfs dirent has been moved? */
if (dentry->d_parent->d_fsdata != sd->s_parent)
goto out_bad;
/* The sysfs dirent has been renamed */
if (strcmp(dentry->d_name.name, sd->s_name) != 0)
goto out_bad;
mutex_unlock(&sysfs_mutex);
out_valid:
return 1;
out_bad:
/* Remove the dentry from the dcache hashes.
* If this is a deleted dentry we use d_drop instead of d_delete
* so sysfs doesn't need to cope with negative dentries.
*
* If this is a dentry that has simply been renamed we
* use d_drop to remove it from the dcache lookup on its
* old parent. If this dentry persists later when a lookup
* is performed at its new name the dentry will be readded
* to the dcache hashes.
*/
is_dir = (sysfs_type(sd) == SYSFS_DIR);
mutex_unlock(&sysfs_mutex);
if (is_dir) {
/* If we have submounts we must allow the vfs caches
* to lie about the state of the filesystem to prevent
* leaks and other nasty things.
*/
if (have_submounts(dentry))
goto out_valid;
shrink_dcache_parent(dentry);
}
d_drop(dentry);
return 0;
}
static void sysfs_dentry_iput(struct dentry *dentry, struct inode *inode)
{ {
struct sysfs_dirent * sd = dentry->d_fsdata; struct sysfs_dirent * sd = dentry->d_fsdata;
...@@ -307,7 +320,9 @@ static void sysfs_d_iput(struct dentry * dentry, struct inode * inode) ...@@ -307,7 +320,9 @@ static void sysfs_d_iput(struct dentry * dentry, struct inode * inode)
} }
static const struct dentry_operations sysfs_dentry_ops = { static const struct dentry_operations sysfs_dentry_ops = {
.d_iput = sysfs_d_iput, .d_revalidate = sysfs_dentry_revalidate,
.d_delete = sysfs_dentry_delete,
.d_iput = sysfs_dentry_iput,
}; };
struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type) struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)
...@@ -344,12 +359,6 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type) ...@@ -344,12 +359,6 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)
return NULL; return NULL;
} }
static int sysfs_ilookup_test(struct inode *inode, void *arg)
{
struct sysfs_dirent *sd = arg;
return inode->i_ino == sd->s_ino;
}
/** /**
* sysfs_addrm_start - prepare for sysfs_dirent add/remove * sysfs_addrm_start - prepare for sysfs_dirent add/remove
* @acxt: pointer to sysfs_addrm_cxt to be used * @acxt: pointer to sysfs_addrm_cxt to be used
...@@ -357,47 +366,20 @@ static int sysfs_ilookup_test(struct inode *inode, void *arg) ...@@ -357,47 +366,20 @@ static int sysfs_ilookup_test(struct inode *inode, void *arg)
* *
* This function is called when the caller is about to add or * This function is called when the caller is about to add or
* remove sysfs_dirent under @parent_sd. This function acquires * remove sysfs_dirent under @parent_sd. This function acquires
* sysfs_mutex, grabs inode for @parent_sd if available and lock * sysfs_mutex. @acxt is used to keep and pass context to
* i_mutex of it. @acxt is used to keep and pass context to
* other addrm functions. * other addrm functions.
* *
* LOCKING: * LOCKING:
* Kernel thread context (may sleep). sysfs_mutex is locked on * Kernel thread context (may sleep). sysfs_mutex is locked on
* return. i_mutex of parent inode is locked on return if * return.
* available.
*/ */
void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt,
struct sysfs_dirent *parent_sd) struct sysfs_dirent *parent_sd)
{ {
struct inode *inode;
memset(acxt, 0, sizeof(*acxt)); memset(acxt, 0, sizeof(*acxt));
acxt->parent_sd = parent_sd; acxt->parent_sd = parent_sd;
/* Lookup parent inode. inode initialization is protected by
* sysfs_mutex, so inode existence can be determined by
* looking up inode while holding sysfs_mutex.
*/
mutex_lock(&sysfs_mutex); mutex_lock(&sysfs_mutex);
inode = ilookup5(sysfs_sb, parent_sd->s_ino, sysfs_ilookup_test,
parent_sd);
if (inode) {
WARN_ON(inode->i_state & I_NEW);
/* parent inode available */
acxt->parent_inode = inode;
/* sysfs_mutex is below i_mutex in lock hierarchy.
* First, trylock i_mutex. If fails, unlock
* sysfs_mutex and lock them in order.
*/
if (!mutex_trylock(&inode->i_mutex)) {
mutex_unlock(&sysfs_mutex);
mutex_lock(&inode->i_mutex);
mutex_lock(&sysfs_mutex);
}
}
} }
/** /**
...@@ -422,18 +404,22 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, ...@@ -422,18 +404,22 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt,
*/ */
int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
{ {
struct sysfs_inode_attrs *ps_iattr;
if (sysfs_find_dirent(acxt->parent_sd, sd->s_name)) if (sysfs_find_dirent(acxt->parent_sd, sd->s_name))
return -EEXIST; return -EEXIST;
sd->s_parent = sysfs_get(acxt->parent_sd); sd->s_parent = sysfs_get(acxt->parent_sd);
if (sysfs_type(sd) == SYSFS_DIR && acxt->parent_inode)
inc_nlink(acxt->parent_inode);
acxt->cnt++;
sysfs_link_sibling(sd); sysfs_link_sibling(sd);
/* Update timestamps on the parent */
ps_iattr = acxt->parent_sd->s_iattr;
if (ps_iattr) {
struct iattr *ps_iattrs = &ps_iattr->ia_iattr;
ps_iattrs->ia_ctime = ps_iattrs->ia_mtime = CURRENT_TIME;
}
return 0; return 0;
} }
...@@ -512,70 +498,22 @@ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) ...@@ -512,70 +498,22 @@ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
*/ */
void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
{ {
struct sysfs_inode_attrs *ps_iattr;
BUG_ON(sd->s_flags & SYSFS_FLAG_REMOVED); BUG_ON(sd->s_flags & SYSFS_FLAG_REMOVED);
sysfs_unlink_sibling(sd); sysfs_unlink_sibling(sd);
/* Update timestamps on the parent */
ps_iattr = acxt->parent_sd->s_iattr;
if (ps_iattr) {
struct iattr *ps_iattrs = &ps_iattr->ia_iattr;
ps_iattrs->ia_ctime = ps_iattrs->ia_mtime = CURRENT_TIME;
}
sd->s_flags |= SYSFS_FLAG_REMOVED; sd->s_flags |= SYSFS_FLAG_REMOVED;
sd->s_sibling = acxt->removed; sd->s_sibling = acxt->removed;
acxt->removed = sd; acxt->removed = sd;
if (sysfs_type(sd) == SYSFS_DIR && acxt->parent_inode)
drop_nlink(acxt->parent_inode);
acxt->cnt++;
}
/**
* sysfs_drop_dentry - drop dentry for the specified sysfs_dirent
* @sd: target sysfs_dirent
*
* Drop dentry for @sd. @sd must have been unlinked from its
* parent on entry to this function such that it can't be looked
* up anymore.
*/
static void sysfs_drop_dentry(struct sysfs_dirent *sd)
{
struct inode *inode;
struct dentry *dentry;
inode = ilookup(sysfs_sb, sd->s_ino);
if (!inode)
return;
/* Drop any existing dentries associated with sd.
*
* For the dentry to be properly freed we need to grab a
* reference to the dentry under the dcache lock, unhash it,
* and then put it. The playing with the dentry count allows
* dput to immediately free the dentry if it is not in use.
*/
repeat:
spin_lock(&dcache_lock);
list_for_each_entry(dentry, &inode->i_dentry, d_alias) {
if (d_unhashed(dentry))
continue;
dget_locked(dentry);
spin_lock(&dentry->d_lock);
__d_drop(dentry);
spin_unlock(&dentry->d_lock);
spin_unlock(&dcache_lock);
dput(dentry);
goto repeat;
}
spin_unlock(&dcache_lock);
/* adjust nlink and update timestamp */
mutex_lock(&inode->i_mutex);
inode->i_ctime = CURRENT_TIME;
drop_nlink(inode);
if (sysfs_type(sd) == SYSFS_DIR)
drop_nlink(inode);
mutex_unlock(&inode->i_mutex);
iput(inode);
} }
/** /**
...@@ -584,25 +522,15 @@ static void sysfs_drop_dentry(struct sysfs_dirent *sd) ...@@ -584,25 +522,15 @@ static void sysfs_drop_dentry(struct sysfs_dirent *sd)
* *
* Finish up sysfs_dirent add/remove. Resources acquired by * Finish up sysfs_dirent add/remove. Resources acquired by
* sysfs_addrm_start() are released and removed sysfs_dirents are * sysfs_addrm_start() are released and removed sysfs_dirents are
* cleaned up. Timestamps on the parent inode are updated. * cleaned up.
* *
* LOCKING: * LOCKING:
* All mutexes acquired by sysfs_addrm_start() are released. * sysfs_mutex is released.
*/ */
void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt)
{ {
/* release resources acquired by sysfs_addrm_start() */ /* release resources acquired by sysfs_addrm_start() */
mutex_unlock(&sysfs_mutex); mutex_unlock(&sysfs_mutex);
if (acxt->parent_inode) {
struct inode *inode = acxt->parent_inode;
/* if added/removed, update timestamps on the parent */
if (acxt->cnt)
inode->i_ctime = inode->i_mtime = CURRENT_TIME;
mutex_unlock(&inode->i_mutex);
iput(inode);
}
/* kill removed sysfs_dirents */ /* kill removed sysfs_dirents */
while (acxt->removed) { while (acxt->removed) {
...@@ -611,7 +539,6 @@ void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) ...@@ -611,7 +539,6 @@ void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt)
acxt->removed = sd->s_sibling; acxt->removed = sd->s_sibling;
sd->s_sibling = NULL; sd->s_sibling = NULL;
sysfs_drop_dentry(sd);
sysfs_deactivate(sd); sysfs_deactivate(sd);
unmap_bin_file(sd); unmap_bin_file(sd);
sysfs_put(sd); sysfs_put(sd);
...@@ -751,10 +678,15 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, ...@@ -751,10 +678,15 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
} }
/* instantiate and hash dentry */ /* instantiate and hash dentry */
dentry->d_op = &sysfs_dentry_ops; ret = d_find_alias(inode);
dentry->d_fsdata = sysfs_get(sd); if (!ret) {
d_instantiate(dentry, inode); dentry->d_op = &sysfs_dentry_ops;
d_rehash(dentry); dentry->d_fsdata = sysfs_get(sd);
d_add(dentry, inode);
} else {
d_move(ret, dentry);
iput(inode);
}
out_unlock: out_unlock:
mutex_unlock(&sysfs_mutex); mutex_unlock(&sysfs_mutex);
...@@ -763,7 +695,9 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, ...@@ -763,7 +695,9 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
const struct inode_operations sysfs_dir_inode_operations = { const struct inode_operations sysfs_dir_inode_operations = {
.lookup = sysfs_lookup, .lookup = sysfs_lookup,
.permission = sysfs_permission,
.setattr = sysfs_setattr, .setattr = sysfs_setattr,
.getattr = sysfs_getattr,
.setxattr = sysfs_setxattr, .setxattr = sysfs_setxattr,
}; };
...@@ -826,141 +760,65 @@ void sysfs_remove_dir(struct kobject * kobj) ...@@ -826,141 +760,65 @@ void sysfs_remove_dir(struct kobject * kobj)
__sysfs_remove_dir(sd); __sysfs_remove_dir(sd);
} }
int sysfs_rename_dir(struct kobject * kobj, const char *new_name) int sysfs_rename(struct sysfs_dirent *sd,
struct sysfs_dirent *new_parent_sd, const char *new_name)
{ {
struct sysfs_dirent *sd = kobj->sd;
struct dentry *parent = NULL;
struct dentry *old_dentry = NULL, *new_dentry = NULL;
const char *dup_name = NULL; const char *dup_name = NULL;
int error; int error;
mutex_lock(&sysfs_rename_mutex); mutex_lock(&sysfs_mutex);
error = 0; error = 0;
if (strcmp(sd->s_name, new_name) == 0) if ((sd->s_parent == new_parent_sd) &&
(strcmp(sd->s_name, new_name) == 0))
goto out; /* nothing to rename */ goto out; /* nothing to rename */
/* get the original dentry */
old_dentry = sysfs_get_dentry(sd);
if (IS_ERR(old_dentry)) {
error = PTR_ERR(old_dentry);
old_dentry = NULL;
goto out;
}
parent = old_dentry->d_parent;
/* lock parent and get dentry for new name */
mutex_lock(&parent->d_inode->i_mutex);
mutex_lock(&sysfs_mutex);
error = -EEXIST; error = -EEXIST;
if (sysfs_find_dirent(sd->s_parent, new_name)) if (sysfs_find_dirent(new_parent_sd, new_name))
goto out_unlock; goto out;
error = -ENOMEM;
new_dentry = d_alloc_name(parent, new_name);
if (!new_dentry)
goto out_unlock;
/* rename sysfs_dirent */ /* rename sysfs_dirent */
error = -ENOMEM; if (strcmp(sd->s_name, new_name) != 0) {
new_name = dup_name = kstrdup(new_name, GFP_KERNEL); error = -ENOMEM;
if (!new_name) new_name = dup_name = kstrdup(new_name, GFP_KERNEL);
goto out_unlock; if (!new_name)
goto out;
dup_name = sd->s_name;
sd->s_name = new_name; dup_name = sd->s_name;
sd->s_name = new_name;
}
/* rename */ /* Remove from old parent's list and insert into new parent's list. */
d_add(new_dentry, NULL); if (sd->s_parent != new_parent_sd) {
d_move(old_dentry, new_dentry); sysfs_unlink_sibling(sd);
sysfs_get(new_parent_sd);
sysfs_put(sd->s_parent);
sd->s_parent = new_parent_sd;
sysfs_link_sibling(sd);
}
error = 0; error = 0;
out_unlock: out:
mutex_unlock(&sysfs_mutex); mutex_unlock(&sysfs_mutex);
mutex_unlock(&parent->d_inode->i_mutex);
kfree(dup_name); kfree(dup_name);
dput(old_dentry);
dput(new_dentry);
out:
mutex_unlock(&sysfs_rename_mutex);
return error; return error;
} }
int sysfs_rename_dir(struct kobject *kobj, const char *new_name)
{
return sysfs_rename(kobj->sd, kobj->sd->s_parent, new_name);
}
int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj) int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj)
{ {
struct sysfs_dirent *sd = kobj->sd; struct sysfs_dirent *sd = kobj->sd;
struct sysfs_dirent *new_parent_sd; struct sysfs_dirent *new_parent_sd;
struct dentry *old_parent, *new_parent = NULL;
struct dentry *old_dentry = NULL, *new_dentry = NULL;
int error;
mutex_lock(&sysfs_rename_mutex);
BUG_ON(!sd->s_parent); BUG_ON(!sd->s_parent);
new_parent_sd = (new_parent_kobj && new_parent_kobj->sd) ? new_parent_sd = new_parent_kobj && new_parent_kobj->sd ?
new_parent_kobj->sd : &sysfs_root; new_parent_kobj->sd : &sysfs_root;
error = 0; return sysfs_rename(sd, new_parent_sd, sd->s_name);
if (sd->s_parent == new_parent_sd)
goto out; /* nothing to move */
/* get dentries */
old_dentry = sysfs_get_dentry(sd);
if (IS_ERR(old_dentry)) {
error = PTR_ERR(old_dentry);
old_dentry = NULL;
goto out;
}
old_parent = old_dentry->d_parent;
new_parent = sysfs_get_dentry(new_parent_sd);
if (IS_ERR(new_parent)) {
error = PTR_ERR(new_parent);
new_parent = NULL;
goto out;
}
again:
mutex_lock(&old_parent->d_inode->i_mutex);
if (!mutex_trylock(&new_parent->d_inode->i_mutex)) {
mutex_unlock(&old_parent->d_inode->i_mutex);
goto again;
}
mutex_lock(&sysfs_mutex);
error = -EEXIST;
if (sysfs_find_dirent(new_parent_sd, sd->s_name))
goto out_unlock;
error = -ENOMEM;
new_dentry = d_alloc_name(new_parent, sd->s_name);
if (!new_dentry)
goto out_unlock;
error = 0;
d_add(new_dentry, NULL);
d_move(old_dentry, new_dentry);
/* Remove from old parent's list and insert into new parent's list. */
sysfs_unlink_sibling(sd);
sysfs_get(new_parent_sd);
drop_nlink(old_parent->d_inode);
sysfs_put(sd->s_parent);
sd->s_parent = new_parent_sd;
inc_nlink(new_parent->d_inode);
sysfs_link_sibling(sd);
out_unlock:
mutex_unlock(&sysfs_mutex);
mutex_unlock(&new_parent->d_inode->i_mutex);
mutex_unlock(&old_parent->d_inode->i_mutex);
out:
dput(new_parent);
dput(old_dentry);
dput(new_dentry);
mutex_unlock(&sysfs_rename_mutex);
return error;
} }
/* Relationship between s_mode and the DT_xxx types */ /* Relationship between s_mode and the DT_xxx types */
......
...@@ -579,46 +579,23 @@ EXPORT_SYMBOL_GPL(sysfs_add_file_to_group); ...@@ -579,46 +579,23 @@ EXPORT_SYMBOL_GPL(sysfs_add_file_to_group);
*/ */
int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode) int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode)
{ {
struct sysfs_dirent *victim_sd = NULL; struct sysfs_dirent *sd;
struct dentry *victim = NULL;
struct inode * inode;
struct iattr newattrs; struct iattr newattrs;
int rc; int rc;
rc = -ENOENT; mutex_lock(&sysfs_mutex);
victim_sd = sysfs_get_dirent(kobj->sd, attr->name);
if (!victim_sd)
goto out;
mutex_lock(&sysfs_rename_mutex); rc = -ENOENT;
victim = sysfs_get_dentry(victim_sd); sd = sysfs_find_dirent(kobj->sd, attr->name);
mutex_unlock(&sysfs_rename_mutex); if (!sd)
if (IS_ERR(victim)) {
rc = PTR_ERR(victim);
victim = NULL;
goto out; goto out;
}
inode = victim->d_inode;
mutex_lock(&inode->i_mutex);
newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); newattrs.ia_mode = (mode & S_IALLUGO) | (sd->s_mode & ~S_IALLUGO);
newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; newattrs.ia_valid = ATTR_MODE;
newattrs.ia_ctime = current_fs_time(inode->i_sb); rc = sysfs_sd_setattr(sd, &newattrs);
rc = sysfs_setattr(victim, &newattrs);
if (rc == 0) {
fsnotify_change(victim, newattrs.ia_valid);
mutex_lock(&sysfs_mutex);
victim_sd->s_mode = newattrs.ia_mode;
mutex_unlock(&sysfs_mutex);
}
mutex_unlock(&inode->i_mutex);
out: out:
dput(victim); mutex_unlock(&sysfs_mutex);
sysfs_put(victim_sd);
return rc; return rc;
} }
EXPORT_SYMBOL_GPL(sysfs_chmod_file); EXPORT_SYMBOL_GPL(sysfs_chmod_file);
......
...@@ -37,7 +37,9 @@ static struct backing_dev_info sysfs_backing_dev_info = { ...@@ -37,7 +37,9 @@ static struct backing_dev_info sysfs_backing_dev_info = {
}; };
static const struct inode_operations sysfs_inode_operations ={ static const struct inode_operations sysfs_inode_operations ={
.permission = sysfs_permission,
.setattr = sysfs_setattr, .setattr = sysfs_setattr,
.getattr = sysfs_getattr,
.setxattr = sysfs_setxattr, .setxattr = sysfs_setxattr,
}; };
...@@ -46,7 +48,7 @@ int __init sysfs_inode_init(void) ...@@ -46,7 +48,7 @@ int __init sysfs_inode_init(void)
return bdi_init(&sysfs_backing_dev_info); return bdi_init(&sysfs_backing_dev_info);
} }
struct sysfs_inode_attrs *sysfs_init_inode_attrs(struct sysfs_dirent *sd) static struct sysfs_inode_attrs *sysfs_init_inode_attrs(struct sysfs_dirent *sd)
{ {
struct sysfs_inode_attrs *attrs; struct sysfs_inode_attrs *attrs;
struct iattr *iattrs; struct iattr *iattrs;
...@@ -64,30 +66,15 @@ struct sysfs_inode_attrs *sysfs_init_inode_attrs(struct sysfs_dirent *sd) ...@@ -64,30 +66,15 @@ struct sysfs_inode_attrs *sysfs_init_inode_attrs(struct sysfs_dirent *sd)
return attrs; return attrs;
} }
int sysfs_setattr(struct dentry * dentry, struct iattr * iattr)
int sysfs_sd_setattr(struct sysfs_dirent *sd, struct iattr * iattr)
{ {
struct inode * inode = dentry->d_inode;
struct sysfs_dirent * sd = dentry->d_fsdata;
struct sysfs_inode_attrs *sd_attrs; struct sysfs_inode_attrs *sd_attrs;
struct iattr *iattrs; struct iattr *iattrs;
unsigned int ia_valid = iattr->ia_valid; unsigned int ia_valid = iattr->ia_valid;
int error;
if (!sd)
return -EINVAL;
sd_attrs = sd->s_iattr; sd_attrs = sd->s_iattr;
error = inode_change_ok(inode, iattr);
if (error)
return error;
iattr->ia_valid &= ~ATTR_SIZE; /* ignore size changes */
error = inode_setattr(inode, iattr);
if (error)
return error;
if (!sd_attrs) { if (!sd_attrs) {
/* setting attributes for the first time, allocate now */ /* setting attributes for the first time, allocate now */
sd_attrs = sysfs_init_inode_attrs(sd); sd_attrs = sysfs_init_inode_attrs(sd);
...@@ -103,42 +90,78 @@ int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) ...@@ -103,42 +90,78 @@ int sysfs_setattr(struct dentry * dentry, struct iattr * iattr)
if (ia_valid & ATTR_GID) if (ia_valid & ATTR_GID)
iattrs->ia_gid = iattr->ia_gid; iattrs->ia_gid = iattr->ia_gid;
if (ia_valid & ATTR_ATIME) if (ia_valid & ATTR_ATIME)
iattrs->ia_atime = timespec_trunc(iattr->ia_atime, iattrs->ia_atime = iattr->ia_atime;
inode->i_sb->s_time_gran);
if (ia_valid & ATTR_MTIME) if (ia_valid & ATTR_MTIME)
iattrs->ia_mtime = timespec_trunc(iattr->ia_mtime, iattrs->ia_mtime = iattr->ia_mtime;
inode->i_sb->s_time_gran);
if (ia_valid & ATTR_CTIME) if (ia_valid & ATTR_CTIME)
iattrs->ia_ctime = timespec_trunc(iattr->ia_ctime, iattrs->ia_ctime = iattr->ia_ctime;
inode->i_sb->s_time_gran);
if (ia_valid & ATTR_MODE) { if (ia_valid & ATTR_MODE) {
umode_t mode = iattr->ia_mode; umode_t mode = iattr->ia_mode;
if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID))
mode &= ~S_ISGID;
iattrs->ia_mode = sd->s_mode = mode; iattrs->ia_mode = sd->s_mode = mode;
} }
} }
return 0;
}
int sysfs_setattr(struct dentry *dentry, struct iattr *iattr)
{
struct inode *inode = dentry->d_inode;
struct sysfs_dirent *sd = dentry->d_fsdata;
int error;
if (!sd)
return -EINVAL;
error = inode_change_ok(inode, iattr);
if (error)
return error;
iattr->ia_valid &= ~ATTR_SIZE; /* ignore size changes */
error = inode_setattr(inode, iattr);
if (error)
return error;
mutex_lock(&sysfs_mutex);
error = sysfs_sd_setattr(sd, iattr);
mutex_unlock(&sysfs_mutex);
return error; return error;
} }
static int sysfs_sd_setsecdata(struct sysfs_dirent *sd, void **secdata, u32 *secdata_len)
{
struct sysfs_inode_attrs *iattrs;
void *old_secdata;
size_t old_secdata_len;
iattrs = sd->s_iattr;
if (!iattrs)
iattrs = sysfs_init_inode_attrs(sd);
if (!iattrs)
return -ENOMEM;
old_secdata = iattrs->ia_secdata;
old_secdata_len = iattrs->ia_secdata_len;
iattrs->ia_secdata = *secdata;
iattrs->ia_secdata_len = *secdata_len;
*secdata = old_secdata;
*secdata_len = old_secdata_len;
return 0;
}
int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value,
size_t size, int flags) size_t size, int flags)
{ {
struct sysfs_dirent *sd = dentry->d_fsdata; struct sysfs_dirent *sd = dentry->d_fsdata;
struct sysfs_inode_attrs *iattrs;
void *secdata; void *secdata;
int error; int error;
u32 secdata_len = 0; u32 secdata_len = 0;
if (!sd) if (!sd)
return -EINVAL; return -EINVAL;
if (!sd->s_iattr)
sd->s_iattr = sysfs_init_inode_attrs(sd);
if (!sd->s_iattr)
return -ENOMEM;
iattrs = sd->s_iattr;
if (!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN)) { if (!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN)) {
const char *suffix = name + XATTR_SECURITY_PREFIX_LEN; const char *suffix = name + XATTR_SECURITY_PREFIX_LEN;
...@@ -150,12 +173,13 @@ int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, ...@@ -150,12 +173,13 @@ int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value,
&secdata, &secdata_len); &secdata, &secdata_len);
if (error) if (error)
goto out; goto out;
if (iattrs->ia_secdata)
security_release_secctx(iattrs->ia_secdata,
iattrs->ia_secdata_len);
iattrs->ia_secdata = secdata;
iattrs->ia_secdata_len = secdata_len;
mutex_lock(&sysfs_mutex);
error = sysfs_sd_setsecdata(sd, &secdata, &secdata_len);
mutex_unlock(&sysfs_mutex);
if (secdata)
security_release_secctx(secdata, secdata_len);
} else } else
return -EINVAL; return -EINVAL;
out: out:
...@@ -170,7 +194,6 @@ static inline void set_default_inode_attr(struct inode * inode, mode_t mode) ...@@ -170,7 +194,6 @@ static inline void set_default_inode_attr(struct inode * inode, mode_t mode)
static inline void set_inode_attr(struct inode * inode, struct iattr * iattr) static inline void set_inode_attr(struct inode * inode, struct iattr * iattr)
{ {
inode->i_mode = iattr->ia_mode;
inode->i_uid = iattr->ia_uid; inode->i_uid = iattr->ia_uid;
inode->i_gid = iattr->ia_gid; inode->i_gid = iattr->ia_gid;
inode->i_atime = iattr->ia_atime; inode->i_atime = iattr->ia_atime;
...@@ -178,17 +201,6 @@ static inline void set_inode_attr(struct inode * inode, struct iattr * iattr) ...@@ -178,17 +201,6 @@ static inline void set_inode_attr(struct inode * inode, struct iattr * iattr)
inode->i_ctime = iattr->ia_ctime; inode->i_ctime = iattr->ia_ctime;
} }
/*
* sysfs has a different i_mutex lock order behavior for i_mutex than other
* filesystems; sysfs i_mutex is called in many places with subsystem locks
* held. At the same time, many of the VFS locking rules do not apply to
* sysfs at all (cross directory rename for example). To untangle this mess
* (which gives false positives in lockdep), we're giving sysfs inodes their
* own class for i_mutex.
*/
static struct lock_class_key sysfs_inode_imutex_key;
static int sysfs_count_nlink(struct sysfs_dirent *sd) static int sysfs_count_nlink(struct sysfs_dirent *sd)
{ {
struct sysfs_dirent *child; struct sysfs_dirent *child;
...@@ -201,38 +213,55 @@ static int sysfs_count_nlink(struct sysfs_dirent *sd) ...@@ -201,38 +213,55 @@ static int sysfs_count_nlink(struct sysfs_dirent *sd)
return nr + 2; return nr + 2;
} }
static void sysfs_refresh_inode(struct sysfs_dirent *sd, struct inode *inode)
{
struct sysfs_inode_attrs *iattrs = sd->s_iattr;
inode->i_mode = sd->s_mode;
if (iattrs) {
/* sysfs_dirent has non-default attributes
* get them from persistent copy in sysfs_dirent
*/
set_inode_attr(inode, &iattrs->ia_iattr);
security_inode_notifysecctx(inode,
iattrs->ia_secdata,
iattrs->ia_secdata_len);
}
if (sysfs_type(sd) == SYSFS_DIR)
inode->i_nlink = sysfs_count_nlink(sd);
}
int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
{
struct sysfs_dirent *sd = dentry->d_fsdata;
struct inode *inode = dentry->d_inode;
mutex_lock(&sysfs_mutex);
sysfs_refresh_inode(sd, inode);
mutex_unlock(&sysfs_mutex);
generic_fillattr(inode, stat);
return 0;
}
static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)
{ {
struct bin_attribute *bin_attr; struct bin_attribute *bin_attr;
struct sysfs_inode_attrs *iattrs;
inode->i_private = sysfs_get(sd); inode->i_private = sysfs_get(sd);
inode->i_mapping->a_ops = &sysfs_aops; inode->i_mapping->a_ops = &sysfs_aops;
inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info; inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info;
inode->i_op = &sysfs_inode_operations; inode->i_op = &sysfs_inode_operations;
inode->i_ino = sd->s_ino;
lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key);
iattrs = sd->s_iattr; set_default_inode_attr(inode, sd->s_mode);
if (iattrs) { sysfs_refresh_inode(sd, inode);
/* sysfs_dirent has non-default attributes
* get them for the new inode from persistent copy
* in sysfs_dirent
*/
set_inode_attr(inode, &iattrs->ia_iattr);
if (iattrs->ia_secdata)
security_inode_notifysecctx(inode,
iattrs->ia_secdata,
iattrs->ia_secdata_len);
} else
set_default_inode_attr(inode, sd->s_mode);
/* initialize inode according to type */ /* initialize inode according to type */
switch (sysfs_type(sd)) { switch (sysfs_type(sd)) {
case SYSFS_DIR: case SYSFS_DIR:
inode->i_op = &sysfs_dir_inode_operations; inode->i_op = &sysfs_dir_inode_operations;
inode->i_fop = &sysfs_dir_operations; inode->i_fop = &sysfs_dir_operations;
inode->i_nlink = sysfs_count_nlink(sd);
break; break;
case SYSFS_KOBJ_ATTR: case SYSFS_KOBJ_ATTR:
inode->i_size = PAGE_SIZE; inode->i_size = PAGE_SIZE;
...@@ -315,3 +344,14 @@ int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name) ...@@ -315,3 +344,14 @@ int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name)
else else
return -ENOENT; return -ENOENT;
} }
int sysfs_permission(struct inode *inode, int mask)
{
struct sysfs_dirent *sd = inode->i_private;
mutex_lock(&sysfs_mutex);
sysfs_refresh_inode(sd, inode);
mutex_unlock(&sysfs_mutex);
return generic_permission(inode, mask, NULL);
}
...@@ -210,10 +210,13 @@ static void sysfs_put_link(struct dentry *dentry, struct nameidata *nd, void *co ...@@ -210,10 +210,13 @@ static void sysfs_put_link(struct dentry *dentry, struct nameidata *nd, void *co
} }
const struct inode_operations sysfs_symlink_inode_operations = { const struct inode_operations sysfs_symlink_inode_operations = {
.setxattr = sysfs_setxattr, .setxattr = sysfs_setxattr,
.readlink = generic_readlink, .readlink = generic_readlink,
.follow_link = sysfs_follow_link, .follow_link = sysfs_follow_link,
.put_link = sysfs_put_link, .put_link = sysfs_put_link,
.setattr = sysfs_setattr,
.getattr = sysfs_getattr,
.permission = sysfs_permission,
}; };
......
...@@ -89,9 +89,7 @@ static inline unsigned int sysfs_type(struct sysfs_dirent *sd) ...@@ -89,9 +89,7 @@ static inline unsigned int sysfs_type(struct sysfs_dirent *sd)
*/ */
struct sysfs_addrm_cxt { struct sysfs_addrm_cxt {
struct sysfs_dirent *parent_sd; struct sysfs_dirent *parent_sd;
struct inode *parent_inode;
struct sysfs_dirent *removed; struct sysfs_dirent *removed;
int cnt;
}; };
/* /*
...@@ -105,7 +103,6 @@ extern struct kmem_cache *sysfs_dir_cachep; ...@@ -105,7 +103,6 @@ extern struct kmem_cache *sysfs_dir_cachep;
* dir.c * dir.c
*/ */
extern struct mutex sysfs_mutex; extern struct mutex sysfs_mutex;
extern struct mutex sysfs_rename_mutex;
extern spinlock_t sysfs_assoc_lock; extern spinlock_t sysfs_assoc_lock;
extern const struct file_operations sysfs_dir_operations; extern const struct file_operations sysfs_dir_operations;
...@@ -133,6 +130,9 @@ int sysfs_create_subdir(struct kobject *kobj, const char *name, ...@@ -133,6 +130,9 @@ int sysfs_create_subdir(struct kobject *kobj, const char *name,
struct sysfs_dirent **p_sd); struct sysfs_dirent **p_sd);
void sysfs_remove_subdir(struct sysfs_dirent *sd); void sysfs_remove_subdir(struct sysfs_dirent *sd);
int sysfs_rename(struct sysfs_dirent *sd,
struct sysfs_dirent *new_parent_sd, const char *new_name);
static inline struct sysfs_dirent *__sysfs_get(struct sysfs_dirent *sd) static inline struct sysfs_dirent *__sysfs_get(struct sysfs_dirent *sd)
{ {
if (sd) { if (sd) {
...@@ -155,7 +155,10 @@ static inline void __sysfs_put(struct sysfs_dirent *sd) ...@@ -155,7 +155,10 @@ static inline void __sysfs_put(struct sysfs_dirent *sd)
*/ */
struct inode *sysfs_get_inode(struct sysfs_dirent *sd); struct inode *sysfs_get_inode(struct sysfs_dirent *sd);
void sysfs_delete_inode(struct inode *inode); void sysfs_delete_inode(struct inode *inode);
int sysfs_sd_setattr(struct sysfs_dirent *sd, struct iattr *iattr);
int sysfs_permission(struct inode *inode, int mask);
int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); int sysfs_setattr(struct dentry *dentry, struct iattr *iattr);
int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat);
int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value,
size_t size, int flags); size_t size, int flags);
int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name); int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name);
......
...@@ -558,7 +558,7 @@ extern void wait_for_device_probe(void); ...@@ -558,7 +558,7 @@ extern void wait_for_device_probe(void);
#ifdef CONFIG_DEVTMPFS #ifdef CONFIG_DEVTMPFS
extern int devtmpfs_create_node(struct device *dev); extern int devtmpfs_create_node(struct device *dev);
extern int devtmpfs_delete_node(struct device *dev); extern int devtmpfs_delete_node(struct device *dev);
extern int devtmpfs_mount(const char *mountpoint); extern int devtmpfs_mount(const char *mntdir);
#else #else
static inline int devtmpfs_create_node(struct device *dev) { return 0; } static inline int devtmpfs_create_node(struct device *dev) { return 0; }
static inline int devtmpfs_delete_node(struct device *dev) { return 0; } static inline int devtmpfs_delete_node(struct device *dev) { return 0; }
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/gfp.h>
#define FW_ACTION_NOHOTPLUG 0 #define FW_ACTION_NOHOTPLUG 0
#define FW_ACTION_HOTPLUG 1 #define FW_ACTION_HOTPLUG 1
...@@ -38,7 +39,7 @@ int request_firmware(const struct firmware **fw, const char *name, ...@@ -38,7 +39,7 @@ int request_firmware(const struct firmware **fw, const char *name,
struct device *device); struct device *device);
int request_firmware_nowait( int request_firmware_nowait(
struct module *module, int uevent, struct module *module, int uevent,
const char *name, struct device *device, void *context, const char *name, struct device *device, gfp_t gfp, void *context,
void (*cont)(const struct firmware *fw, void *context)); void (*cont)(const struct firmware *fw, void *context));
void release_firmware(const struct firmware *fw); void release_firmware(const struct firmware *fw);
...@@ -51,7 +52,7 @@ static inline int request_firmware(const struct firmware **fw, ...@@ -51,7 +52,7 @@ static inline int request_firmware(const struct firmware **fw,
} }
static inline int request_firmware_nowait( static inline int request_firmware_nowait(
struct module *module, int uevent, struct module *module, int uevent,
const char *name, struct device *device, void *context, const char *name, struct device *device, gfp_t gfp, void *context,
void (*cont)(const struct firmware *fw, void *context)) void (*cont)(const struct firmware *fw, void *context))
{ {
return -EINVAL; return -EINVAL;
......
...@@ -76,7 +76,6 @@ extern struct file *nameidata_to_filp(struct nameidata *nd, int flags); ...@@ -76,7 +76,6 @@ extern struct file *nameidata_to_filp(struct nameidata *nd, int flags);
extern void release_open_intent(struct nameidata *); extern void release_open_intent(struct nameidata *);
extern struct dentry *lookup_one_len(const char *, struct dentry *, int); extern struct dentry *lookup_one_len(const char *, struct dentry *, int);
extern struct dentry *lookup_one_noperm(const char *, struct dentry *);
extern int follow_down(struct path *); extern int follow_down(struct path *);
extern int follow_up(struct path *); extern int follow_up(struct path *);
......
...@@ -83,6 +83,8 @@ struct early_platform_driver { ...@@ -83,6 +83,8 @@ struct early_platform_driver {
struct platform_driver *pdrv; struct platform_driver *pdrv;
struct list_head list; struct list_head list;
int requested_id; int requested_id;
char *buffer;
int bufsize;
}; };
#define EARLY_PLATFORM_ID_UNSET -2 #define EARLY_PLATFORM_ID_UNSET -2
...@@ -102,21 +104,29 @@ extern int early_platform_driver_probe(char *class_str, ...@@ -102,21 +104,29 @@ extern int early_platform_driver_probe(char *class_str,
int nr_probe, int user_only); int nr_probe, int user_only);
extern void early_platform_cleanup(void); extern void early_platform_cleanup(void);
#define early_platform_init(class_string, platdrv) \
early_platform_init_buffer(class_string, platdrv, NULL, 0)
#ifndef MODULE #ifndef MODULE
#define early_platform_init(class_string, platform_driver) \ #define early_platform_init_buffer(class_string, platdrv, buf, bufsiz) \
static __initdata struct early_platform_driver early_driver = { \ static __initdata struct early_platform_driver early_driver = { \
.class_str = class_string, \ .class_str = class_string, \
.pdrv = platform_driver, \ .buffer = buf, \
.bufsize = bufsiz, \
.pdrv = platdrv, \
.requested_id = EARLY_PLATFORM_ID_UNSET, \ .requested_id = EARLY_PLATFORM_ID_UNSET, \
}; \ }; \
static int __init early_platform_driver_setup_func(char *buf) \ static int __init early_platform_driver_setup_func(char *buffer) \
{ \ { \
return early_platform_driver_register(&early_driver, buf); \ return early_platform_driver_register(&early_driver, buffer); \
} \ } \
early_param(class_string, early_platform_driver_setup_func) early_param(class_string, early_platform_driver_setup_func)
#else /* MODULE */ #else /* MODULE */
#define early_platform_init(class_string, platform_driver) #define early_platform_init_buffer(class_string, platdrv, buf, bufsiz) \
static inline char *early_platform_driver_setup_func(void) \
{ \
return bufsiz ? buf : NULL; \
}
#endif /* MODULE */ #endif /* MODULE */
#endif /* _PLATFORM_DEVICE_H_ */ #endif /* _PLATFORM_DEVICE_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment