diff options
| author | Steven Whitehouse <swhiteho@redhat.com> | 2008-12-19 10:32:06 -0500 |
|---|---|---|
| committer | Steven Whitehouse <swhiteho@redhat.com> | 2009-01-05 02:39:18 -0500 |
| commit | fefc03bfedeff2002f14e848ecb7c0cd77ee0b15 (patch) | |
| tree | 830ec1d36b8688a70580e8c5c18ac5f40015448f | |
| parent | 7ed122e42c72b3e4531f8b4a9f72159e8303ac15 (diff) | |
Revert "GFS2: Fix use-after-free bug on umount"
This reverts commit 78802499912f1ba31ce83a94c55b5a980f250a43.
The original patch is causing problems in relation to order of
operations at umount in relation to jdata files. I need to fix
this a different way.
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
| -rw-r--r-- | fs/gfs2/glock.c | 3 | ||||
| -rw-r--r-- | fs/gfs2/glock.h | 2 | ||||
| -rw-r--r-- | fs/gfs2/ops_fstype.c | 98 | ||||
| -rw-r--r-- | fs/gfs2/ops_super.c | 68 | ||||
| -rw-r--r-- | fs/gfs2/super.c | 34 | ||||
| -rw-r--r-- | fs/gfs2/super.h | 3 |
6 files changed, 114 insertions, 94 deletions
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 5eae62e7f778..6e298b070117 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c | |||
| @@ -1547,9 +1547,8 @@ static void clear_glock(struct gfs2_glock *gl) | |||
| 1547 | * Called when unmounting the filesystem. | 1547 | * Called when unmounting the filesystem. |
| 1548 | */ | 1548 | */ |
| 1549 | 1549 | ||
| 1550 | void gfs2_gl_hash_clear(struct super_block *sb) | 1550 | void gfs2_gl_hash_clear(struct gfs2_sbd *sdp) |
| 1551 | { | 1551 | { |
| 1552 | struct gfs2_sbd *sdp = sb->s_fs_info; | ||
| 1553 | unsigned long t; | 1552 | unsigned long t; |
| 1554 | unsigned int x; | 1553 | unsigned int x; |
| 1555 | int cont; | 1554 | int cont; |
diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index ce54f338cff9..543ec7ecfbda 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h | |||
| @@ -130,7 +130,7 @@ void gfs2_lvb_unhold(struct gfs2_glock *gl); | |||
| 130 | 130 | ||
| 131 | void gfs2_glock_cb(void *cb_data, unsigned int type, void *data); | 131 | void gfs2_glock_cb(void *cb_data, unsigned int type, void *data); |
| 132 | void gfs2_reclaim_glock(struct gfs2_sbd *sdp); | 132 | void gfs2_reclaim_glock(struct gfs2_sbd *sdp); |
| 133 | void gfs2_gl_hash_clear(struct super_block *sb); | 133 | void gfs2_gl_hash_clear(struct gfs2_sbd *sdp); |
| 134 | void gfs2_glock_finish_truncate(struct gfs2_inode *ip); | 134 | void gfs2_glock_finish_truncate(struct gfs2_inode *ip); |
| 135 | 135 | ||
| 136 | int __init gfs2_glock_init(void); | 136 | int __init gfs2_glock_init(void); |
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 2e735bece6b9..4cae60f4a175 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c | |||
| @@ -705,40 +705,6 @@ static int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh) | |||
| 705 | return error; | 705 | return error; |
| 706 | } | 706 | } |
| 707 | 707 | ||
| 708 | /** | ||
| 709 | * gfs2_jindex_free - Clear all the journal index information | ||
| 710 | * @sdp: The GFS2 superblock | ||
| 711 | * | ||
| 712 | */ | ||
| 713 | |||
| 714 | static void gfs2_jindex_free(struct gfs2_sbd *sdp) | ||
| 715 | { | ||
| 716 | struct list_head list, *head; | ||
| 717 | struct gfs2_jdesc *jd; | ||
| 718 | struct gfs2_journal_extent *jext; | ||
| 719 | |||
| 720 | spin_lock(&sdp->sd_jindex_spin); | ||
| 721 | list_add(&list, &sdp->sd_jindex_list); | ||
| 722 | list_del_init(&sdp->sd_jindex_list); | ||
| 723 | sdp->sd_journals = 0; | ||
| 724 | spin_unlock(&sdp->sd_jindex_spin); | ||
| 725 | |||
| 726 | while (!list_empty(&list)) { | ||
| 727 | jd = list_entry(list.next, struct gfs2_jdesc, jd_list); | ||
| 728 | head = &jd->extent_list; | ||
| 729 | while (!list_empty(head)) { | ||
| 730 | jext = list_entry(head->next, | ||
| 731 | struct gfs2_journal_extent, | ||
| 732 | extent_list); | ||
| 733 | list_del(&jext->extent_list); | ||
| 734 | kfree(jext); | ||
| 735 | } | ||
| 736 | list_del(&jd->jd_list); | ||
| 737 | iput(jd->jd_inode); | ||
| 738 | kfree(jd); | ||
| 739 | } | ||
| 740 | } | ||
| 741 | |||
| 742 | static int init_journal(struct gfs2_sbd *sdp, int undo) | 708 | static int init_journal(struct gfs2_sbd *sdp, int undo) |
| 743 | { | 709 | { |
| 744 | struct inode *master = sdp->sd_master_dir->d_inode; | 710 | struct inode *master = sdp->sd_master_dir->d_inode; |
| @@ -1237,7 +1203,7 @@ fail_sb: | |||
| 1237 | fail_locking: | 1203 | fail_locking: |
| 1238 | init_locking(sdp, &mount_gh, UNDO); | 1204 | init_locking(sdp, &mount_gh, UNDO); |
| 1239 | fail_lm: | 1205 | fail_lm: |
| 1240 | gfs2_gl_hash_clear(sb); | 1206 | gfs2_gl_hash_clear(sdp); |
| 1241 | gfs2_lm_unmount(sdp); | 1207 | gfs2_lm_unmount(sdp); |
| 1242 | while (invalidate_inodes(sb)) | 1208 | while (invalidate_inodes(sb)) |
| 1243 | yield(); | 1209 | yield(); |
| @@ -1297,61 +1263,17 @@ static int gfs2_get_sb_meta(struct file_system_type *fs_type, int flags, | |||
| 1297 | static void gfs2_kill_sb(struct super_block *sb) | 1263 | static void gfs2_kill_sb(struct super_block *sb) |
| 1298 | { | 1264 | { |
| 1299 | struct gfs2_sbd *sdp = sb->s_fs_info; | 1265 | struct gfs2_sbd *sdp = sb->s_fs_info; |
| 1300 | 1266 | if (sdp) { | |
| 1301 | if (sdp == NULL) { | 1267 | gfs2_meta_syncfs(sdp); |
| 1302 | kill_block_super(sb); | 1268 | dput(sdp->sd_root_dir); |
| 1303 | return; | 1269 | dput(sdp->sd_master_dir); |
| 1304 | } | 1270 | sdp->sd_root_dir = NULL; |
| 1305 | gfs2_meta_syncfs(sdp); | 1271 | sdp->sd_master_dir = NULL; |
| 1306 | dput(sdp->sd_root_dir); | ||
| 1307 | dput(sdp->sd_master_dir); | ||
| 1308 | sdp->sd_root_dir = NULL; | ||
| 1309 | sdp->sd_master_dir = NULL; | ||
| 1310 | |||
| 1311 | /* Unfreeze the filesystem, if we need to */ | ||
| 1312 | mutex_lock(&sdp->sd_freeze_lock); | ||
| 1313 | if (sdp->sd_freeze_count) | ||
| 1314 | gfs2_glock_dq_uninit(&sdp->sd_freeze_gh); | ||
| 1315 | mutex_unlock(&sdp->sd_freeze_lock); | ||
| 1316 | |||
| 1317 | kthread_stop(sdp->sd_quotad_process); | ||
| 1318 | kthread_stop(sdp->sd_logd_process); | ||
| 1319 | kthread_stop(sdp->sd_recoverd_process); | ||
| 1320 | |||
| 1321 | if (!(sb->s_flags & MS_RDONLY)) { | ||
| 1322 | int error = gfs2_make_fs_ro(sdp); | ||
| 1323 | if (error) | ||
| 1324 | gfs2_io_error(sdp); | ||
| 1325 | } | ||
| 1326 | |||
| 1327 | /* At this point, we're through modifying the disk */ | ||
| 1328 | gfs2_jindex_free(sdp); | ||
| 1329 | gfs2_clear_rgrpd(sdp); | ||
| 1330 | iput(sdp->sd_jindex); | ||
| 1331 | iput(sdp->sd_inum_inode); | ||
| 1332 | iput(sdp->sd_statfs_inode); | ||
| 1333 | iput(sdp->sd_rindex); | ||
| 1334 | iput(sdp->sd_quota_inode); | ||
| 1335 | |||
| 1336 | gfs2_glock_put(sdp->sd_rename_gl); | ||
| 1337 | gfs2_glock_put(sdp->sd_trans_gl); | ||
| 1338 | |||
| 1339 | if (!sdp->sd_args.ar_spectator) { | ||
| 1340 | gfs2_glock_dq_uninit(&sdp->sd_journal_gh); | ||
| 1341 | gfs2_glock_dq_uninit(&sdp->sd_jinode_gh); | ||
| 1342 | gfs2_glock_dq_uninit(&sdp->sd_ir_gh); | ||
| 1343 | gfs2_glock_dq_uninit(&sdp->sd_sc_gh); | ||
| 1344 | gfs2_glock_dq_uninit(&sdp->sd_qc_gh); | ||
| 1345 | iput(sdp->sd_ir_inode); | ||
| 1346 | iput(sdp->sd_sc_inode); | ||
| 1347 | iput(sdp->sd_qc_inode); | ||
| 1348 | } | 1272 | } |
| 1349 | gfs2_glock_dq_uninit(&sdp->sd_live_gh); | 1273 | shrink_dcache_sb(sb); |
| 1350 | kill_block_super(sb); | 1274 | kill_block_super(sb); |
| 1351 | gfs2_lm_unmount(sdp); | 1275 | if (sdp) |
| 1352 | gfs2_sys_fs_del(sdp); | 1276 | gfs2_delete_debugfs_file(sdp); |
| 1353 | gfs2_delete_debugfs_file(sdp); | ||
| 1354 | kfree(sdp); | ||
| 1355 | } | 1277 | } |
| 1356 | 1278 | ||
| 1357 | struct file_system_type gfs2_fs_type = { | 1279 | struct file_system_type gfs2_fs_type = { |
diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c index bd08a0a8d9bf..08837a728635 100644 --- a/fs/gfs2/ops_super.c +++ b/fs/gfs2/ops_super.c | |||
| @@ -95,7 +95,7 @@ do_flush: | |||
| 95 | * Returns: errno | 95 | * Returns: errno |
| 96 | */ | 96 | */ |
| 97 | 97 | ||
| 98 | int gfs2_make_fs_ro(struct gfs2_sbd *sdp) | 98 | static int gfs2_make_fs_ro(struct gfs2_sbd *sdp) |
| 99 | { | 99 | { |
| 100 | struct gfs2_holder t_gh; | 100 | struct gfs2_holder t_gh; |
| 101 | int error; | 101 | int error; |
| @@ -122,6 +122,70 @@ int gfs2_make_fs_ro(struct gfs2_sbd *sdp) | |||
| 122 | } | 122 | } |
| 123 | 123 | ||
| 124 | /** | 124 | /** |
| 125 | * gfs2_put_super - Unmount the filesystem | ||
| 126 | * @sb: The VFS superblock | ||
| 127 | * | ||
| 128 | */ | ||
| 129 | |||
| 130 | static void gfs2_put_super(struct super_block *sb) | ||
| 131 | { | ||
| 132 | struct gfs2_sbd *sdp = sb->s_fs_info; | ||
| 133 | int error; | ||
| 134 | |||
| 135 | /* Unfreeze the filesystem, if we need to */ | ||
| 136 | |||
| 137 | mutex_lock(&sdp->sd_freeze_lock); | ||
| 138 | if (sdp->sd_freeze_count) | ||
| 139 | gfs2_glock_dq_uninit(&sdp->sd_freeze_gh); | ||
| 140 | mutex_unlock(&sdp->sd_freeze_lock); | ||
| 141 | |||
| 142 | kthread_stop(sdp->sd_quotad_process); | ||
| 143 | kthread_stop(sdp->sd_logd_process); | ||
| 144 | kthread_stop(sdp->sd_recoverd_process); | ||
| 145 | |||
| 146 | if (!(sb->s_flags & MS_RDONLY)) { | ||
| 147 | error = gfs2_make_fs_ro(sdp); | ||
| 148 | if (error) | ||
| 149 | gfs2_io_error(sdp); | ||
| 150 | } | ||
| 151 | /* At this point, we're through modifying the disk */ | ||
| 152 | |||
| 153 | /* Release stuff */ | ||
| 154 | |||
| 155 | iput(sdp->sd_jindex); | ||
| 156 | iput(sdp->sd_inum_inode); | ||
| 157 | iput(sdp->sd_statfs_inode); | ||
| 158 | iput(sdp->sd_rindex); | ||
| 159 | iput(sdp->sd_quota_inode); | ||
| 160 | |||
| 161 | gfs2_glock_put(sdp->sd_rename_gl); | ||
| 162 | gfs2_glock_put(sdp->sd_trans_gl); | ||
| 163 | |||
| 164 | if (!sdp->sd_args.ar_spectator) { | ||
| 165 | gfs2_glock_dq_uninit(&sdp->sd_journal_gh); | ||
| 166 | gfs2_glock_dq_uninit(&sdp->sd_jinode_gh); | ||
| 167 | gfs2_glock_dq_uninit(&sdp->sd_ir_gh); | ||
| 168 | gfs2_glock_dq_uninit(&sdp->sd_sc_gh); | ||
| 169 | gfs2_glock_dq_uninit(&sdp->sd_qc_gh); | ||
| 170 | iput(sdp->sd_ir_inode); | ||
| 171 | iput(sdp->sd_sc_inode); | ||
| 172 | iput(sdp->sd_qc_inode); | ||
| 173 | } | ||
| 174 | |||
| 175 | gfs2_glock_dq_uninit(&sdp->sd_live_gh); | ||
| 176 | gfs2_clear_rgrpd(sdp); | ||
| 177 | gfs2_jindex_free(sdp); | ||
| 178 | /* Take apart glock structures and buffer lists */ | ||
| 179 | gfs2_gl_hash_clear(sdp); | ||
| 180 | /* Unmount the locking protocol */ | ||
| 181 | gfs2_lm_unmount(sdp); | ||
| 182 | |||
| 183 | /* At this point, we're through participating in the lockspace */ | ||
| 184 | gfs2_sys_fs_del(sdp); | ||
| 185 | kfree(sdp); | ||
| 186 | } | ||
| 187 | |||
| 188 | /** | ||
| 125 | * gfs2_write_super | 189 | * gfs2_write_super |
| 126 | * @sb: the superblock | 190 | * @sb: the superblock |
| 127 | * | 191 | * |
| @@ -622,7 +686,7 @@ const struct super_operations gfs2_super_ops = { | |||
| 622 | .destroy_inode = gfs2_destroy_inode, | 686 | .destroy_inode = gfs2_destroy_inode, |
| 623 | .write_inode = gfs2_write_inode, | 687 | .write_inode = gfs2_write_inode, |
| 624 | .delete_inode = gfs2_delete_inode, | 688 | .delete_inode = gfs2_delete_inode, |
| 625 | .put_super = gfs2_gl_hash_clear, | 689 | .put_super = gfs2_put_super, |
| 626 | .write_super = gfs2_write_super, | 690 | .write_super = gfs2_write_super, |
| 627 | .sync_fs = gfs2_sync_fs, | 691 | .sync_fs = gfs2_sync_fs, |
| 628 | .write_super_lockfs = gfs2_write_super_lockfs, | 692 | .write_super_lockfs = gfs2_write_super_lockfs, |
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index f14658b20204..141b781f2fcc 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c | |||
| @@ -33,6 +33,40 @@ | |||
| 33 | #include "trans.h" | 33 | #include "trans.h" |
| 34 | #include "util.h" | 34 | #include "util.h" |
| 35 | 35 | ||
| 36 | /** | ||
| 37 | * gfs2_jindex_free - Clear all the journal index information | ||
| 38 | * @sdp: The GFS2 superblock | ||
| 39 | * | ||
| 40 | */ | ||
| 41 | |||
| 42 | void gfs2_jindex_free(struct gfs2_sbd *sdp) | ||
| 43 | { | ||
| 44 | struct list_head list, *head; | ||
| 45 | struct gfs2_jdesc *jd; | ||
| 46 | struct gfs2_journal_extent *jext; | ||
| 47 | |||
| 48 | spin_lock(&sdp->sd_jindex_spin); | ||
| 49 | list_add(&list, &sdp->sd_jindex_list); | ||
| 50 | list_del_init(&sdp->sd_jindex_list); | ||
| 51 | sdp->sd_journals = 0; | ||
| 52 | spin_unlock(&sdp->sd_jindex_spin); | ||
| 53 | |||
| 54 | while (!list_empty(&list)) { | ||
| 55 | jd = list_entry(list.next, struct gfs2_jdesc, jd_list); | ||
| 56 | head = &jd->extent_list; | ||
| 57 | while (!list_empty(head)) { | ||
| 58 | jext = list_entry(head->next, | ||
| 59 | struct gfs2_journal_extent, | ||
| 60 | extent_list); | ||
| 61 | list_del(&jext->extent_list); | ||
| 62 | kfree(jext); | ||
| 63 | } | ||
| 64 | list_del(&jd->jd_list); | ||
| 65 | iput(jd->jd_inode); | ||
| 66 | kfree(jd); | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 36 | static struct gfs2_jdesc *jdesc_find_i(struct list_head *head, unsigned int jid) | 70 | static struct gfs2_jdesc *jdesc_find_i(struct list_head *head, unsigned int jid) |
| 37 | { | 71 | { |
| 38 | struct gfs2_jdesc *jd; | 72 | struct gfs2_jdesc *jd; |
diff --git a/fs/gfs2/super.h b/fs/gfs2/super.h index 4d2492b3e7ef..f6b8b00ad881 100644 --- a/fs/gfs2/super.h +++ b/fs/gfs2/super.h | |||
| @@ -25,6 +25,8 @@ static inline unsigned int gfs2_jindex_size(struct gfs2_sbd *sdp) | |||
| 25 | return x; | 25 | return x; |
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | void gfs2_jindex_free(struct gfs2_sbd *sdp); | ||
| 29 | |||
| 28 | struct gfs2_jdesc *gfs2_jdesc_find(struct gfs2_sbd *sdp, unsigned int jid); | 30 | struct gfs2_jdesc *gfs2_jdesc_find(struct gfs2_sbd *sdp, unsigned int jid); |
| 29 | int gfs2_jdesc_check(struct gfs2_jdesc *jd); | 31 | int gfs2_jdesc_check(struct gfs2_jdesc *jd); |
| 30 | 32 | ||
| @@ -32,7 +34,6 @@ int gfs2_lookup_in_master_dir(struct gfs2_sbd *sdp, char *filename, | |||
| 32 | struct gfs2_inode **ipp); | 34 | struct gfs2_inode **ipp); |
| 33 | 35 | ||
| 34 | int gfs2_make_fs_rw(struct gfs2_sbd *sdp); | 36 | int gfs2_make_fs_rw(struct gfs2_sbd *sdp); |
| 35 | int gfs2_make_fs_ro(struct gfs2_sbd *sdp); | ||
| 36 | 37 | ||
| 37 | int gfs2_statfs_init(struct gfs2_sbd *sdp); | 38 | int gfs2_statfs_init(struct gfs2_sbd *sdp); |
| 38 | void gfs2_statfs_change(struct gfs2_sbd *sdp, | 39 | void gfs2_statfs_change(struct gfs2_sbd *sdp, |
