diff options
author | Bob Peterson <rpeterso@redhat.com> | 2012-06-13 10:27:41 -0400 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2012-06-13 10:59:48 -0400 |
commit | 0d515210b6969ecfc161f71a4515831d9a6e58f4 (patch) | |
tree | 2e5a5da49dae5d8c036d56fc7ae14532044dfac3 /fs/gfs2 | |
parent | 0fe2f1e929ecabf834f4af2ffd300fe70700f4b3 (diff) |
GFS2: Add kobject release method
This patch adds a kobject release function that properly maintains
the kobject use count, so that accesses to the sysfs files do not
cause an access to freed kernel memory after an unmount.
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2')
-rw-r--r-- | fs/gfs2/ops_fstype.c | 36 | ||||
-rw-r--r-- | fs/gfs2/sys.c | 21 |
2 files changed, 42 insertions, 15 deletions
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index b8c250fc4922..9b2389756acd 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c | |||
@@ -1118,20 +1118,33 @@ static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent | |||
1118 | } | 1118 | } |
1119 | 1119 | ||
1120 | error = init_names(sdp, silent); | 1120 | error = init_names(sdp, silent); |
1121 | if (error) | 1121 | if (error) { |
1122 | goto fail; | 1122 | /* In this case, we haven't initialized sysfs, so we have to |
1123 | manually free the sdp. */ | ||
1124 | free_percpu(sdp->sd_lkstats); | ||
1125 | kfree(sdp); | ||
1126 | sb->s_fs_info = NULL; | ||
1127 | return error; | ||
1128 | } | ||
1123 | 1129 | ||
1124 | snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s", sdp->sd_table_name); | 1130 | snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s", sdp->sd_table_name); |
1125 | 1131 | ||
1126 | gfs2_create_debugfs_file(sdp); | ||
1127 | |||
1128 | error = gfs2_sys_fs_add(sdp); | 1132 | error = gfs2_sys_fs_add(sdp); |
1133 | /* | ||
1134 | * If we hit an error here, gfs2_sys_fs_add will have called function | ||
1135 | * kobject_put which causes the sysfs usage count to go to zero, which | ||
1136 | * causes sysfs to call function gfs2_sbd_release, which frees sdp. | ||
1137 | * Subsequent error paths here will call gfs2_sys_fs_del, which also | ||
1138 | * kobject_put to free sdp. | ||
1139 | */ | ||
1129 | if (error) | 1140 | if (error) |
1130 | goto fail; | 1141 | return error; |
1142 | |||
1143 | gfs2_create_debugfs_file(sdp); | ||
1131 | 1144 | ||
1132 | error = gfs2_lm_mount(sdp, silent); | 1145 | error = gfs2_lm_mount(sdp, silent); |
1133 | if (error) | 1146 | if (error) |
1134 | goto fail_sys; | 1147 | goto fail_debug; |
1135 | 1148 | ||
1136 | error = init_locking(sdp, &mount_gh, DO); | 1149 | error = init_locking(sdp, &mount_gh, DO); |
1137 | if (error) | 1150 | if (error) |
@@ -1215,12 +1228,12 @@ fail_locking: | |||
1215 | fail_lm: | 1228 | fail_lm: |
1216 | gfs2_gl_hash_clear(sdp); | 1229 | gfs2_gl_hash_clear(sdp); |
1217 | gfs2_lm_unmount(sdp); | 1230 | gfs2_lm_unmount(sdp); |
1218 | fail_sys: | 1231 | fail_debug: |
1219 | gfs2_sys_fs_del(sdp); | ||
1220 | fail: | ||
1221 | gfs2_delete_debugfs_file(sdp); | 1232 | gfs2_delete_debugfs_file(sdp); |
1222 | free_percpu(sdp->sd_lkstats); | 1233 | free_percpu(sdp->sd_lkstats); |
1223 | kfree(sdp); | 1234 | /* gfs2_sys_fs_del must be the last thing we do, since it causes |
1235 | * sysfs to call function gfs2_sbd_release, which frees sdp. */ | ||
1236 | gfs2_sys_fs_del(sdp); | ||
1224 | sb->s_fs_info = NULL; | 1237 | sb->s_fs_info = NULL; |
1225 | return error; | 1238 | return error; |
1226 | } | 1239 | } |
@@ -1390,10 +1403,9 @@ static void gfs2_kill_sb(struct super_block *sb) | |||
1390 | sdp->sd_root_dir = NULL; | 1403 | sdp->sd_root_dir = NULL; |
1391 | sdp->sd_master_dir = NULL; | 1404 | sdp->sd_master_dir = NULL; |
1392 | shrink_dcache_sb(sb); | 1405 | shrink_dcache_sb(sb); |
1393 | kill_block_super(sb); | ||
1394 | gfs2_delete_debugfs_file(sdp); | 1406 | gfs2_delete_debugfs_file(sdp); |
1395 | free_percpu(sdp->sd_lkstats); | 1407 | free_percpu(sdp->sd_lkstats); |
1396 | kfree(sdp); | 1408 | kill_block_super(sb); |
1397 | } | 1409 | } |
1398 | 1410 | ||
1399 | struct file_system_type gfs2_fs_type = { | 1411 | struct file_system_type gfs2_fs_type = { |
diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index 9c2592b1d5ff..e4bee4bebbf6 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c | |||
@@ -276,7 +276,15 @@ static struct attribute *gfs2_attrs[] = { | |||
276 | NULL, | 276 | NULL, |
277 | }; | 277 | }; |
278 | 278 | ||
279 | static void gfs2_sbd_release(struct kobject *kobj) | ||
280 | { | ||
281 | struct gfs2_sbd *sdp = container_of(kobj, struct gfs2_sbd, sd_kobj); | ||
282 | |||
283 | kfree(sdp); | ||
284 | } | ||
285 | |||
279 | static struct kobj_type gfs2_ktype = { | 286 | static struct kobj_type gfs2_ktype = { |
287 | .release = gfs2_sbd_release, | ||
280 | .default_attrs = gfs2_attrs, | 288 | .default_attrs = gfs2_attrs, |
281 | .sysfs_ops = &gfs2_attr_ops, | 289 | .sysfs_ops = &gfs2_attr_ops, |
282 | }; | 290 | }; |
@@ -583,6 +591,7 @@ int gfs2_sys_fs_add(struct gfs2_sbd *sdp) | |||
583 | char ro[20]; | 591 | char ro[20]; |
584 | char spectator[20]; | 592 | char spectator[20]; |
585 | char *envp[] = { ro, spectator, NULL }; | 593 | char *envp[] = { ro, spectator, NULL }; |
594 | int sysfs_frees_sdp = 0; | ||
586 | 595 | ||
587 | sprintf(ro, "RDONLY=%d", (sb->s_flags & MS_RDONLY) ? 1 : 0); | 596 | sprintf(ro, "RDONLY=%d", (sb->s_flags & MS_RDONLY) ? 1 : 0); |
588 | sprintf(spectator, "SPECTATOR=%d", sdp->sd_args.ar_spectator ? 1 : 0); | 597 | sprintf(spectator, "SPECTATOR=%d", sdp->sd_args.ar_spectator ? 1 : 0); |
@@ -591,8 +600,10 @@ int gfs2_sys_fs_add(struct gfs2_sbd *sdp) | |||
591 | error = kobject_init_and_add(&sdp->sd_kobj, &gfs2_ktype, NULL, | 600 | error = kobject_init_and_add(&sdp->sd_kobj, &gfs2_ktype, NULL, |
592 | "%s", sdp->sd_table_name); | 601 | "%s", sdp->sd_table_name); |
593 | if (error) | 602 | if (error) |
594 | goto fail; | 603 | goto fail_reg; |
595 | 604 | ||
605 | sysfs_frees_sdp = 1; /* Freeing sdp is now done by sysfs calling | ||
606 | function gfs2_sbd_release. */ | ||
596 | error = sysfs_create_group(&sdp->sd_kobj, &tune_group); | 607 | error = sysfs_create_group(&sdp->sd_kobj, &tune_group); |
597 | if (error) | 608 | if (error) |
598 | goto fail_reg; | 609 | goto fail_reg; |
@@ -615,9 +626,13 @@ fail_lock_module: | |||
615 | fail_tune: | 626 | fail_tune: |
616 | sysfs_remove_group(&sdp->sd_kobj, &tune_group); | 627 | sysfs_remove_group(&sdp->sd_kobj, &tune_group); |
617 | fail_reg: | 628 | fail_reg: |
618 | kobject_put(&sdp->sd_kobj); | 629 | free_percpu(sdp->sd_lkstats); |
619 | fail: | ||
620 | fs_err(sdp, "error %d adding sysfs files", error); | 630 | fs_err(sdp, "error %d adding sysfs files", error); |
631 | if (sysfs_frees_sdp) | ||
632 | kobject_put(&sdp->sd_kobj); | ||
633 | else | ||
634 | kfree(sdp); | ||
635 | sb->s_fs_info = NULL; | ||
621 | return error; | 636 | return error; |
622 | } | 637 | } |
623 | 638 | ||