diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/debugfs/file.c | 42 | ||||
-rw-r--r-- | fs/namei.c | 72 | ||||
-rw-r--r-- | fs/super.c | 12 | ||||
-rw-r--r-- | fs/sysfs/bin.c | 2 | ||||
-rw-r--r-- | fs/sysfs/file.c | 14 | ||||
-rw-r--r-- | fs/sysfs/group.c | 6 |
6 files changed, 110 insertions, 38 deletions
diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index 682f928b7f4d..2e124e0075c5 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c | |||
@@ -179,6 +179,48 @@ struct dentry *debugfs_create_u32(const char *name, mode_t mode, | |||
179 | } | 179 | } |
180 | EXPORT_SYMBOL_GPL(debugfs_create_u32); | 180 | EXPORT_SYMBOL_GPL(debugfs_create_u32); |
181 | 181 | ||
182 | static void debugfs_u64_set(void *data, u64 val) | ||
183 | { | ||
184 | *(u64 *)data = val; | ||
185 | } | ||
186 | |||
187 | static u64 debugfs_u64_get(void *data) | ||
188 | { | ||
189 | return *(u64 *)data; | ||
190 | } | ||
191 | DEFINE_SIMPLE_ATTRIBUTE(fops_u64, debugfs_u64_get, debugfs_u64_set, "%llu\n"); | ||
192 | |||
193 | /** | ||
194 | * debugfs_create_u64 - create a debugfs file that is used to read and write an unsigned 64-bit value | ||
195 | * @name: a pointer to a string containing the name of the file to create. | ||
196 | * @mode: the permission that the file should have | ||
197 | * @parent: a pointer to the parent dentry for this file. This should be a | ||
198 | * directory dentry if set. If this parameter is %NULL, then the | ||
199 | * file will be created in the root of the debugfs filesystem. | ||
200 | * @value: a pointer to the variable that the file should read to and write | ||
201 | * from. | ||
202 | * | ||
203 | * This function creates a file in debugfs with the given name that | ||
204 | * contains the value of the variable @value. If the @mode variable is so | ||
205 | * set, it can be read from, and written to. | ||
206 | * | ||
207 | * This function will return a pointer to a dentry if it succeeds. This | ||
208 | * pointer must be passed to the debugfs_remove() function when the file is | ||
209 | * to be removed (no automatic cleanup happens if your module is unloaded, | ||
210 | * you are responsible here.) If an error occurs, %NULL will be returned. | ||
211 | * | ||
212 | * If debugfs is not enabled in the kernel, the value -%ENODEV will be | ||
213 | * returned. It is not wise to check for this value, but rather, check for | ||
214 | * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling | ||
215 | * code. | ||
216 | */ | ||
217 | struct dentry *debugfs_create_u64(const char *name, mode_t mode, | ||
218 | struct dentry *parent, u64 *value) | ||
219 | { | ||
220 | return debugfs_create_file(name, mode, parent, value, &fops_u64); | ||
221 | } | ||
222 | EXPORT_SYMBOL_GPL(debugfs_create_u64); | ||
223 | |||
182 | static ssize_t read_file_bool(struct file *file, char __user *user_buf, | 224 | static ssize_t read_file_bool(struct file *file, char __user *user_buf, |
183 | size_t count, loff_t *ppos) | 225 | size_t count, loff_t *ppos) |
184 | { | 226 | { |
diff --git a/fs/namei.c b/fs/namei.c index ee60cc4d3453..880052cadbcd 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -1243,22 +1243,13 @@ int __user_path_lookup_open(const char __user *name, unsigned int lookup_flags, | |||
1243 | return err; | 1243 | return err; |
1244 | } | 1244 | } |
1245 | 1245 | ||
1246 | /* | 1246 | static inline struct dentry *__lookup_hash_kern(struct qstr *name, struct dentry *base, struct nameidata *nd) |
1247 | * Restricted form of lookup. Doesn't follow links, single-component only, | ||
1248 | * needs parent already locked. Doesn't follow mounts. | ||
1249 | * SMP-safe. | ||
1250 | */ | ||
1251 | static struct dentry * __lookup_hash(struct qstr *name, struct dentry * base, struct nameidata *nd) | ||
1252 | { | 1247 | { |
1253 | struct dentry * dentry; | 1248 | struct dentry *dentry; |
1254 | struct inode *inode; | 1249 | struct inode *inode; |
1255 | int err; | 1250 | int err; |
1256 | 1251 | ||
1257 | inode = base->d_inode; | 1252 | inode = base->d_inode; |
1258 | err = permission(inode, MAY_EXEC, nd); | ||
1259 | dentry = ERR_PTR(err); | ||
1260 | if (err) | ||
1261 | goto out; | ||
1262 | 1253 | ||
1263 | /* | 1254 | /* |
1264 | * See if the low-level filesystem might want | 1255 | * See if the low-level filesystem might want |
@@ -1287,35 +1278,76 @@ out: | |||
1287 | return dentry; | 1278 | return dentry; |
1288 | } | 1279 | } |
1289 | 1280 | ||
1281 | /* | ||
1282 | * Restricted form of lookup. Doesn't follow links, single-component only, | ||
1283 | * needs parent already locked. Doesn't follow mounts. | ||
1284 | * SMP-safe. | ||
1285 | */ | ||
1286 | static inline struct dentry * __lookup_hash(struct qstr *name, struct dentry *base, struct nameidata *nd) | ||
1287 | { | ||
1288 | struct dentry *dentry; | ||
1289 | struct inode *inode; | ||
1290 | int err; | ||
1291 | |||
1292 | inode = base->d_inode; | ||
1293 | |||
1294 | err = permission(inode, MAY_EXEC, nd); | ||
1295 | dentry = ERR_PTR(err); | ||
1296 | if (err) | ||
1297 | goto out; | ||
1298 | |||
1299 | dentry = __lookup_hash_kern(name, base, nd); | ||
1300 | out: | ||
1301 | return dentry; | ||
1302 | } | ||
1303 | |||
1290 | static struct dentry *lookup_hash(struct nameidata *nd) | 1304 | static struct dentry *lookup_hash(struct nameidata *nd) |
1291 | { | 1305 | { |
1292 | return __lookup_hash(&nd->last, nd->dentry, nd); | 1306 | return __lookup_hash(&nd->last, nd->dentry, nd); |
1293 | } | 1307 | } |
1294 | 1308 | ||
1295 | /* SMP-safe */ | 1309 | /* SMP-safe */ |
1296 | struct dentry * lookup_one_len(const char * name, struct dentry * base, int len) | 1310 | static inline int __lookup_one_len(const char *name, struct qstr *this, struct dentry *base, int len) |
1297 | { | 1311 | { |
1298 | unsigned long hash; | 1312 | unsigned long hash; |
1299 | struct qstr this; | ||
1300 | unsigned int c; | 1313 | unsigned int c; |
1301 | 1314 | ||
1302 | this.name = name; | 1315 | this->name = name; |
1303 | this.len = len; | 1316 | this->len = len; |
1304 | if (!len) | 1317 | if (!len) |
1305 | goto access; | 1318 | return -EACCES; |
1306 | 1319 | ||
1307 | hash = init_name_hash(); | 1320 | hash = init_name_hash(); |
1308 | while (len--) { | 1321 | while (len--) { |
1309 | c = *(const unsigned char *)name++; | 1322 | c = *(const unsigned char *)name++; |
1310 | if (c == '/' || c == '\0') | 1323 | if (c == '/' || c == '\0') |
1311 | goto access; | 1324 | return -EACCES; |
1312 | hash = partial_name_hash(c, hash); | 1325 | hash = partial_name_hash(c, hash); |
1313 | } | 1326 | } |
1314 | this.hash = end_name_hash(hash); | 1327 | this->hash = end_name_hash(hash); |
1328 | return 0; | ||
1329 | } | ||
1315 | 1330 | ||
1331 | struct dentry *lookup_one_len(const char *name, struct dentry *base, int len) | ||
1332 | { | ||
1333 | int err; | ||
1334 | struct qstr this; | ||
1335 | |||
1336 | err = __lookup_one_len(name, &this, base, len); | ||
1337 | if (err) | ||
1338 | return ERR_PTR(err); | ||
1316 | return __lookup_hash(&this, base, NULL); | 1339 | return __lookup_hash(&this, base, NULL); |
1317 | access: | 1340 | } |
1318 | return ERR_PTR(-EACCES); | 1341 | |
1342 | struct dentry *lookup_one_len_kern(const char *name, struct dentry *base, int len) | ||
1343 | { | ||
1344 | int err; | ||
1345 | struct qstr this; | ||
1346 | |||
1347 | err = __lookup_one_len(name, &this, base, len); | ||
1348 | if (err) | ||
1349 | return ERR_PTR(err); | ||
1350 | return __lookup_hash_kern(&this, base, NULL); | ||
1319 | } | 1351 | } |
1320 | 1352 | ||
1321 | /* | 1353 | /* |
diff --git a/fs/super.c b/fs/super.c index 60b1e50cbf53..8341e4e1d738 100644 --- a/fs/super.c +++ b/fs/super.c | |||
@@ -725,16 +725,6 @@ static int test_bdev_super(struct super_block *s, void *data) | |||
725 | return (void *)s->s_bdev == data; | 725 | return (void *)s->s_bdev == data; |
726 | } | 726 | } |
727 | 727 | ||
728 | static void bdev_uevent(struct block_device *bdev, enum kobject_action action) | ||
729 | { | ||
730 | if (bdev->bd_disk) { | ||
731 | if (bdev->bd_part) | ||
732 | kobject_uevent(&bdev->bd_part->kobj, action); | ||
733 | else | ||
734 | kobject_uevent(&bdev->bd_disk->kobj, action); | ||
735 | } | ||
736 | } | ||
737 | |||
738 | int get_sb_bdev(struct file_system_type *fs_type, | 728 | int get_sb_bdev(struct file_system_type *fs_type, |
739 | int flags, const char *dev_name, void *data, | 729 | int flags, const char *dev_name, void *data, |
740 | int (*fill_super)(struct super_block *, void *, int), | 730 | int (*fill_super)(struct super_block *, void *, int), |
@@ -782,7 +772,6 @@ int get_sb_bdev(struct file_system_type *fs_type, | |||
782 | } | 772 | } |
783 | 773 | ||
784 | s->s_flags |= MS_ACTIVE; | 774 | s->s_flags |= MS_ACTIVE; |
785 | bdev_uevent(bdev, KOBJ_MOUNT); | ||
786 | } | 775 | } |
787 | 776 | ||
788 | return simple_set_mnt(mnt, s); | 777 | return simple_set_mnt(mnt, s); |
@@ -801,7 +790,6 @@ void kill_block_super(struct super_block *sb) | |||
801 | { | 790 | { |
802 | struct block_device *bdev = sb->s_bdev; | 791 | struct block_device *bdev = sb->s_bdev; |
803 | 792 | ||
804 | bdev_uevent(bdev, KOBJ_UMOUNT); | ||
805 | generic_shutdown_super(sb); | 793 | generic_shutdown_super(sb); |
806 | sync_blockdev(bdev); | 794 | sync_blockdev(bdev); |
807 | close_bdev_excl(bdev); | 795 | close_bdev_excl(bdev); |
diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c index d3b9f5f07db1..8ea2a51ce883 100644 --- a/fs/sysfs/bin.c +++ b/fs/sysfs/bin.c | |||
@@ -59,7 +59,7 @@ read(struct file * file, char __user * userbuf, size_t count, loff_t * off) | |||
59 | if (copy_to_user(userbuf, buffer, count)) | 59 | if (copy_to_user(userbuf, buffer, count)) |
60 | return -EFAULT; | 60 | return -EFAULT; |
61 | 61 | ||
62 | pr_debug("offs = %lld, *off = %lld, count = %zd\n", offs, *off, count); | 62 | pr_debug("offs = %lld, *off = %lld, count = %d\n", offs, *off, count); |
63 | 63 | ||
64 | *off = offs + count; | 64 | *off = offs + count; |
65 | 65 | ||
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index fc4633378dc0..db0413a411d6 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c | |||
@@ -633,6 +633,7 @@ struct sysfs_schedule_callback_struct { | |||
633 | struct kobject *kobj; | 633 | struct kobject *kobj; |
634 | void (*func)(void *); | 634 | void (*func)(void *); |
635 | void *data; | 635 | void *data; |
636 | struct module *owner; | ||
636 | struct work_struct work; | 637 | struct work_struct work; |
637 | }; | 638 | }; |
638 | 639 | ||
@@ -643,6 +644,7 @@ static void sysfs_schedule_callback_work(struct work_struct *work) | |||
643 | 644 | ||
644 | (ss->func)(ss->data); | 645 | (ss->func)(ss->data); |
645 | kobject_put(ss->kobj); | 646 | kobject_put(ss->kobj); |
647 | module_put(ss->owner); | ||
646 | kfree(ss); | 648 | kfree(ss); |
647 | } | 649 | } |
648 | 650 | ||
@@ -651,6 +653,7 @@ static void sysfs_schedule_callback_work(struct work_struct *work) | |||
651 | * @kobj: object we're acting for. | 653 | * @kobj: object we're acting for. |
652 | * @func: callback function to invoke later. | 654 | * @func: callback function to invoke later. |
653 | * @data: argument to pass to @func. | 655 | * @data: argument to pass to @func. |
656 | * @owner: module owning the callback code | ||
654 | * | 657 | * |
655 | * sysfs attribute methods must not unregister themselves or their parent | 658 | * sysfs attribute methods must not unregister themselves or their parent |
656 | * kobject (which would amount to the same thing). Attempts to do so will | 659 | * kobject (which would amount to the same thing). Attempts to do so will |
@@ -663,20 +666,25 @@ static void sysfs_schedule_callback_work(struct work_struct *work) | |||
663 | * until @func returns. | 666 | * until @func returns. |
664 | * | 667 | * |
665 | * Returns 0 if the request was submitted, -ENOMEM if storage could not | 668 | * Returns 0 if the request was submitted, -ENOMEM if storage could not |
666 | * be allocated. | 669 | * be allocated, -ENODEV if a reference to @owner isn't available. |
667 | */ | 670 | */ |
668 | int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *), | 671 | int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *), |
669 | void *data) | 672 | void *data, struct module *owner) |
670 | { | 673 | { |
671 | struct sysfs_schedule_callback_struct *ss; | 674 | struct sysfs_schedule_callback_struct *ss; |
672 | 675 | ||
676 | if (!try_module_get(owner)) | ||
677 | return -ENODEV; | ||
673 | ss = kmalloc(sizeof(*ss), GFP_KERNEL); | 678 | ss = kmalloc(sizeof(*ss), GFP_KERNEL); |
674 | if (!ss) | 679 | if (!ss) { |
680 | module_put(owner); | ||
675 | return -ENOMEM; | 681 | return -ENOMEM; |
682 | } | ||
676 | kobject_get(kobj); | 683 | kobject_get(kobj); |
677 | ss->kobj = kobj; | 684 | ss->kobj = kobj; |
678 | ss->func = func; | 685 | ss->func = func; |
679 | ss->data = data; | 686 | ss->data = data; |
687 | ss->owner = owner; | ||
680 | INIT_WORK(&ss->work, sysfs_schedule_callback_work); | 688 | INIT_WORK(&ss->work, sysfs_schedule_callback_work); |
681 | schedule_work(&ss->work); | 689 | schedule_work(&ss->work); |
682 | return 0; | 690 | return 0; |
diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c index b20951c93761..52eed2a7a5ef 100644 --- a/fs/sysfs/group.c +++ b/fs/sysfs/group.c | |||
@@ -70,9 +70,11 @@ void sysfs_remove_group(struct kobject * kobj, | |||
70 | { | 70 | { |
71 | struct dentry * dir; | 71 | struct dentry * dir; |
72 | 72 | ||
73 | if (grp->name) | 73 | if (grp->name) { |
74 | dir = lookup_one_len(grp->name, kobj->dentry, | 74 | dir = lookup_one_len_kern(grp->name, kobj->dentry, |
75 | strlen(grp->name)); | 75 | strlen(grp->name)); |
76 | BUG_ON(IS_ERR(dir)); | ||
77 | } | ||
76 | else | 78 | else |
77 | dir = dget(kobj->dentry); | 79 | dir = dget(kobj->dentry); |
78 | 80 | ||