diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-11 18:24:56 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-11 18:24:56 -0500 |
| commit | f58df54a54451c5feb2fdc4bc2f4fb12cf79be01 (patch) | |
| tree | 930b5892717ce84de93508407ebc35757bbc5ea0 | |
| parent | 748e566b7e24541e05e3e70be311887a1262f2a1 (diff) | |
| parent | 3589972e51fac1e02d0aaa576fa47f568cb94d40 (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: (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
...
| -rw-r--r-- | drivers/base/core.c | 14 | ||||
| -rw-r--r-- | drivers/base/devtmpfs.c | 100 | ||||
| -rw-r--r-- | drivers/base/firmware_class.c | 14 | ||||
| -rw-r--r-- | drivers/base/platform.c | 29 | ||||
| -rw-r--r-- | drivers/firmware/dell_rbu.c | 9 | ||||
| -rw-r--r-- | drivers/misc/hpilo.h | 13 | ||||
| -rw-r--r-- | drivers/serial/ucc_uart.c | 8 | ||||
| -rw-r--r-- | drivers/staging/comedi/drivers/usbdux.c | 5 | ||||
| -rw-r--r-- | drivers/staging/comedi/drivers/usbduxfast.c | 5 | ||||
| -rw-r--r-- | drivers/usb/atm/ueagle-atm.c | 7 | ||||
| -rw-r--r-- | fs/debugfs/inode.c | 55 | ||||
| -rw-r--r-- | fs/namei.c | 22 | ||||
| -rw-r--r-- | fs/sysfs/dir.c | 388 | ||||
| -rw-r--r-- | fs/sysfs/file.c | 41 | ||||
| -rw-r--r-- | fs/sysfs/inode.c | 176 | ||||
| -rw-r--r-- | fs/sysfs/symlink.c | 11 | ||||
| -rw-r--r-- | fs/sysfs/sysfs.h | 9 | ||||
| -rw-r--r-- | include/linux/device.h | 2 | ||||
| -rw-r--r-- | include/linux/firmware.h | 5 | ||||
| -rw-r--r-- | include/linux/namei.h | 1 | ||||
| -rw-r--r-- | include/linux/platform_device.h | 20 |
21 files changed, 428 insertions, 506 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c index 6bee6af8d8e1..f1290cbd1350 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c | |||
| @@ -56,7 +56,14 @@ static inline int device_is_not_partition(struct device *dev) | |||
| 56 | */ | 56 | */ |
| 57 | const char *dev_driver_string(const struct device *dev) | 57 | const char *dev_driver_string(const struct device *dev) |
| 58 | { | 58 | { |
| 59 | return dev->driver ? dev->driver->name : | 59 | struct device_driver *drv; |
| 60 | |||
| 61 | /* dev->driver can change to NULL underneath us because of unbinding, | ||
| 62 | * so be careful about accessing it. dev->bus and dev->class should | ||
| 63 | * never change once they are set, so they don't need special care. | ||
| 64 | */ | ||
| 65 | drv = ACCESS_ONCE(dev->driver); | ||
| 66 | return drv ? drv->name : | ||
| 60 | (dev->bus ? dev->bus->name : | 67 | (dev->bus ? dev->bus->name : |
| 61 | (dev->class ? dev->class->name : "")); | 68 | (dev->class ? dev->class->name : "")); |
| 62 | } | 69 | } |
| @@ -987,6 +994,8 @@ done: | |||
| 987 | device_remove_class_symlinks(dev); | 994 | device_remove_class_symlinks(dev); |
| 988 | SymlinkError: | 995 | SymlinkError: |
| 989 | if (MAJOR(dev->devt)) | 996 | if (MAJOR(dev->devt)) |
| 997 | devtmpfs_delete_node(dev); | ||
| 998 | if (MAJOR(dev->devt)) | ||
| 990 | device_remove_sys_dev_entry(dev); | 999 | device_remove_sys_dev_entry(dev); |
| 991 | devtattrError: | 1000 | devtattrError: |
| 992 | if (MAJOR(dev->devt)) | 1001 | if (MAJOR(dev->devt)) |
| @@ -1728,8 +1737,5 @@ void device_shutdown(void) | |||
| 1728 | dev->driver->shutdown(dev); | 1737 | dev->driver->shutdown(dev); |
| 1729 | } | 1738 | } |
| 1730 | } | 1739 | } |
| 1731 | kobject_put(sysfs_dev_char_kobj); | ||
| 1732 | kobject_put(sysfs_dev_block_kobj); | ||
| 1733 | kobject_put(dev_kobj); | ||
| 1734 | async_synchronize_full(); | 1740 | async_synchronize_full(); |
| 1735 | } | 1741 | } |
diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c index a1cb5afe6801..50375bb8e51d 100644 --- a/drivers/base/devtmpfs.c +++ b/drivers/base/devtmpfs.c | |||
| @@ -32,6 +32,8 @@ static int dev_mount = 1; | |||
| 32 | static int dev_mount; | 32 | static int dev_mount; |
| 33 | #endif | 33 | #endif |
| 34 | 34 | ||
| 35 | static rwlock_t dirlock; | ||
| 36 | |||
| 35 | static int __init mount_param(char *str) | 37 | static int __init mount_param(char *str) |
| 36 | { | 38 | { |
| 37 | dev_mount = simple_strtoul(str, NULL, 0); | 39 | dev_mount = simple_strtoul(str, NULL, 0); |
| @@ -74,47 +76,35 @@ static int dev_mkdir(const char *name, mode_t mode) | |||
| 74 | dentry = lookup_create(&nd, 1); | 76 | dentry = lookup_create(&nd, 1); |
| 75 | if (!IS_ERR(dentry)) { | 77 | if (!IS_ERR(dentry)) { |
| 76 | err = vfs_mkdir(nd.path.dentry->d_inode, dentry, mode); | 78 | err = vfs_mkdir(nd.path.dentry->d_inode, dentry, mode); |
| 79 | if (!err) | ||
| 80 | /* mark as kernel-created inode */ | ||
| 81 | dentry->d_inode->i_private = &dev_mnt; | ||
| 77 | dput(dentry); | 82 | dput(dentry); |
| 78 | } else { | 83 | } else { |
| 79 | err = PTR_ERR(dentry); | 84 | err = PTR_ERR(dentry); |
| 80 | } | 85 | } |
| 81 | mutex_unlock(&nd.path.dentry->d_inode->i_mutex); | ||
| 82 | 86 | ||
| 87 | mutex_unlock(&nd.path.dentry->d_inode->i_mutex); | ||
| 83 | path_put(&nd.path); | 88 | path_put(&nd.path); |
| 84 | return err; | 89 | return err; |
| 85 | } | 90 | } |
| 86 | 91 | ||
| 87 | static int create_path(const char *nodepath) | 92 | static int create_path(const char *nodepath) |
| 88 | { | 93 | { |
| 89 | char *path; | 94 | int err; |
| 90 | struct nameidata nd; | ||
| 91 | int err = 0; | ||
| 92 | |||
| 93 | path = kstrdup(nodepath, GFP_KERNEL); | ||
| 94 | if (!path) | ||
| 95 | return -ENOMEM; | ||
| 96 | |||
| 97 | err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, | ||
| 98 | path, LOOKUP_PARENT, &nd); | ||
| 99 | if (err == 0) { | ||
| 100 | struct dentry *dentry; | ||
| 101 | |||
| 102 | /* create directory right away */ | ||
| 103 | dentry = lookup_create(&nd, 1); | ||
| 104 | if (!IS_ERR(dentry)) { | ||
| 105 | err = vfs_mkdir(nd.path.dentry->d_inode, | ||
| 106 | dentry, 0755); | ||
| 107 | dput(dentry); | ||
| 108 | } | ||
| 109 | mutex_unlock(&nd.path.dentry->d_inode->i_mutex); | ||
| 110 | 95 | ||
| 111 | path_put(&nd.path); | 96 | read_lock(&dirlock); |
| 112 | } else if (err == -ENOENT) { | 97 | err = dev_mkdir(nodepath, 0755); |
| 98 | if (err == -ENOENT) { | ||
| 99 | char *path; | ||
| 113 | char *s; | 100 | char *s; |
| 114 | 101 | ||
| 115 | /* parent directories do not exist, create them */ | 102 | /* parent directories do not exist, create them */ |
| 103 | path = kstrdup(nodepath, GFP_KERNEL); | ||
| 104 | if (!path) | ||
| 105 | return -ENOMEM; | ||
| 116 | s = path; | 106 | s = path; |
| 117 | while (1) { | 107 | for (;;) { |
| 118 | s = strchr(s, '/'); | 108 | s = strchr(s, '/'); |
| 119 | if (!s) | 109 | if (!s) |
| 120 | break; | 110 | break; |
| @@ -125,9 +115,9 @@ static int create_path(const char *nodepath) | |||
| 125 | s[0] = '/'; | 115 | s[0] = '/'; |
| 126 | s++; | 116 | s++; |
| 127 | } | 117 | } |
| 118 | kfree(path); | ||
| 128 | } | 119 | } |
| 129 | 120 | read_unlock(&dirlock); | |
| 130 | kfree(path); | ||
| 131 | return err; | 121 | return err; |
| 132 | } | 122 | } |
| 133 | 123 | ||
| @@ -156,34 +146,40 @@ int devtmpfs_create_node(struct device *dev) | |||
| 156 | mode |= S_IFCHR; | 146 | mode |= S_IFCHR; |
| 157 | 147 | ||
| 158 | curr_cred = override_creds(&init_cred); | 148 | curr_cred = override_creds(&init_cred); |
| 149 | |||
| 159 | err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, | 150 | err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, |
| 160 | nodename, LOOKUP_PARENT, &nd); | 151 | nodename, LOOKUP_PARENT, &nd); |
| 161 | if (err == -ENOENT) { | 152 | if (err == -ENOENT) { |
| 162 | /* create missing parent directories */ | ||
| 163 | create_path(nodename); | 153 | create_path(nodename); |
| 164 | err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, | 154 | err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, |
| 165 | nodename, LOOKUP_PARENT, &nd); | 155 | nodename, LOOKUP_PARENT, &nd); |
| 166 | if (err) | ||
| 167 | goto out; | ||
| 168 | } | 156 | } |
| 157 | if (err) | ||
| 158 | goto out; | ||
| 169 | 159 | ||
| 170 | dentry = lookup_create(&nd, 0); | 160 | dentry = lookup_create(&nd, 0); |
| 171 | if (!IS_ERR(dentry)) { | 161 | if (!IS_ERR(dentry)) { |
| 172 | int umask; | ||
| 173 | |||
| 174 | umask = sys_umask(0000); | ||
| 175 | err = vfs_mknod(nd.path.dentry->d_inode, | 162 | err = vfs_mknod(nd.path.dentry->d_inode, |
| 176 | dentry, mode, dev->devt); | 163 | dentry, mode, dev->devt); |
| 177 | sys_umask(umask); | 164 | if (!err) { |
| 178 | /* mark as kernel created inode */ | 165 | struct iattr newattrs; |
| 179 | if (!err) | 166 | |
| 167 | /* fixup possibly umasked mode */ | ||
| 168 | newattrs.ia_mode = mode; | ||
| 169 | newattrs.ia_valid = ATTR_MODE; | ||
| 170 | mutex_lock(&dentry->d_inode->i_mutex); | ||
| 171 | notify_change(dentry, &newattrs); | ||
| 172 | mutex_unlock(&dentry->d_inode->i_mutex); | ||
| 173 | |||
| 174 | /* mark as kernel-created inode */ | ||
| 180 | dentry->d_inode->i_private = &dev_mnt; | 175 | dentry->d_inode->i_private = &dev_mnt; |
| 176 | } | ||
| 181 | dput(dentry); | 177 | dput(dentry); |
| 182 | } else { | 178 | } else { |
| 183 | err = PTR_ERR(dentry); | 179 | err = PTR_ERR(dentry); |
| 184 | } | 180 | } |
| 185 | mutex_unlock(&nd.path.dentry->d_inode->i_mutex); | ||
| 186 | 181 | ||
| 182 | mutex_unlock(&nd.path.dentry->d_inode->i_mutex); | ||
| 187 | path_put(&nd.path); | 183 | path_put(&nd.path); |
| 188 | out: | 184 | out: |
| 189 | kfree(tmp); | 185 | kfree(tmp); |
| @@ -205,16 +201,21 @@ static int dev_rmdir(const char *name) | |||
| 205 | mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT); | 201 | mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT); |
| 206 | dentry = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len); | 202 | dentry = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len); |
| 207 | if (!IS_ERR(dentry)) { | 203 | if (!IS_ERR(dentry)) { |
| 208 | if (dentry->d_inode) | 204 | if (dentry->d_inode) { |
| 209 | err = vfs_rmdir(nd.path.dentry->d_inode, dentry); | 205 | if (dentry->d_inode->i_private == &dev_mnt) |
| 210 | else | 206 | err = vfs_rmdir(nd.path.dentry->d_inode, |
| 207 | dentry); | ||
| 208 | else | ||
| 209 | err = -EPERM; | ||
| 210 | } else { | ||
| 211 | err = -ENOENT; | 211 | err = -ENOENT; |
| 212 | } | ||
| 212 | dput(dentry); | 213 | dput(dentry); |
| 213 | } else { | 214 | } else { |
| 214 | err = PTR_ERR(dentry); | 215 | err = PTR_ERR(dentry); |
| 215 | } | 216 | } |
| 216 | mutex_unlock(&nd.path.dentry->d_inode->i_mutex); | ||
| 217 | 217 | ||
| 218 | mutex_unlock(&nd.path.dentry->d_inode->i_mutex); | ||
| 218 | path_put(&nd.path); | 219 | path_put(&nd.path); |
| 219 | return err; | 220 | return err; |
| 220 | } | 221 | } |
| @@ -228,7 +229,8 @@ static int delete_path(const char *nodepath) | |||
| 228 | if (!path) | 229 | if (!path) |
| 229 | return -ENOMEM; | 230 | return -ENOMEM; |
| 230 | 231 | ||
| 231 | while (1) { | 232 | write_lock(&dirlock); |
| 233 | for (;;) { | ||
| 232 | char *base; | 234 | char *base; |
| 233 | 235 | ||
| 234 | base = strrchr(path, '/'); | 236 | base = strrchr(path, '/'); |
| @@ -239,6 +241,7 @@ static int delete_path(const char *nodepath) | |||
| 239 | if (err) | 241 | if (err) |
| 240 | break; | 242 | break; |
| 241 | } | 243 | } |
| 244 | write_unlock(&dirlock); | ||
| 242 | 245 | ||
| 243 | kfree(path); | 246 | kfree(path); |
| 244 | return err; | 247 | return err; |
| @@ -322,9 +325,8 @@ out: | |||
| 322 | * If configured, or requested by the commandline, devtmpfs will be | 325 | * If configured, or requested by the commandline, devtmpfs will be |
| 323 | * auto-mounted after the kernel mounted the root filesystem. | 326 | * auto-mounted after the kernel mounted the root filesystem. |
| 324 | */ | 327 | */ |
| 325 | int devtmpfs_mount(const char *mountpoint) | 328 | int devtmpfs_mount(const char *mntdir) |
| 326 | { | 329 | { |
| 327 | struct path path; | ||
| 328 | int err; | 330 | int err; |
| 329 | 331 | ||
| 330 | if (!dev_mount) | 332 | if (!dev_mount) |
| @@ -333,15 +335,11 @@ int devtmpfs_mount(const char *mountpoint) | |||
| 333 | if (!dev_mnt) | 335 | if (!dev_mnt) |
| 334 | return 0; | 336 | return 0; |
| 335 | 337 | ||
| 336 | err = kern_path(mountpoint, LOOKUP_FOLLOW, &path); | 338 | err = sys_mount("devtmpfs", (char *)mntdir, "devtmpfs", MS_SILENT, NULL); |
| 337 | if (err) | ||
| 338 | return err; | ||
| 339 | err = do_add_mount(dev_mnt, &path, 0, NULL); | ||
| 340 | if (err) | 339 | if (err) |
| 341 | printk(KERN_INFO "devtmpfs: error mounting %i\n", err); | 340 | printk(KERN_INFO "devtmpfs: error mounting %i\n", err); |
| 342 | else | 341 | else |
| 343 | printk(KERN_INFO "devtmpfs: mounted\n"); | 342 | printk(KERN_INFO "devtmpfs: mounted\n"); |
| 344 | path_put(&path); | ||
| 345 | return err; | 343 | return err; |
| 346 | } | 344 | } |
| 347 | 345 | ||
| @@ -354,6 +352,8 @@ int __init devtmpfs_init(void) | |||
| 354 | int err; | 352 | int err; |
| 355 | struct vfsmount *mnt; | 353 | struct vfsmount *mnt; |
| 356 | 354 | ||
| 355 | rwlock_init(&dirlock); | ||
| 356 | |||
| 357 | err = register_filesystem(&dev_fs_type); | 357 | err = register_filesystem(&dev_fs_type); |
| 358 | if (err) { | 358 | if (err) { |
| 359 | printk(KERN_ERR "devtmpfs: unable to register devtmpfs " | 359 | printk(KERN_ERR "devtmpfs: unable to register devtmpfs " |
| @@ -361,7 +361,7 @@ int __init devtmpfs_init(void) | |||
| 361 | return err; | 361 | return err; |
| 362 | } | 362 | } |
| 363 | 363 | ||
| 364 | mnt = kern_mount(&dev_fs_type); | 364 | mnt = kern_mount_data(&dev_fs_type, "mode=0755"); |
| 365 | if (IS_ERR(mnt)) { | 365 | if (IS_ERR(mnt)) { |
| 366 | err = PTR_ERR(mnt); | 366 | err = PTR_ERR(mnt); |
| 367 | printk(KERN_ERR "devtmpfs: unable to create devtmpfs %i\n", err); | 367 | printk(KERN_ERR "devtmpfs: unable to create devtmpfs %i\n", err); |
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 7376367bcb80..a95024166b66 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c | |||
| @@ -601,12 +601,9 @@ request_firmware_work_func(void *arg) | |||
| 601 | } | 601 | } |
| 602 | ret = _request_firmware(&fw, fw_work->name, fw_work->device, | 602 | ret = _request_firmware(&fw, fw_work->name, fw_work->device, |
| 603 | fw_work->uevent); | 603 | fw_work->uevent); |
| 604 | if (ret < 0) | 604 | |
| 605 | fw_work->cont(NULL, fw_work->context); | 605 | fw_work->cont(fw, fw_work->context); |
| 606 | else { | 606 | |
| 607 | fw_work->cont(fw, fw_work->context); | ||
| 608 | release_firmware(fw); | ||
| 609 | } | ||
| 610 | module_put(fw_work->module); | 607 | module_put(fw_work->module); |
| 611 | kfree(fw_work); | 608 | kfree(fw_work); |
| 612 | return ret; | 609 | return ret; |
| @@ -619,6 +616,7 @@ request_firmware_work_func(void *arg) | |||
| 619 | * is non-zero else the firmware copy must be done manually. | 616 | * is non-zero else the firmware copy must be done manually. |
| 620 | * @name: name of firmware file | 617 | * @name: name of firmware file |
| 621 | * @device: device for which firmware is being loaded | 618 | * @device: device for which firmware is being loaded |
| 619 | * @gfp: allocation flags | ||
| 622 | * @context: will be passed over to @cont, and | 620 | * @context: will be passed over to @cont, and |
| 623 | * @fw may be %NULL if firmware request fails. | 621 | * @fw may be %NULL if firmware request fails. |
| 624 | * @cont: function will be called asynchronously when the firmware | 622 | * @cont: function will be called asynchronously when the firmware |
| @@ -631,12 +629,12 @@ request_firmware_work_func(void *arg) | |||
| 631 | int | 629 | int |
| 632 | request_firmware_nowait( | 630 | request_firmware_nowait( |
| 633 | struct module *module, int uevent, | 631 | struct module *module, int uevent, |
| 634 | const char *name, struct device *device, void *context, | 632 | const char *name, struct device *device, gfp_t gfp, void *context, |
| 635 | void (*cont)(const struct firmware *fw, void *context)) | 633 | void (*cont)(const struct firmware *fw, void *context)) |
| 636 | { | 634 | { |
| 637 | struct task_struct *task; | 635 | struct task_struct *task; |
| 638 | struct firmware_work *fw_work = kmalloc(sizeof (struct firmware_work), | 636 | struct firmware_work *fw_work = kmalloc(sizeof (struct firmware_work), |
| 639 | GFP_ATOMIC); | 637 | gfp); |
| 640 | 638 | ||
| 641 | if (!fw_work) | 639 | if (!fw_work) |
| 642 | return -ENOMEM; | 640 | return -ENOMEM; |
diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 4fa954b07ac4..9d2ee25deaf5 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c | |||
| @@ -1000,7 +1000,7 @@ static __initdata LIST_HEAD(early_platform_device_list); | |||
| 1000 | int __init early_platform_driver_register(struct early_platform_driver *epdrv, | 1000 | int __init early_platform_driver_register(struct early_platform_driver *epdrv, |
| 1001 | char *buf) | 1001 | char *buf) |
| 1002 | { | 1002 | { |
| 1003 | unsigned long index; | 1003 | char *tmp; |
| 1004 | int n; | 1004 | int n; |
| 1005 | 1005 | ||
| 1006 | /* Simply add the driver to the end of the global list. | 1006 | /* 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 | if (buf && !strncmp(buf, epdrv->pdrv->driver.name, n)) { | 1019 | if (buf && !strncmp(buf, epdrv->pdrv->driver.name, n)) { |
| 1020 | list_move(&epdrv->list, &early_platform_driver_list); | 1020 | list_move(&epdrv->list, &early_platform_driver_list); |
| 1021 | 1021 | ||
| 1022 | if (!strcmp(buf, epdrv->pdrv->driver.name)) | 1022 | /* Allow passing parameters after device name */ |
| 1023 | if (buf[n] == '\0' || buf[n] == ',') | ||
| 1023 | epdrv->requested_id = -1; | 1024 | epdrv->requested_id = -1; |
| 1024 | else if (buf[n] == '.' && strict_strtoul(&buf[n + 1], 10, | 1025 | else { |
| 1025 | &index) == 0) | 1026 | epdrv->requested_id = simple_strtoul(&buf[n + 1], |
| 1026 | epdrv->requested_id = index; | 1027 | &tmp, 10); |
| 1027 | else | 1028 | |
| 1028 | epdrv->requested_id = EARLY_PLATFORM_ID_ERROR; | 1029 | if (buf[n] != '.' || (tmp == &buf[n + 1])) { |
| 1030 | epdrv->requested_id = EARLY_PLATFORM_ID_ERROR; | ||
| 1031 | n = 0; | ||
| 1032 | } else | ||
| 1033 | n += strcspn(&buf[n + 1], ",") + 1; | ||
| 1034 | } | ||
| 1035 | |||
| 1036 | if (buf[n] == ',') | ||
| 1037 | n++; | ||
| 1038 | |||
| 1039 | if (epdrv->bufsize) { | ||
| 1040 | memcpy(epdrv->buffer, &buf[n], | ||
| 1041 | min_t(int, epdrv->bufsize, strlen(&buf[n]) + 1)); | ||
| 1042 | epdrv->buffer[epdrv->bufsize - 1] = '\0'; | ||
| 1043 | } | ||
| 1029 | } | 1044 | } |
| 1030 | 1045 | ||
| 1031 | return 0; | 1046 | return 0; |
diff --git a/drivers/firmware/dell_rbu.c b/drivers/firmware/dell_rbu.c index b4704e150b28..b3a0cf57442e 100644 --- a/drivers/firmware/dell_rbu.c +++ b/drivers/firmware/dell_rbu.c | |||
| @@ -544,9 +544,12 @@ static void callbackfn_rbu(const struct firmware *fw, void *context) | |||
| 544 | { | 544 | { |
| 545 | rbu_data.entry_created = 0; | 545 | rbu_data.entry_created = 0; |
| 546 | 546 | ||
| 547 | if (!fw || !fw->size) | 547 | if (!fw) |
| 548 | return; | 548 | return; |
| 549 | 549 | ||
| 550 | if (!fw->size) | ||
| 551 | goto out; | ||
| 552 | |||
| 550 | spin_lock(&rbu_data.lock); | 553 | spin_lock(&rbu_data.lock); |
| 551 | if (!strcmp(image_type, "mono")) { | 554 | if (!strcmp(image_type, "mono")) { |
| 552 | if (!img_update_realloc(fw->size)) | 555 | if (!img_update_realloc(fw->size)) |
| @@ -568,6 +571,8 @@ static void callbackfn_rbu(const struct firmware *fw, void *context) | |||
| 568 | } else | 571 | } else |
| 569 | pr_debug("invalid image type specified.\n"); | 572 | pr_debug("invalid image type specified.\n"); |
| 570 | spin_unlock(&rbu_data.lock); | 573 | spin_unlock(&rbu_data.lock); |
| 574 | out: | ||
| 575 | release_firmware(fw); | ||
| 571 | } | 576 | } |
| 572 | 577 | ||
| 573 | static ssize_t read_rbu_image_type(struct kobject *kobj, | 578 | 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 | spin_unlock(&rbu_data.lock); | 620 | spin_unlock(&rbu_data.lock); |
| 616 | req_firm_rc = request_firmware_nowait(THIS_MODULE, | 621 | req_firm_rc = request_firmware_nowait(THIS_MODULE, |
| 617 | FW_ACTION_NOHOTPLUG, "dell_rbu", | 622 | FW_ACTION_NOHOTPLUG, "dell_rbu", |
| 618 | &rbu_device->dev, &context, | 623 | &rbu_device->dev, GFP_KERNEL, &context, |
| 619 | callbackfn_rbu); | 624 | callbackfn_rbu); |
| 620 | if (req_firm_rc) { | 625 | if (req_firm_rc) { |
| 621 | printk(KERN_ERR | 626 | printk(KERN_ERR |
diff --git a/drivers/misc/hpilo.h b/drivers/misc/hpilo.h index 38576050776a..247eb386a973 100644 --- a/drivers/misc/hpilo.h +++ b/drivers/misc/hpilo.h | |||
| @@ -44,9 +44,20 @@ struct ilo_hwinfo { | |||
| 44 | 44 | ||
| 45 | struct pci_dev *ilo_dev; | 45 | struct pci_dev *ilo_dev; |
| 46 | 46 | ||
| 47 | /* | ||
| 48 | * open_lock serializes ccb_cnt during open and close | ||
| 49 | * [ irq disabled ] | ||
| 50 | * -> alloc_lock used when adding/removing/searching ccb_alloc, | ||
| 51 | * which represents all ccbs open on the device | ||
| 52 | * --> fifo_lock controls access to fifo queues shared with hw | ||
| 53 | * | ||
| 54 | * Locks must be taken in this order, but open_lock and alloc_lock | ||
| 55 | * are optional, they do not need to be held in order to take a | ||
| 56 | * lower level lock. | ||
| 57 | */ | ||
| 58 | spinlock_t open_lock; | ||
| 47 | spinlock_t alloc_lock; | 59 | spinlock_t alloc_lock; |
| 48 | spinlock_t fifo_lock; | 60 | spinlock_t fifo_lock; |
| 49 | spinlock_t open_lock; | ||
| 50 | 61 | ||
| 51 | struct cdev cdev; | 62 | struct cdev cdev; |
| 52 | }; | 63 | }; |
diff --git a/drivers/serial/ucc_uart.c b/drivers/serial/ucc_uart.c index 46de564aaea0..465f2fae1025 100644 --- a/drivers/serial/ucc_uart.c +++ b/drivers/serial/ucc_uart.c | |||
| @@ -1179,16 +1179,18 @@ static void uart_firmware_cont(const struct firmware *fw, void *context) | |||
| 1179 | 1179 | ||
| 1180 | if (firmware->header.length != fw->size) { | 1180 | if (firmware->header.length != fw->size) { |
| 1181 | dev_err(dev, "invalid firmware\n"); | 1181 | dev_err(dev, "invalid firmware\n"); |
| 1182 | return; | 1182 | goto out; |
| 1183 | } | 1183 | } |
| 1184 | 1184 | ||
| 1185 | ret = qe_upload_firmware(firmware); | 1185 | ret = qe_upload_firmware(firmware); |
| 1186 | if (ret) { | 1186 | if (ret) { |
| 1187 | dev_err(dev, "could not load firmware\n"); | 1187 | dev_err(dev, "could not load firmware\n"); |
| 1188 | return; | 1188 | goto out; |
| 1189 | } | 1189 | } |
| 1190 | 1190 | ||
| 1191 | firmware_loaded = 1; | 1191 | firmware_loaded = 1; |
| 1192 | out: | ||
| 1193 | release_firmware(fw); | ||
| 1192 | } | 1194 | } |
| 1193 | 1195 | ||
| 1194 | static int ucc_uart_probe(struct of_device *ofdev, | 1196 | static int ucc_uart_probe(struct of_device *ofdev, |
| @@ -1247,7 +1249,7 @@ static int ucc_uart_probe(struct of_device *ofdev, | |||
| 1247 | */ | 1249 | */ |
| 1248 | ret = request_firmware_nowait(THIS_MODULE, | 1250 | ret = request_firmware_nowait(THIS_MODULE, |
| 1249 | FW_ACTION_HOTPLUG, filename, &ofdev->dev, | 1251 | FW_ACTION_HOTPLUG, filename, &ofdev->dev, |
| 1250 | &ofdev->dev, uart_firmware_cont); | 1252 | GFP_KERNEL, &ofdev->dev, uart_firmware_cont); |
| 1251 | if (ret) { | 1253 | if (ret) { |
| 1252 | dev_err(&ofdev->dev, | 1254 | dev_err(&ofdev->dev, |
| 1253 | "could not load firmware %s\n", | 1255 | "could not load firmware %s\n", |
diff --git a/drivers/staging/comedi/drivers/usbdux.c b/drivers/staging/comedi/drivers/usbdux.c index cca4e869f0ec..dfcd12bec86b 100644 --- a/drivers/staging/comedi/drivers/usbdux.c +++ b/drivers/staging/comedi/drivers/usbdux.c | |||
| @@ -2327,9 +2327,11 @@ static void usbdux_firmware_request_complete_handler(const struct firmware *fw, | |||
| 2327 | if (ret) { | 2327 | if (ret) { |
| 2328 | dev_err(&usbdev->dev, | 2328 | dev_err(&usbdev->dev, |
| 2329 | "Could not upload firmware (err=%d)\n", ret); | 2329 | "Could not upload firmware (err=%d)\n", ret); |
| 2330 | return; | 2330 | goto out; |
| 2331 | } | 2331 | } |
| 2332 | comedi_usb_auto_config(usbdev, BOARDNAME); | 2332 | comedi_usb_auto_config(usbdev, BOARDNAME); |
| 2333 | out: | ||
| 2334 | release_firmware(fw); | ||
| 2333 | } | 2335 | } |
| 2334 | 2336 | ||
| 2335 | /* allocate memory for the urbs and initialise them */ | 2337 | /* allocate memory for the urbs and initialise them */ |
| @@ -2580,6 +2582,7 @@ static int usbduxsub_probe(struct usb_interface *uinterf, | |||
| 2580 | FW_ACTION_HOTPLUG, | 2582 | FW_ACTION_HOTPLUG, |
| 2581 | "usbdux_firmware.bin", | 2583 | "usbdux_firmware.bin", |
| 2582 | &udev->dev, | 2584 | &udev->dev, |
| 2585 | GFP_KERNEL, | ||
| 2583 | usbduxsub + index, | 2586 | usbduxsub + index, |
| 2584 | usbdux_firmware_request_complete_handler); | 2587 | usbdux_firmware_request_complete_handler); |
| 2585 | 2588 | ||
diff --git a/drivers/staging/comedi/drivers/usbduxfast.c b/drivers/staging/comedi/drivers/usbduxfast.c index d143222579c2..2e675cce7dbf 100644 --- a/drivers/staging/comedi/drivers/usbduxfast.c +++ b/drivers/staging/comedi/drivers/usbduxfast.c | |||
| @@ -1451,10 +1451,12 @@ static void usbduxfast_firmware_request_complete_handler(const struct firmware | |||
| 1451 | if (ret) { | 1451 | if (ret) { |
| 1452 | dev_err(&usbdev->dev, | 1452 | dev_err(&usbdev->dev, |
| 1453 | "Could not upload firmware (err=%d)\n", ret); | 1453 | "Could not upload firmware (err=%d)\n", ret); |
| 1454 | return; | 1454 | goto out; |
| 1455 | } | 1455 | } |
| 1456 | 1456 | ||
| 1457 | comedi_usb_auto_config(usbdev, BOARDNAME); | 1457 | comedi_usb_auto_config(usbdev, BOARDNAME); |
| 1458 | out: | ||
| 1459 | release_firmware(fw); | ||
| 1458 | } | 1460 | } |
| 1459 | 1461 | ||
| 1460 | /* | 1462 | /* |
| @@ -1569,6 +1571,7 @@ static int usbduxfastsub_probe(struct usb_interface *uinterf, | |||
| 1569 | FW_ACTION_HOTPLUG, | 1571 | FW_ACTION_HOTPLUG, |
| 1570 | "usbduxfast_firmware.bin", | 1572 | "usbduxfast_firmware.bin", |
| 1571 | &udev->dev, | 1573 | &udev->dev, |
| 1574 | GFP_KERNEL, | ||
| 1572 | usbduxfastsub + index, | 1575 | usbduxfastsub + index, |
| 1573 | usbduxfast_firmware_request_complete_handler); | 1576 | usbduxfast_firmware_request_complete_handler); |
| 1574 | 1577 | ||
diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index bba4d3eabe0f..c5395246886d 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c | |||
| @@ -667,12 +667,12 @@ static void uea_upload_pre_firmware(const struct firmware *fw_entry, void *conte | |||
| 667 | else | 667 | else |
| 668 | uea_info(usb, "firmware uploaded\n"); | 668 | uea_info(usb, "firmware uploaded\n"); |
| 669 | 669 | ||
| 670 | uea_leaves(usb); | 670 | goto err; |
| 671 | return; | ||
| 672 | 671 | ||
| 673 | err_fw_corrupted: | 672 | err_fw_corrupted: |
| 674 | uea_err(usb, "firmware is corrupted\n"); | 673 | uea_err(usb, "firmware is corrupted\n"); |
| 675 | err: | 674 | err: |
| 675 | release_firmware(fw_entry); | ||
| 676 | uea_leaves(usb); | 676 | uea_leaves(usb); |
| 677 | } | 677 | } |
| 678 | 678 | ||
| @@ -705,7 +705,8 @@ static int uea_load_firmware(struct usb_device *usb, unsigned int ver) | |||
| 705 | break; | 705 | break; |
| 706 | } | 706 | } |
| 707 | 707 | ||
| 708 | ret = request_firmware_nowait(THIS_MODULE, 1, fw_name, &usb->dev, usb, uea_upload_pre_firmware); | 708 | ret = request_firmware_nowait(THIS_MODULE, 1, fw_name, &usb->dev, |
| 709 | GFP_KERNEL, usb, uea_upload_pre_firmware); | ||
| 709 | if (ret) | 710 | if (ret) |
| 710 | uea_err(usb, "firmware %s is not available\n", fw_name); | 711 | uea_err(usb, "firmware %s is not available\n", fw_name); |
| 711 | else | 712 | else |
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 0d23b52dd22c..b486169f42bf 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c | |||
| @@ -32,7 +32,9 @@ static struct vfsmount *debugfs_mount; | |||
| 32 | static int debugfs_mount_count; | 32 | static int debugfs_mount_count; |
| 33 | static bool debugfs_registered; | 33 | static bool debugfs_registered; |
| 34 | 34 | ||
| 35 | static struct inode *debugfs_get_inode(struct super_block *sb, int mode, dev_t dev) | 35 | static struct inode *debugfs_get_inode(struct super_block *sb, int mode, dev_t dev, |
| 36 | void *data, const struct file_operations *fops) | ||
| 37 | |||
| 36 | { | 38 | { |
| 37 | struct inode *inode = new_inode(sb); | 39 | struct inode *inode = new_inode(sb); |
| 38 | 40 | ||
| @@ -44,14 +46,18 @@ static struct inode *debugfs_get_inode(struct super_block *sb, int mode, dev_t d | |||
| 44 | init_special_inode(inode, mode, dev); | 46 | init_special_inode(inode, mode, dev); |
| 45 | break; | 47 | break; |
| 46 | case S_IFREG: | 48 | case S_IFREG: |
| 47 | inode->i_fop = &debugfs_file_operations; | 49 | inode->i_fop = fops ? fops : &debugfs_file_operations; |
| 50 | inode->i_private = data; | ||
| 48 | break; | 51 | break; |
| 49 | case S_IFLNK: | 52 | case S_IFLNK: |
| 50 | inode->i_op = &debugfs_link_operations; | 53 | inode->i_op = &debugfs_link_operations; |
| 54 | inode->i_fop = fops; | ||
| 55 | inode->i_private = data; | ||
| 51 | break; | 56 | break; |
| 52 | case S_IFDIR: | 57 | case S_IFDIR: |
| 53 | inode->i_op = &simple_dir_inode_operations; | 58 | inode->i_op = &simple_dir_inode_operations; |
| 54 | inode->i_fop = &simple_dir_operations; | 59 | inode->i_fop = fops ? fops : &simple_dir_operations; |
| 60 | inode->i_private = data; | ||
| 55 | 61 | ||
| 56 | /* directory inodes start off with i_nlink == 2 | 62 | /* directory inodes start off with i_nlink == 2 |
| 57 | * (for "." entry) */ | 63 | * (for "." entry) */ |
| @@ -64,7 +70,8 @@ static struct inode *debugfs_get_inode(struct super_block *sb, int mode, dev_t d | |||
| 64 | 70 | ||
| 65 | /* SMP-safe */ | 71 | /* SMP-safe */ |
| 66 | static int debugfs_mknod(struct inode *dir, struct dentry *dentry, | 72 | static int debugfs_mknod(struct inode *dir, struct dentry *dentry, |
| 67 | int mode, dev_t dev) | 73 | int mode, dev_t dev, void *data, |
| 74 | const struct file_operations *fops) | ||
| 68 | { | 75 | { |
| 69 | struct inode *inode; | 76 | struct inode *inode; |
| 70 | int error = -EPERM; | 77 | int error = -EPERM; |
| @@ -72,7 +79,7 @@ static int debugfs_mknod(struct inode *dir, struct dentry *dentry, | |||
| 72 | if (dentry->d_inode) | 79 | if (dentry->d_inode) |
| 73 | return -EEXIST; | 80 | return -EEXIST; |
| 74 | 81 | ||
| 75 | inode = debugfs_get_inode(dir->i_sb, mode, dev); | 82 | inode = debugfs_get_inode(dir->i_sb, mode, dev, data, fops); |
| 76 | if (inode) { | 83 | if (inode) { |
| 77 | d_instantiate(dentry, inode); | 84 | d_instantiate(dentry, inode); |
| 78 | dget(dentry); | 85 | dget(dentry); |
| @@ -81,12 +88,13 @@ static int debugfs_mknod(struct inode *dir, struct dentry *dentry, | |||
| 81 | return error; | 88 | return error; |
| 82 | } | 89 | } |
| 83 | 90 | ||
| 84 | static int debugfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | 91 | static int debugfs_mkdir(struct inode *dir, struct dentry *dentry, int mode, |
| 92 | void *data, const struct file_operations *fops) | ||
| 85 | { | 93 | { |
| 86 | int res; | 94 | int res; |
| 87 | 95 | ||
| 88 | mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR; | 96 | mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR; |
| 89 | res = debugfs_mknod(dir, dentry, mode, 0); | 97 | res = debugfs_mknod(dir, dentry, mode, 0, data, fops); |
| 90 | if (!res) { | 98 | if (!res) { |
| 91 | inc_nlink(dir); | 99 | inc_nlink(dir); |
| 92 | fsnotify_mkdir(dir, dentry); | 100 | fsnotify_mkdir(dir, dentry); |
| @@ -94,18 +102,20 @@ static int debugfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
| 94 | return res; | 102 | return res; |
| 95 | } | 103 | } |
| 96 | 104 | ||
| 97 | static int debugfs_link(struct inode *dir, struct dentry *dentry, int mode) | 105 | static int debugfs_link(struct inode *dir, struct dentry *dentry, int mode, |
| 106 | void *data, const struct file_operations *fops) | ||
| 98 | { | 107 | { |
| 99 | mode = (mode & S_IALLUGO) | S_IFLNK; | 108 | mode = (mode & S_IALLUGO) | S_IFLNK; |
| 100 | return debugfs_mknod(dir, dentry, mode, 0); | 109 | return debugfs_mknod(dir, dentry, mode, 0, data, fops); |
| 101 | } | 110 | } |
| 102 | 111 | ||
| 103 | static int debugfs_create(struct inode *dir, struct dentry *dentry, int mode) | 112 | static int debugfs_create(struct inode *dir, struct dentry *dentry, int mode, |
| 113 | void *data, const struct file_operations *fops) | ||
| 104 | { | 114 | { |
| 105 | int res; | 115 | int res; |
| 106 | 116 | ||
| 107 | mode = (mode & S_IALLUGO) | S_IFREG; | 117 | mode = (mode & S_IALLUGO) | S_IFREG; |
| 108 | res = debugfs_mknod(dir, dentry, mode, 0); | 118 | res = debugfs_mknod(dir, dentry, mode, 0, data, fops); |
| 109 | if (!res) | 119 | if (!res) |
| 110 | fsnotify_create(dir, dentry); | 120 | fsnotify_create(dir, dentry); |
| 111 | return res; | 121 | return res; |
| @@ -139,7 +149,9 @@ static struct file_system_type debug_fs_type = { | |||
| 139 | 149 | ||
| 140 | static int debugfs_create_by_name(const char *name, mode_t mode, | 150 | static int debugfs_create_by_name(const char *name, mode_t mode, |
| 141 | struct dentry *parent, | 151 | struct dentry *parent, |
| 142 | struct dentry **dentry) | 152 | struct dentry **dentry, |
| 153 | void *data, | ||
| 154 | const struct file_operations *fops) | ||
| 143 | { | 155 | { |
| 144 | int error = 0; | 156 | int error = 0; |
| 145 | 157 | ||
| @@ -164,13 +176,16 @@ static int debugfs_create_by_name(const char *name, mode_t mode, | |||
| 164 | if (!IS_ERR(*dentry)) { | 176 | if (!IS_ERR(*dentry)) { |
| 165 | switch (mode & S_IFMT) { | 177 | switch (mode & S_IFMT) { |
| 166 | case S_IFDIR: | 178 | case S_IFDIR: |
| 167 | error = debugfs_mkdir(parent->d_inode, *dentry, mode); | 179 | error = debugfs_mkdir(parent->d_inode, *dentry, mode, |
| 180 | data, fops); | ||
| 168 | break; | 181 | break; |
| 169 | case S_IFLNK: | 182 | case S_IFLNK: |
| 170 | error = debugfs_link(parent->d_inode, *dentry, mode); | 183 | error = debugfs_link(parent->d_inode, *dentry, mode, |
| 184 | data, fops); | ||
| 171 | break; | 185 | break; |
| 172 | default: | 186 | default: |
| 173 | error = debugfs_create(parent->d_inode, *dentry, mode); | 187 | error = debugfs_create(parent->d_inode, *dentry, mode, |
| 188 | data, fops); | ||
| 174 | break; | 189 | break; |
| 175 | } | 190 | } |
| 176 | dput(*dentry); | 191 | dput(*dentry); |
| @@ -221,19 +236,13 @@ struct dentry *debugfs_create_file(const char *name, mode_t mode, | |||
| 221 | if (error) | 236 | if (error) |
| 222 | goto exit; | 237 | goto exit; |
| 223 | 238 | ||
| 224 | error = debugfs_create_by_name(name, mode, parent, &dentry); | 239 | error = debugfs_create_by_name(name, mode, parent, &dentry, |
| 240 | data, fops); | ||
| 225 | if (error) { | 241 | if (error) { |
| 226 | dentry = NULL; | 242 | dentry = NULL; |
| 227 | simple_release_fs(&debugfs_mount, &debugfs_mount_count); | 243 | simple_release_fs(&debugfs_mount, &debugfs_mount_count); |
| 228 | goto exit; | 244 | goto exit; |
| 229 | } | 245 | } |
| 230 | |||
| 231 | if (dentry->d_inode) { | ||
| 232 | if (data) | ||
| 233 | dentry->d_inode->i_private = data; | ||
| 234 | if (fops) | ||
| 235 | dentry->d_inode->i_fop = fops; | ||
| 236 | } | ||
| 237 | exit: | 246 | exit: |
| 238 | return dentry; | 247 | return dentry; |
| 239 | } | 248 | } |
diff --git a/fs/namei.c b/fs/namei.c index d11f404667e9..d3c190c35fcc 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
| @@ -1279,28 +1279,6 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len) | |||
| 1279 | return __lookup_hash(&this, base, NULL); | 1279 | return __lookup_hash(&this, base, NULL); |
| 1280 | } | 1280 | } |
| 1281 | 1281 | ||
| 1282 | /** | ||
| 1283 | * lookup_one_noperm - bad hack for sysfs | ||
| 1284 | * @name: pathname component to lookup | ||
| 1285 | * @base: base directory to lookup from | ||
| 1286 | * | ||
| 1287 | * This is a variant of lookup_one_len that doesn't perform any permission | ||
| 1288 | * checks. It's a horrible hack to work around the braindead sysfs | ||
| 1289 | * architecture and should not be used anywhere else. | ||
| 1290 | * | ||
| 1291 | * DON'T USE THIS FUNCTION EVER, thanks. | ||
| 1292 | */ | ||
| 1293 | struct dentry *lookup_one_noperm(const char *name, struct dentry *base) | ||
| 1294 | { | ||
| 1295 | int err; | ||
| 1296 | struct qstr this; | ||
| 1297 | |||
| 1298 | err = __lookup_one_len(name, &this, base, strlen(name)); | ||
| 1299 | if (err) | ||
| 1300 | return ERR_PTR(err); | ||
| 1301 | return __lookup_hash(&this, base, NULL); | ||
| 1302 | } | ||
| 1303 | |||
| 1304 | int user_path_at(int dfd, const char __user *name, unsigned flags, | 1282 | int user_path_at(int dfd, const char __user *name, unsigned flags, |
| 1305 | struct path *path) | 1283 | struct path *path) |
| 1306 | { | 1284 | { |
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index e0201837d244..f05f2303a8b8 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c | |||
| @@ -25,7 +25,6 @@ | |||
| 25 | #include "sysfs.h" | 25 | #include "sysfs.h" |
| 26 | 26 | ||
| 27 | DEFINE_MUTEX(sysfs_mutex); | 27 | DEFINE_MUTEX(sysfs_mutex); |
| 28 | DEFINE_MUTEX(sysfs_rename_mutex); | ||
| 29 | DEFINE_SPINLOCK(sysfs_assoc_lock); | 28 | DEFINE_SPINLOCK(sysfs_assoc_lock); |
| 30 | 29 | ||
| 31 | static DEFINE_SPINLOCK(sysfs_ino_lock); | 30 | static DEFINE_SPINLOCK(sysfs_ino_lock); |
| @@ -85,46 +84,6 @@ static void sysfs_unlink_sibling(struct sysfs_dirent *sd) | |||
| 85 | } | 84 | } |
| 86 | 85 | ||
| 87 | /** | 86 | /** |
| 88 | * sysfs_get_dentry - get dentry for the given sysfs_dirent | ||
| 89 | * @sd: sysfs_dirent of interest | ||
| 90 | * | ||
| 91 | * Get dentry for @sd. Dentry is looked up if currently not | ||
| 92 | * present. This function descends from the root looking up | ||
| 93 | * dentry for each step. | ||
| 94 | * | ||
| 95 | * LOCKING: | ||
| 96 | * mutex_lock(sysfs_rename_mutex) | ||
| 97 | * | ||
| 98 | * RETURNS: | ||
| 99 | * Pointer to found dentry on success, ERR_PTR() value on error. | ||
| 100 | */ | ||
| 101 | struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd) | ||
| 102 | { | ||
| 103 | struct dentry *dentry = dget(sysfs_sb->s_root); | ||
| 104 | |||
| 105 | while (dentry->d_fsdata != sd) { | ||
| 106 | struct sysfs_dirent *cur; | ||
| 107 | struct dentry *parent; | ||
| 108 | |||
| 109 | /* find the first ancestor which hasn't been looked up */ | ||
| 110 | cur = sd; | ||
| 111 | while (cur->s_parent != dentry->d_fsdata) | ||
| 112 | cur = cur->s_parent; | ||
| 113 | |||
| 114 | /* look it up */ | ||
| 115 | parent = dentry; | ||
| 116 | mutex_lock(&parent->d_inode->i_mutex); | ||
| 117 | dentry = lookup_one_noperm(cur->s_name, parent); | ||
| 118 | mutex_unlock(&parent->d_inode->i_mutex); | ||
| 119 | dput(parent); | ||
| 120 | |||
| 121 | if (IS_ERR(dentry)) | ||
| 122 | break; | ||
| 123 | } | ||
| 124 | return dentry; | ||
| 125 | } | ||
| 126 | |||
| 127 | /** | ||
| 128 | * sysfs_get_active - get an active reference to sysfs_dirent | 87 | * sysfs_get_active - get an active reference to sysfs_dirent |
| 129 | * @sd: sysfs_dirent to get an active reference to | 88 | * @sd: sysfs_dirent to get an active reference to |
| 130 | * | 89 | * |
| @@ -298,7 +257,61 @@ void release_sysfs_dirent(struct sysfs_dirent * sd) | |||
| 298 | goto repeat; | 257 | goto repeat; |
| 299 | } | 258 | } |
| 300 | 259 | ||
| 301 | static void sysfs_d_iput(struct dentry * dentry, struct inode * inode) | 260 | static int sysfs_dentry_delete(struct dentry *dentry) |
| 261 | { | ||
| 262 | struct sysfs_dirent *sd = dentry->d_fsdata; | ||
| 263 | return !!(sd->s_flags & SYSFS_FLAG_REMOVED); | ||
| 264 | } | ||
| 265 | |||
| 266 | static int sysfs_dentry_revalidate(struct dentry *dentry, struct nameidata *nd) | ||
| 267 | { | ||
| 268 | struct sysfs_dirent *sd = dentry->d_fsdata; | ||
| 269 | int is_dir; | ||
| 270 | |||
| 271 | mutex_lock(&sysfs_mutex); | ||
| 272 | |||
| 273 | /* The sysfs dirent has been deleted */ | ||
| 274 | if (sd->s_flags & SYSFS_FLAG_REMOVED) | ||
| 275 | goto out_bad; | ||
| 276 | |||
| 277 | /* The sysfs dirent has been moved? */ | ||
| 278 | if (dentry->d_parent->d_fsdata != sd->s_parent) | ||
| 279 | goto out_bad; | ||
| 280 | |||
| 281 | /* The sysfs dirent has been renamed */ | ||
| 282 | if (strcmp(dentry->d_name.name, sd->s_name) != 0) | ||
| 283 | goto out_bad; | ||
| 284 | |||
| 285 | mutex_unlock(&sysfs_mutex); | ||
| 286 | out_valid: | ||
| 287 | return 1; | ||
| 288 | out_bad: | ||
| 289 | /* Remove the dentry from the dcache hashes. | ||
| 290 | * If this is a deleted dentry we use d_drop instead of d_delete | ||
| 291 | * so sysfs doesn't need to cope with negative dentries. | ||
| 292 | * | ||
| 293 | * If this is a dentry that has simply been renamed we | ||
| 294 | * use d_drop to remove it from the dcache lookup on its | ||
| 295 | * old parent. If this dentry persists later when a lookup | ||
| 296 | * is performed at its new name the dentry will be readded | ||
| 297 | * to the dcache hashes. | ||
| 298 | */ | ||
| 299 | is_dir = (sysfs_type(sd) == SYSFS_DIR); | ||
| 300 | mutex_unlock(&sysfs_mutex); | ||
| 301 | if (is_dir) { | ||
| 302 | /* If we have submounts we must allow the vfs caches | ||
| 303 | * to lie about the state of the filesystem to prevent | ||
| 304 | * leaks and other nasty things. | ||
| 305 | */ | ||
| 306 | if (have_submounts(dentry)) | ||
| 307 | goto out_valid; | ||
| 308 | shrink_dcache_parent(dentry); | ||
| 309 | } | ||
| 310 | d_drop(dentry); | ||
| 311 | return 0; | ||
| 312 | } | ||
| 313 | |||
| 314 | static void sysfs_dentry_iput(struct dentry *dentry, struct inode *inode) | ||
| 302 | { | 315 | { |
| 303 | struct sysfs_dirent * sd = dentry->d_fsdata; | 316 | struct sysfs_dirent * sd = dentry->d_fsdata; |
| 304 | 317 | ||
| @@ -307,7 +320,9 @@ static void sysfs_d_iput(struct dentry * dentry, struct inode * inode) | |||
| 307 | } | 320 | } |
| 308 | 321 | ||
| 309 | static const struct dentry_operations sysfs_dentry_ops = { | 322 | static const struct dentry_operations sysfs_dentry_ops = { |
| 310 | .d_iput = sysfs_d_iput, | 323 | .d_revalidate = sysfs_dentry_revalidate, |
| 324 | .d_delete = sysfs_dentry_delete, | ||
| 325 | .d_iput = sysfs_dentry_iput, | ||
| 311 | }; | 326 | }; |
| 312 | 327 | ||
| 313 | struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type) | 328 | 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 | return NULL; | 359 | return NULL; |
| 345 | } | 360 | } |
| 346 | 361 | ||
| 347 | static int sysfs_ilookup_test(struct inode *inode, void *arg) | ||
| 348 | { | ||
| 349 | struct sysfs_dirent *sd = arg; | ||
| 350 | return inode->i_ino == sd->s_ino; | ||
| 351 | } | ||
| 352 | |||
| 353 | /** | 362 | /** |
| 354 | * sysfs_addrm_start - prepare for sysfs_dirent add/remove | 363 | * sysfs_addrm_start - prepare for sysfs_dirent add/remove |
| 355 | * @acxt: pointer to sysfs_addrm_cxt to be used | 364 | * @acxt: pointer to sysfs_addrm_cxt to be used |
| @@ -357,47 +366,20 @@ static int sysfs_ilookup_test(struct inode *inode, void *arg) | |||
| 357 | * | 366 | * |
| 358 | * This function is called when the caller is about to add or | 367 | * This function is called when the caller is about to add or |
| 359 | * remove sysfs_dirent under @parent_sd. This function acquires | 368 | * remove sysfs_dirent under @parent_sd. This function acquires |
| 360 | * sysfs_mutex, grabs inode for @parent_sd if available and lock | 369 | * sysfs_mutex. @acxt is used to keep and pass context to |
| 361 | * i_mutex of it. @acxt is used to keep and pass context to | ||
| 362 | * other addrm functions. | 370 | * other addrm functions. |
| 363 | * | 371 | * |
| 364 | * LOCKING: | 372 | * LOCKING: |
| 365 | * Kernel thread context (may sleep). sysfs_mutex is locked on | 373 | * Kernel thread context (may sleep). sysfs_mutex is locked on |
| 366 | * return. i_mutex of parent inode is locked on return if | 374 | * return. |
| 367 | * available. | ||
| 368 | */ | 375 | */ |
| 369 | void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, | 376 | void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, |
| 370 | struct sysfs_dirent *parent_sd) | 377 | struct sysfs_dirent *parent_sd) |
| 371 | { | 378 | { |
| 372 | struct inode *inode; | ||
| 373 | |||
| 374 | memset(acxt, 0, sizeof(*acxt)); | 379 | memset(acxt, 0, sizeof(*acxt)); |
| 375 | acxt->parent_sd = parent_sd; | 380 | acxt->parent_sd = parent_sd; |
| 376 | 381 | ||
| 377 | /* Lookup parent inode. inode initialization is protected by | ||
| 378 | * sysfs_mutex, so inode existence can be determined by | ||
| 379 | * looking up inode while holding sysfs_mutex. | ||
| 380 | */ | ||
| 381 | mutex_lock(&sysfs_mutex); | 382 | mutex_lock(&sysfs_mutex); |
| 382 | |||
| 383 | inode = ilookup5(sysfs_sb, parent_sd->s_ino, sysfs_ilookup_test, | ||
| 384 | parent_sd); | ||
| 385 | if (inode) { | ||
| 386 | WARN_ON(inode->i_state & I_NEW); | ||
| 387 | |||
| 388 | /* parent inode available */ | ||
| 389 | acxt->parent_inode = inode; | ||
| 390 | |||
| 391 | /* sysfs_mutex is below i_mutex in lock hierarchy. | ||
| 392 | * First, trylock i_mutex. If fails, unlock | ||
| 393 | * sysfs_mutex and lock them in order. | ||
| 394 | */ | ||
| 395 | if (!mutex_trylock(&inode->i_mutex)) { | ||
| 396 | mutex_unlock(&sysfs_mutex); | ||
| 397 | mutex_lock(&inode->i_mutex); | ||
| 398 | mutex_lock(&sysfs_mutex); | ||
| 399 | } | ||
| 400 | } | ||
| 401 | } | 383 | } |
| 402 | 384 | ||
| 403 | /** | 385 | /** |
| @@ -422,18 +404,22 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, | |||
| 422 | */ | 404 | */ |
| 423 | int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | 405 | int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) |
| 424 | { | 406 | { |
| 407 | struct sysfs_inode_attrs *ps_iattr; | ||
| 408 | |||
| 425 | if (sysfs_find_dirent(acxt->parent_sd, sd->s_name)) | 409 | if (sysfs_find_dirent(acxt->parent_sd, sd->s_name)) |
| 426 | return -EEXIST; | 410 | return -EEXIST; |
| 427 | 411 | ||
| 428 | sd->s_parent = sysfs_get(acxt->parent_sd); | 412 | sd->s_parent = sysfs_get(acxt->parent_sd); |
| 429 | 413 | ||
| 430 | if (sysfs_type(sd) == SYSFS_DIR && acxt->parent_inode) | ||
| 431 | inc_nlink(acxt->parent_inode); | ||
| 432 | |||
| 433 | acxt->cnt++; | ||
| 434 | |||
| 435 | sysfs_link_sibling(sd); | 414 | sysfs_link_sibling(sd); |
| 436 | 415 | ||
| 416 | /* Update timestamps on the parent */ | ||
| 417 | ps_iattr = acxt->parent_sd->s_iattr; | ||
| 418 | if (ps_iattr) { | ||
| 419 | struct iattr *ps_iattrs = &ps_iattr->ia_iattr; | ||
| 420 | ps_iattrs->ia_ctime = ps_iattrs->ia_mtime = CURRENT_TIME; | ||
| 421 | } | ||
| 422 | |||
| 437 | return 0; | 423 | return 0; |
| 438 | } | 424 | } |
| 439 | 425 | ||
| @@ -512,70 +498,22 @@ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | |||
| 512 | */ | 498 | */ |
| 513 | void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | 499 | void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) |
| 514 | { | 500 | { |
| 501 | struct sysfs_inode_attrs *ps_iattr; | ||
| 502 | |||
| 515 | BUG_ON(sd->s_flags & SYSFS_FLAG_REMOVED); | 503 | BUG_ON(sd->s_flags & SYSFS_FLAG_REMOVED); |
| 516 | 504 | ||
| 517 | sysfs_unlink_sibling(sd); | 505 | sysfs_unlink_sibling(sd); |
| 518 | 506 | ||
| 507 | /* Update timestamps on the parent */ | ||
| 508 | ps_iattr = acxt->parent_sd->s_iattr; | ||
| 509 | if (ps_iattr) { | ||
| 510 | struct iattr *ps_iattrs = &ps_iattr->ia_iattr; | ||
| 511 | ps_iattrs->ia_ctime = ps_iattrs->ia_mtime = CURRENT_TIME; | ||
| 512 | } | ||
| 513 | |||
| 519 | sd->s_flags |= SYSFS_FLAG_REMOVED; | 514 | sd->s_flags |= SYSFS_FLAG_REMOVED; |
| 520 | sd->s_sibling = acxt->removed; | 515 | sd->s_sibling = acxt->removed; |
| 521 | acxt->removed = sd; | 516 | acxt->removed = sd; |
| 522 | |||
| 523 | if (sysfs_type(sd) == SYSFS_DIR && acxt->parent_inode) | ||
| 524 | drop_nlink(acxt->parent_inode); | ||
| 525 | |||
| 526 | acxt->cnt++; | ||
| 527 | } | ||
| 528 | |||
| 529 | /** | ||
| 530 | * sysfs_drop_dentry - drop dentry for the specified sysfs_dirent | ||
| 531 | * @sd: target sysfs_dirent | ||
| 532 | * | ||
| 533 | * Drop dentry for @sd. @sd must have been unlinked from its | ||
| 534 | * parent on entry to this function such that it can't be looked | ||
| 535 | * up anymore. | ||
| 536 | */ | ||
| 537 | static void sysfs_drop_dentry(struct sysfs_dirent *sd) | ||
| 538 | { | ||
| 539 | struct inode *inode; | ||
| 540 | struct dentry *dentry; | ||
| 541 | |||
| 542 | inode = ilookup(sysfs_sb, sd->s_ino); | ||
| 543 | if (!inode) | ||
| 544 | return; | ||
| 545 | |||
| 546 | /* Drop any existing dentries associated with sd. | ||
| 547 | * | ||
| 548 | * For the dentry to be properly freed we need to grab a | ||
| 549 | * reference to the dentry under the dcache lock, unhash it, | ||
| 550 | * and then put it. The playing with the dentry count allows | ||
| 551 | * dput to immediately free the dentry if it is not in use. | ||
| 552 | */ | ||
| 553 | repeat: | ||
| 554 | spin_lock(&dcache_lock); | ||
| 555 | list_for_each_entry(dentry, &inode->i_dentry, d_alias) { | ||
| 556 | if (d_unhashed(dentry)) | ||
| 557 | continue; | ||
| 558 | dget_locked(dentry); | ||
| 559 | spin_lock(&dentry->d_lock); | ||
| 560 | __d_drop(dentry); | ||
| 561 | spin_unlock(&dentry->d_lock); | ||
| 562 | spin_unlock(&dcache_lock); | ||
| 563 | dput(dentry); | ||
| 564 | goto repeat; | ||
| 565 | } | ||
| 566 | spin_unlock(&dcache_lock); | ||
| 567 | |||
| 568 | /* adjust nlink and update timestamp */ | ||
| 569 | mutex_lock(&inode->i_mutex); | ||
| 570 | |||
| 571 | inode->i_ctime = CURRENT_TIME; | ||
| 572 | drop_nlink(inode); | ||
| 573 | if (sysfs_type(sd) == SYSFS_DIR) | ||
| 574 | drop_nlink(inode); | ||
| 575 | |||
| 576 | mutex_unlock(&inode->i_mutex); | ||
| 577 | |||
| 578 | iput(inode); | ||
| 579 | } | 517 | } |
| 580 | 518 | ||
| 581 | /** | 519 | /** |
| @@ -584,25 +522,15 @@ repeat: | |||
| 584 | * | 522 | * |
| 585 | * Finish up sysfs_dirent add/remove. Resources acquired by | 523 | * Finish up sysfs_dirent add/remove. Resources acquired by |
| 586 | * sysfs_addrm_start() are released and removed sysfs_dirents are | 524 | * sysfs_addrm_start() are released and removed sysfs_dirents are |
| 587 | * cleaned up. Timestamps on the parent inode are updated. | 525 | * cleaned up. |
| 588 | * | 526 | * |
| 589 | * LOCKING: | 527 | * LOCKING: |
| 590 | * All mutexes acquired by sysfs_addrm_start() are released. | 528 | * sysfs_mutex is released. |
| 591 | */ | 529 | */ |
| 592 | void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) | 530 | void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) |
| 593 | { | 531 | { |
| 594 | /* release resources acquired by sysfs_addrm_start() */ | 532 | /* release resources acquired by sysfs_addrm_start() */ |
| 595 | mutex_unlock(&sysfs_mutex); | 533 | mutex_unlock(&sysfs_mutex); |
| 596 | if (acxt->parent_inode) { | ||
| 597 | struct inode *inode = acxt->parent_inode; | ||
| 598 | |||
| 599 | /* if added/removed, update timestamps on the parent */ | ||
| 600 | if (acxt->cnt) | ||
| 601 | inode->i_ctime = inode->i_mtime = CURRENT_TIME; | ||
| 602 | |||
| 603 | mutex_unlock(&inode->i_mutex); | ||
| 604 | iput(inode); | ||
| 605 | } | ||
| 606 | 534 | ||
| 607 | /* kill removed sysfs_dirents */ | 535 | /* kill removed sysfs_dirents */ |
| 608 | while (acxt->removed) { | 536 | while (acxt->removed) { |
| @@ -611,7 +539,6 @@ void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) | |||
| 611 | acxt->removed = sd->s_sibling; | 539 | acxt->removed = sd->s_sibling; |
| 612 | sd->s_sibling = NULL; | 540 | sd->s_sibling = NULL; |
| 613 | 541 | ||
| 614 | sysfs_drop_dentry(sd); | ||
| 615 | sysfs_deactivate(sd); | 542 | sysfs_deactivate(sd); |
| 616 | unmap_bin_file(sd); | 543 | unmap_bin_file(sd); |
| 617 | sysfs_put(sd); | 544 | sysfs_put(sd); |
| @@ -751,10 +678,15 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, | |||
| 751 | } | 678 | } |
| 752 | 679 | ||
| 753 | /* instantiate and hash dentry */ | 680 | /* instantiate and hash dentry */ |
| 754 | dentry->d_op = &sysfs_dentry_ops; | 681 | ret = d_find_alias(inode); |
| 755 | dentry->d_fsdata = sysfs_get(sd); | 682 | if (!ret) { |
| 756 | d_instantiate(dentry, inode); | 683 | dentry->d_op = &sysfs_dentry_ops; |
| 757 | d_rehash(dentry); | 684 | dentry->d_fsdata = sysfs_get(sd); |
| 685 | d_add(dentry, inode); | ||
| 686 | } else { | ||
| 687 | d_move(ret, dentry); | ||
| 688 | iput(inode); | ||
| 689 | } | ||
| 758 | 690 | ||
| 759 | out_unlock: | 691 | out_unlock: |
| 760 | mutex_unlock(&sysfs_mutex); | 692 | mutex_unlock(&sysfs_mutex); |
| @@ -763,7 +695,9 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, | |||
| 763 | 695 | ||
| 764 | const struct inode_operations sysfs_dir_inode_operations = { | 696 | const struct inode_operations sysfs_dir_inode_operations = { |
| 765 | .lookup = sysfs_lookup, | 697 | .lookup = sysfs_lookup, |
| 698 | .permission = sysfs_permission, | ||
| 766 | .setattr = sysfs_setattr, | 699 | .setattr = sysfs_setattr, |
| 700 | .getattr = sysfs_getattr, | ||
| 767 | .setxattr = sysfs_setxattr, | 701 | .setxattr = sysfs_setxattr, |
| 768 | }; | 702 | }; |
| 769 | 703 | ||
| @@ -826,141 +760,65 @@ void sysfs_remove_dir(struct kobject * kobj) | |||
| 826 | __sysfs_remove_dir(sd); | 760 | __sysfs_remove_dir(sd); |
| 827 | } | 761 | } |
| 828 | 762 | ||
| 829 | int sysfs_rename_dir(struct kobject * kobj, const char *new_name) | 763 | int sysfs_rename(struct sysfs_dirent *sd, |
| 764 | struct sysfs_dirent *new_parent_sd, const char *new_name) | ||
| 830 | { | 765 | { |
| 831 | struct sysfs_dirent *sd = kobj->sd; | ||
| 832 | struct dentry *parent = NULL; | ||
| 833 | struct dentry *old_dentry = NULL, *new_dentry = NULL; | ||
| 834 | const char *dup_name = NULL; | 766 | const char *dup_name = NULL; |
| 835 | int error; | 767 | int error; |
| 836 | 768 | ||
| 837 | mutex_lock(&sysfs_rename_mutex); | 769 | mutex_lock(&sysfs_mutex); |
| 838 | 770 | ||
| 839 | error = 0; | 771 | error = 0; |
| 840 | if (strcmp(sd->s_name, new_name) == 0) | 772 | if ((sd->s_parent == new_parent_sd) && |
| 773 | (strcmp(sd->s_name, new_name) == 0)) | ||
| 841 | goto out; /* nothing to rename */ | 774 | goto out; /* nothing to rename */ |
| 842 | 775 | ||
| 843 | /* get the original dentry */ | ||
| 844 | old_dentry = sysfs_get_dentry(sd); | ||
| 845 | if (IS_ERR(old_dentry)) { | ||
| 846 | error = PTR_ERR(old_dentry); | ||
| 847 | old_dentry = NULL; | ||
| 848 | goto out; | ||
| 849 | } | ||
| 850 | |||
| 851 | parent = old_dentry->d_parent; | ||
| 852 | |||
| 853 | /* lock parent and get dentry for new name */ | ||
| 854 | mutex_lock(&parent->d_inode->i_mutex); | ||
| 855 | mutex_lock(&sysfs_mutex); | ||
| 856 | |||
| 857 | error = -EEXIST; | 776 | error = -EEXIST; |
| 858 | if (sysfs_find_dirent(sd->s_parent, new_name)) | 777 | if (sysfs_find_dirent(new_parent_sd, new_name)) |
| 859 | goto out_unlock; | 778 | goto out; |
| 860 | |||
| 861 | error = -ENOMEM; | ||
| 862 | new_dentry = d_alloc_name(parent, new_name); | ||
| 863 | if (!new_dentry) | ||
| 864 | goto out_unlock; | ||
| 865 | 779 | ||
| 866 | /* rename sysfs_dirent */ | 780 | /* rename sysfs_dirent */ |
| 867 | error = -ENOMEM; | 781 | if (strcmp(sd->s_name, new_name) != 0) { |
| 868 | new_name = dup_name = kstrdup(new_name, GFP_KERNEL); | 782 | error = -ENOMEM; |
| 869 | if (!new_name) | 783 | new_name = dup_name = kstrdup(new_name, GFP_KERNEL); |
| 870 | goto out_unlock; | 784 | if (!new_name) |
| 871 | 785 | goto out; | |
| 872 | dup_name = sd->s_name; | 786 | |
| 873 | sd->s_name = new_name; | 787 | dup_name = sd->s_name; |
| 788 | sd->s_name = new_name; | ||
| 789 | } | ||
| 874 | 790 | ||
| 875 | /* rename */ | 791 | /* Remove from old parent's list and insert into new parent's list. */ |
| 876 | d_add(new_dentry, NULL); | 792 | if (sd->s_parent != new_parent_sd) { |
| 877 | d_move(old_dentry, new_dentry); | 793 | sysfs_unlink_sibling(sd); |
| 794 | sysfs_get(new_parent_sd); | ||
| 795 | sysfs_put(sd->s_parent); | ||
| 796 | sd->s_parent = new_parent_sd; | ||
| 797 | sysfs_link_sibling(sd); | ||
| 798 | } | ||
| 878 | 799 | ||
| 879 | error = 0; | 800 | error = 0; |
| 880 | out_unlock: | 801 | out: |
| 881 | mutex_unlock(&sysfs_mutex); | 802 | mutex_unlock(&sysfs_mutex); |
| 882 | mutex_unlock(&parent->d_inode->i_mutex); | ||
| 883 | kfree(dup_name); | 803 | kfree(dup_name); |
| 884 | dput(old_dentry); | ||
| 885 | dput(new_dentry); | ||
| 886 | out: | ||
| 887 | mutex_unlock(&sysfs_rename_mutex); | ||
| 888 | return error; | 804 | return error; |
| 889 | } | 805 | } |
| 890 | 806 | ||
| 807 | int sysfs_rename_dir(struct kobject *kobj, const char *new_name) | ||
| 808 | { | ||
| 809 | return sysfs_rename(kobj->sd, kobj->sd->s_parent, new_name); | ||
| 810 | } | ||
| 811 | |||
| 891 | int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj) | 812 | int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj) |
| 892 | { | 813 | { |
| 893 | struct sysfs_dirent *sd = kobj->sd; | 814 | struct sysfs_dirent *sd = kobj->sd; |
| 894 | struct sysfs_dirent *new_parent_sd; | 815 | struct sysfs_dirent *new_parent_sd; |
| 895 | struct dentry *old_parent, *new_parent = NULL; | ||
| 896 | struct dentry *old_dentry = NULL, *new_dentry = NULL; | ||
| 897 | int error; | ||
| 898 | 816 | ||
| 899 | mutex_lock(&sysfs_rename_mutex); | ||
| 900 | BUG_ON(!sd->s_parent); | 817 | BUG_ON(!sd->s_parent); |
| 901 | new_parent_sd = (new_parent_kobj && new_parent_kobj->sd) ? | 818 | new_parent_sd = new_parent_kobj && new_parent_kobj->sd ? |
| 902 | new_parent_kobj->sd : &sysfs_root; | 819 | new_parent_kobj->sd : &sysfs_root; |
| 903 | 820 | ||
| 904 | error = 0; | 821 | return sysfs_rename(sd, new_parent_sd, sd->s_name); |
| 905 | if (sd->s_parent == new_parent_sd) | ||
| 906 | goto out; /* nothing to move */ | ||
| 907 | |||
| 908 | /* get dentries */ | ||
| 909 | old_dentry = sysfs_get_dentry(sd); | ||
| 910 | if (IS_ERR(old_dentry)) { | ||
| 911 | error = PTR_ERR(old_dentry); | ||
| 912 | old_dentry = NULL; | ||
| 913 | goto out; | ||
| 914 | } | ||
| 915 | old_parent = old_dentry->d_parent; | ||
| 916 | |||
| 917 | new_parent = sysfs_get_dentry(new_parent_sd); | ||
| 918 | if (IS_ERR(new_parent)) { | ||
| 919 | error = PTR_ERR(new_parent); | ||
| 920 | new_parent = NULL; | ||
| 921 | goto out; | ||
| 922 | } | ||
| 923 | |||
| 924 | again: | ||
| 925 | mutex_lock(&old_parent->d_inode->i_mutex); | ||
| 926 | if (!mutex_trylock(&new_parent->d_inode->i_mutex)) { | ||
| 927 | mutex_unlock(&old_parent->d_inode->i_mutex); | ||
| 928 | goto again; | ||
| 929 | } | ||
| 930 | mutex_lock(&sysfs_mutex); | ||
| 931 | |||
| 932 | error = -EEXIST; | ||
| 933 | if (sysfs_find_dirent(new_parent_sd, sd->s_name)) | ||
| 934 | goto out_unlock; | ||
| 935 | |||
| 936 | error = -ENOMEM; | ||
| 937 | new_dentry = d_alloc_name(new_parent, sd->s_name); | ||
| 938 | if (!new_dentry) | ||
| 939 | goto out_unlock; | ||
| 940 | |||
| 941 | error = 0; | ||
| 942 | d_add(new_dentry, NULL); | ||
| 943 | d_move(old_dentry, new_dentry); | ||
| 944 | |||
| 945 | /* Remove from old parent's list and insert into new parent's list. */ | ||
| 946 | sysfs_unlink_sibling(sd); | ||
| 947 | sysfs_get(new_parent_sd); | ||
| 948 | drop_nlink(old_parent->d_inode); | ||
| 949 | sysfs_put(sd->s_parent); | ||
| 950 | sd->s_parent = new_parent_sd; | ||
| 951 | inc_nlink(new_parent->d_inode); | ||
| 952 | sysfs_link_sibling(sd); | ||
| 953 | |||
| 954 | out_unlock: | ||
| 955 | mutex_unlock(&sysfs_mutex); | ||
| 956 | mutex_unlock(&new_parent->d_inode->i_mutex); | ||
| 957 | mutex_unlock(&old_parent->d_inode->i_mutex); | ||
| 958 | out: | ||
| 959 | dput(new_parent); | ||
| 960 | dput(old_dentry); | ||
| 961 | dput(new_dentry); | ||
| 962 | mutex_unlock(&sysfs_rename_mutex); | ||
| 963 | return error; | ||
| 964 | } | 822 | } |
| 965 | 823 | ||
| 966 | /* Relationship between s_mode and the DT_xxx types */ | 824 | /* Relationship between s_mode and the DT_xxx types */ |
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index f5ea4680f15f..dc30d9e31683 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c | |||
| @@ -579,46 +579,23 @@ EXPORT_SYMBOL_GPL(sysfs_add_file_to_group); | |||
| 579 | */ | 579 | */ |
| 580 | int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode) | 580 | int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode) |
| 581 | { | 581 | { |
| 582 | struct sysfs_dirent *victim_sd = NULL; | 582 | struct sysfs_dirent *sd; |
| 583 | struct dentry *victim = NULL; | ||
| 584 | struct inode * inode; | ||
| 585 | struct iattr newattrs; | 583 | struct iattr newattrs; |
| 586 | int rc; | 584 | int rc; |
| 587 | 585 | ||
| 588 | rc = -ENOENT; | 586 | mutex_lock(&sysfs_mutex); |
| 589 | victim_sd = sysfs_get_dirent(kobj->sd, attr->name); | ||
| 590 | if (!victim_sd) | ||
| 591 | goto out; | ||
| 592 | 587 | ||
| 593 | mutex_lock(&sysfs_rename_mutex); | 588 | rc = -ENOENT; |
| 594 | victim = sysfs_get_dentry(victim_sd); | 589 | sd = sysfs_find_dirent(kobj->sd, attr->name); |
| 595 | mutex_unlock(&sysfs_rename_mutex); | 590 | if (!sd) |
| 596 | if (IS_ERR(victim)) { | ||
| 597 | rc = PTR_ERR(victim); | ||
| 598 | victim = NULL; | ||
| 599 | goto out; | 591 | goto out; |
| 600 | } | ||
| 601 | |||
| 602 | inode = victim->d_inode; | ||
| 603 | |||
| 604 | mutex_lock(&inode->i_mutex); | ||
| 605 | 592 | ||
| 606 | newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); | 593 | newattrs.ia_mode = (mode & S_IALLUGO) | (sd->s_mode & ~S_IALLUGO); |
| 607 | newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; | 594 | newattrs.ia_valid = ATTR_MODE; |
| 608 | newattrs.ia_ctime = current_fs_time(inode->i_sb); | 595 | rc = sysfs_sd_setattr(sd, &newattrs); |
| 609 | rc = sysfs_setattr(victim, &newattrs); | ||
| 610 | 596 | ||
| 611 | if (rc == 0) { | ||
| 612 | fsnotify_change(victim, newattrs.ia_valid); | ||
| 613 | mutex_lock(&sysfs_mutex); | ||
| 614 | victim_sd->s_mode = newattrs.ia_mode; | ||
| 615 | mutex_unlock(&sysfs_mutex); | ||
| 616 | } | ||
| 617 | |||
| 618 | mutex_unlock(&inode->i_mutex); | ||
| 619 | out: | 597 | out: |
| 620 | dput(victim); | 598 | mutex_unlock(&sysfs_mutex); |
| 621 | sysfs_put(victim_sd); | ||
| 622 | return rc; | 599 | return rc; |
| 623 | } | 600 | } |
| 624 | EXPORT_SYMBOL_GPL(sysfs_chmod_file); | 601 | EXPORT_SYMBOL_GPL(sysfs_chmod_file); |
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index e28cecf179f5..220b758523ae 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c | |||
| @@ -37,7 +37,9 @@ static struct backing_dev_info sysfs_backing_dev_info = { | |||
| 37 | }; | 37 | }; |
| 38 | 38 | ||
| 39 | static const struct inode_operations sysfs_inode_operations ={ | 39 | static const struct inode_operations sysfs_inode_operations ={ |
| 40 | .permission = sysfs_permission, | ||
| 40 | .setattr = sysfs_setattr, | 41 | .setattr = sysfs_setattr, |
| 42 | .getattr = sysfs_getattr, | ||
| 41 | .setxattr = sysfs_setxattr, | 43 | .setxattr = sysfs_setxattr, |
| 42 | }; | 44 | }; |
| 43 | 45 | ||
| @@ -46,7 +48,7 @@ int __init sysfs_inode_init(void) | |||
| 46 | return bdi_init(&sysfs_backing_dev_info); | 48 | return bdi_init(&sysfs_backing_dev_info); |
| 47 | } | 49 | } |
| 48 | 50 | ||
| 49 | struct sysfs_inode_attrs *sysfs_init_inode_attrs(struct sysfs_dirent *sd) | 51 | static struct sysfs_inode_attrs *sysfs_init_inode_attrs(struct sysfs_dirent *sd) |
| 50 | { | 52 | { |
| 51 | struct sysfs_inode_attrs *attrs; | 53 | struct sysfs_inode_attrs *attrs; |
| 52 | struct iattr *iattrs; | 54 | struct iattr *iattrs; |
| @@ -64,30 +66,15 @@ struct sysfs_inode_attrs *sysfs_init_inode_attrs(struct sysfs_dirent *sd) | |||
| 64 | 66 | ||
| 65 | return attrs; | 67 | return attrs; |
| 66 | } | 68 | } |
| 67 | int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) | 69 | |
| 70 | int sysfs_sd_setattr(struct sysfs_dirent *sd, struct iattr * iattr) | ||
| 68 | { | 71 | { |
| 69 | struct inode * inode = dentry->d_inode; | ||
| 70 | struct sysfs_dirent * sd = dentry->d_fsdata; | ||
| 71 | struct sysfs_inode_attrs *sd_attrs; | 72 | struct sysfs_inode_attrs *sd_attrs; |
| 72 | struct iattr *iattrs; | 73 | struct iattr *iattrs; |
| 73 | unsigned int ia_valid = iattr->ia_valid; | 74 | unsigned int ia_valid = iattr->ia_valid; |
| 74 | int error; | ||
| 75 | |||
| 76 | if (!sd) | ||
| 77 | return -EINVAL; | ||
| 78 | 75 | ||
| 79 | sd_attrs = sd->s_iattr; | 76 | sd_attrs = sd->s_iattr; |
| 80 | 77 | ||
| 81 | error = inode_change_ok(inode, iattr); | ||
| 82 | if (error) | ||
| 83 | return error; | ||
| 84 | |||
| 85 | iattr->ia_valid &= ~ATTR_SIZE; /* ignore size changes */ | ||
| 86 | |||
| 87 | error = inode_setattr(inode, iattr); | ||
| 88 | if (error) | ||
| 89 | return error; | ||
| 90 | |||
| 91 | if (!sd_attrs) { | 78 | if (!sd_attrs) { |
| 92 | /* setting attributes for the first time, allocate now */ | 79 | /* setting attributes for the first time, allocate now */ |
| 93 | sd_attrs = sysfs_init_inode_attrs(sd); | 80 | sd_attrs = sysfs_init_inode_attrs(sd); |
| @@ -103,42 +90,78 @@ int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) | |||
| 103 | if (ia_valid & ATTR_GID) | 90 | if (ia_valid & ATTR_GID) |
| 104 | iattrs->ia_gid = iattr->ia_gid; | 91 | iattrs->ia_gid = iattr->ia_gid; |
| 105 | if (ia_valid & ATTR_ATIME) | 92 | if (ia_valid & ATTR_ATIME) |
| 106 | iattrs->ia_atime = timespec_trunc(iattr->ia_atime, | 93 | iattrs->ia_atime = iattr->ia_atime; |
| 107 | inode->i_sb->s_time_gran); | ||
| 108 | if (ia_valid & ATTR_MTIME) | 94 | if (ia_valid & ATTR_MTIME) |
| 109 | iattrs->ia_mtime = timespec_trunc(iattr->ia_mtime, | 95 | iattrs->ia_mtime = iattr->ia_mtime; |
| 110 | inode->i_sb->s_time_gran); | ||
| 111 | if (ia_valid & ATTR_CTIME) | 96 | if (ia_valid & ATTR_CTIME) |
| 112 | iattrs->ia_ctime = timespec_trunc(iattr->ia_ctime, | 97 | iattrs->ia_ctime = iattr->ia_ctime; |
| 113 | inode->i_sb->s_time_gran); | ||
| 114 | if (ia_valid & ATTR_MODE) { | 98 | if (ia_valid & ATTR_MODE) { |
| 115 | umode_t mode = iattr->ia_mode; | 99 | umode_t mode = iattr->ia_mode; |
| 116 | |||
| 117 | if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) | ||
| 118 | mode &= ~S_ISGID; | ||
| 119 | iattrs->ia_mode = sd->s_mode = mode; | 100 | iattrs->ia_mode = sd->s_mode = mode; |
| 120 | } | 101 | } |
| 121 | } | 102 | } |
| 103 | return 0; | ||
| 104 | } | ||
| 105 | |||
| 106 | int sysfs_setattr(struct dentry *dentry, struct iattr *iattr) | ||
| 107 | { | ||
| 108 | struct inode *inode = dentry->d_inode; | ||
| 109 | struct sysfs_dirent *sd = dentry->d_fsdata; | ||
| 110 | int error; | ||
| 111 | |||
| 112 | if (!sd) | ||
| 113 | return -EINVAL; | ||
| 114 | |||
| 115 | error = inode_change_ok(inode, iattr); | ||
| 116 | if (error) | ||
| 117 | return error; | ||
| 118 | |||
| 119 | iattr->ia_valid &= ~ATTR_SIZE; /* ignore size changes */ | ||
| 120 | |||
| 121 | error = inode_setattr(inode, iattr); | ||
| 122 | if (error) | ||
| 123 | return error; | ||
| 124 | |||
| 125 | mutex_lock(&sysfs_mutex); | ||
| 126 | error = sysfs_sd_setattr(sd, iattr); | ||
| 127 | mutex_unlock(&sysfs_mutex); | ||
| 128 | |||
| 122 | return error; | 129 | return error; |
| 123 | } | 130 | } |
| 124 | 131 | ||
| 132 | static int sysfs_sd_setsecdata(struct sysfs_dirent *sd, void **secdata, u32 *secdata_len) | ||
| 133 | { | ||
| 134 | struct sysfs_inode_attrs *iattrs; | ||
| 135 | void *old_secdata; | ||
| 136 | size_t old_secdata_len; | ||
| 137 | |||
| 138 | iattrs = sd->s_iattr; | ||
| 139 | if (!iattrs) | ||
| 140 | iattrs = sysfs_init_inode_attrs(sd); | ||
| 141 | if (!iattrs) | ||
| 142 | return -ENOMEM; | ||
| 143 | |||
| 144 | old_secdata = iattrs->ia_secdata; | ||
| 145 | old_secdata_len = iattrs->ia_secdata_len; | ||
| 146 | |||
| 147 | iattrs->ia_secdata = *secdata; | ||
| 148 | iattrs->ia_secdata_len = *secdata_len; | ||
| 149 | |||
| 150 | *secdata = old_secdata; | ||
| 151 | *secdata_len = old_secdata_len; | ||
| 152 | return 0; | ||
| 153 | } | ||
| 154 | |||
| 125 | int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, | 155 | int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, |
| 126 | size_t size, int flags) | 156 | size_t size, int flags) |
| 127 | { | 157 | { |
| 128 | struct sysfs_dirent *sd = dentry->d_fsdata; | 158 | struct sysfs_dirent *sd = dentry->d_fsdata; |
| 129 | struct sysfs_inode_attrs *iattrs; | ||
| 130 | void *secdata; | 159 | void *secdata; |
| 131 | int error; | 160 | int error; |
| 132 | u32 secdata_len = 0; | 161 | u32 secdata_len = 0; |
| 133 | 162 | ||
| 134 | if (!sd) | 163 | if (!sd) |
| 135 | return -EINVAL; | 164 | return -EINVAL; |
| 136 | if (!sd->s_iattr) | ||
| 137 | sd->s_iattr = sysfs_init_inode_attrs(sd); | ||
| 138 | if (!sd->s_iattr) | ||
| 139 | return -ENOMEM; | ||
| 140 | |||
| 141 | iattrs = sd->s_iattr; | ||
| 142 | 165 | ||
| 143 | if (!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN)) { | 166 | if (!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN)) { |
| 144 | const char *suffix = name + XATTR_SECURITY_PREFIX_LEN; | 167 | 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 | &secdata, &secdata_len); | 173 | &secdata, &secdata_len); |
| 151 | if (error) | 174 | if (error) |
| 152 | goto out; | 175 | goto out; |
| 153 | if (iattrs->ia_secdata) | ||
| 154 | security_release_secctx(iattrs->ia_secdata, | ||
| 155 | iattrs->ia_secdata_len); | ||
| 156 | iattrs->ia_secdata = secdata; | ||
| 157 | iattrs->ia_secdata_len = secdata_len; | ||
| 158 | 176 | ||
| 177 | mutex_lock(&sysfs_mutex); | ||
| 178 | error = sysfs_sd_setsecdata(sd, &secdata, &secdata_len); | ||
| 179 | mutex_unlock(&sysfs_mutex); | ||
| 180 | |||
| 181 | if (secdata) | ||
| 182 | security_release_secctx(secdata, secdata_len); | ||
| 159 | } else | 183 | } else |
| 160 | return -EINVAL; | 184 | return -EINVAL; |
| 161 | out: | 185 | out: |
| @@ -170,7 +194,6 @@ static inline void set_default_inode_attr(struct inode * inode, mode_t mode) | |||
| 170 | 194 | ||
| 171 | static inline void set_inode_attr(struct inode * inode, struct iattr * iattr) | 195 | static inline void set_inode_attr(struct inode * inode, struct iattr * iattr) |
| 172 | { | 196 | { |
| 173 | inode->i_mode = iattr->ia_mode; | ||
| 174 | inode->i_uid = iattr->ia_uid; | 197 | inode->i_uid = iattr->ia_uid; |
| 175 | inode->i_gid = iattr->ia_gid; | 198 | inode->i_gid = iattr->ia_gid; |
| 176 | inode->i_atime = iattr->ia_atime; | 199 | inode->i_atime = iattr->ia_atime; |
| @@ -178,17 +201,6 @@ static inline void set_inode_attr(struct inode * inode, struct iattr * iattr) | |||
| 178 | inode->i_ctime = iattr->ia_ctime; | 201 | inode->i_ctime = iattr->ia_ctime; |
| 179 | } | 202 | } |
| 180 | 203 | ||
| 181 | |||
| 182 | /* | ||
| 183 | * sysfs has a different i_mutex lock order behavior for i_mutex than other | ||
| 184 | * filesystems; sysfs i_mutex is called in many places with subsystem locks | ||
| 185 | * held. At the same time, many of the VFS locking rules do not apply to | ||
| 186 | * sysfs at all (cross directory rename for example). To untangle this mess | ||
| 187 | * (which gives false positives in lockdep), we're giving sysfs inodes their | ||
| 188 | * own class for i_mutex. | ||
| 189 | */ | ||
| 190 | static struct lock_class_key sysfs_inode_imutex_key; | ||
| 191 | |||
| 192 | static int sysfs_count_nlink(struct sysfs_dirent *sd) | 204 | static int sysfs_count_nlink(struct sysfs_dirent *sd) |
| 193 | { | 205 | { |
| 194 | struct sysfs_dirent *child; | 206 | struct sysfs_dirent *child; |
| @@ -201,38 +213,55 @@ static int sysfs_count_nlink(struct sysfs_dirent *sd) | |||
| 201 | return nr + 2; | 213 | return nr + 2; |
| 202 | } | 214 | } |
| 203 | 215 | ||
| 216 | static void sysfs_refresh_inode(struct sysfs_dirent *sd, struct inode *inode) | ||
| 217 | { | ||
| 218 | struct sysfs_inode_attrs *iattrs = sd->s_iattr; | ||
| 219 | |||
| 220 | inode->i_mode = sd->s_mode; | ||
| 221 | if (iattrs) { | ||
| 222 | /* sysfs_dirent has non-default attributes | ||
| 223 | * get them from persistent copy in sysfs_dirent | ||
| 224 | */ | ||
| 225 | set_inode_attr(inode, &iattrs->ia_iattr); | ||
| 226 | security_inode_notifysecctx(inode, | ||
| 227 | iattrs->ia_secdata, | ||
| 228 | iattrs->ia_secdata_len); | ||
| 229 | } | ||
| 230 | |||
| 231 | if (sysfs_type(sd) == SYSFS_DIR) | ||
| 232 | inode->i_nlink = sysfs_count_nlink(sd); | ||
| 233 | } | ||
| 234 | |||
| 235 | int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) | ||
| 236 | { | ||
| 237 | struct sysfs_dirent *sd = dentry->d_fsdata; | ||
| 238 | struct inode *inode = dentry->d_inode; | ||
| 239 | |||
| 240 | mutex_lock(&sysfs_mutex); | ||
| 241 | sysfs_refresh_inode(sd, inode); | ||
| 242 | mutex_unlock(&sysfs_mutex); | ||
| 243 | |||
| 244 | generic_fillattr(inode, stat); | ||
| 245 | return 0; | ||
| 246 | } | ||
| 247 | |||
| 204 | static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) | 248 | static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) |
| 205 | { | 249 | { |
| 206 | struct bin_attribute *bin_attr; | 250 | struct bin_attribute *bin_attr; |
| 207 | struct sysfs_inode_attrs *iattrs; | ||
| 208 | 251 | ||
| 209 | inode->i_private = sysfs_get(sd); | 252 | inode->i_private = sysfs_get(sd); |
| 210 | inode->i_mapping->a_ops = &sysfs_aops; | 253 | inode->i_mapping->a_ops = &sysfs_aops; |
| 211 | inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info; | 254 | inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info; |
| 212 | inode->i_op = &sysfs_inode_operations; | 255 | inode->i_op = &sysfs_inode_operations; |
| 213 | inode->i_ino = sd->s_ino; | ||
| 214 | lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key); | ||
| 215 | 256 | ||
| 216 | iattrs = sd->s_iattr; | 257 | set_default_inode_attr(inode, sd->s_mode); |
| 217 | if (iattrs) { | 258 | sysfs_refresh_inode(sd, inode); |
| 218 | /* sysfs_dirent has non-default attributes | ||
| 219 | * get them for the new inode from persistent copy | ||
| 220 | * in sysfs_dirent | ||
| 221 | */ | ||
| 222 | set_inode_attr(inode, &iattrs->ia_iattr); | ||
| 223 | if (iattrs->ia_secdata) | ||
| 224 | security_inode_notifysecctx(inode, | ||
| 225 | iattrs->ia_secdata, | ||
| 226 | iattrs->ia_secdata_len); | ||
| 227 | } else | ||
| 228 | set_default_inode_attr(inode, sd->s_mode); | ||
| 229 | 259 | ||
| 230 | /* initialize inode according to type */ | 260 | /* initialize inode according to type */ |
| 231 | switch (sysfs_type(sd)) { | 261 | switch (sysfs_type(sd)) { |
| 232 | case SYSFS_DIR: | 262 | case SYSFS_DIR: |
| 233 | inode->i_op = &sysfs_dir_inode_operations; | 263 | inode->i_op = &sysfs_dir_inode_operations; |
| 234 | inode->i_fop = &sysfs_dir_operations; | 264 | inode->i_fop = &sysfs_dir_operations; |
| 235 | inode->i_nlink = sysfs_count_nlink(sd); | ||
| 236 | break; | 265 | break; |
| 237 | case SYSFS_KOBJ_ATTR: | 266 | case SYSFS_KOBJ_ATTR: |
| 238 | inode->i_size = PAGE_SIZE; | 267 | inode->i_size = PAGE_SIZE; |
| @@ -315,3 +344,14 @@ int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name) | |||
| 315 | else | 344 | else |
| 316 | return -ENOENT; | 345 | return -ENOENT; |
| 317 | } | 346 | } |
| 347 | |||
| 348 | int sysfs_permission(struct inode *inode, int mask) | ||
| 349 | { | ||
| 350 | struct sysfs_dirent *sd = inode->i_private; | ||
| 351 | |||
| 352 | mutex_lock(&sysfs_mutex); | ||
| 353 | sysfs_refresh_inode(sd, inode); | ||
| 354 | mutex_unlock(&sysfs_mutex); | ||
| 355 | |||
| 356 | return generic_permission(inode, mask, NULL); | ||
| 357 | } | ||
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index c5081ad77026..c5eff49fa41b 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c | |||
| @@ -210,10 +210,13 @@ static void sysfs_put_link(struct dentry *dentry, struct nameidata *nd, void *co | |||
| 210 | } | 210 | } |
| 211 | 211 | ||
| 212 | const struct inode_operations sysfs_symlink_inode_operations = { | 212 | const struct inode_operations sysfs_symlink_inode_operations = { |
| 213 | .setxattr = sysfs_setxattr, | 213 | .setxattr = sysfs_setxattr, |
| 214 | .readlink = generic_readlink, | 214 | .readlink = generic_readlink, |
| 215 | .follow_link = sysfs_follow_link, | 215 | .follow_link = sysfs_follow_link, |
| 216 | .put_link = sysfs_put_link, | 216 | .put_link = sysfs_put_link, |
| 217 | .setattr = sysfs_setattr, | ||
| 218 | .getattr = sysfs_getattr, | ||
| 219 | .permission = sysfs_permission, | ||
| 217 | }; | 220 | }; |
| 218 | 221 | ||
| 219 | 222 | ||
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index af4c4e7482ac..ca52e7b9d8f8 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h | |||
| @@ -89,9 +89,7 @@ static inline unsigned int sysfs_type(struct sysfs_dirent *sd) | |||
| 89 | */ | 89 | */ |
| 90 | struct sysfs_addrm_cxt { | 90 | struct sysfs_addrm_cxt { |
| 91 | struct sysfs_dirent *parent_sd; | 91 | struct sysfs_dirent *parent_sd; |
| 92 | struct inode *parent_inode; | ||
| 93 | struct sysfs_dirent *removed; | 92 | struct sysfs_dirent *removed; |
| 94 | int cnt; | ||
| 95 | }; | 93 | }; |
| 96 | 94 | ||
| 97 | /* | 95 | /* |
| @@ -105,7 +103,6 @@ extern struct kmem_cache *sysfs_dir_cachep; | |||
| 105 | * dir.c | 103 | * dir.c |
| 106 | */ | 104 | */ |
| 107 | extern struct mutex sysfs_mutex; | 105 | extern struct mutex sysfs_mutex; |
| 108 | extern struct mutex sysfs_rename_mutex; | ||
| 109 | extern spinlock_t sysfs_assoc_lock; | 106 | extern spinlock_t sysfs_assoc_lock; |
| 110 | 107 | ||
| 111 | extern const struct file_operations sysfs_dir_operations; | 108 | extern const struct file_operations sysfs_dir_operations; |
| @@ -133,6 +130,9 @@ int sysfs_create_subdir(struct kobject *kobj, const char *name, | |||
| 133 | struct sysfs_dirent **p_sd); | 130 | struct sysfs_dirent **p_sd); |
| 134 | void sysfs_remove_subdir(struct sysfs_dirent *sd); | 131 | void sysfs_remove_subdir(struct sysfs_dirent *sd); |
| 135 | 132 | ||
| 133 | int sysfs_rename(struct sysfs_dirent *sd, | ||
| 134 | struct sysfs_dirent *new_parent_sd, const char *new_name); | ||
| 135 | |||
| 136 | static inline struct sysfs_dirent *__sysfs_get(struct sysfs_dirent *sd) | 136 | static inline struct sysfs_dirent *__sysfs_get(struct sysfs_dirent *sd) |
| 137 | { | 137 | { |
| 138 | if (sd) { | 138 | if (sd) { |
| @@ -155,7 +155,10 @@ static inline void __sysfs_put(struct sysfs_dirent *sd) | |||
| 155 | */ | 155 | */ |
| 156 | struct inode *sysfs_get_inode(struct sysfs_dirent *sd); | 156 | struct inode *sysfs_get_inode(struct sysfs_dirent *sd); |
| 157 | void sysfs_delete_inode(struct inode *inode); | 157 | void sysfs_delete_inode(struct inode *inode); |
| 158 | int sysfs_sd_setattr(struct sysfs_dirent *sd, struct iattr *iattr); | ||
| 159 | int sysfs_permission(struct inode *inode, int mask); | ||
| 158 | int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); | 160 | int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); |
| 161 | int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat); | ||
| 159 | int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, | 162 | int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, |
| 160 | size_t size, int flags); | 163 | size_t size, int flags); |
| 161 | int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name); | 164 | int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name); |
diff --git a/include/linux/device.h b/include/linux/device.h index 2ea3e4921812..2a73d9bcbc9c 100644 --- a/include/linux/device.h +++ b/include/linux/device.h | |||
| @@ -558,7 +558,7 @@ extern void wait_for_device_probe(void); | |||
| 558 | #ifdef CONFIG_DEVTMPFS | 558 | #ifdef CONFIG_DEVTMPFS |
| 559 | extern int devtmpfs_create_node(struct device *dev); | 559 | extern int devtmpfs_create_node(struct device *dev); |
| 560 | extern int devtmpfs_delete_node(struct device *dev); | 560 | extern int devtmpfs_delete_node(struct device *dev); |
| 561 | extern int devtmpfs_mount(const char *mountpoint); | 561 | extern int devtmpfs_mount(const char *mntdir); |
| 562 | #else | 562 | #else |
| 563 | static inline int devtmpfs_create_node(struct device *dev) { return 0; } | 563 | static inline int devtmpfs_create_node(struct device *dev) { return 0; } |
| 564 | static inline int devtmpfs_delete_node(struct device *dev) { return 0; } | 564 | static inline int devtmpfs_delete_node(struct device *dev) { return 0; } |
diff --git a/include/linux/firmware.h b/include/linux/firmware.h index d31544628436..043811f0d277 100644 --- a/include/linux/firmware.h +++ b/include/linux/firmware.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | #include <linux/module.h> | 4 | #include <linux/module.h> |
| 5 | #include <linux/types.h> | 5 | #include <linux/types.h> |
| 6 | #include <linux/compiler.h> | 6 | #include <linux/compiler.h> |
| 7 | #include <linux/gfp.h> | ||
| 7 | 8 | ||
| 8 | #define FW_ACTION_NOHOTPLUG 0 | 9 | #define FW_ACTION_NOHOTPLUG 0 |
| 9 | #define FW_ACTION_HOTPLUG 1 | 10 | #define FW_ACTION_HOTPLUG 1 |
| @@ -38,7 +39,7 @@ int request_firmware(const struct firmware **fw, const char *name, | |||
| 38 | struct device *device); | 39 | struct device *device); |
| 39 | int request_firmware_nowait( | 40 | int request_firmware_nowait( |
| 40 | struct module *module, int uevent, | 41 | struct module *module, int uevent, |
| 41 | const char *name, struct device *device, void *context, | 42 | const char *name, struct device *device, gfp_t gfp, void *context, |
| 42 | void (*cont)(const struct firmware *fw, void *context)); | 43 | void (*cont)(const struct firmware *fw, void *context)); |
| 43 | 44 | ||
| 44 | void release_firmware(const struct firmware *fw); | 45 | void release_firmware(const struct firmware *fw); |
| @@ -51,7 +52,7 @@ static inline int request_firmware(const struct firmware **fw, | |||
| 51 | } | 52 | } |
| 52 | static inline int request_firmware_nowait( | 53 | static inline int request_firmware_nowait( |
| 53 | struct module *module, int uevent, | 54 | struct module *module, int uevent, |
| 54 | const char *name, struct device *device, void *context, | 55 | const char *name, struct device *device, gfp_t gfp, void *context, |
| 55 | void (*cont)(const struct firmware *fw, void *context)) | 56 | void (*cont)(const struct firmware *fw, void *context)) |
| 56 | { | 57 | { |
| 57 | return -EINVAL; | 58 | return -EINVAL; |
diff --git a/include/linux/namei.h b/include/linux/namei.h index ec0f607b364a..028946750289 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h | |||
| @@ -76,7 +76,6 @@ extern struct file *nameidata_to_filp(struct nameidata *nd, int flags); | |||
| 76 | extern void release_open_intent(struct nameidata *); | 76 | extern void release_open_intent(struct nameidata *); |
| 77 | 77 | ||
| 78 | extern struct dentry *lookup_one_len(const char *, struct dentry *, int); | 78 | extern struct dentry *lookup_one_len(const char *, struct dentry *, int); |
| 79 | extern struct dentry *lookup_one_noperm(const char *, struct dentry *); | ||
| 80 | 79 | ||
| 81 | extern int follow_down(struct path *); | 80 | extern int follow_down(struct path *); |
| 82 | extern int follow_up(struct path *); | 81 | extern int follow_up(struct path *); |
diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h index 3c6675c2444b..71ff887ca44e 100644 --- a/include/linux/platform_device.h +++ b/include/linux/platform_device.h | |||
| @@ -83,6 +83,8 @@ struct early_platform_driver { | |||
| 83 | struct platform_driver *pdrv; | 83 | struct platform_driver *pdrv; |
| 84 | struct list_head list; | 84 | struct list_head list; |
| 85 | int requested_id; | 85 | int requested_id; |
| 86 | char *buffer; | ||
| 87 | int bufsize; | ||
| 86 | }; | 88 | }; |
| 87 | 89 | ||
| 88 | #define EARLY_PLATFORM_ID_UNSET -2 | 90 | #define EARLY_PLATFORM_ID_UNSET -2 |
| @@ -102,21 +104,29 @@ extern int early_platform_driver_probe(char *class_str, | |||
| 102 | int nr_probe, int user_only); | 104 | int nr_probe, int user_only); |
| 103 | extern void early_platform_cleanup(void); | 105 | extern void early_platform_cleanup(void); |
| 104 | 106 | ||
| 107 | #define early_platform_init(class_string, platdrv) \ | ||
| 108 | early_platform_init_buffer(class_string, platdrv, NULL, 0) | ||
| 105 | 109 | ||
| 106 | #ifndef MODULE | 110 | #ifndef MODULE |
| 107 | #define early_platform_init(class_string, platform_driver) \ | 111 | #define early_platform_init_buffer(class_string, platdrv, buf, bufsiz) \ |
| 108 | static __initdata struct early_platform_driver early_driver = { \ | 112 | static __initdata struct early_platform_driver early_driver = { \ |
| 109 | .class_str = class_string, \ | 113 | .class_str = class_string, \ |
| 110 | .pdrv = platform_driver, \ | 114 | .buffer = buf, \ |
| 115 | .bufsize = bufsiz, \ | ||
| 116 | .pdrv = platdrv, \ | ||
| 111 | .requested_id = EARLY_PLATFORM_ID_UNSET, \ | 117 | .requested_id = EARLY_PLATFORM_ID_UNSET, \ |
| 112 | }; \ | 118 | }; \ |
| 113 | static int __init early_platform_driver_setup_func(char *buf) \ | 119 | static int __init early_platform_driver_setup_func(char *buffer) \ |
| 114 | { \ | 120 | { \ |
| 115 | return early_platform_driver_register(&early_driver, buf); \ | 121 | return early_platform_driver_register(&early_driver, buffer); \ |
| 116 | } \ | 122 | } \ |
| 117 | early_param(class_string, early_platform_driver_setup_func) | 123 | early_param(class_string, early_platform_driver_setup_func) |
| 118 | #else /* MODULE */ | 124 | #else /* MODULE */ |
| 119 | #define early_platform_init(class_string, platform_driver) | 125 | #define early_platform_init_buffer(class_string, platdrv, buf, bufsiz) \ |
| 126 | static inline char *early_platform_driver_setup_func(void) \ | ||
| 127 | { \ | ||
| 128 | return bufsiz ? buf : NULL; \ | ||
| 129 | } | ||
| 120 | #endif /* MODULE */ | 130 | #endif /* MODULE */ |
| 121 | 131 | ||
| 122 | #endif /* _PLATFORM_DEVICE_H_ */ | 132 | #endif /* _PLATFORM_DEVICE_H_ */ |
