From 500b6a229686896bb964b4f98efdd7c3f149801d Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Wed, 13 Jul 2005 02:00:19 +0000 Subject: [PATCH] Add journaling restart support, required to produce a robust journaling environment. If a journal is writing to one stream and the stream breaks or dies or otherwise fails, this feature gives us the ability to restart the journaling stream on a new descriptor without losing any data. The journaling restart code does a shutdown() of the old descriptor, waits for both directions to cease operation, installs a new stream descriptor, and resets the FIFO index to the last acknowledged offset. This can be demonstrated by opening two windows. In the first window do: mountctl -a2 /usr:test | jscan -d2 stdin Mess around a bit on /usr. Then in the second window do: mountctl -r2 /usr:test | jscan -d2 stdin The first jscan will terminate and the new jscan will pick up the stream. --- sbin/mountctl/mountctl.8 | 30 ++++++-- sbin/mountctl/mountctl.c | 78 ++++++++++++++----- sys/kern/vfs_jops.c | 160 ++++++++++++++++++++++++++++++++------- sys/kern/vfs_journal.c | 160 ++++++++++++++++++++++++++++++++------- sys/sys/journal.h | 5 +- sys/sys/mountctl.h | 9 ++- 6 files changed, 358 insertions(+), 84 deletions(-) diff --git a/sbin/mountctl/mountctl.8 b/sbin/mountctl/mountctl.8 index 98537a86be..a790ea5045 100644 --- a/sbin/mountctl/mountctl.8 +++ b/sbin/mountctl/mountctl.8 @@ -31,7 +31,7 @@ .\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $DragonFly: src/sbin/mountctl/mountctl.8,v 1.4 2005/07/06 06:04:32 dillon Exp $ +.\" $DragonFly: src/sbin/mountctl/mountctl.8,v 1.5 2005/07/13 02:00:19 dillon Exp $ .\" .Dd January 8, 2005 .Dt MOUNTCTL 8 @@ -52,6 +52,12 @@ .Op Fl o Ar option ... .Ar mountpt:tag .Nm +.Fl r +.Op Fl 2 +.Op Fl w Ar output_path +.Op Fl x Ar filedesc +.Ar mountpt:tag +.Nm .Fl d .Op Ar tag/mountpt | mountpt:tag .Nm @@ -95,6 +101,15 @@ kernel-implemented swap backing will be available for journals but that is not the case at the moment. .Pp .Nm +.Fl r +will restart an existing journal, directing it to a new file descriptor. +A shutdown is sent to the old journal and the system waits for the return +diection (if running full-duplex) to EOF. The new descriptor is then +installed and the FIFO index is reset to the last acknowledged transaction. +Clients scanning a journal across such a disconnect must check for repeated +transaction ids since some overlap between the old and new journal may occur. +.Pp +.Nm .Fl d will remove the specified journal(s). A mount point, a tag, or both may be specified. This function will operate on all matching journals. @@ -124,7 +139,7 @@ or .Fl d are not specified. .It Fl S -Start or restart a journal, equivalent to the 'start' keyword. +Start a stopped journal, equivalent to the 'start' keyword. This option implies .Fl m . .It Fl C @@ -184,17 +199,16 @@ buffers larger then 4MB are not recommended. Specify the size of the kernel-managed swap-backed FIFO used to buffer overflows. .It Ar path=filepath -Switch the journal's output stream to a new file. This feature is typically -used to restart a dead stream. +Specify where the journal's output stream should be directed. Note that the .Fl w option is equivalent to specifying the path option. Both should not be specified. .It Ar fd=filedesc -Switch the journal's output stream to a file descriptor specified by number. -Use file descriptor 1 if you wish to reopen the journal to the current -stdout. This feature is typically used to restart a dead stream (for example -if a TCP stream fails). +Specify where the journal's output stream should be directed by handing over +a file desciptor. +Use file descriptor 1 if you wish to output the journal to the current +stdout. Note that the .Fl w option is equivalent to specifying the path option. Both should not be diff --git a/sbin/mountctl/mountctl.c b/sbin/mountctl/mountctl.c index b7975390af..77622ce8ed 100644 --- a/sbin/mountctl/mountctl.c +++ b/sbin/mountctl/mountctl.c @@ -31,7 +31,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sbin/mountctl/mountctl.c,v 1.5 2005/07/06 06:04:32 dillon Exp $ + * $DragonFly: src/sbin/mountctl/mountctl.c,v 1.6 2005/07/13 02:00:19 dillon Exp $ */ /* * This utility implements the userland mountctl command which is used to @@ -61,6 +61,8 @@ static int mountctl_scan(void (*func)(const char *, const char *, int, void *), static void mountctl_list(const char *keyword, const char *mountpt, int __unused fd, void *info); static void mountctl_add(const char *keyword, const char *mountpt, int fd); +static void mountctl_restart(const char *keyword, const char *mountpt, + int fd, void __unused *); static void mountctl_delete(const char *keyword, const char *mountpt, int __unused fd, void __unused *); static void mountctl_modify(const char *keyword, const char *mountpt, int fd, void __unused *); @@ -90,6 +92,7 @@ main(int ac, char **av) int fopt = 0; int lopt = 0; int mopt = 0; + int ropt = 0; int mimplied = 0; const char *wopt = NULL; const char *xopt = NULL; @@ -97,21 +100,28 @@ main(int ac, char **av) const char *mountpt = NULL; char *tmp; - while ((ch = getopt(ac, av, "2adflo:mw:x:ACFSZ")) != -1) { + while ((ch = getopt(ac, av, "2adflmo:rw:x:ACFSZ")) != -1) { switch(ch) { case '2': twoway_opt = 1; break; + case 'r': + ropt = 1; + if (aopt + dopt + lopt + mopt + ropt != 1) { + fprintf(stderr, "too many action options specified\n"); + usage(); + } + break; case 'a': aopt = 1; - if (aopt + dopt + lopt + mopt != 1) { + if (aopt + dopt + lopt + mopt + ropt != 1) { fprintf(stderr, "too many action options specified\n"); usage(); } break; case 'd': dopt = 1; - if (aopt + dopt + lopt + mopt != 1) { + if (aopt + dopt + lopt + mopt + ropt != 1) { fprintf(stderr, "too many action options specified\n"); usage(); } @@ -121,7 +131,7 @@ main(int ac, char **av) break; case 'l': lopt = 1; - if (aopt + dopt + lopt + mopt != 1) { + if (aopt + dopt + lopt + mopt + ropt != 1) { fprintf(stderr, "too many action options specified\n"); usage(); } @@ -131,7 +141,7 @@ main(int ac, char **av) break; case 'm': mopt = 1; - if (aopt + dopt + lopt + mopt != 1) { + if (aopt + dopt + lopt + mopt + ropt != 1) { fprintf(stderr, "too many action options specified\n"); usage(); } @@ -177,7 +187,7 @@ main(int ac, char **av) */ switch(ac) { case 0: - if (aopt) { + if (aopt || ropt) { fprintf(stderr, "action requires a tag and/or mount " "point to be specified\n"); usage(); @@ -204,14 +214,14 @@ main(int ac, char **av) /* * Additional sanity checks */ - if (aopt + dopt + lopt + mopt + mimplied == 0) { + if (aopt + dopt + lopt + mopt + ropt + mimplied == 0) { fprintf(stderr, "no action or implied action options were specified\n"); usage(); } - if (mimplied && aopt + dopt + lopt == 0) + if (mimplied && aopt + dopt + lopt + ropt == 0) mopt = 1; - if ((wopt || xopt) && !(aopt || mopt)) { - fprintf(stderr, "-w/-x/path/fd options may only be used with -m/-a\n"); + if ((wopt || xopt) && !(aopt || ropt || mopt)) { + fprintf(stderr, "-w/-x/path/fd options may only be used with -m/-a/-r\n"); usage(); } if (aopt && (keyword == NULL || mountpt == NULL)) { @@ -239,7 +249,7 @@ main(int ac, char **av) } } else if (xopt) { fd = strtol(xopt, NULL, 0); - } else if (aopt) { + } else if (aopt || ropt) { fd = 1; /* stdout default for -a */ } else { fd = -1; @@ -252,19 +262,26 @@ main(int ac, char **av) mountctl_scan(mountctl_list, keyword, mountpt, fd); if (aopt) mountctl_add(keyword, mountpt, fd); + if (ropt) { + ch = mountctl_scan(mountctl_restart, keyword, mountpt, fd); + if (ch) + fprintf(stderr, "%d journals restarted\n", ch); + else + fprintf(stderr, "Unable to locate any matching journals\n"); + } if (dopt) { ch = mountctl_scan(mountctl_delete, keyword, mountpt, -1); if (ch) - printf("%d journals deleted\n", ch); + fprintf(stderr, "%d journals deleted\n", ch); else - printf("Unable to locate any matching journals\n"); + fprintf(stderr, "Unable to locate any matching journals\n"); } if (mopt) { ch = mountctl_scan(mountctl_modify, keyword, mountpt, fd); if (ch) - printf("%d journals modified\n", ch); + fprintf(stderr, "%d journals modified\n", ch); else - printf("Unable to locate any matching journals\n"); + fprintf(stderr, "Unable to locate any matching journals\n"); } return(exitCode); @@ -487,7 +504,34 @@ mountctl_add(const char *keyword, const char *mountpt, int fd) } static void -mountctl_delete(const char *keyword, const char *mountpt, int __unused fd, void __unused *info) +mountctl_restart(const char *keyword, const char *mountpt, + int fd, void __unused *info) +{ + struct mountctl_restart_journal joinfo; + int error; + + /* XXX make sure descriptor is not on same filesystem as journal */ + + bzero(&joinfo, sizeof(joinfo)); + + snprintf(joinfo.id, sizeof(joinfo.id), "%s", keyword); + if (twoway_opt > 0) + joinfo.flags |= MC_JOURNAL_WANT_FULLDUPLEX; + if (reversable_opt > 0) + joinfo.flags |= MC_JOURNAL_WANT_REVERSABLE; + + error = mountctl(mountpt, MOUNTCTL_RESTART_VFS_JOURNAL, fd, + &joinfo, sizeof(joinfo), NULL, 0); + if (error == 0) { + fprintf(stderr, "%s:%s restarted\n", mountpt, joinfo.id); + } else { + fprintf(stderr, "%s:%s restart failed, error %s\n", mountpt, joinfo.id, strerror(errno)); + } +} + +static void +mountctl_delete(const char *keyword, const char *mountpt, + int __unused fd, void __unused *info) { struct mountctl_remove_journal joinfo; int error; diff --git a/sys/kern/vfs_jops.c b/sys/kern/vfs_jops.c index 506133c3fb..7352a6d91d 100644 --- a/sys/kern/vfs_jops.c +++ b/sys/kern/vfs_jops.c @@ -31,7 +31,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/kern/vfs_jops.c,v 1.17 2005/07/06 06:02:22 dillon Exp $ + * $DragonFly: src/sys/kern/vfs_jops.c,v 1.18 2005/07/13 01:58:20 dillon Exp $ */ /* * Each mount point may have zero or more independantly configured journals @@ -88,6 +88,8 @@ #include #include #include +#include +#include #include @@ -104,14 +106,20 @@ static int journal_attach(struct mount *mp); static void journal_detach(struct mount *mp); static int journal_install_vfs_journal(struct mount *mp, struct file *fp, const struct mountctl_install_journal *info); +static int journal_restart_vfs_journal(struct mount *mp, struct file *fp, + const struct mountctl_restart_journal *info); static int journal_remove_vfs_journal(struct mount *mp, const struct mountctl_remove_journal *info); +static int journal_restart(struct mount *mp, struct file *fp, + struct journal *jo, int flags); static int journal_destroy(struct mount *mp, struct journal *jo, int flags); static int journal_resync_vfs_journal(struct mount *mp, const void *ctl); static int journal_status_vfs_journal(struct mount *mp, const struct mountctl_status_journal *info, struct mountctl_journal_ret_status *rstat, int buflen, int *res); +static void journal_create_threads(struct journal *jo); +static void journal_destroy_threads(struct journal *jo, int flags); static void journal_wthread(void *info); static void journal_rthread(void *info); @@ -199,6 +207,7 @@ journal_mountctl(struct vop_mountctl_args *ap) if (TAILQ_EMPTY(&mp->mnt_jlist)) journal_detach(mp); break; + case MOUNTCTL_RESTART_VFS_JOURNAL: case MOUNTCTL_REMOVE_VFS_JOURNAL: case MOUNTCTL_RESYNC_VFS_JOURNAL: case MOUNTCTL_STATUS_VFS_JOURNAL: @@ -218,6 +227,14 @@ journal_mountctl(struct vop_mountctl_args *ap) if (error == 0) error = journal_install_vfs_journal(mp, ap->a_fp, ap->a_ctl); break; + case MOUNTCTL_RESTART_VFS_JOURNAL: + if (ap->a_ctllen != sizeof(struct mountctl_restart_journal)) + error = EINVAL; + if (error == 0 && ap->a_fp == NULL) + error = EBADF; + if (error == 0) + error = journal_restart_vfs_journal(mp, ap->a_fp, ap->a_ctl); + break; case MOUNTCTL_REMOVE_VFS_JOURNAL: if (ap->a_ctllen != sizeof(struct mountctl_remove_journal)) error = EINVAL; @@ -330,19 +347,7 @@ journal_install_vfs_journal(struct mount *mp, struct file *fp, free(jo, M_JOURNAL); } else { fhold(fp); - jo->flags |= MC_JOURNAL_WACTIVE; - lwkt_create(journal_wthread, jo, NULL, &jo->wthread, - TDF_STOPREQ, -1, "journal w:%.*s", JIDMAX, jo->id); - lwkt_setpri(&jo->wthread, TDPRI_KERN_DAEMON); - lwkt_schedule(&jo->wthread); - - if (jo->flags & MC_JOURNAL_WANT_FULLDUPLEX) { - jo->flags |= MC_JOURNAL_RACTIVE; - lwkt_create(journal_rthread, jo, NULL, &jo->rthread, - TDF_STOPREQ, -1, "journal r:%.*s", JIDMAX, jo->id); - lwkt_setpri(&jo->rthread, TDPRI_KERN_DAEMON); - lwkt_schedule(&jo->rthread); - } + journal_create_threads(jo); jrecord_init(jo, &jrec, JREC_STREAMID_DISCONT); jrecord_write(&jrec, JTYPE_ASSOCIATE, 0); jrecord_done(&jrec, 0); @@ -351,6 +356,71 @@ journal_install_vfs_journal(struct mount *mp, struct file *fp, return(error); } +/* + * Restart a journal with a new descriptor. The existing reader and writer + * threads are terminated and a new descriptor is associated with the + * journal. The FIFO rindex is reset to xindex and the threads are then + * restarted. + */ +static int +journal_restart_vfs_journal(struct mount *mp, struct file *fp, + const struct mountctl_restart_journal *info) +{ + struct journal *jo; + int error; + + TAILQ_FOREACH(jo, &mp->mnt_jlist, jentry) { + if (bcmp(jo->id, info->id, sizeof(jo->id)) == 0) + break; + } + if (jo) + error = journal_restart(mp, fp, jo, info->flags); + else + error = EINVAL; + return (error); +} + +static int +journal_restart(struct mount *mp, struct file *fp, + struct journal *jo, int flags) +{ + /* + * XXX lock the jo + */ + +#if 0 + /* + * Record the fact that we are doing a restart in the journal. + * XXX it isn't safe to do this if the journal is being restarted + * because it was locked up and the writer thread has already exited. + */ + jrecord_init(jo, &jrec, JREC_STREAMID_RESTART); + jrecord_write(&jrec, JTYPE_DISASSOCIATE, 0); + jrecord_done(&jrec, 0); +#endif + + /* + * Stop the reader and writer threads and clean up the current + * descriptor. + */ + printf("RESTART WITH FP %p KILLING %p\n", fp, jo->fp); + journal_destroy_threads(jo, flags); + + if (jo->fp) + fdrop(jo->fp, curthread); + + /* + * Associate the new descriptor, reset the FIFO index, and recreate + * the threads. + */ + fhold(fp); + jo->fp = fp; + jo->fifo.rindex = jo->fifo.xindex; + journal_create_threads(jo); + + return(0); +} + /* * Disassociate a journal from a mount point and terminate its worker thread. * A final termination record is written out before the file pointer is @@ -392,7 +462,6 @@ static int journal_destroy(struct mount *mp, struct journal *jo, int flags) { struct jrecord jrec; - int wcount; TAILQ_REMOVE(&mp->mnt_jlist, jo, jentry); @@ -400,19 +469,8 @@ journal_destroy(struct mount *mp, struct journal *jo, int flags) jrecord_write(&jrec, JTYPE_DISASSOCIATE, 0); jrecord_done(&jrec, 0); - jo->flags |= MC_JOURNAL_STOP_REQ | (flags & MC_JOURNAL_STOP_IMM); - wakeup(&jo->fifo); - wcount = 0; - while (jo->flags & (MC_JOURNAL_WACTIVE | MC_JOURNAL_RACTIVE)) { - tsleep(jo, 0, "jwait", hz); - if (++wcount % 10 == 0) { - printf("Warning: journal %s waiting for descriptors to close\n", - jo->id); - } - } - lwkt_free_thread(&jo->wthread); /* XXX SMP */ - if (jo->flags & MC_JOURNAL_WANT_FULLDUPLEX) - lwkt_free_thread(&jo->rthread); /* XXX SMP */ + journal_destroy_threads(jo, flags); + if (jo->fp) fdrop(jo->fp, curthread); if (jo->fifo.membase) @@ -473,6 +531,51 @@ journal_status_vfs_journal(struct mount *mp, return(error); } +static void +journal_create_threads(struct journal *jo) +{ + jo->flags &= ~(MC_JOURNAL_STOP_REQ | MC_JOURNAL_STOP_IMM); + jo->flags |= MC_JOURNAL_WACTIVE; + lwkt_create(journal_wthread, jo, NULL, &jo->wthread, + TDF_STOPREQ, -1, "journal w:%.*s", JIDMAX, jo->id); + lwkt_setpri(&jo->wthread, TDPRI_KERN_DAEMON); + lwkt_schedule(&jo->wthread); + + if (jo->flags & MC_JOURNAL_WANT_FULLDUPLEX) { + jo->flags |= MC_JOURNAL_RACTIVE; + lwkt_create(journal_rthread, jo, NULL, &jo->rthread, + TDF_STOPREQ, -1, "journal r:%.*s", JIDMAX, jo->id); + lwkt_setpri(&jo->rthread, TDPRI_KERN_DAEMON); + lwkt_schedule(&jo->rthread); + } +} + +static void +journal_destroy_threads(struct journal *jo, int flags) +{ + int wcount; + + jo->flags |= MC_JOURNAL_STOP_REQ | (flags & MC_JOURNAL_STOP_IMM); + wakeup(&jo->fifo); + wcount = 0; + while (jo->flags & (MC_JOURNAL_WACTIVE | MC_JOURNAL_RACTIVE)) { + tsleep(jo, 0, "jwait", hz); + if (++wcount % 10 == 0) { + printf("Warning: journal %s waiting for descriptors to close\n", + jo->id); + } + } + + /* + * XXX SMP - threads should move to cpu requesting the restart or + * termination before finishing up to properly interlock. + */ + tsleep(jo, 0, "jwait", hz); + lwkt_free_thread(&jo->wthread); + if (jo->flags & MC_JOURNAL_WANT_FULLDUPLEX) + lwkt_free_thread(&jo->rthread); +} + /* * The per-journal worker thread is responsible for writing out the * journal's FIFO to the target stream. @@ -598,6 +701,7 @@ journal_wthread(void *info) } } } + fp_shutdown(jo->fp, SHUT_WR); jo->flags &= ~MC_JOURNAL_WACTIVE; wakeup(jo); wakeup(&jo->fifo.windex); diff --git a/sys/kern/vfs_journal.c b/sys/kern/vfs_journal.c index 90f454ab54..283343093f 100644 --- a/sys/kern/vfs_journal.c +++ b/sys/kern/vfs_journal.c @@ -31,7 +31,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/kern/vfs_journal.c,v 1.17 2005/07/06 06:02:22 dillon Exp $ + * $DragonFly: src/sys/kern/vfs_journal.c,v 1.18 2005/07/13 01:58:20 dillon Exp $ */ /* * Each mount point may have zero or more independantly configured journals @@ -88,6 +88,8 @@ #include #include #include +#include +#include #include @@ -104,14 +106,20 @@ static int journal_attach(struct mount *mp); static void journal_detach(struct mount *mp); static int journal_install_vfs_journal(struct mount *mp, struct file *fp, const struct mountctl_install_journal *info); +static int journal_restart_vfs_journal(struct mount *mp, struct file *fp, + const struct mountctl_restart_journal *info); static int journal_remove_vfs_journal(struct mount *mp, const struct mountctl_remove_journal *info); +static int journal_restart(struct mount *mp, struct file *fp, + struct journal *jo, int flags); static int journal_destroy(struct mount *mp, struct journal *jo, int flags); static int journal_resync_vfs_journal(struct mount *mp, const void *ctl); static int journal_status_vfs_journal(struct mount *mp, const struct mountctl_status_journal *info, struct mountctl_journal_ret_status *rstat, int buflen, int *res); +static void journal_create_threads(struct journal *jo); +static void journal_destroy_threads(struct journal *jo, int flags); static void journal_wthread(void *info); static void journal_rthread(void *info); @@ -199,6 +207,7 @@ journal_mountctl(struct vop_mountctl_args *ap) if (TAILQ_EMPTY(&mp->mnt_jlist)) journal_detach(mp); break; + case MOUNTCTL_RESTART_VFS_JOURNAL: case MOUNTCTL_REMOVE_VFS_JOURNAL: case MOUNTCTL_RESYNC_VFS_JOURNAL: case MOUNTCTL_STATUS_VFS_JOURNAL: @@ -218,6 +227,14 @@ journal_mountctl(struct vop_mountctl_args *ap) if (error == 0) error = journal_install_vfs_journal(mp, ap->a_fp, ap->a_ctl); break; + case MOUNTCTL_RESTART_VFS_JOURNAL: + if (ap->a_ctllen != sizeof(struct mountctl_restart_journal)) + error = EINVAL; + if (error == 0 && ap->a_fp == NULL) + error = EBADF; + if (error == 0) + error = journal_restart_vfs_journal(mp, ap->a_fp, ap->a_ctl); + break; case MOUNTCTL_REMOVE_VFS_JOURNAL: if (ap->a_ctllen != sizeof(struct mountctl_remove_journal)) error = EINVAL; @@ -330,19 +347,7 @@ journal_install_vfs_journal(struct mount *mp, struct file *fp, free(jo, M_JOURNAL); } else { fhold(fp); - jo->flags |= MC_JOURNAL_WACTIVE; - lwkt_create(journal_wthread, jo, NULL, &jo->wthread, - TDF_STOPREQ, -1, "journal w:%.*s", JIDMAX, jo->id); - lwkt_setpri(&jo->wthread, TDPRI_KERN_DAEMON); - lwkt_schedule(&jo->wthread); - - if (jo->flags & MC_JOURNAL_WANT_FULLDUPLEX) { - jo->flags |= MC_JOURNAL_RACTIVE; - lwkt_create(journal_rthread, jo, NULL, &jo->rthread, - TDF_STOPREQ, -1, "journal r:%.*s", JIDMAX, jo->id); - lwkt_setpri(&jo->rthread, TDPRI_KERN_DAEMON); - lwkt_schedule(&jo->rthread); - } + journal_create_threads(jo); jrecord_init(jo, &jrec, JREC_STREAMID_DISCONT); jrecord_write(&jrec, JTYPE_ASSOCIATE, 0); jrecord_done(&jrec, 0); @@ -351,6 +356,71 @@ journal_install_vfs_journal(struct mount *mp, struct file *fp, return(error); } +/* + * Restart a journal with a new descriptor. The existing reader and writer + * threads are terminated and a new descriptor is associated with the + * journal. The FIFO rindex is reset to xindex and the threads are then + * restarted. + */ +static int +journal_restart_vfs_journal(struct mount *mp, struct file *fp, + const struct mountctl_restart_journal *info) +{ + struct journal *jo; + int error; + + TAILQ_FOREACH(jo, &mp->mnt_jlist, jentry) { + if (bcmp(jo->id, info->id, sizeof(jo->id)) == 0) + break; + } + if (jo) + error = journal_restart(mp, fp, jo, info->flags); + else + error = EINVAL; + return (error); +} + +static int +journal_restart(struct mount *mp, struct file *fp, + struct journal *jo, int flags) +{ + /* + * XXX lock the jo + */ + +#if 0 + /* + * Record the fact that we are doing a restart in the journal. + * XXX it isn't safe to do this if the journal is being restarted + * because it was locked up and the writer thread has already exited. + */ + jrecord_init(jo, &jrec, JREC_STREAMID_RESTART); + jrecord_write(&jrec, JTYPE_DISASSOCIATE, 0); + jrecord_done(&jrec, 0); +#endif + + /* + * Stop the reader and writer threads and clean up the current + * descriptor. + */ + printf("RESTART WITH FP %p KILLING %p\n", fp, jo->fp); + journal_destroy_threads(jo, flags); + + if (jo->fp) + fdrop(jo->fp, curthread); + + /* + * Associate the new descriptor, reset the FIFO index, and recreate + * the threads. + */ + fhold(fp); + jo->fp = fp; + jo->fifo.rindex = jo->fifo.xindex; + journal_create_threads(jo); + + return(0); +} + /* * Disassociate a journal from a mount point and terminate its worker thread. * A final termination record is written out before the file pointer is @@ -392,7 +462,6 @@ static int journal_destroy(struct mount *mp, struct journal *jo, int flags) { struct jrecord jrec; - int wcount; TAILQ_REMOVE(&mp->mnt_jlist, jo, jentry); @@ -400,19 +469,8 @@ journal_destroy(struct mount *mp, struct journal *jo, int flags) jrecord_write(&jrec, JTYPE_DISASSOCIATE, 0); jrecord_done(&jrec, 0); - jo->flags |= MC_JOURNAL_STOP_REQ | (flags & MC_JOURNAL_STOP_IMM); - wakeup(&jo->fifo); - wcount = 0; - while (jo->flags & (MC_JOURNAL_WACTIVE | MC_JOURNAL_RACTIVE)) { - tsleep(jo, 0, "jwait", hz); - if (++wcount % 10 == 0) { - printf("Warning: journal %s waiting for descriptors to close\n", - jo->id); - } - } - lwkt_free_thread(&jo->wthread); /* XXX SMP */ - if (jo->flags & MC_JOURNAL_WANT_FULLDUPLEX) - lwkt_free_thread(&jo->rthread); /* XXX SMP */ + journal_destroy_threads(jo, flags); + if (jo->fp) fdrop(jo->fp, curthread); if (jo->fifo.membase) @@ -473,6 +531,51 @@ journal_status_vfs_journal(struct mount *mp, return(error); } +static void +journal_create_threads(struct journal *jo) +{ + jo->flags &= ~(MC_JOURNAL_STOP_REQ | MC_JOURNAL_STOP_IMM); + jo->flags |= MC_JOURNAL_WACTIVE; + lwkt_create(journal_wthread, jo, NULL, &jo->wthread, + TDF_STOPREQ, -1, "journal w:%.*s", JIDMAX, jo->id); + lwkt_setpri(&jo->wthread, TDPRI_KERN_DAEMON); + lwkt_schedule(&jo->wthread); + + if (jo->flags & MC_JOURNAL_WANT_FULLDUPLEX) { + jo->flags |= MC_JOURNAL_RACTIVE; + lwkt_create(journal_rthread, jo, NULL, &jo->rthread, + TDF_STOPREQ, -1, "journal r:%.*s", JIDMAX, jo->id); + lwkt_setpri(&jo->rthread, TDPRI_KERN_DAEMON); + lwkt_schedule(&jo->rthread); + } +} + +static void +journal_destroy_threads(struct journal *jo, int flags) +{ + int wcount; + + jo->flags |= MC_JOURNAL_STOP_REQ | (flags & MC_JOURNAL_STOP_IMM); + wakeup(&jo->fifo); + wcount = 0; + while (jo->flags & (MC_JOURNAL_WACTIVE | MC_JOURNAL_RACTIVE)) { + tsleep(jo, 0, "jwait", hz); + if (++wcount % 10 == 0) { + printf("Warning: journal %s waiting for descriptors to close\n", + jo->id); + } + } + + /* + * XXX SMP - threads should move to cpu requesting the restart or + * termination before finishing up to properly interlock. + */ + tsleep(jo, 0, "jwait", hz); + lwkt_free_thread(&jo->wthread); + if (jo->flags & MC_JOURNAL_WANT_FULLDUPLEX) + lwkt_free_thread(&jo->rthread); +} + /* * The per-journal worker thread is responsible for writing out the * journal's FIFO to the target stream. @@ -598,6 +701,7 @@ journal_wthread(void *info) } } } + fp_shutdown(jo->fp, SHUT_WR); jo->flags &= ~MC_JOURNAL_WACTIVE; wakeup(jo); wakeup(&jo->fifo.windex); diff --git a/sys/sys/journal.h b/sys/sys/journal.h index 89124245d7..9f6271c649 100644 --- a/sys/sys/journal.h +++ b/sys/sys/journal.h @@ -31,7 +31,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/sys/journal.h,v 1.5 2005/07/06 06:02:23 dillon Exp $ + * $DragonFly: src/sys/sys/journal.h,v 1.6 2005/07/13 01:58:23 dillon Exp $ */ #ifndef _SYS_JOURNAL_H_ @@ -152,7 +152,8 @@ struct journal_ackrecord { #define JREC_STREAMID_DISCONT 0x0002 /* discontinuity */ #define JREC_STREAMID_ANNOTATE 0x0003 /* annotation */ #define JREC_STREAMID_ACK 0x0004 /* acknowledgement */ - /* 0x0005-0x007F reserved by DragonFly */ +#define JREC_STREAMID_RESTART 0x0005 /* disctoninuity - journal restart */ + /* 0x0006-0x007F reserved by DragonFly */ /* 0x0080-0x00FF for third party use */ #define JREC_STREAMID_JMIN 0x0100 /* lowest allowed general id */ #define JREC_STREAMID_JMAX 0x2000 /* (one past the highest allowed id) */ diff --git a/sys/sys/mountctl.h b/sys/sys/mountctl.h index d6dc846d8c..d7f1fd9270 100644 --- a/sys/sys/mountctl.h +++ b/sys/sys/mountctl.h @@ -31,7 +31,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/sys/mountctl.h,v 1.8 2005/07/06 06:02:23 dillon Exp $ + * $DragonFly: src/sys/sys/mountctl.h,v 1.9 2005/07/13 01:58:23 dillon Exp $ */ #ifndef _SYS_MOUNTCTL_H_ @@ -50,6 +50,7 @@ #define MOUNTCTL_REMOVE_VFS_JOURNAL 2 #define MOUNTCTL_RESYNC_VFS_JOURNAL 3 #define MOUNTCTL_STATUS_VFS_JOURNAL 4 +#define MOUNTCTL_RESTART_VFS_JOURNAL 5 #define MOUNTCTL_INSTALL_BLK_JOURNAL 8 #define MOUNTCTL_REMOVE_BLK_JOURNAL 9 @@ -80,6 +81,12 @@ struct mountctl_install_journal { #define MC_JOURNAL_WANT_REVERSABLE 0x00020000 /* reversable stream */ #define MC_JOURNAL_WANT_FULLDUPLEX 0x00040000 /* has ack stream */ +struct mountctl_restart_journal { + char id[JIDMAX]; + int flags; + int unused01; +}; + struct mountctl_remove_journal { char id[JIDMAX]; int flags; -- 2.41.0