--- a/sys/kern/vfs_sync.c +++ b/sys/kern/vfs_sync.c @@ -198,6 +198,8 @@ int slot; ctx = vp->v_mount->mnt_syncer_ctx; + if (ctx == NULL) + return; lwkt_gettoken(&ctx->sc_token); if (vp->v_flag & VONWORKLST) { @@ -234,6 +236,8 @@ struct syncer_ctx *ctx; ctx = vp->v_mount->mnt_syncer_ctx; + if (ctx == NULL) + return; lwkt_gettoken(&ctx->sc_token); if ((vp->v_flag & (VISDIRTY | VONWORKLST | VOBJDIRTY)) == VONWORKLST && @@ -281,6 +285,8 @@ if ((vp->v_flag & VISDIRTY) == 0) { ctx = vp->v_mount->mnt_syncer_ctx; vsetflags(vp, VISDIRTY); + if (ctx == NULL) + return; lwkt_gettoken(&ctx->sc_token); if ((vp->v_flag & VONWORKLST) == 0) vn_syncer_add(vp, syncdelay); @@ -296,6 +302,8 @@ if ((vp->v_flag & VOBJDIRTY) == 0) { ctx = vp->v_mount->mnt_syncer_ctx; vsetflags(vp, VOBJDIRTY); + if (ctx == NULL) + return; lwkt_gettoken(&ctx->sc_token); if ((vp->v_flag & VONWORKLST) == 0) vn_syncer_add(vp, syncdelay); @@ -350,11 +358,20 @@ lwkt_gettoken(&ctx->sc_token); } - mp->mnt_syncer_ctx = NULL; lwkt_reltoken(&ctx->sc_token); + /* + * Interlock against the lock-free trigger_syncer*() / speedup_syncer() + * users, which load mp->mnt_syncer_ctx and then operate on the ctx + * without any other synchronization. Publish the NULL and free the + * ctx while holding mnt_token exclusively so any user that already + * loaded the pointer completes before the memory is destroyed. + */ + lwkt_gettoken(&mp->mnt_token); + mp->mnt_syncer_ctx = NULL; hashdestroy(ctx->syncer_workitem_pending, M_DEVBUF, ctx->syncer_mask); kfree(ctx, M_TEMP); + lwkt_reltoken(&mp->mnt_token); } struct thread *updatethread; @@ -567,8 +584,12 @@ */ atomic_add_int(&rushjob, 1); ++stat_rush_requests; - if (mp && mp->mnt_syncer_ctx) - wakeup(mp->mnt_syncer_ctx); + if (mp) { + lwkt_gettoken_shared(&mp->mnt_token); + if (mp->mnt_syncer_ctx) + wakeup(mp->mnt_syncer_ctx); + lwkt_reltoken(&mp->mnt_token); + } } /* @@ -581,10 +602,14 @@ { struct syncer_ctx *ctx; - if (mp && (ctx = mp->mnt_syncer_ctx) != NULL) { + if (mp == NULL) + return; + lwkt_gettoken_shared(&mp->mnt_token); + if ((ctx = mp->mnt_syncer_ctx) != NULL) { if (atomic_fetchadd_int(&ctx->syncer_trigger, 2) <= 1) wakeup(ctx); } + lwkt_reltoken(&mp->mnt_token); } void @@ -592,9 +617,13 @@ { struct syncer_ctx *ctx; - if (mp && (ctx = mp->mnt_syncer_ctx) != NULL) { + if (mp == NULL) + return; + lwkt_gettoken_shared(&mp->mnt_token); + if ((ctx = mp->mnt_syncer_ctx) != NULL) { atomic_add_int(&ctx->syncer_trigger, -2); } + lwkt_reltoken(&mp->mnt_token); } /* @@ -605,12 +634,16 @@ { struct syncer_ctx *ctx; - if (mp && (ctx = mp->mnt_syncer_ctx) != NULL) { + if (mp == NULL) + return; + lwkt_gettoken_shared(&mp->mnt_token); + if ((ctx = mp->mnt_syncer_ctx) != NULL) { if ((ctx->syncer_trigger & 1) == 0) { atomic_set_int(&ctx->syncer_trigger, 1); wakeup(ctx); } } + lwkt_reltoken(&mp->mnt_token); } /*