aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2
diff options
context:
space:
mode:
authorBob Peterson <rpeterso@redhat.com>2012-06-13 10:27:41 -0400
committerSteven Whitehouse <swhiteho@redhat.com>2012-06-13 10:59:48 -0400
commit0d515210b6969ecfc161f71a4515831d9a6e58f4 (patch)
tree2e5a5da49dae5d8c036d56fc7ae14532044dfac3 /fs/gfs2
parent0fe2f1e929ecabf834f4af2ffd300fe70700f4b3 (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.c36
-rw-r--r--fs/gfs2/sys.c21
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:
1215fail_lm: 1228fail_lm:
1216 gfs2_gl_hash_clear(sdp); 1229 gfs2_gl_hash_clear(sdp);
1217 gfs2_lm_unmount(sdp); 1230 gfs2_lm_unmount(sdp);
1218fail_sys: 1231fail_debug:
1219 gfs2_sys_fs_del(sdp);
1220fail:
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
1399struct file_system_type gfs2_fs_type = { 1411struct 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
279static 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
279static struct kobj_type gfs2_ktype = { 286static 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:
615fail_tune: 626fail_tune:
616 sysfs_remove_group(&sdp->sd_kobj, &tune_group); 627 sysfs_remove_group(&sdp->sd_kobj, &tune_group);
617fail_reg: 628fail_reg:
618 kobject_put(&sdp->sd_kobj); 629 free_percpu(sdp->sd_lkstats);
619fail:
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