mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-23 09:19:51 +00:00
ocfs2: fix NULL pointer dereference in ocfs2_abort_trigger()
commit685d03c379
upstream. bdev->bd_super has been removed and commit8887b94d93
change the usage from bdev->bd_super to b_assoc_map->host->i_sb. Since ocfs2 hasn't set bh->b_assoc_map, it will trigger NULL pointer dereference when calling into ocfs2_abort_trigger(). Actually this was pointed out in history, see commit74e364ad1b
. But I've made a mistake when reviewing commit8887b94d93
and then re-introduce this regression. Since we cannot revive bdev in buffer head, so fix this issue by initializing all types of ocfs2 triggers when fill super, and then get the specific ocfs2 trigger from ocfs2_caching_info when access journal. [joseph.qi@linux.alibaba.com: v2] Link: https://lkml.kernel.org/r/20240602112045.1112708-1-joseph.qi@linux.alibaba.com Link: https://lkml.kernel.org/r/20240530110630.3933832-2-joseph.qi@linux.alibaba.com Fixes:8887b94d93
("ocfs2: stop using bdev->bd_super for journal error logging") Signed-off-by: Joseph Qi <joseph.qi@linux.alibaba.com> Reviewed-by: Heming Zhao <heming.zhao@suse.com> Cc: Mark Fasheh <mark@fasheh.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Junxiao Bi <junxiao.bi@oracle.com> Cc: Changwei Ge <gechangwei@live.cn> Cc: Gang He <ghe@suse.com> Cc: Jun Piao <piaojun@huawei.com> Cc: <stable@vger.kernel.org> [6.6+] Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
72663d3e09
commit
eb63357ef2
3 changed files with 131 additions and 82 deletions
|
@ -479,12 +479,6 @@ int ocfs2_allocate_extend_trans(handle_t *handle, int thresh)
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct ocfs2_triggers {
|
|
||||||
struct jbd2_buffer_trigger_type ot_triggers;
|
|
||||||
int ot_offset;
|
|
||||||
};
|
|
||||||
|
|
||||||
static inline struct ocfs2_triggers *to_ocfs2_trigger(struct jbd2_buffer_trigger_type *triggers)
|
static inline struct ocfs2_triggers *to_ocfs2_trigger(struct jbd2_buffer_trigger_type *triggers)
|
||||||
{
|
{
|
||||||
return container_of(triggers, struct ocfs2_triggers, ot_triggers);
|
return container_of(triggers, struct ocfs2_triggers, ot_triggers);
|
||||||
|
@ -548,85 +542,76 @@ static void ocfs2_db_frozen_trigger(struct jbd2_buffer_trigger_type *triggers,
|
||||||
static void ocfs2_abort_trigger(struct jbd2_buffer_trigger_type *triggers,
|
static void ocfs2_abort_trigger(struct jbd2_buffer_trigger_type *triggers,
|
||||||
struct buffer_head *bh)
|
struct buffer_head *bh)
|
||||||
{
|
{
|
||||||
|
struct ocfs2_triggers *ot = to_ocfs2_trigger(triggers);
|
||||||
|
|
||||||
mlog(ML_ERROR,
|
mlog(ML_ERROR,
|
||||||
"ocfs2_abort_trigger called by JBD2. bh = 0x%lx, "
|
"ocfs2_abort_trigger called by JBD2. bh = 0x%lx, "
|
||||||
"bh->b_blocknr = %llu\n",
|
"bh->b_blocknr = %llu\n",
|
||||||
(unsigned long)bh,
|
(unsigned long)bh,
|
||||||
(unsigned long long)bh->b_blocknr);
|
(unsigned long long)bh->b_blocknr);
|
||||||
|
|
||||||
ocfs2_error(bh->b_assoc_map->host->i_sb,
|
ocfs2_error(ot->sb,
|
||||||
"JBD2 has aborted our journal, ocfs2 cannot continue\n");
|
"JBD2 has aborted our journal, ocfs2 cannot continue\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct ocfs2_triggers di_triggers = {
|
static void ocfs2_setup_csum_triggers(struct super_block *sb,
|
||||||
.ot_triggers = {
|
enum ocfs2_journal_trigger_type type,
|
||||||
.t_frozen = ocfs2_frozen_trigger,
|
struct ocfs2_triggers *ot)
|
||||||
.t_abort = ocfs2_abort_trigger,
|
{
|
||||||
},
|
BUG_ON(type >= OCFS2_JOURNAL_TRIGGER_COUNT);
|
||||||
.ot_offset = offsetof(struct ocfs2_dinode, i_check),
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct ocfs2_triggers eb_triggers = {
|
switch (type) {
|
||||||
.ot_triggers = {
|
case OCFS2_JTR_DI:
|
||||||
.t_frozen = ocfs2_frozen_trigger,
|
ot->ot_triggers.t_frozen = ocfs2_frozen_trigger;
|
||||||
.t_abort = ocfs2_abort_trigger,
|
ot->ot_offset = offsetof(struct ocfs2_dinode, i_check);
|
||||||
},
|
break;
|
||||||
.ot_offset = offsetof(struct ocfs2_extent_block, h_check),
|
case OCFS2_JTR_EB:
|
||||||
};
|
ot->ot_triggers.t_frozen = ocfs2_frozen_trigger;
|
||||||
|
ot->ot_offset = offsetof(struct ocfs2_extent_block, h_check);
|
||||||
|
break;
|
||||||
|
case OCFS2_JTR_RB:
|
||||||
|
ot->ot_triggers.t_frozen = ocfs2_frozen_trigger;
|
||||||
|
ot->ot_offset = offsetof(struct ocfs2_refcount_block, rf_check);
|
||||||
|
break;
|
||||||
|
case OCFS2_JTR_GD:
|
||||||
|
ot->ot_triggers.t_frozen = ocfs2_frozen_trigger;
|
||||||
|
ot->ot_offset = offsetof(struct ocfs2_group_desc, bg_check);
|
||||||
|
break;
|
||||||
|
case OCFS2_JTR_DB:
|
||||||
|
ot->ot_triggers.t_frozen = ocfs2_db_frozen_trigger;
|
||||||
|
break;
|
||||||
|
case OCFS2_JTR_XB:
|
||||||
|
ot->ot_triggers.t_frozen = ocfs2_frozen_trigger;
|
||||||
|
ot->ot_offset = offsetof(struct ocfs2_xattr_block, xb_check);
|
||||||
|
break;
|
||||||
|
case OCFS2_JTR_DQ:
|
||||||
|
ot->ot_triggers.t_frozen = ocfs2_dq_frozen_trigger;
|
||||||
|
break;
|
||||||
|
case OCFS2_JTR_DR:
|
||||||
|
ot->ot_triggers.t_frozen = ocfs2_frozen_trigger;
|
||||||
|
ot->ot_offset = offsetof(struct ocfs2_dx_root_block, dr_check);
|
||||||
|
break;
|
||||||
|
case OCFS2_JTR_DL:
|
||||||
|
ot->ot_triggers.t_frozen = ocfs2_frozen_trigger;
|
||||||
|
ot->ot_offset = offsetof(struct ocfs2_dx_leaf, dl_check);
|
||||||
|
break;
|
||||||
|
case OCFS2_JTR_NONE:
|
||||||
|
/* To make compiler happy... */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
static struct ocfs2_triggers rb_triggers = {
|
ot->ot_triggers.t_abort = ocfs2_abort_trigger;
|
||||||
.ot_triggers = {
|
ot->sb = sb;
|
||||||
.t_frozen = ocfs2_frozen_trigger,
|
}
|
||||||
.t_abort = ocfs2_abort_trigger,
|
|
||||||
},
|
|
||||||
.ot_offset = offsetof(struct ocfs2_refcount_block, rf_check),
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct ocfs2_triggers gd_triggers = {
|
void ocfs2_initialize_journal_triggers(struct super_block *sb,
|
||||||
.ot_triggers = {
|
struct ocfs2_triggers triggers[])
|
||||||
.t_frozen = ocfs2_frozen_trigger,
|
{
|
||||||
.t_abort = ocfs2_abort_trigger,
|
enum ocfs2_journal_trigger_type type;
|
||||||
},
|
|
||||||
.ot_offset = offsetof(struct ocfs2_group_desc, bg_check),
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct ocfs2_triggers db_triggers = {
|
for (type = OCFS2_JTR_DI; type < OCFS2_JOURNAL_TRIGGER_COUNT; type++)
|
||||||
.ot_triggers = {
|
ocfs2_setup_csum_triggers(sb, type, &triggers[type]);
|
||||||
.t_frozen = ocfs2_db_frozen_trigger,
|
}
|
||||||
.t_abort = ocfs2_abort_trigger,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct ocfs2_triggers xb_triggers = {
|
|
||||||
.ot_triggers = {
|
|
||||||
.t_frozen = ocfs2_frozen_trigger,
|
|
||||||
.t_abort = ocfs2_abort_trigger,
|
|
||||||
},
|
|
||||||
.ot_offset = offsetof(struct ocfs2_xattr_block, xb_check),
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct ocfs2_triggers dq_triggers = {
|
|
||||||
.ot_triggers = {
|
|
||||||
.t_frozen = ocfs2_dq_frozen_trigger,
|
|
||||||
.t_abort = ocfs2_abort_trigger,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct ocfs2_triggers dr_triggers = {
|
|
||||||
.ot_triggers = {
|
|
||||||
.t_frozen = ocfs2_frozen_trigger,
|
|
||||||
.t_abort = ocfs2_abort_trigger,
|
|
||||||
},
|
|
||||||
.ot_offset = offsetof(struct ocfs2_dx_root_block, dr_check),
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct ocfs2_triggers dl_triggers = {
|
|
||||||
.ot_triggers = {
|
|
||||||
.t_frozen = ocfs2_frozen_trigger,
|
|
||||||
.t_abort = ocfs2_abort_trigger,
|
|
||||||
},
|
|
||||||
.ot_offset = offsetof(struct ocfs2_dx_leaf, dl_check),
|
|
||||||
};
|
|
||||||
|
|
||||||
static int __ocfs2_journal_access(handle_t *handle,
|
static int __ocfs2_journal_access(handle_t *handle,
|
||||||
struct ocfs2_caching_info *ci,
|
struct ocfs2_caching_info *ci,
|
||||||
|
@ -708,56 +693,91 @@ static int __ocfs2_journal_access(handle_t *handle,
|
||||||
int ocfs2_journal_access_di(handle_t *handle, struct ocfs2_caching_info *ci,
|
int ocfs2_journal_access_di(handle_t *handle, struct ocfs2_caching_info *ci,
|
||||||
struct buffer_head *bh, int type)
|
struct buffer_head *bh, int type)
|
||||||
{
|
{
|
||||||
return __ocfs2_journal_access(handle, ci, bh, &di_triggers, type);
|
struct ocfs2_super *osb = OCFS2_SB(ocfs2_metadata_cache_get_super(ci));
|
||||||
|
|
||||||
|
return __ocfs2_journal_access(handle, ci, bh,
|
||||||
|
&osb->s_journal_triggers[OCFS2_JTR_DI],
|
||||||
|
type);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ocfs2_journal_access_eb(handle_t *handle, struct ocfs2_caching_info *ci,
|
int ocfs2_journal_access_eb(handle_t *handle, struct ocfs2_caching_info *ci,
|
||||||
struct buffer_head *bh, int type)
|
struct buffer_head *bh, int type)
|
||||||
{
|
{
|
||||||
return __ocfs2_journal_access(handle, ci, bh, &eb_triggers, type);
|
struct ocfs2_super *osb = OCFS2_SB(ocfs2_metadata_cache_get_super(ci));
|
||||||
|
|
||||||
|
return __ocfs2_journal_access(handle, ci, bh,
|
||||||
|
&osb->s_journal_triggers[OCFS2_JTR_EB],
|
||||||
|
type);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ocfs2_journal_access_rb(handle_t *handle, struct ocfs2_caching_info *ci,
|
int ocfs2_journal_access_rb(handle_t *handle, struct ocfs2_caching_info *ci,
|
||||||
struct buffer_head *bh, int type)
|
struct buffer_head *bh, int type)
|
||||||
{
|
{
|
||||||
return __ocfs2_journal_access(handle, ci, bh, &rb_triggers,
|
struct ocfs2_super *osb = OCFS2_SB(ocfs2_metadata_cache_get_super(ci));
|
||||||
|
|
||||||
|
return __ocfs2_journal_access(handle, ci, bh,
|
||||||
|
&osb->s_journal_triggers[OCFS2_JTR_RB],
|
||||||
type);
|
type);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ocfs2_journal_access_gd(handle_t *handle, struct ocfs2_caching_info *ci,
|
int ocfs2_journal_access_gd(handle_t *handle, struct ocfs2_caching_info *ci,
|
||||||
struct buffer_head *bh, int type)
|
struct buffer_head *bh, int type)
|
||||||
{
|
{
|
||||||
return __ocfs2_journal_access(handle, ci, bh, &gd_triggers, type);
|
struct ocfs2_super *osb = OCFS2_SB(ocfs2_metadata_cache_get_super(ci));
|
||||||
|
|
||||||
|
return __ocfs2_journal_access(handle, ci, bh,
|
||||||
|
&osb->s_journal_triggers[OCFS2_JTR_GD],
|
||||||
|
type);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ocfs2_journal_access_db(handle_t *handle, struct ocfs2_caching_info *ci,
|
int ocfs2_journal_access_db(handle_t *handle, struct ocfs2_caching_info *ci,
|
||||||
struct buffer_head *bh, int type)
|
struct buffer_head *bh, int type)
|
||||||
{
|
{
|
||||||
return __ocfs2_journal_access(handle, ci, bh, &db_triggers, type);
|
struct ocfs2_super *osb = OCFS2_SB(ocfs2_metadata_cache_get_super(ci));
|
||||||
|
|
||||||
|
return __ocfs2_journal_access(handle, ci, bh,
|
||||||
|
&osb->s_journal_triggers[OCFS2_JTR_DB],
|
||||||
|
type);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ocfs2_journal_access_xb(handle_t *handle, struct ocfs2_caching_info *ci,
|
int ocfs2_journal_access_xb(handle_t *handle, struct ocfs2_caching_info *ci,
|
||||||
struct buffer_head *bh, int type)
|
struct buffer_head *bh, int type)
|
||||||
{
|
{
|
||||||
return __ocfs2_journal_access(handle, ci, bh, &xb_triggers, type);
|
struct ocfs2_super *osb = OCFS2_SB(ocfs2_metadata_cache_get_super(ci));
|
||||||
|
|
||||||
|
return __ocfs2_journal_access(handle, ci, bh,
|
||||||
|
&osb->s_journal_triggers[OCFS2_JTR_XB],
|
||||||
|
type);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ocfs2_journal_access_dq(handle_t *handle, struct ocfs2_caching_info *ci,
|
int ocfs2_journal_access_dq(handle_t *handle, struct ocfs2_caching_info *ci,
|
||||||
struct buffer_head *bh, int type)
|
struct buffer_head *bh, int type)
|
||||||
{
|
{
|
||||||
return __ocfs2_journal_access(handle, ci, bh, &dq_triggers, type);
|
struct ocfs2_super *osb = OCFS2_SB(ocfs2_metadata_cache_get_super(ci));
|
||||||
|
|
||||||
|
return __ocfs2_journal_access(handle, ci, bh,
|
||||||
|
&osb->s_journal_triggers[OCFS2_JTR_DQ],
|
||||||
|
type);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ocfs2_journal_access_dr(handle_t *handle, struct ocfs2_caching_info *ci,
|
int ocfs2_journal_access_dr(handle_t *handle, struct ocfs2_caching_info *ci,
|
||||||
struct buffer_head *bh, int type)
|
struct buffer_head *bh, int type)
|
||||||
{
|
{
|
||||||
return __ocfs2_journal_access(handle, ci, bh, &dr_triggers, type);
|
struct ocfs2_super *osb = OCFS2_SB(ocfs2_metadata_cache_get_super(ci));
|
||||||
|
|
||||||
|
return __ocfs2_journal_access(handle, ci, bh,
|
||||||
|
&osb->s_journal_triggers[OCFS2_JTR_DR],
|
||||||
|
type);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ocfs2_journal_access_dl(handle_t *handle, struct ocfs2_caching_info *ci,
|
int ocfs2_journal_access_dl(handle_t *handle, struct ocfs2_caching_info *ci,
|
||||||
struct buffer_head *bh, int type)
|
struct buffer_head *bh, int type)
|
||||||
{
|
{
|
||||||
return __ocfs2_journal_access(handle, ci, bh, &dl_triggers, type);
|
struct ocfs2_super *osb = OCFS2_SB(ocfs2_metadata_cache_get_super(ci));
|
||||||
|
|
||||||
|
return __ocfs2_journal_access(handle, ci, bh,
|
||||||
|
&osb->s_journal_triggers[OCFS2_JTR_DL],
|
||||||
|
type);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ocfs2_journal_access(handle_t *handle, struct ocfs2_caching_info *ci,
|
int ocfs2_journal_access(handle_t *handle, struct ocfs2_caching_info *ci,
|
||||||
|
|
|
@ -284,6 +284,30 @@ enum ocfs2_mount_options
|
||||||
#define OCFS2_OSB_ERROR_FS 0x0004
|
#define OCFS2_OSB_ERROR_FS 0x0004
|
||||||
#define OCFS2_DEFAULT_ATIME_QUANTUM 60
|
#define OCFS2_DEFAULT_ATIME_QUANTUM 60
|
||||||
|
|
||||||
|
struct ocfs2_triggers {
|
||||||
|
struct jbd2_buffer_trigger_type ot_triggers;
|
||||||
|
int ot_offset;
|
||||||
|
struct super_block *sb;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ocfs2_journal_trigger_type {
|
||||||
|
OCFS2_JTR_DI,
|
||||||
|
OCFS2_JTR_EB,
|
||||||
|
OCFS2_JTR_RB,
|
||||||
|
OCFS2_JTR_GD,
|
||||||
|
OCFS2_JTR_DB,
|
||||||
|
OCFS2_JTR_XB,
|
||||||
|
OCFS2_JTR_DQ,
|
||||||
|
OCFS2_JTR_DR,
|
||||||
|
OCFS2_JTR_DL,
|
||||||
|
OCFS2_JTR_NONE /* This must be the last entry */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define OCFS2_JOURNAL_TRIGGER_COUNT OCFS2_JTR_NONE
|
||||||
|
|
||||||
|
void ocfs2_initialize_journal_triggers(struct super_block *sb,
|
||||||
|
struct ocfs2_triggers triggers[]);
|
||||||
|
|
||||||
struct ocfs2_journal;
|
struct ocfs2_journal;
|
||||||
struct ocfs2_slot_info;
|
struct ocfs2_slot_info;
|
||||||
struct ocfs2_recovery_map;
|
struct ocfs2_recovery_map;
|
||||||
|
@ -351,6 +375,9 @@ struct ocfs2_super
|
||||||
struct ocfs2_journal *journal;
|
struct ocfs2_journal *journal;
|
||||||
unsigned long osb_commit_interval;
|
unsigned long osb_commit_interval;
|
||||||
|
|
||||||
|
/* Journal triggers for checksum */
|
||||||
|
struct ocfs2_triggers s_journal_triggers[OCFS2_JOURNAL_TRIGGER_COUNT];
|
||||||
|
|
||||||
struct delayed_work la_enable_wq;
|
struct delayed_work la_enable_wq;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -1075,9 +1075,11 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
|
||||||
debugfs_create_file("fs_state", S_IFREG|S_IRUSR, osb->osb_debug_root,
|
debugfs_create_file("fs_state", S_IFREG|S_IRUSR, osb->osb_debug_root,
|
||||||
osb, &ocfs2_osb_debug_fops);
|
osb, &ocfs2_osb_debug_fops);
|
||||||
|
|
||||||
if (ocfs2_meta_ecc(osb))
|
if (ocfs2_meta_ecc(osb)) {
|
||||||
|
ocfs2_initialize_journal_triggers(sb, osb->s_journal_triggers);
|
||||||
ocfs2_blockcheck_stats_debugfs_install( &osb->osb_ecc_stats,
|
ocfs2_blockcheck_stats_debugfs_install( &osb->osb_ecc_stats,
|
||||||
osb->osb_debug_root);
|
osb->osb_debug_root);
|
||||||
|
}
|
||||||
|
|
||||||
status = ocfs2_mount_volume(sb);
|
status = ocfs2_mount_volume(sb);
|
||||||
if (status < 0)
|
if (status < 0)
|
||||||
|
|
Loading…
Reference in a new issue