Slightly reorganize the transaction data. Instead of placing the REDO data
[dragonfly.git] / sys / kern / vfs_journal.c
1 /*
2  * Copyright (c) 2004 The DragonFly Project.  All rights reserved.
3  * 
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  * 
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  * 
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  * $DragonFly: src/sys/kern/vfs_journal.c,v 1.22 2005/09/07 19:04:18 dillon Exp $
35  */
36 /*
37  * Each mount point may have zero or more independantly configured journals
38  * attached to it.  Each journal is represented by a memory FIFO and worker
39  * thread.  Journal events are streamed through the FIFO to the thread,
40  * batched up (typically on one-second intervals), and written out by the
41  * thread. 
42  *
43  * Journal vnode ops are executed instead of mnt_vn_norm_ops when one or
44  * more journals have been installed on a mount point.  It becomes the
45  * responsibility of the journal op to call the underlying normal op as
46  * appropriate.
47  *
48  * The journaling protocol is intended to evolve into a two-way stream
49  * whereby transaction IDs can be acknowledged by the journaling target
50  * when the data has been committed to hard storage.  Both implicit and
51  * explicit acknowledgement schemes will be supported, depending on the
52  * sophistication of the journaling stream, plus resynchronization and
53  * restart when a journaling stream is interrupted.  This information will
54  * also be made available to journaling-aware filesystems to allow better
55  * management of their own physical storage synchronization mechanisms as
56  * well as to allow such filesystems to take direct advantage of the kernel's
57  * journaling layer so they don't have to roll their own.
58  *
59  * In addition, the worker thread will have access to much larger 
60  * spooling areas then the memory buffer is able to provide by e.g. 
61  * reserving swap space, in order to absorb potentially long interruptions
62  * of off-site journaling streams, and to prevent 'slow' off-site linkages
63  * from radically slowing down local filesystem operations.  
64  *
65  * Because of the non-trivial algorithms the journaling system will be
66  * required to support, use of a worker thread is mandatory.  Efficiencies
67  * are maintained by utilitizing the memory FIFO to batch transactions when
68  * possible, reducing the number of gratuitous thread switches and taking
69  * advantage of cpu caches through the use of shorter batched code paths
70  * rather then trying to do everything in the context of the process
71  * originating the filesystem op.  In the future the memory FIFO can be
72  * made per-cpu to remove BGL or other locking requirements.
73  */
74 #include <sys/param.h>
75 #include <sys/systm.h>
76 #include <sys/buf.h>
77 #include <sys/conf.h>
78 #include <sys/kernel.h>
79 #include <sys/queue.h>
80 #include <sys/lock.h>
81 #include <sys/malloc.h>
82 #include <sys/mount.h>
83 #include <sys/unistd.h>
84 #include <sys/vnode.h>
85 #include <sys/poll.h>
86 #include <sys/mountctl.h>
87 #include <sys/journal.h>
88 #include <sys/file.h>
89 #include <sys/proc.h>
90 #include <sys/msfbuf.h>
91 #include <sys/socket.h>
92 #include <sys/socketvar.h>
93
94 #include <machine/limits.h>
95
96 #include <vm/vm.h>
97 #include <vm/vm_object.h>
98 #include <vm/vm_page.h>
99 #include <vm/vm_pager.h>
100 #include <vm/vnode_pager.h>
101
102 #include <sys/file2.h>
103 #include <sys/thread2.h>
104
105 static int journal_attach(struct mount *mp);
106 static void journal_detach(struct mount *mp);
107 static int journal_install_vfs_journal(struct mount *mp, struct file *fp,
108                             const struct mountctl_install_journal *info);
109 static int journal_restart_vfs_journal(struct mount *mp, struct file *fp,
110                             const struct mountctl_restart_journal *info);
111 static int journal_remove_vfs_journal(struct mount *mp,
112                             const struct mountctl_remove_journal *info);
113 static int journal_restart(struct mount *mp, struct file *fp,
114                             struct journal *jo, int flags);
115 static int journal_destroy(struct mount *mp, struct journal *jo, int flags);
116 static int journal_resync_vfs_journal(struct mount *mp, const void *ctl);
117 static int journal_status_vfs_journal(struct mount *mp,
118                        const struct mountctl_status_journal *info,
119                        struct mountctl_journal_ret_status *rstat,
120                        int buflen, int *res);
121 static void journal_create_threads(struct journal *jo);
122 static void journal_destroy_threads(struct journal *jo, int flags);
123 static void journal_wthread(void *info);
124 static void journal_rthread(void *info);
125
126 static void *journal_reserve(struct journal *jo, 
127                             struct journal_rawrecbeg **rawpp, 
128                             int16_t streamid, int bytes);
129 static void *journal_extend(struct journal *jo,
130                             struct journal_rawrecbeg **rawpp,
131                             int truncbytes, int bytes, int *newstreamrecp);
132 static void journal_abort(struct journal *jo, 
133                             struct journal_rawrecbeg **rawpp);
134 static void journal_commit(struct journal *jo, 
135                             struct journal_rawrecbeg **rawpp, 
136                             int bytes, int closeout);
137
138 static void jrecord_init(struct journal *jo, 
139                             struct jrecord *jrec, int16_t streamid);
140 static struct journal_subrecord *jrecord_push(
141                             struct jrecord *jrec, int16_t rectype);
142 static void jrecord_pop(struct jrecord *jrec, struct journal_subrecord *parent);
143 static struct journal_subrecord *jrecord_write(struct jrecord *jrec,
144                             int16_t rectype, int bytes);
145 static void jrecord_data(struct jrecord *jrec, const void *buf, int bytes);
146 static void jrecord_done(struct jrecord *jrec, int abortit);
147 static void jrecord_undo_file(struct jrecord *jrec, struct vnode *vp, 
148                             int jrflags, off_t off, off_t bytes);
149
150 static int journal_setattr(struct vop_setattr_args *ap);
151 static int journal_write(struct vop_write_args *ap);
152 static int journal_fsync(struct vop_fsync_args *ap);
153 static int journal_putpages(struct vop_putpages_args *ap);
154 static int journal_setacl(struct vop_setacl_args *ap);
155 static int journal_setextattr(struct vop_setextattr_args *ap);
156 static int journal_ncreate(struct vop_ncreate_args *ap);
157 static int journal_nmknod(struct vop_nmknod_args *ap);
158 static int journal_nlink(struct vop_nlink_args *ap);
159 static int journal_nsymlink(struct vop_nsymlink_args *ap);
160 static int journal_nwhiteout(struct vop_nwhiteout_args *ap);
161 static int journal_nremove(struct vop_nremove_args *ap);
162 static int journal_nmkdir(struct vop_nmkdir_args *ap);
163 static int journal_nrmdir(struct vop_nrmdir_args *ap);
164 static int journal_nrename(struct vop_nrename_args *ap);
165
166 #define JRUNDO_SIZE     0x00000001
167 #define JRUNDO_UID      0x00000002
168 #define JRUNDO_GID      0x00000004
169 #define JRUNDO_FSID     0x00000008
170 #define JRUNDO_MODES    0x00000010
171 #define JRUNDO_INUM     0x00000020
172 #define JRUNDO_ATIME    0x00000040
173 #define JRUNDO_MTIME    0x00000080
174 #define JRUNDO_CTIME    0x00000100
175 #define JRUNDO_GEN      0x00000200
176 #define JRUNDO_FLAGS    0x00000400
177 #define JRUNDO_UDEV     0x00000800
178 #define JRUNDO_NLINK    0x00001000
179 #define JRUNDO_FILEDATA 0x00010000
180 #define JRUNDO_GETVP    0x00020000
181 #define JRUNDO_CONDLINK 0x00040000      /* write file data if link count 1 */
182 #define JRUNDO_VATTR    (JRUNDO_SIZE|JRUNDO_UID|JRUNDO_GID|JRUNDO_FSID|\
183                          JRUNDO_MODES|JRUNDO_INUM|JRUNDO_ATIME|JRUNDO_MTIME|\
184                          JRUNDO_CTIME|JRUNDO_GEN|JRUNDO_FLAGS|JRUNDO_UDEV|\
185                          JRUNDO_NLINK)
186 #define JRUNDO_ALL      (JRUNDO_VATTR|JRUNDO_FILEDATA)
187
188 static struct vnodeopv_entry_desc journal_vnodeop_entries[] = {
189     { &vop_default_desc,                vop_journal_operate_ap },
190     { &vop_mountctl_desc,               (void *)journal_mountctl },
191     { &vop_setattr_desc,                (void *)journal_setattr },
192     { &vop_write_desc,                  (void *)journal_write },
193     { &vop_fsync_desc,                  (void *)journal_fsync },
194     { &vop_putpages_desc,               (void *)journal_putpages },
195     { &vop_setacl_desc,                 (void *)journal_setacl },
196     { &vop_setextattr_desc,             (void *)journal_setextattr },
197     { &vop_ncreate_desc,                (void *)journal_ncreate },
198     { &vop_nmknod_desc,                 (void *)journal_nmknod },
199     { &vop_nlink_desc,                  (void *)journal_nlink },
200     { &vop_nsymlink_desc,               (void *)journal_nsymlink },
201     { &vop_nwhiteout_desc,              (void *)journal_nwhiteout },
202     { &vop_nremove_desc,                (void *)journal_nremove },
203     { &vop_nmkdir_desc,                 (void *)journal_nmkdir },
204     { &vop_nrmdir_desc,                 (void *)journal_nrmdir },
205     { &vop_nrename_desc,                (void *)journal_nrename },
206     { NULL, NULL }
207 };
208
209 static MALLOC_DEFINE(M_JOURNAL, "journal", "Journaling structures");
210 static MALLOC_DEFINE(M_JFIFO, "journal-fifo", "Journal FIFO");
211
212 int
213 journal_mountctl(struct vop_mountctl_args *ap)
214 {
215     struct mount *mp;
216     int error = 0;
217
218     mp = ap->a_head.a_ops->vv_mount;
219     KKASSERT(mp);
220
221     if (mp->mnt_vn_journal_ops == NULL) {
222         switch(ap->a_op) {
223         case MOUNTCTL_INSTALL_VFS_JOURNAL:
224             error = journal_attach(mp);
225             if (error == 0 && ap->a_ctllen != sizeof(struct mountctl_install_journal))
226                 error = EINVAL;
227             if (error == 0 && ap->a_fp == NULL)
228                 error = EBADF;
229             if (error == 0)
230                 error = journal_install_vfs_journal(mp, ap->a_fp, ap->a_ctl);
231             if (TAILQ_EMPTY(&mp->mnt_jlist))
232                 journal_detach(mp);
233             break;
234         case MOUNTCTL_RESTART_VFS_JOURNAL:
235         case MOUNTCTL_REMOVE_VFS_JOURNAL:
236         case MOUNTCTL_RESYNC_VFS_JOURNAL:
237         case MOUNTCTL_STATUS_VFS_JOURNAL:
238             error = ENOENT;
239             break;
240         default:
241             error = EOPNOTSUPP;
242             break;
243         }
244     } else {
245         switch(ap->a_op) {
246         case MOUNTCTL_INSTALL_VFS_JOURNAL:
247             if (ap->a_ctllen != sizeof(struct mountctl_install_journal))
248                 error = EINVAL;
249             if (error == 0 && ap->a_fp == NULL)
250                 error = EBADF;
251             if (error == 0)
252                 error = journal_install_vfs_journal(mp, ap->a_fp, ap->a_ctl);
253             break;
254         case MOUNTCTL_RESTART_VFS_JOURNAL:
255             if (ap->a_ctllen != sizeof(struct mountctl_restart_journal))
256                 error = EINVAL;
257             if (error == 0 && ap->a_fp == NULL)
258                 error = EBADF;
259             if (error == 0)
260                 error = journal_restart_vfs_journal(mp, ap->a_fp, ap->a_ctl);
261             break;
262         case MOUNTCTL_REMOVE_VFS_JOURNAL:
263             if (ap->a_ctllen != sizeof(struct mountctl_remove_journal))
264                 error = EINVAL;
265             if (error == 0)
266                 error = journal_remove_vfs_journal(mp, ap->a_ctl);
267             if (TAILQ_EMPTY(&mp->mnt_jlist))
268                 journal_detach(mp);
269             break;
270         case MOUNTCTL_RESYNC_VFS_JOURNAL:
271             if (ap->a_ctllen != 0)
272                 error = EINVAL;
273             error = journal_resync_vfs_journal(mp, ap->a_ctl);
274             break;
275         case MOUNTCTL_STATUS_VFS_JOURNAL:
276             if (ap->a_ctllen != sizeof(struct mountctl_status_journal))
277                 error = EINVAL;
278             if (error == 0) {
279                 error = journal_status_vfs_journal(mp, ap->a_ctl, 
280                                         ap->a_buf, ap->a_buflen, ap->a_res);
281             }
282             break;
283         default:
284             error = EOPNOTSUPP;
285             break;
286         }
287     }
288     return (error);
289 }
290
291 /*
292  * High level mount point setup.  When a 
293  */
294 static int
295 journal_attach(struct mount *mp)
296 {
297     vfs_add_vnodeops(mp, &mp->mnt_vn_journal_ops, journal_vnodeop_entries);
298     return(0);
299 }
300
301 static void
302 journal_detach(struct mount *mp)
303 {
304     if (mp->mnt_vn_journal_ops)
305         vfs_rm_vnodeops(&mp->mnt_vn_journal_ops);
306 }
307
308 /*
309  * Install a journal on a mount point.  Each journal has an associated worker
310  * thread which is responsible for buffering and spooling the data to the
311  * target.  A mount point may have multiple journals attached to it.  An
312  * initial start record is generated when the journal is associated.
313  */
314 static int
315 journal_install_vfs_journal(struct mount *mp, struct file *fp, 
316                             const struct mountctl_install_journal *info)
317 {
318     struct journal *jo;
319     struct jrecord jrec;
320     int error = 0;
321     int size;
322
323     jo = malloc(sizeof(struct journal), M_JOURNAL, M_WAITOK|M_ZERO);
324     bcopy(info->id, jo->id, sizeof(jo->id));
325     jo->flags = info->flags & ~(MC_JOURNAL_WACTIVE | MC_JOURNAL_RACTIVE |
326                                 MC_JOURNAL_STOP_REQ);
327
328     /*
329      * Memory FIFO size, round to nearest power of 2
330      */
331     if (info->membufsize) {
332         if (info->membufsize < 65536)
333             size = 65536;
334         else if (info->membufsize > 128 * 1024 * 1024)
335             size = 128 * 1024 * 1024;
336         else
337             size = (int)info->membufsize;
338     } else {
339         size = 1024 * 1024;
340     }
341     jo->fifo.size = 1;
342     while (jo->fifo.size < size)
343         jo->fifo.size <<= 1;
344
345     /*
346      * Other parameters.  If not specified the starting transaction id
347      * will be the current date.
348      */
349     if (info->transid) {
350         jo->transid = info->transid;
351     } else {
352         struct timespec ts;
353         getnanotime(&ts);
354         jo->transid = ((int64_t)ts.tv_sec << 30) | ts.tv_nsec;
355     }
356
357     jo->fp = fp;
358
359     /*
360      * Allocate the memory FIFO
361      */
362     jo->fifo.mask = jo->fifo.size - 1;
363     jo->fifo.membase = malloc(jo->fifo.size, M_JFIFO, M_WAITOK|M_ZERO|M_NULLOK);
364     if (jo->fifo.membase == NULL)
365         error = ENOMEM;
366
367     /*
368      * Create the worker threads and generate the association record.
369      */
370     if (error) {
371         free(jo, M_JOURNAL);
372     } else {
373         fhold(fp);
374         journal_create_threads(jo);
375         jrecord_init(jo, &jrec, JREC_STREAMID_DISCONT);
376         jrecord_write(&jrec, JTYPE_ASSOCIATE, 0);
377         jrecord_done(&jrec, 0);
378         TAILQ_INSERT_TAIL(&mp->mnt_jlist, jo, jentry);
379     }
380     return(error);
381 }
382
383 /*
384  * Restart a journal with a new descriptor.   The existing reader and writer
385  * threads are terminated and a new descriptor is associated with the
386  * journal.  The FIFO rindex is reset to xindex and the threads are then
387  * restarted.
388  */
389 static int
390 journal_restart_vfs_journal(struct mount *mp, struct file *fp,
391                            const struct mountctl_restart_journal *info)
392 {
393     struct journal *jo;
394     int error;
395
396     TAILQ_FOREACH(jo, &mp->mnt_jlist, jentry) {
397         if (bcmp(jo->id, info->id, sizeof(jo->id)) == 0)
398             break;
399     }
400     if (jo)
401         error = journal_restart(mp, fp, jo, info->flags);
402     else
403         error = EINVAL;
404     return (error);
405 }
406
407 static int
408 journal_restart(struct mount *mp, struct file *fp, 
409                 struct journal *jo, int flags)
410 {
411     /*
412      * XXX lock the jo
413      */
414
415 #if 0
416     /*
417      * Record the fact that we are doing a restart in the journal.
418      * XXX it isn't safe to do this if the journal is being restarted
419      * because it was locked up and the writer thread has already exited.
420      */
421     jrecord_init(jo, &jrec, JREC_STREAMID_RESTART);
422     jrecord_write(&jrec, JTYPE_DISASSOCIATE, 0);
423     jrecord_done(&jrec, 0);
424 #endif
425
426     /*
427      * Stop the reader and writer threads and clean up the current 
428      * descriptor.
429      */
430     printf("RESTART WITH FP %p KILLING %p\n", fp, jo->fp);
431     journal_destroy_threads(jo, flags);
432
433     if (jo->fp)
434         fdrop(jo->fp, curthread);
435
436     /*
437      * Associate the new descriptor, reset the FIFO index, and recreate
438      * the threads.
439      */
440     fhold(fp);
441     jo->fp = fp;
442     jo->fifo.rindex = jo->fifo.xindex;
443     journal_create_threads(jo);
444
445     return(0);
446 }
447
448 /*
449  * Disassociate a journal from a mount point and terminate its worker thread.
450  * A final termination record is written out before the file pointer is
451  * dropped.
452  */
453 static int
454 journal_remove_vfs_journal(struct mount *mp, 
455                            const struct mountctl_remove_journal *info)
456 {
457     struct journal *jo;
458     int error;
459
460     TAILQ_FOREACH(jo, &mp->mnt_jlist, jentry) {
461         if (bcmp(jo->id, info->id, sizeof(jo->id)) == 0)
462             break;
463     }
464     if (jo)
465         error = journal_destroy(mp, jo, info->flags);
466     else
467         error = EINVAL;
468     return (error);
469 }
470
471 /*
472  * Remove all journals associated with a mount point.  Usually called
473  * by the umount code.
474  */
475 void
476 journal_remove_all_journals(struct mount *mp, int flags)
477 {
478     struct journal *jo;
479
480     while ((jo = TAILQ_FIRST(&mp->mnt_jlist)) != NULL) {
481         journal_destroy(mp, jo, flags);
482     }
483 }
484
485 static int
486 journal_destroy(struct mount *mp, struct journal *jo, int flags)
487 {
488     struct jrecord jrec;
489
490     TAILQ_REMOVE(&mp->mnt_jlist, jo, jentry);
491
492     jrecord_init(jo, &jrec, JREC_STREAMID_DISCONT);
493     jrecord_write(&jrec, JTYPE_DISASSOCIATE, 0);
494     jrecord_done(&jrec, 0);
495
496     journal_destroy_threads(jo, flags);
497
498     if (jo->fp)
499         fdrop(jo->fp, curthread);
500     if (jo->fifo.membase)
501         free(jo->fifo.membase, M_JFIFO);
502     free(jo, M_JOURNAL);
503     return(0);
504 }
505
506 static int
507 journal_resync_vfs_journal(struct mount *mp, const void *ctl)
508 {
509     return(EINVAL);
510 }
511
512 static int
513 journal_status_vfs_journal(struct mount *mp, 
514                        const struct mountctl_status_journal *info,
515                        struct mountctl_journal_ret_status *rstat,
516                        int buflen, int *res)
517 {
518     struct journal *jo;
519     int error = 0;
520     int index;
521
522     index = 0;
523     *res = 0;
524     TAILQ_FOREACH(jo, &mp->mnt_jlist, jentry) {
525         if (info->index == MC_JOURNAL_INDEX_ID) {
526             if (bcmp(jo->id, info->id, sizeof(jo->id)) != 0)
527                 continue;
528         } else if (info->index >= 0) {
529             if (info->index < index)
530                 continue;
531         } else if (info->index != MC_JOURNAL_INDEX_ALL) {
532             continue;
533         }
534         if (buflen < sizeof(*rstat)) {
535             if (*res)
536                 rstat[-1].flags |= MC_JOURNAL_STATUS_MORETOCOME;
537             else
538                 error = EINVAL;
539             break;
540         }
541         bzero(rstat, sizeof(*rstat));
542         rstat->recsize = sizeof(*rstat);
543         bcopy(jo->id, rstat->id, sizeof(jo->id));
544         rstat->index = index;
545         rstat->membufsize = jo->fifo.size;
546         rstat->membufused = jo->fifo.windex - jo->fifo.xindex;
547         rstat->membufunacked = jo->fifo.rindex - jo->fifo.xindex;
548         rstat->bytessent = jo->total_acked;
549         rstat->fifostalls = jo->fifostalls;
550         ++rstat;
551         ++index;
552         *res += sizeof(*rstat);
553         buflen -= sizeof(*rstat);
554     }
555     return(error);
556 }
557
558 static void
559 journal_create_threads(struct journal *jo)
560 {
561         jo->flags &= ~(MC_JOURNAL_STOP_REQ | MC_JOURNAL_STOP_IMM);
562         jo->flags |= MC_JOURNAL_WACTIVE;
563         lwkt_create(journal_wthread, jo, NULL, &jo->wthread,
564                         TDF_STOPREQ, -1, "journal w:%.*s", JIDMAX, jo->id);
565         lwkt_setpri(&jo->wthread, TDPRI_KERN_DAEMON);
566         lwkt_schedule(&jo->wthread);
567
568         if (jo->flags & MC_JOURNAL_WANT_FULLDUPLEX) {
569             jo->flags |= MC_JOURNAL_RACTIVE;
570             lwkt_create(journal_rthread, jo, NULL, &jo->rthread,
571                         TDF_STOPREQ, -1, "journal r:%.*s", JIDMAX, jo->id);
572             lwkt_setpri(&jo->rthread, TDPRI_KERN_DAEMON);
573             lwkt_schedule(&jo->rthread);
574         }
575 }
576
577 static void
578 journal_destroy_threads(struct journal *jo, int flags)
579 {
580     int wcount;
581
582     jo->flags |= MC_JOURNAL_STOP_REQ | (flags & MC_JOURNAL_STOP_IMM);
583     wakeup(&jo->fifo);
584     wcount = 0;
585     while (jo->flags & (MC_JOURNAL_WACTIVE | MC_JOURNAL_RACTIVE)) {
586         tsleep(jo, 0, "jwait", hz);
587         if (++wcount % 10 == 0) {
588             printf("Warning: journal %s waiting for descriptors to close\n",
589                 jo->id);
590         }
591     }
592
593     /*
594      * XXX SMP - threads should move to cpu requesting the restart or
595      * termination before finishing up to properly interlock.
596      */
597     tsleep(jo, 0, "jwait", hz);
598     lwkt_free_thread(&jo->wthread);
599     if (jo->flags & MC_JOURNAL_WANT_FULLDUPLEX)
600         lwkt_free_thread(&jo->rthread);
601 }
602
603 /*
604  * The per-journal worker thread is responsible for writing out the
605  * journal's FIFO to the target stream.
606  */
607 static void
608 journal_wthread(void *info)
609 {
610     struct journal *jo = info;
611     struct journal_rawrecbeg *rawp;
612     int bytes;
613     int error;
614     int avail;
615     int res;
616
617     for (;;) {
618         /*
619          * Calculate the number of bytes available to write.  This buffer
620          * area may contain reserved records so we can't just write it out
621          * without further checks.
622          */
623         bytes = jo->fifo.windex - jo->fifo.rindex;
624
625         /*
626          * sleep if no bytes are available or if an incomplete record is
627          * encountered (it needs to be filled in before we can write it
628          * out), and skip any pad records that we encounter.
629          */
630         if (bytes == 0) {
631             if (jo->flags & MC_JOURNAL_STOP_REQ)
632                 break;
633             tsleep(&jo->fifo, 0, "jfifo", hz);
634             continue;
635         }
636
637         /*
638          * Sleep if we can not go any further due to hitting an incomplete
639          * record.  This case should occur rarely but may have to be better
640          * optimized XXX.
641          */
642         rawp = (void *)(jo->fifo.membase + (jo->fifo.rindex & jo->fifo.mask));
643         if (rawp->begmagic == JREC_INCOMPLETEMAGIC) {
644             tsleep(&jo->fifo, 0, "jpad", hz);
645             continue;
646         }
647
648         /*
649          * Skip any pad records.  We do not write out pad records if we can
650          * help it. 
651          */
652         if (rawp->streamid == JREC_STREAMID_PAD) {
653             if ((jo->flags & MC_JOURNAL_WANT_FULLDUPLEX) == 0) {
654                 if (jo->fifo.rindex == jo->fifo.xindex) {
655                     jo->fifo.xindex += (rawp->recsize + 15) & ~15;
656                     jo->total_acked += (rawp->recsize + 15) & ~15;
657                 }
658             }
659             jo->fifo.rindex += (rawp->recsize + 15) & ~15;
660             jo->total_acked += bytes;
661             KKASSERT(jo->fifo.windex - jo->fifo.rindex >= 0);
662             continue;
663         }
664
665         /*
666          * 'bytes' is the amount of data that can potentially be written out.  
667          * Calculate 'res', the amount of data that can actually be written
668          * out.  res is bounded either by hitting the end of the physical
669          * memory buffer or by hitting an incomplete record.  Incomplete
670          * records often occur due to the way the space reservation model
671          * works.
672          */
673         res = 0;
674         avail = jo->fifo.size - (jo->fifo.rindex & jo->fifo.mask);
675         while (res < bytes && rawp->begmagic == JREC_BEGMAGIC) {
676             res += (rawp->recsize + 15) & ~15;
677             if (res >= avail) {
678                 KKASSERT(res == avail);
679                 break;
680             }
681             rawp = (void *)((char *)rawp + ((rawp->recsize + 15) & ~15));
682         }
683
684         /*
685          * Issue the write and deal with any errors or other conditions.
686          * For now assume blocking I/O.  Since we are record-aware the
687          * code cannot yet handle partial writes.
688          *
689          * We bump rindex prior to issuing the write to avoid racing
690          * the acknowledgement coming back (which could prevent the ack
691          * from bumping xindex).  Restarts are always based on xindex so
692          * we do not try to undo the rindex if an error occurs.
693          *
694          * XXX EWOULDBLOCK/NBIO
695          * XXX notification on failure
696          * XXX permanent verses temporary failures
697          * XXX two-way acknowledgement stream in the return direction / xindex
698          */
699         bytes = res;
700         jo->fifo.rindex += bytes;
701         error = fp_write(jo->fp, 
702                         jo->fifo.membase + ((jo->fifo.rindex - bytes) & jo->fifo.mask),
703                         bytes, &res);
704         if (error) {
705             printf("journal_thread(%s) write, error %d\n", jo->id, error);
706             /* XXX */
707         } else {
708             KKASSERT(res == bytes);
709         }
710
711         /*
712          * Advance rindex.  If the journal stream is not full duplex we also
713          * advance xindex, otherwise the rjournal thread is responsible for
714          * advancing xindex.
715          */
716         if ((jo->flags & MC_JOURNAL_WANT_FULLDUPLEX) == 0) {
717             jo->fifo.xindex += bytes;
718             jo->total_acked += bytes;
719         }
720         KKASSERT(jo->fifo.windex - jo->fifo.rindex >= 0);
721         if ((jo->flags & MC_JOURNAL_WANT_FULLDUPLEX) == 0) {
722             if (jo->flags & MC_JOURNAL_WWAIT) {
723                 jo->flags &= ~MC_JOURNAL_WWAIT; /* XXX hysteresis */
724                 wakeup(&jo->fifo.windex);
725             }
726         }
727     }
728     fp_shutdown(jo->fp, SHUT_WR);
729     jo->flags &= ~MC_JOURNAL_WACTIVE;
730     wakeup(jo);
731     wakeup(&jo->fifo.windex);
732 }
733
734 /*
735  * A second per-journal worker thread is created for two-way journaling
736  * streams to deal with the return acknowledgement stream.
737  */
738 static void
739 journal_rthread(void *info)
740 {
741     struct journal_rawrecbeg *rawp;
742     struct journal_ackrecord ack;
743     struct journal *jo = info;
744     int64_t transid;
745     int error;
746     int count;
747     int bytes;
748
749     transid = 0;
750     error = 0;
751
752     for (;;) {
753         /*
754          * We have been asked to stop
755          */
756         if (jo->flags & MC_JOURNAL_STOP_REQ)
757                 break;
758
759         /*
760          * If we have no active transaction id, get one from the return
761          * stream.
762          */
763         if (transid == 0) {
764             error = fp_read(jo->fp, &ack, sizeof(ack), &count, 1);
765 #if 0
766             printf("fp_read ack error %d count %d\n", error, count);
767 #endif
768             if (error || count != sizeof(ack))
769                 break;
770             if (error) {
771                 printf("read error %d on receive stream\n", error);
772                 break;
773             }
774             if (ack.rbeg.begmagic != JREC_BEGMAGIC ||
775                 ack.rend.endmagic != JREC_ENDMAGIC
776             ) {
777                 printf("bad begmagic or endmagic on receive stream\n");
778                 break;
779             }
780             transid = ack.rbeg.transid;
781         }
782
783         /*
784          * Calculate the number of unacknowledged bytes.  If there are no
785          * unacknowledged bytes then unsent data was acknowledged, report,
786          * sleep a bit, and loop in that case.  This should not happen 
787          * normally.  The ack record is thrown away.
788          */
789         bytes = jo->fifo.rindex - jo->fifo.xindex;
790
791         if (bytes == 0) {
792             printf("warning: unsent data acknowledged transid %08llx\n", transid);
793             tsleep(&jo->fifo.xindex, 0, "jrseq", hz);
794             transid = 0;
795             continue;
796         }
797
798         /*
799          * Since rindex has advanced, the record pointed to by xindex
800          * must be a valid record.
801          */
802         rawp = (void *)(jo->fifo.membase + (jo->fifo.xindex & jo->fifo.mask));
803         KKASSERT(rawp->begmagic == JREC_BEGMAGIC);
804         KKASSERT(rawp->recsize <= bytes);
805
806         /*
807          * The target can acknowledge several records at once.
808          */
809         if (rawp->transid < transid) {
810 #if 1
811             printf("ackskip %08llx/%08llx\n", rawp->transid, transid);
812 #endif
813             jo->fifo.xindex += (rawp->recsize + 15) & ~15;
814             jo->total_acked += (rawp->recsize + 15) & ~15;
815             if (jo->flags & MC_JOURNAL_WWAIT) {
816                 jo->flags &= ~MC_JOURNAL_WWAIT; /* XXX hysteresis */
817                 wakeup(&jo->fifo.windex);
818             }
819             continue;
820         }
821         if (rawp->transid == transid) {
822 #if 1
823             printf("ackskip %08llx/%08llx\n", rawp->transid, transid);
824 #endif
825             jo->fifo.xindex += (rawp->recsize + 15) & ~15;
826             jo->total_acked += (rawp->recsize + 15) & ~15;
827             if (jo->flags & MC_JOURNAL_WWAIT) {
828                 jo->flags &= ~MC_JOURNAL_WWAIT; /* XXX hysteresis */
829                 wakeup(&jo->fifo.windex);
830             }
831             transid = 0;
832             continue;
833         }
834         printf("warning: unsent data(2) acknowledged transid %08llx\n", transid);
835         transid = 0;
836     }
837     jo->flags &= ~MC_JOURNAL_RACTIVE;
838     wakeup(jo);
839     wakeup(&jo->fifo.windex);
840 }
841
842 /*
843  * This builds a pad record which the journaling thread will skip over.  Pad
844  * records are required when we are unable to reserve sufficient stream space
845  * due to insufficient space at the end of the physical memory fifo.
846  *
847  * Even though the record is not transmitted, a normal transid must be 
848  * assigned to it so link recovery operations after a failure work properly.
849  */
850 static
851 void
852 journal_build_pad(struct journal_rawrecbeg *rawp, int recsize, int64_t transid)
853 {
854     struct journal_rawrecend *rendp;
855     
856     KKASSERT((recsize & 15) == 0 && recsize >= 16);
857
858     rawp->streamid = JREC_STREAMID_PAD;
859     rawp->recsize = recsize;    /* must be 16-byte aligned */
860     rawp->transid = transid;
861     /*
862      * WARNING, rendp may overlap rawp->transid.  This is necessary to
863      * allow PAD records to fit in 16 bytes.  Use cpu_ccfence() to
864      * hopefully cause the compiler to not make any assumptions.
865      */
866     rendp = (void *)((char *)rawp + rawp->recsize - sizeof(*rendp));
867     rendp->endmagic = JREC_ENDMAGIC;
868     rendp->check = 0;
869     rendp->recsize = rawp->recsize;
870
871     /*
872      * Set the begin magic last.  This is what will allow the journal
873      * thread to write the record out.  Use a store fence to prevent
874      * compiler and cpu reordering of the writes.
875      */
876     cpu_sfence();
877     rawp->begmagic = JREC_BEGMAGIC;
878 }
879
880 /*
881  * Wake up the worker thread if the FIFO is more then half full or if
882  * someone is waiting for space to be freed up.  Otherwise let the 
883  * heartbeat deal with it.  Being able to avoid waking up the worker
884  * is the key to the journal's cpu performance.
885  */
886 static __inline
887 void
888 journal_commit_wakeup(struct journal *jo)
889 {
890     int avail;
891
892     avail = jo->fifo.size - (jo->fifo.windex - jo->fifo.xindex);
893     KKASSERT(avail >= 0);
894     if ((avail < (jo->fifo.size >> 1)) || (jo->flags & MC_JOURNAL_WWAIT))
895         wakeup(&jo->fifo);
896 }
897
898 /*
899  * Create a new BEGIN stream record with the specified streamid and the
900  * specified amount of payload space.  *rawpp will be set to point to the
901  * base of the new stream record and a pointer to the base of the payload
902  * space will be returned.  *rawpp does not need to be pre-NULLd prior to
903  * making this call.  The raw record header will be partially initialized.
904  *
905  * A stream can be extended, aborted, or committed by other API calls
906  * below.  This may result in a sequence of potentially disconnected
907  * stream records to be output to the journaling target.  The first record
908  * (the one created by this function) will be marked JREC_STREAMCTL_BEGIN,
909  * while the last record on commit or abort will be marked JREC_STREAMCTL_END
910  * (and possibly also JREC_STREAMCTL_ABORTED).  The last record could wind
911  * up being the same as the first, in which case the bits are all set in
912  * the first record.
913  *
914  * The stream record is created in an incomplete state by setting the begin
915  * magic to JREC_INCOMPLETEMAGIC.  This prevents the worker thread from
916  * flushing the fifo past our record until we have finished populating it.
917  * Other threads can reserve and operate on their own space without stalling
918  * but the stream output will stall until we have completed operations.  The
919  * memory FIFO is intended to be large enough to absorb such situations
920  * without stalling out other threads.
921  */
922 static
923 void *
924 journal_reserve(struct journal *jo, struct journal_rawrecbeg **rawpp,
925                 int16_t streamid, int bytes)
926 {
927     struct journal_rawrecbeg *rawp;
928     int avail;
929     int availtoend;
930     int req;
931
932     /*
933      * Add header and trailer overheads to the passed payload.  Note that
934      * the passed payload size need not be aligned in any way.
935      */
936     bytes += sizeof(struct journal_rawrecbeg);
937     bytes += sizeof(struct journal_rawrecend);
938
939     for (;;) {
940         /*
941          * First, check boundary conditions.  If the request would wrap around
942          * we have to skip past the ending block and return to the beginning
943          * of the FIFO's buffer.  Calculate 'req' which is the actual number
944          * of bytes being reserved, including wrap-around dead space.
945          *
946          * Neither 'bytes' or 'req' are aligned.
947          *
948          * Note that availtoend is not truncated to avail and so cannot be
949          * used to determine whether the reservation is possible by itself.
950          * Also, since all fifo ops are 16-byte aligned, we can check
951          * the size before calculating the aligned size.
952          */
953         availtoend = jo->fifo.size - (jo->fifo.windex & jo->fifo.mask);
954         KKASSERT((availtoend & 15) == 0);
955         if (bytes > availtoend) 
956             req = bytes + availtoend;   /* add pad to end */
957         else
958             req = bytes;
959
960         /*
961          * Next calculate the total available space and see if it is
962          * sufficient.  We cannot overwrite previously buffered data
963          * past xindex because otherwise we would not be able to restart
964          * a broken link at the target's last point of commit.
965          */
966         avail = jo->fifo.size - (jo->fifo.windex - jo->fifo.xindex);
967         KKASSERT(avail >= 0 && (avail & 15) == 0);
968
969         if (avail < req) {
970             /* XXX MC_JOURNAL_STOP_IMM */
971             jo->flags |= MC_JOURNAL_WWAIT;
972             ++jo->fifostalls;
973             tsleep(&jo->fifo.windex, 0, "jwrite", 0);
974             continue;
975         }
976
977         /*
978          * Create a pad record for any dead space and create an incomplete
979          * record for the live space, then return a pointer to the
980          * contiguous buffer space that was requested.
981          *
982          * NOTE: The worker thread will not flush past an incomplete
983          * record, so the reserved space can be filled in at-will.  The
984          * journaling code must also be aware the reserved sections occuring
985          * after this one will also not be written out even if completed
986          * until this one is completed.
987          *
988          * The transaction id must accomodate real and potential pad creation.
989          */
990         rawp = (void *)(jo->fifo.membase + (jo->fifo.windex & jo->fifo.mask));
991         if (req != bytes) {
992             journal_build_pad(rawp, availtoend, jo->transid);
993             ++jo->transid;
994             rawp = (void *)jo->fifo.membase;
995         }
996         rawp->begmagic = JREC_INCOMPLETEMAGIC;  /* updated by abort/commit */
997         rawp->recsize = bytes;                  /* (unaligned size) */
998         rawp->streamid = streamid | JREC_STREAMCTL_BEGIN;
999         rawp->transid = jo->transid;
1000         jo->transid += 2;
1001
1002         /*
1003          * Issue a memory barrier to guarentee that the record data has been
1004          * properly initialized before we advance the write index and return
1005          * a pointer to the reserved record.  Otherwise the worker thread
1006          * could accidently run past us.
1007          *
1008          * Note that stream records are always 16-byte aligned.
1009          */
1010         cpu_sfence();
1011         jo->fifo.windex += (req + 15) & ~15;
1012         *rawpp = rawp;
1013         return(rawp + 1);
1014     }
1015     /* not reached */
1016     *rawpp = NULL;
1017     return(NULL);
1018 }
1019
1020 /*
1021  * Attempt to extend the stream record by <bytes> worth of payload space.
1022  *
1023  * If it is possible to extend the existing stream record no truncation
1024  * occurs and the record is extended as specified.  A pointer to the 
1025  * truncation offset within the payload space is returned.
1026  *
1027  * If it is not possible to do this the existing stream record is truncated
1028  * and committed, and a new stream record of size <bytes> is created.  A
1029  * pointer to the base of the new stream record's payload space is returned.
1030  *
1031  * *rawpp is set to the new reservation in the case of a new record but
1032  * the caller cannot depend on a comparison with the old rawp to determine if
1033  * this case occurs because we could end up using the same memory FIFO
1034  * offset for the new stream record.  Use *newstreamrecp instead.
1035  */
1036 static void *
1037 journal_extend(struct journal *jo, struct journal_rawrecbeg **rawpp, 
1038                 int truncbytes, int bytes, int *newstreamrecp)
1039 {
1040     struct journal_rawrecbeg *rawp;
1041     int16_t streamid;
1042     int availtoend;
1043     int avail;
1044     int osize;
1045     int nsize;
1046     int wbase;
1047     void *rptr;
1048
1049     *newstreamrecp = 0;
1050     rawp = *rawpp;
1051     osize = (rawp->recsize + 15) & ~15;
1052     nsize = (rawp->recsize + bytes + 15) & ~15;
1053     wbase = (char *)rawp - jo->fifo.membase;
1054
1055     /*
1056      * If the aligned record size does not change we can trivially adjust
1057      * the record size.
1058      */
1059     if (nsize == osize) {
1060         rawp->recsize += bytes;
1061         return((char *)(rawp + 1) + truncbytes);
1062     }
1063
1064     /*
1065      * If the fifo's write index hasn't been modified since we made the
1066      * reservation and we do not hit any boundary conditions, we can 
1067      * trivially make the record smaller or larger.
1068      */
1069     if ((jo->fifo.windex & jo->fifo.mask) == wbase + osize) {
1070         availtoend = jo->fifo.size - wbase;
1071         avail = jo->fifo.size - (jo->fifo.windex - jo->fifo.xindex) + osize;
1072         KKASSERT((availtoend & 15) == 0);
1073         KKASSERT((avail & 15) == 0);
1074         if (nsize <= avail && nsize <= availtoend) {
1075             jo->fifo.windex += nsize - osize;
1076             rawp->recsize += bytes;
1077             return((char *)(rawp + 1) + truncbytes);
1078         }
1079     }
1080
1081     /*
1082      * It was not possible to extend the buffer.  Commit the current
1083      * buffer and create a new one.  We manually clear the BEGIN mark that
1084      * journal_reserve() creates (because this is a continuing record, not
1085      * the start of a new stream).
1086      */
1087     streamid = rawp->streamid & JREC_STREAMID_MASK;
1088     journal_commit(jo, rawpp, truncbytes, 0);
1089     rptr = journal_reserve(jo, rawpp, streamid, bytes);
1090     rawp = *rawpp;
1091     rawp->streamid &= ~JREC_STREAMCTL_BEGIN;
1092     *newstreamrecp = 1;
1093     return(rptr);
1094 }
1095
1096 /*
1097  * Abort a journal record.  If the transaction record represents a stream
1098  * BEGIN and we can reverse the fifo's write index we can simply reverse
1099  * index the entire record, as if it were never reserved in the first place.
1100  *
1101  * Otherwise we set the JREC_STREAMCTL_ABORTED bit and commit the record
1102  * with the payload truncated to 0 bytes.
1103  */
1104 static void
1105 journal_abort(struct journal *jo, struct journal_rawrecbeg **rawpp)
1106 {
1107     struct journal_rawrecbeg *rawp;
1108     int osize;
1109
1110     rawp = *rawpp;
1111     osize = (rawp->recsize + 15) & ~15;
1112
1113     if ((rawp->streamid & JREC_STREAMCTL_BEGIN) &&
1114         (jo->fifo.windex & jo->fifo.mask) == 
1115          (char *)rawp - jo->fifo.membase + osize)
1116     {
1117         jo->fifo.windex -= osize;
1118         *rawpp = NULL;
1119     } else {
1120         rawp->streamid |= JREC_STREAMCTL_ABORTED;
1121         journal_commit(jo, rawpp, 0, 1);
1122     }
1123 }
1124
1125 /*
1126  * Commit a journal record and potentially truncate it to the specified
1127  * number of payload bytes.  If you do not want to truncate the record,
1128  * simply pass -1 for the bytes parameter.  Do not pass rawp->recsize, that
1129  * field includes header and trailer and will not be correct.  Note that
1130  * passing 0 will truncate the entire data payload of the record.
1131  *
1132  * The logical stream is terminated by this function.
1133  *
1134  * If truncation occurs, and it is not possible to physically optimize the
1135  * memory FIFO due to other threads having reserved space after ours,
1136  * the remaining reserved space will be covered by a pad record.
1137  */
1138 static void
1139 journal_commit(struct journal *jo, struct journal_rawrecbeg **rawpp,
1140                 int bytes, int closeout)
1141 {
1142     struct journal_rawrecbeg *rawp;
1143     struct journal_rawrecend *rendp;
1144     int osize;
1145     int nsize;
1146
1147     rawp = *rawpp;
1148     *rawpp = NULL;
1149
1150     KKASSERT((char *)rawp >= jo->fifo.membase &&
1151              (char *)rawp + rawp->recsize <= jo->fifo.membase + jo->fifo.size);
1152     KKASSERT(((intptr_t)rawp & 15) == 0);
1153
1154     /*
1155      * Truncate the record if necessary.  If the FIFO write index as still
1156      * at the end of our record we can optimally backindex it.  Otherwise
1157      * we have to insert a pad record to cover the dead space.
1158      *
1159      * We calculate osize which is the 16-byte-aligned original recsize.
1160      * We calculate nsize which is the 16-byte-aligned new recsize.
1161      *
1162      * Due to alignment issues or in case the passed truncation bytes is
1163      * the same as the original payload, nsize may be equal to osize even
1164      * if the committed bytes is less then the originally reserved bytes.
1165      */
1166     if (bytes >= 0) {
1167         KKASSERT(bytes >= 0 && bytes <= rawp->recsize - sizeof(struct journal_rawrecbeg) - sizeof(struct journal_rawrecend));
1168         osize = (rawp->recsize + 15) & ~15;
1169         rawp->recsize = bytes + sizeof(struct journal_rawrecbeg) +
1170                         sizeof(struct journal_rawrecend);
1171         nsize = (rawp->recsize + 15) & ~15;
1172         KKASSERT(nsize <= osize);
1173         if (osize == nsize) {
1174             /* do nothing */
1175         } else if ((jo->fifo.windex & jo->fifo.mask) == (char *)rawp - jo->fifo.membase + osize) {
1176             /* we are able to backindex the fifo */
1177             jo->fifo.windex -= osize - nsize;
1178         } else {
1179             /* we cannot backindex the fifo, emplace a pad in the dead space */
1180             journal_build_pad((void *)((char *)rawp + nsize), osize - nsize,
1181                                 rawp->transid + 1);
1182         }
1183     }
1184
1185     /*
1186      * Fill in the trailer.  Note that unlike pad records, the trailer will
1187      * never overlap the header.
1188      */
1189     rendp = (void *)((char *)rawp + 
1190             ((rawp->recsize + 15) & ~15) - sizeof(*rendp));
1191     rendp->endmagic = JREC_ENDMAGIC;
1192     rendp->recsize = rawp->recsize;
1193     rendp->check = 0;           /* XXX check word, disabled for now */
1194
1195     /*
1196      * Fill in begmagic last.  This will allow the worker thread to proceed.
1197      * Use a memory barrier to guarentee write ordering.  Mark the stream
1198      * as terminated if closeout is set.  This is the typical case.
1199      */
1200     if (closeout)
1201         rawp->streamid |= JREC_STREAMCTL_END;
1202     cpu_sfence();               /* memory and compiler barrier */
1203     rawp->begmagic = JREC_BEGMAGIC;
1204
1205     journal_commit_wakeup(jo);
1206 }
1207
1208 /************************************************************************
1209  *                      PARALLEL TRANSACTION SUPPORT ROUTINES           *
1210  ************************************************************************
1211  *
1212  * JRECLIST_*() - routines which create and iterate over jrecord structures,
1213  *                because a mount point may have multiple attached journals.
1214  */
1215
1216 /*
1217  * Initialize the passed jrecord_list and create a jrecord for each 
1218  * journal we need to write to.  Unnecessary mallocs are avoided by
1219  * using the passed jrecord structure as the first jrecord in the list.
1220  * A starting transaction is pushed for each jrecord.
1221  *
1222  * Returns non-zero if any of the journals require undo records.
1223  */
1224 static
1225 int
1226 jreclist_init(struct mount *mp, struct jrecord_list *jreclist, 
1227               struct jrecord *jreccache, int16_t rectype)
1228 {
1229     struct journal *jo;
1230     struct jrecord *jrec;
1231     int wantrev = 0;
1232     int count = 0;
1233
1234     TAILQ_INIT(jreclist);
1235     TAILQ_FOREACH(jo, &mp->mnt_jlist, jentry) {
1236         if (count == 0)
1237             jrec = jreccache;
1238         else
1239             jrec = malloc(sizeof(*jrec), M_JOURNAL, M_WAITOK);
1240         jrecord_init(jo, jrec, -1);
1241         jrec->user_save = jrecord_push(jrec, rectype);
1242         TAILQ_INSERT_TAIL(jreclist, jrec, user_entry);
1243         if (jo->flags & MC_JOURNAL_WANT_REVERSABLE)
1244             wantrev = 1;
1245         ++count;
1246     }
1247     return(wantrev);
1248 }
1249
1250 /*
1251  * Terminate the journaled transactions started by jreclist_init().  If
1252  * an error occured, the transaction records will be aborted.
1253  */
1254 static
1255 void
1256 jreclist_done(struct jrecord_list *jreclist, int error)
1257 {
1258     struct jrecord *jrec;
1259     int count;
1260
1261     TAILQ_FOREACH(jrec, jreclist, user_entry) {
1262         jrecord_pop(jrec, jrec->user_save);
1263         jrecord_done(jrec, error);
1264     }
1265     count = 0;
1266     while ((jrec = TAILQ_FIRST(jreclist)) != NULL) {
1267         TAILQ_REMOVE(jreclist, jrec, user_entry);
1268         if (count)
1269             free(jrec, M_JOURNAL);
1270         ++count;
1271     }
1272 }
1273
1274 /*
1275  * This procedure writes out UNDO records for available reversable
1276  * journals.
1277  *
1278  * XXX could use improvement.  There is no need to re-read the file
1279  * for each journal.
1280  */
1281 static
1282 void
1283 jreclist_undo_file(struct jrecord_list *jreclist, struct vnode *vp, 
1284                    int jrflags, off_t off, off_t bytes)
1285 {
1286     struct jrecord *jrec;
1287     int error;
1288
1289     error = 0;
1290     if (jrflags & JRUNDO_GETVP)
1291         error = vget(vp, LK_SHARED, curthread);
1292     if (error == 0) {
1293         TAILQ_FOREACH(jrec, jreclist, user_entry) {
1294             if (jrec->jo->flags & MC_JOURNAL_WANT_REVERSABLE) {
1295                 jrecord_undo_file(jrec, vp, jrflags, off, bytes);
1296             }
1297         }
1298     }
1299     if (error == 0 && jrflags & JRUNDO_GETVP)
1300         vput(vp);
1301 }
1302
1303 /************************************************************************
1304  *                      TRANSACTION SUPPORT ROUTINES                    *
1305  ************************************************************************
1306  *
1307  * JRECORD_*() - routines to create subrecord transactions and embed them
1308  *               in the logical streams managed by the journal_*() routines.
1309  */
1310
1311 static int16_t sid = JREC_STREAMID_JMIN;
1312
1313 /*
1314  * Initialize the passed jrecord structure and start a new stream transaction
1315  * by reserving an initial build space in the journal's memory FIFO.
1316  */
1317 static void
1318 jrecord_init(struct journal *jo, struct jrecord *jrec, int16_t streamid)
1319 {
1320     bzero(jrec, sizeof(*jrec));
1321     jrec->jo = jo;
1322     if (streamid < 0) {
1323         streamid = sid++;       /* XXX need to track stream ids! */
1324         if (sid == JREC_STREAMID_JMAX)
1325             sid = JREC_STREAMID_JMIN;
1326     }
1327     jrec->streamid = streamid;
1328     jrec->stream_residual = JREC_DEFAULTSIZE;
1329     jrec->stream_reserved = jrec->stream_residual;
1330     jrec->stream_ptr = 
1331         journal_reserve(jo, &jrec->rawp, streamid, jrec->stream_reserved);
1332 }
1333
1334 /*
1335  * Push a recursive record type.  All pushes should have matching pops.
1336  * The old parent is returned and the newly pushed record becomes the
1337  * new parent.  Note that the old parent's pointer may already be invalid
1338  * or may become invalid if jrecord_write() had to build a new stream
1339  * record, so the caller should not mess with the returned pointer in
1340  * any way other then to save it.
1341  */
1342 static 
1343 struct journal_subrecord *
1344 jrecord_push(struct jrecord *jrec, int16_t rectype)
1345 {
1346     struct journal_subrecord *save;
1347
1348     save = jrec->parent;
1349     jrec->parent = jrecord_write(jrec, rectype|JMASK_NESTED, 0);
1350     jrec->last = NULL;
1351     KKASSERT(jrec->parent != NULL);
1352     ++jrec->pushcount;
1353     ++jrec->pushptrgood;        /* cleared on flush */
1354     return(save);
1355 }
1356
1357 /*
1358  * Pop a previously pushed sub-transaction.  We must set JMASK_LAST
1359  * on the last record written within the subtransaction.  If the last 
1360  * record written is not accessible or if the subtransaction is empty,
1361  * we must write out a pad record with JMASK_LAST set before popping.
1362  *
1363  * When popping a subtransaction the parent record's recsize field
1364  * will be properly set.  If the parent pointer is no longer valid
1365  * (which can occur if the data has already been flushed out to the
1366  * stream), the protocol spec allows us to leave it 0.
1367  *
1368  * The saved parent pointer which we restore may or may not be valid,
1369  * and if not valid may or may not be NULL, depending on the value
1370  * of pushptrgood.
1371  */
1372 static void
1373 jrecord_pop(struct jrecord *jrec, struct journal_subrecord *save)
1374 {
1375     struct journal_subrecord *last;
1376
1377     KKASSERT(jrec->pushcount > 0);
1378     KKASSERT(jrec->residual == 0);
1379
1380     /*
1381      * Set JMASK_LAST on the last record we wrote at the current
1382      * level.  If last is NULL we either no longer have access to the
1383      * record or the subtransaction was empty and we must write out a pad
1384      * record.
1385      */
1386     if ((last = jrec->last) == NULL) {
1387         jrecord_write(jrec, JLEAF_PAD|JMASK_LAST, 0);
1388         last = jrec->last;      /* reload after possible flush */
1389     } else {
1390         last->rectype |= JMASK_LAST;
1391     }
1392
1393     /*
1394      * pushptrgood tells us how many levels of parent record pointers
1395      * are valid.  The jrec only stores the current parent record pointer
1396      * (and it is only valid if pushptrgood != 0).  The higher level parent
1397      * record pointers are saved by the routines calling jrecord_push() and
1398      * jrecord_pop().  These pointers may become stale and we determine
1399      * that fact by tracking the count of valid parent pointers with 
1400      * pushptrgood.  Pointers become invalid when their related stream
1401      * record gets pushed out.
1402      *
1403      * If no pointer is available (the data has already been pushed out),
1404      * then no fixup of e.g. the length field is possible for non-leaf
1405      * nodes.  The protocol allows for this situation by placing a larger
1406      * burden on the program scanning the stream on the other end.
1407      *
1408      * [parentA]
1409      *    [node X]
1410      *    [parentB]
1411      *       [node Y]
1412      *       [node Z]
1413      *    (pop B)       see NOTE B
1414      * (pop A)          see NOTE A
1415      *
1416      * NOTE B:  This pop sets LAST in node Z if the node is still accessible,
1417      *          else a PAD record is appended and LAST is set in that.
1418      *
1419      *          This pop sets the record size in parentB if parentB is still
1420      *          accessible, else the record size is left 0 (the scanner must
1421      *          deal with that).
1422      *
1423      *          This pop sets the new 'last' record to parentB, the pointer
1424      *          to which may or may not still be accessible.
1425      *
1426      * NOTE A:  This pop sets LAST in parentB if the node is still accessible,
1427      *          else a PAD record is appended and LAST is set in that.
1428      *
1429      *          This pop sets the record size in parentA if parentA is still
1430      *          accessible, else the record size is left 0 (the scanner must
1431      *          deal with that).
1432      *
1433      *          This pop sets the new 'last' record to parentA, the pointer
1434      *          to which may or may not still be accessible.
1435      *
1436      * Also note that the last record in the stream transaction, which in
1437      * the above example is parentA, does not currently have the LAST bit
1438      * set.
1439      *
1440      * The current parent becomes the last record relative to the
1441      * saved parent passed into us.  It's validity is based on 
1442      * whether pushptrgood is non-zero prior to decrementing.  The saved
1443      * parent becomes the new parent, and its validity is based on whether
1444      * pushptrgood is non-zero after decrementing.
1445      *
1446      * The old jrec->parent may be NULL if it is no longer accessible.
1447      * If pushptrgood is non-zero, however, it is guarenteed to not
1448      * be NULL (since no flush occured).
1449      */
1450     jrec->last = jrec->parent;
1451     --jrec->pushcount;
1452     if (jrec->pushptrgood) {
1453         KKASSERT(jrec->last != NULL && last != NULL);
1454         if (--jrec->pushptrgood == 0) {
1455             jrec->parent = NULL;        /* 'save' contains garbage or NULL */
1456         } else {
1457             KKASSERT(save != NULL);
1458             jrec->parent = save;        /* 'save' must not be NULL */
1459         }
1460
1461         /*
1462          * Set the record size in the old parent.  'last' still points to
1463          * the original last record in the subtransaction being popped,
1464          * jrec->last points to the old parent (which became the last
1465          * record relative to the new parent being popped into).
1466          */
1467         jrec->last->recsize = (char *)last + last->recsize - (char *)jrec->last;
1468     } else {
1469         jrec->parent = NULL;
1470         KKASSERT(jrec->last == NULL);
1471     }
1472 }
1473
1474 /*
1475  * Write out a leaf record, including associated data.
1476  */
1477 static
1478 void
1479 jrecord_leaf(struct jrecord *jrec, int16_t rectype, void *ptr, int bytes)
1480 {
1481     jrecord_write(jrec, rectype, bytes);
1482     jrecord_data(jrec, ptr, bytes);
1483 }
1484
1485 /*
1486  * Write a leaf record out and return a pointer to its base.  The leaf
1487  * record may contain potentially megabytes of data which is supplied
1488  * in jrecord_data() calls.  The exact amount must be specified in this
1489  * call.
1490  *
1491  * THE RETURNED SUBRECORD POINTER IS ONLY VALID IMMEDIATELY AFTER THE
1492  * CALL AND MAY BECOME INVALID AT ANY TIME.  ONLY THE PUSH/POP CODE SHOULD
1493  * USE THE RETURN VALUE.
1494  */
1495 static
1496 struct journal_subrecord *
1497 jrecord_write(struct jrecord *jrec, int16_t rectype, int bytes)
1498 {
1499     struct journal_subrecord *last;
1500     int pusheditout;
1501
1502     /*
1503      * Try to catch some obvious errors.  Nesting records must specify a
1504      * size of 0, and there should be no left-overs from previous operations
1505      * (such as incomplete data writeouts).
1506      */
1507     KKASSERT(bytes == 0 || (rectype & JMASK_NESTED) == 0);
1508     KKASSERT(jrec->residual == 0);
1509
1510     /*
1511      * Check to see if the current stream record has enough room for
1512      * the new subrecord header.  If it doesn't we extend the current
1513      * stream record.
1514      *
1515      * This may have the side effect of pushing out the current stream record
1516      * and creating a new one.  We must adjust our stream tracking fields
1517      * accordingly.
1518      */
1519     if (jrec->stream_residual < sizeof(struct journal_subrecord)) {
1520         jrec->stream_ptr = journal_extend(jrec->jo, &jrec->rawp,
1521                                 jrec->stream_reserved - jrec->stream_residual,
1522                                 JREC_DEFAULTSIZE, &pusheditout);
1523         if (pusheditout) {
1524             /*
1525              * If a pushout occured, the pushed out stream record was
1526              * truncated as specified and the new record is exactly the
1527              * extension size specified.
1528              */
1529             jrec->stream_reserved = JREC_DEFAULTSIZE;
1530             jrec->stream_residual = JREC_DEFAULTSIZE;
1531             jrec->parent = NULL;        /* no longer accessible */
1532             jrec->pushptrgood = 0;      /* restored parents in pops no good */
1533         } else {
1534             /*
1535              * If no pushout occured the stream record is NOT truncated and
1536              * IS extended.
1537              */
1538             jrec->stream_reserved += JREC_DEFAULTSIZE;
1539             jrec->stream_residual += JREC_DEFAULTSIZE;
1540         }
1541     }
1542     last = (void *)jrec->stream_ptr;
1543     last->rectype = rectype;
1544     last->reserved = 0;
1545
1546     /*
1547      * We may not know the record size for recursive records and the 
1548      * header may become unavailable due to limited FIFO space.  Write
1549      * -1 to indicate this special case.
1550      */
1551     if ((rectype & JMASK_NESTED) && bytes == 0)
1552         last->recsize = -1;
1553     else
1554         last->recsize = sizeof(struct journal_subrecord) + bytes;
1555     jrec->last = last;
1556     jrec->residual = bytes;             /* remaining data to be posted */
1557     jrec->residual_align = -bytes & 7;  /* post-data alignment required */
1558     jrec->stream_ptr += sizeof(*last);  /* current write pointer */
1559     jrec->stream_residual -= sizeof(*last); /* space remaining in stream */
1560     return(last);
1561 }
1562
1563 /*
1564  * Write out the data associated with a leaf record.  Any number of calls
1565  * to this routine may be made as long as the byte count adds up to the
1566  * amount originally specified in jrecord_write().
1567  *
1568  * The act of writing out the leaf data may result in numerous stream records
1569  * being pushed out.   Callers should be aware that even the associated
1570  * subrecord header may become inaccessible due to stream record pushouts.
1571  */
1572 static void
1573 jrecord_data(struct jrecord *jrec, const void *buf, int bytes)
1574 {
1575     int pusheditout;
1576     int extsize;
1577
1578     KKASSERT(bytes >= 0 && bytes <= jrec->residual);
1579
1580     /*
1581      * Push out stream records as long as there is insufficient room to hold
1582      * the remaining data.
1583      */
1584     while (jrec->stream_residual < bytes) {
1585         /*
1586          * Fill in any remaining space in the current stream record.
1587          */
1588         bcopy(buf, jrec->stream_ptr, jrec->stream_residual);
1589         buf = (const char *)buf + jrec->stream_residual;
1590         bytes -= jrec->stream_residual;
1591         /*jrec->stream_ptr += jrec->stream_residual;*/
1592         jrec->residual -= jrec->stream_residual;
1593         jrec->stream_residual = 0;
1594
1595         /*
1596          * Try to extend the current stream record, but no more then 1/4
1597          * the size of the FIFO.
1598          */
1599         extsize = jrec->jo->fifo.size >> 2;
1600         if (extsize > bytes)
1601             extsize = (bytes + 15) & ~15;
1602
1603         jrec->stream_ptr = journal_extend(jrec->jo, &jrec->rawp,
1604                                 jrec->stream_reserved - jrec->stream_residual,
1605                                 extsize, &pusheditout);
1606         if (pusheditout) {
1607             jrec->stream_reserved = extsize;
1608             jrec->stream_residual = extsize;
1609             jrec->parent = NULL;        /* no longer accessible */
1610             jrec->last = NULL;          /* no longer accessible */
1611             jrec->pushptrgood = 0;      /* restored parents in pops no good */
1612         } else {
1613             jrec->stream_reserved += extsize;
1614             jrec->stream_residual += extsize;
1615         }
1616     }
1617
1618     /*
1619      * Push out any remaining bytes into the current stream record.
1620      */
1621     if (bytes) {
1622         bcopy(buf, jrec->stream_ptr, bytes);
1623         jrec->stream_ptr += bytes;
1624         jrec->stream_residual -= bytes;
1625         jrec->residual -= bytes;
1626     }
1627
1628     /*
1629      * Handle data alignment requirements for the subrecord.  Because the
1630      * stream record's data space is more strictly aligned, it must already
1631      * have sufficient space to hold any subrecord alignment slop.
1632      */
1633     if (jrec->residual == 0 && jrec->residual_align) {
1634         KKASSERT(jrec->residual_align <= jrec->stream_residual);
1635         bzero(jrec->stream_ptr, jrec->residual_align);
1636         jrec->stream_ptr += jrec->residual_align;
1637         jrec->stream_residual -= jrec->residual_align;
1638         jrec->residual_align = 0;
1639     }
1640 }
1641
1642 /*
1643  * We are finished with the transaction.  This closes the transaction created
1644  * by jrecord_init().
1645  *
1646  * NOTE: If abortit is not set then we must be at the top level with no
1647  *       residual subrecord data left to output.
1648  *
1649  *       If abortit is set then we can be in any state, all pushes will be 
1650  *       popped and it is ok for there to be residual data.  This works 
1651  *       because the virtual stream itself is truncated.  Scanners must deal
1652  *       with this situation.
1653  *
1654  * The stream record will be committed or aborted as specified and jrecord
1655  * resources will be cleaned up.
1656  */
1657 static void
1658 jrecord_done(struct jrecord *jrec, int abortit)
1659 {
1660     KKASSERT(jrec->rawp != NULL);
1661
1662     if (abortit) {
1663         journal_abort(jrec->jo, &jrec->rawp);
1664     } else {
1665         KKASSERT(jrec->pushcount == 0 && jrec->residual == 0);
1666         journal_commit(jrec->jo, &jrec->rawp, 
1667                         jrec->stream_reserved - jrec->stream_residual, 1);
1668     }
1669
1670     /*
1671      * jrec should not be used beyond this point without another init,
1672      * but clean up some fields to ensure that we panic if it is.
1673      *
1674      * Note that jrec->rawp is NULLd out by journal_abort/journal_commit.
1675      */
1676     jrec->jo = NULL;
1677     jrec->stream_ptr = NULL;
1678 }
1679
1680 /************************************************************************
1681  *                      LOW LEVEL RECORD SUPPORT ROUTINES               *
1682  ************************************************************************
1683  *
1684  * These routine create low level recursive and leaf subrecords representing
1685  * common filesystem structures.
1686  */
1687
1688 /*
1689  * Write out a filename path relative to the base of the mount point.
1690  * rectype is typically JLEAF_PATH{1,2,3,4}.
1691  */
1692 static void
1693 jrecord_write_path(struct jrecord *jrec, int16_t rectype, struct namecache *ncp)
1694 {
1695     char buf[64];       /* local buffer if it fits, else malloced */
1696     char *base;
1697     int pathlen;
1698     int index;
1699     struct namecache *scan;
1700
1701     /*
1702      * Pass 1 - figure out the number of bytes required.  Include terminating
1703      *         \0 on last element and '/' separator on other elements.
1704      */
1705 again:
1706     pathlen = 0;
1707     for (scan = ncp; 
1708          scan && (scan->nc_flag & NCF_MOUNTPT) == 0; 
1709          scan = scan->nc_parent
1710     ) {
1711         pathlen += scan->nc_nlen + 1;
1712     }
1713
1714     if (pathlen <= sizeof(buf))
1715         base = buf;
1716     else
1717         base = malloc(pathlen, M_TEMP, M_INTWAIT);
1718
1719     /*
1720      * Pass 2 - generate the path buffer
1721      */
1722     index = pathlen;
1723     for (scan = ncp; 
1724          scan && (scan->nc_flag & NCF_MOUNTPT) == 0; 
1725          scan = scan->nc_parent
1726     ) {
1727         if (scan->nc_nlen >= index) {
1728             if (base != buf)
1729                 free(base, M_TEMP);
1730             goto again;
1731         }
1732         if (index == pathlen)
1733             base[--index] = 0;
1734         else
1735             base[--index] = '/';
1736         index -= scan->nc_nlen;
1737         bcopy(scan->nc_name, base + index, scan->nc_nlen);
1738     }
1739     jrecord_leaf(jrec, rectype, base + index, pathlen - index);
1740     if (base != buf)
1741         free(base, M_TEMP);
1742 }
1743
1744 /*
1745  * Write out a file attribute structure.  While somewhat inefficient, using
1746  * a recursive data structure is the most portable and extensible way.
1747  */
1748 static void
1749 jrecord_write_vattr(struct jrecord *jrec, struct vattr *vat)
1750 {
1751     void *save;
1752
1753     save = jrecord_push(jrec, JTYPE_VATTR);
1754     if (vat->va_type != VNON)
1755         jrecord_leaf(jrec, JLEAF_VTYPE, &vat->va_type, sizeof(vat->va_type));
1756     if (vat->va_mode != (mode_t)VNOVAL)
1757         jrecord_leaf(jrec, JLEAF_MODES, &vat->va_mode, sizeof(vat->va_mode));
1758     if (vat->va_nlink != VNOVAL)
1759         jrecord_leaf(jrec, JLEAF_NLINK, &vat->va_nlink, sizeof(vat->va_nlink));
1760     if (vat->va_uid != VNOVAL)
1761         jrecord_leaf(jrec, JLEAF_UID, &vat->va_uid, sizeof(vat->va_uid));
1762     if (vat->va_gid != VNOVAL)
1763         jrecord_leaf(jrec, JLEAF_GID, &vat->va_gid, sizeof(vat->va_gid));
1764     if (vat->va_fsid != VNOVAL)
1765         jrecord_leaf(jrec, JLEAF_FSID, &vat->va_fsid, sizeof(vat->va_fsid));
1766     if (vat->va_fileid != VNOVAL)
1767         jrecord_leaf(jrec, JLEAF_INUM, &vat->va_fileid, sizeof(vat->va_fileid));
1768     if (vat->va_size != VNOVAL)
1769         jrecord_leaf(jrec, JLEAF_SIZE, &vat->va_size, sizeof(vat->va_size));
1770     if (vat->va_atime.tv_sec != VNOVAL)
1771         jrecord_leaf(jrec, JLEAF_ATIME, &vat->va_atime, sizeof(vat->va_atime));
1772     if (vat->va_mtime.tv_sec != VNOVAL)
1773         jrecord_leaf(jrec, JLEAF_MTIME, &vat->va_mtime, sizeof(vat->va_mtime));
1774     if (vat->va_ctime.tv_sec != VNOVAL)
1775         jrecord_leaf(jrec, JLEAF_CTIME, &vat->va_ctime, sizeof(vat->va_ctime));
1776     if (vat->va_gen != VNOVAL)
1777         jrecord_leaf(jrec, JLEAF_GEN, &vat->va_gen, sizeof(vat->va_gen));
1778     if (vat->va_flags != VNOVAL)
1779         jrecord_leaf(jrec, JLEAF_FLAGS, &vat->va_flags, sizeof(vat->va_flags));
1780     if (vat->va_rdev != VNOVAL)
1781         jrecord_leaf(jrec, JLEAF_UDEV, &vat->va_rdev, sizeof(vat->va_rdev));
1782 #if 0
1783     if (vat->va_filerev != VNOVAL)
1784         jrecord_leaf(jrec, JLEAF_FILEREV, &vat->va_filerev, sizeof(vat->va_filerev));
1785 #endif
1786     jrecord_pop(jrec, save);
1787 }
1788
1789 /*
1790  * Write out the creds used to issue a file operation.  If a process is
1791  * available write out additional tracking information related to the 
1792  * process.
1793  *
1794  * XXX additional tracking info
1795  * XXX tty line info
1796  */
1797 static void
1798 jrecord_write_cred(struct jrecord *jrec, struct thread *td, struct ucred *cred)
1799 {
1800     void *save;
1801     struct proc *p;
1802
1803     save = jrecord_push(jrec, JTYPE_CRED);
1804     jrecord_leaf(jrec, JLEAF_UID, &cred->cr_uid, sizeof(cred->cr_uid));
1805     jrecord_leaf(jrec, JLEAF_GID, &cred->cr_gid, sizeof(cred->cr_gid));
1806     if (td && (p = td->td_proc) != NULL) {
1807         jrecord_leaf(jrec, JLEAF_PID, &p->p_pid, sizeof(p->p_pid));
1808         jrecord_leaf(jrec, JLEAF_COMM, p->p_comm, sizeof(p->p_comm));
1809     }
1810     jrecord_pop(jrec, save);
1811 }
1812
1813 /*
1814  * Write out information required to identify a vnode
1815  *
1816  * XXX this needs work.  We should write out the inode number as well,
1817  * and in fact avoid writing out the file path for seqential writes
1818  * occuring within e.g. a certain period of time.
1819  */
1820 static void
1821 jrecord_write_vnode_ref(struct jrecord *jrec, struct vnode *vp)
1822 {
1823     struct namecache *ncp;
1824
1825     TAILQ_FOREACH(ncp, &vp->v_namecache, nc_vnode) {
1826         if ((ncp->nc_flag & (NCF_UNRESOLVED|NCF_DESTROYED)) == 0)
1827             break;
1828     }
1829     if (ncp)
1830         jrecord_write_path(jrec, JLEAF_PATH_REF, ncp);
1831 }
1832
1833 static void
1834 jrecord_write_vnode_link(struct jrecord *jrec, struct vnode *vp, 
1835                          struct namecache *notncp)
1836 {
1837     struct namecache *ncp;
1838
1839     TAILQ_FOREACH(ncp, &vp->v_namecache, nc_vnode) {
1840         if (ncp == notncp)
1841             continue;
1842         if ((ncp->nc_flag & (NCF_UNRESOLVED|NCF_DESTROYED)) == 0)
1843             break;
1844     }
1845     if (ncp)
1846         jrecord_write_path(jrec, JLEAF_PATH_REF, ncp);
1847 }
1848
1849 #if 0
1850 /*
1851  * Write out the current contents of the file within the specified
1852  * range.  This is typically called from within an UNDO section.  A
1853  * locked vnode must be passed.
1854  */
1855 static int
1856 jrecord_write_filearea(struct jrecord *jrec, struct vnode *vp, 
1857                         off_t begoff, off_t endoff)
1858 {
1859 }
1860 #endif
1861
1862 /*
1863  * Write out the data represented by a pagelist
1864  */
1865 static void
1866 jrecord_write_pagelist(struct jrecord *jrec, int16_t rectype,
1867                         struct vm_page **pglist, int *rtvals, int pgcount,
1868                         off_t offset)
1869 {
1870     struct msf_buf *msf;
1871     int error;
1872     int b;
1873     int i;
1874
1875     i = 0;
1876     while (i < pgcount) {
1877         /*
1878          * Find the next valid section.  Skip any invalid elements
1879          */
1880         if (rtvals[i] != VM_PAGER_OK) {
1881             ++i;
1882             offset += PAGE_SIZE;
1883             continue;
1884         }
1885
1886         /*
1887          * Figure out how big the valid section is, capping I/O at what the
1888          * MSFBUF can represent.
1889          */
1890         b = i;
1891         while (i < pgcount && i - b != XIO_INTERNAL_PAGES && 
1892                rtvals[i] == VM_PAGER_OK
1893         ) {
1894             ++i;
1895         }
1896
1897         /*
1898          * And write it out.
1899          */
1900         if (i - b) {
1901             error = msf_map_pagelist(&msf, pglist + b, i - b, 0);
1902             if (error == 0) {
1903                 printf("RECORD PUTPAGES %d\n", msf_buf_bytes(msf));
1904                 jrecord_leaf(jrec, JLEAF_SEEKPOS, &offset, sizeof(offset));
1905                 jrecord_leaf(jrec, rectype, 
1906                              msf_buf_kva(msf), msf_buf_bytes(msf));
1907                 msf_buf_free(msf);
1908             } else {
1909                 printf("jrecord_write_pagelist: mapping failure\n");
1910             }
1911             offset += (off_t)(i - b) << PAGE_SHIFT;
1912         }
1913     }
1914 }
1915
1916 /*
1917  * Write out the data represented by a UIO.
1918  */
1919 struct jwuio_info {
1920     struct jrecord *jrec;
1921     int16_t rectype;
1922 };
1923
1924 static int jrecord_write_uio_callback(void *info, char *buf, int bytes);
1925
1926 static void
1927 jrecord_write_uio(struct jrecord *jrec, int16_t rectype, struct uio *uio)
1928 {
1929     struct jwuio_info info = { jrec, rectype };
1930     int error;
1931
1932     if (uio->uio_segflg != UIO_NOCOPY) {
1933         jrecord_leaf(jrec, JLEAF_SEEKPOS, &uio->uio_offset, 
1934                      sizeof(uio->uio_offset));
1935         error = msf_uio_iterate(uio, jrecord_write_uio_callback, &info);
1936         if (error)
1937             printf("XXX warning uio iterate failed %d\n", error);
1938     }
1939 }
1940
1941 static int
1942 jrecord_write_uio_callback(void *info_arg, char *buf, int bytes)
1943 {
1944     struct jwuio_info *info = info_arg;
1945
1946     jrecord_leaf(info->jrec, info->rectype, buf, bytes);
1947     return(0);
1948 }
1949
1950 static void
1951 jrecord_file_data(struct jrecord *jrec, struct vnode *vp, 
1952                   off_t off, off_t bytes)
1953 {
1954     const int bufsize = 8192;
1955     char *buf;
1956     int error;
1957     int n;
1958
1959     buf = malloc(bufsize, M_JOURNAL, M_WAITOK);
1960     jrecord_leaf(jrec, JLEAF_SEEKPOS, &off, sizeof(off));
1961     while (bytes) {
1962         n = (bytes > bufsize) ? bufsize : (int)bytes;
1963         error = vn_rdwr(UIO_READ, vp, buf, n, off, UIO_SYSSPACE, IO_NODELOCKED,
1964                         proc0.p_ucred, NULL, curthread);
1965         if (error) {
1966             jrecord_leaf(jrec, JLEAF_ERROR, &error, sizeof(error));
1967             break;
1968         }
1969         jrecord_leaf(jrec, JLEAF_FILEDATA, buf, n);
1970         bytes -= n;
1971         off += n;
1972     }
1973     free(buf, M_JOURNAL);
1974 }
1975
1976 /************************************************************************
1977  *                      LOW LEVEL UNDO SUPPORT ROUTINE                  *
1978  ************************************************************************
1979  *
1980  * This function is used to support UNDO records.  It will generate an
1981  * appropriate record with the requested portion of the file data.  Note
1982  * that file data is only recorded if JRUNDO_FILEDATA is passed.  If bytes
1983  * is -1, it will be set to the size of the file.
1984  */
1985 static void
1986 jrecord_undo_file(struct jrecord *jrec, struct vnode *vp, int jrflags, 
1987                   off_t off, off_t bytes)
1988 {
1989     struct vattr attr;
1990     void *save1; /* warning, save pointers do not always remain valid */
1991     void *save2;
1992     int error;
1993
1994     /*
1995      * Setup.  Start the UNDO record, obtain a shared lock on the vnode,
1996      * and retrieve attribute info.
1997      */
1998     save1 = jrecord_push(jrec, JTYPE_UNDO);
1999     error = VOP_GETATTR(vp, &attr, curthread);
2000     if (error)
2001         goto done;
2002
2003     /*
2004      * Generate UNDO records as requested.
2005      */
2006     if (jrflags & JRUNDO_VATTR) {
2007         save2 = jrecord_push(jrec, JTYPE_VATTR);
2008         jrecord_leaf(jrec, JLEAF_VTYPE, &attr.va_type, sizeof(attr.va_type));
2009         if ((jrflags & JRUNDO_NLINK) && attr.va_nlink != VNOVAL)
2010             jrecord_leaf(jrec, JLEAF_NLINK, &attr.va_nlink, sizeof(attr.va_nlink));
2011         if ((jrflags & JRUNDO_SIZE) && attr.va_size != VNOVAL)
2012             jrecord_leaf(jrec, JLEAF_SIZE, &attr.va_size, sizeof(attr.va_size));
2013         if ((jrflags & JRUNDO_UID) && attr.va_uid != VNOVAL)
2014             jrecord_leaf(jrec, JLEAF_UID, &attr.va_uid, sizeof(attr.va_uid));
2015         if ((jrflags & JRUNDO_GID) && attr.va_gid != VNOVAL)
2016             jrecord_leaf(jrec, JLEAF_GID, &attr.va_gid, sizeof(attr.va_gid));
2017         if ((jrflags & JRUNDO_FSID) && attr.va_fsid != VNOVAL)
2018             jrecord_leaf(jrec, JLEAF_FSID, &attr.va_fsid, sizeof(attr.va_fsid));
2019         if ((jrflags & JRUNDO_MODES) && attr.va_mode != (mode_t)VNOVAL)
2020             jrecord_leaf(jrec, JLEAF_MODES, &attr.va_mode, sizeof(attr.va_mode));
2021         if ((jrflags & JRUNDO_INUM) && attr.va_fileid != VNOVAL)
2022             jrecord_leaf(jrec, JLEAF_INUM, &attr.va_fileid, sizeof(attr.va_fileid));
2023         if ((jrflags & JRUNDO_ATIME) && attr.va_atime.tv_sec != VNOVAL)
2024             jrecord_leaf(jrec, JLEAF_ATIME, &attr.va_atime, sizeof(attr.va_atime));
2025         if ((jrflags & JRUNDO_MTIME) && attr.va_mtime.tv_sec != VNOVAL)
2026             jrecord_leaf(jrec, JLEAF_MTIME, &attr.va_mtime, sizeof(attr.va_mtime));
2027         if ((jrflags & JRUNDO_CTIME) && attr.va_ctime.tv_sec != VNOVAL)
2028             jrecord_leaf(jrec, JLEAF_CTIME, &attr.va_ctime, sizeof(attr.va_ctime));
2029         if ((jrflags & JRUNDO_GEN) && attr.va_gen != VNOVAL)
2030             jrecord_leaf(jrec, JLEAF_GEN, &attr.va_gen, sizeof(attr.va_gen));
2031         if ((jrflags & JRUNDO_FLAGS) && attr.va_flags != VNOVAL)
2032             jrecord_leaf(jrec, JLEAF_FLAGS, &attr.va_flags, sizeof(attr.va_flags));
2033         if ((jrflags & JRUNDO_UDEV) && attr.va_rdev != VNOVAL)
2034             jrecord_leaf(jrec, JLEAF_UDEV, &attr.va_rdev, sizeof(attr.va_rdev));
2035         jrecord_pop(jrec, save2);
2036     }
2037
2038     /*
2039      * Output the file data being overwritten by reading the file and
2040      * writing it out to the journal prior to the write operation.  We
2041      * do not need to write out data past the current file EOF.
2042      *
2043      * XXX support JRUNDO_CONDLINK - do not write out file data for files
2044      * with a link count > 1.  The undo code needs to locate the inode and
2045      * regenerate the hardlink.
2046      */
2047     if ((jrflags & JRUNDO_FILEDATA) && attr.va_type == VREG) {
2048         if (attr.va_size != VNOVAL) {
2049             if (bytes == -1)
2050                 bytes = attr.va_size - off;
2051             if (off + bytes > attr.va_size)
2052                 bytes = attr.va_size - off;
2053             if (bytes > 0)
2054                 jrecord_file_data(jrec, vp, off, bytes);
2055         } else {
2056             error = EINVAL;
2057         }
2058     }
2059     if ((jrflags & JRUNDO_FILEDATA) && attr.va_type == VLNK) {
2060         struct iovec aiov;
2061         struct uio auio;
2062         char *buf;
2063
2064         buf = malloc(PATH_MAX, M_JOURNAL, M_WAITOK);
2065         aiov.iov_base = buf;
2066         aiov.iov_len = PATH_MAX;
2067         auio.uio_iov = &aiov;
2068         auio.uio_iovcnt = 1;
2069         auio.uio_offset = 0;
2070         auio.uio_rw = UIO_READ;
2071         auio.uio_segflg = UIO_SYSSPACE;
2072         auio.uio_td = curthread;
2073         auio.uio_resid = PATH_MAX;
2074         error = VOP_READLINK(vp, &auio, proc0.p_ucred);
2075         if (error == 0) {
2076                 jrecord_leaf(jrec, JLEAF_SYMLINKDATA, buf, 
2077                                 PATH_MAX - auio.uio_resid);
2078         }
2079         free(buf, M_JOURNAL);
2080     }
2081 done:
2082     if (error)
2083         jrecord_leaf(jrec, JLEAF_ERROR, &error, sizeof(error));
2084     jrecord_pop(jrec, save1);
2085 }
2086
2087 /************************************************************************
2088  *                      JOURNAL VNOPS                                   *
2089  ************************************************************************
2090  *
2091  * These are function shims replacing the normal filesystem ops.  We become
2092  * responsible for calling the underlying filesystem ops.  We have the choice
2093  * of executing the underlying op first and then generating the journal entry,
2094  * or starting the journal entry, executing the underlying op, and then
2095  * either completing or aborting it.  
2096  *
2097  * The journal is supposed to be a high-level entity, which generally means
2098  * identifying files by name rather then by inode.  Supplying both allows
2099  * the journal to be used both for inode-number-compatible 'mirrors' and
2100  * for simple filesystem replication.
2101  *
2102  * Writes are particularly difficult to deal with because a single write may
2103  * represent a hundred megabyte buffer or more, and both writes and truncations
2104  * require the 'old' data to be written out as well as the new data if the
2105  * log is reversable.  Other issues:
2106  *
2107  * - How to deal with operations on unlinked files (no path available),
2108  *   but which may still be filesystem visible due to hard links.
2109  *
2110  * - How to deal with modifications made via a memory map.
2111  *
2112  * - Future cache coherency support will require cache coherency API calls
2113  *   both prior to and after the call to the underlying VFS.
2114  *
2115  * ALSO NOTE: We do not have to shim compatibility VOPs like MKDIR which have
2116  * new VFS equivalents (NMKDIR).
2117  */
2118
2119 /*
2120  * Journal vop_settattr { a_vp, a_vap, a_cred, a_td }
2121  */
2122 static
2123 int
2124 journal_setattr(struct vop_setattr_args *ap)
2125 {
2126     struct jrecord_list jreclist;
2127     struct jrecord jreccache;
2128     struct jrecord *jrec;
2129     struct mount *mp;
2130     void *save;
2131     int error;
2132
2133     mp = ap->a_head.a_ops->vv_mount;
2134     if (jreclist_init(mp, &jreclist, &jreccache, JTYPE_SETATTR)) {
2135         jreclist_undo_file(&jreclist, ap->a_vp, JRUNDO_VATTR, 0, 0);
2136     }
2137     error = vop_journal_operate_ap(&ap->a_head);
2138     if (error == 0) {
2139         TAILQ_FOREACH(jrec, &jreclist, user_entry) {
2140             jrecord_write_cred(jrec, ap->a_td, ap->a_cred);
2141             jrecord_write_vnode_ref(jrec, ap->a_vp);
2142             save = jrecord_push(jrec, JTYPE_REDO);
2143             jrecord_write_vattr(jrec, ap->a_vap);
2144             jrecord_pop(jrec, save);
2145         }
2146     }
2147     jreclist_done(&jreclist, error);
2148     return (error);
2149 }
2150
2151 /*
2152  * Journal vop_write { a_vp, a_uio, a_ioflag, a_cred }
2153  */
2154 static
2155 int
2156 journal_write(struct vop_write_args *ap)
2157 {
2158     struct jrecord_list jreclist;
2159     struct jrecord jreccache;
2160     struct jrecord *jrec;
2161     struct mount *mp;
2162     struct uio uio_copy;
2163     struct iovec uio_one_iovec;
2164     void *save;
2165     int error;
2166
2167     /*
2168      * This is really nasty.  UIO's don't retain sufficient information to
2169      * be reusable once they've gone through the VOP chain.  The iovecs get
2170      * cleared, so we have to copy the UIO.
2171      *
2172      * XXX fix the UIO code to not destroy iov's during a scan so we can
2173      *     reuse the uio over and over again.
2174      *
2175      * XXX UNDO code needs to journal the old data prior to the write.
2176      */
2177     uio_copy = *ap->a_uio;
2178     if (uio_copy.uio_iovcnt == 1) {
2179         uio_one_iovec = ap->a_uio->uio_iov[0];
2180         uio_copy.uio_iov = &uio_one_iovec;
2181     } else {
2182         uio_copy.uio_iov = malloc(uio_copy.uio_iovcnt * sizeof(struct iovec),
2183                                     M_JOURNAL, M_WAITOK);
2184         bcopy(ap->a_uio->uio_iov, uio_copy.uio_iov, 
2185                 uio_copy.uio_iovcnt * sizeof(struct iovec));
2186     }
2187
2188     /*
2189      * Write out undo data.  Note that uio_offset is incorrect if
2190      * IO_APPEND is set, but fortunately we have no undo file data to
2191      * write out in that case.
2192      */
2193     mp = ap->a_head.a_ops->vv_mount;
2194     if (jreclist_init(mp, &jreclist, &jreccache, JTYPE_WRITE)) {
2195         if (ap->a_ioflag & IO_APPEND) {
2196             jreclist_undo_file(&jreclist, ap->a_vp, JRUNDO_SIZE|JRUNDO_MTIME, 0, 0);
2197         } else {
2198             jreclist_undo_file(&jreclist, ap->a_vp, 
2199                                JRUNDO_FILEDATA|JRUNDO_SIZE|JRUNDO_MTIME, 
2200                                uio_copy.uio_offset, uio_copy.uio_resid);
2201         }
2202     }
2203     error = vop_journal_operate_ap(&ap->a_head);
2204
2205     /*
2206      * XXX bad hack to figure out the offset for O_APPEND writes (note: 
2207      * uio field state after the VFS operation).
2208      */
2209     uio_copy.uio_offset = ap->a_uio->uio_offset - 
2210                           (uio_copy.uio_resid - ap->a_uio->uio_resid);
2211
2212     /*
2213      * Output the write data to the journal.
2214      */
2215     if (error == 0) {
2216         TAILQ_FOREACH(jrec, &jreclist, user_entry) {
2217             jrecord_write_cred(jrec, NULL, ap->a_cred);
2218             jrecord_write_vnode_ref(jrec, ap->a_vp);
2219             save = jrecord_push(jrec, JTYPE_REDO);
2220             jrecord_write_uio(jrec, JLEAF_FILEDATA, &uio_copy);
2221             jrecord_pop(jrec, save);
2222         }
2223     }
2224     jreclist_done(&jreclist, error);
2225
2226     if (uio_copy.uio_iov != &uio_one_iovec)
2227         free(uio_copy.uio_iov, M_JOURNAL);
2228     return (error);
2229 }
2230
2231 /*
2232  * Journal vop_fsync { a_vp, a_waitfor, a_td }
2233  */
2234 static
2235 int
2236 journal_fsync(struct vop_fsync_args *ap)
2237 {
2238 #if 0
2239     struct mount *mp;
2240     struct journal *jo;
2241 #endif
2242     int error;
2243
2244     error = vop_journal_operate_ap(&ap->a_head);
2245 #if 0
2246     mp = ap->a_head.a_ops->vv_mount;
2247     if (error == 0) {
2248         TAILQ_FOREACH(jo, &mp->mnt_jlist, jentry) {
2249             /* XXX synchronize pending journal records */
2250         }
2251     }
2252 #endif
2253     return (error);
2254 }
2255
2256 /*
2257  * Journal vop_putpages { a_vp, a_m, a_count, a_sync, a_rtvals, a_offset }
2258  *
2259  * note: a_count is in bytes.
2260  */
2261 static
2262 int
2263 journal_putpages(struct vop_putpages_args *ap)
2264 {
2265     struct jrecord_list jreclist;
2266     struct jrecord jreccache;
2267     struct jrecord *jrec;
2268     struct mount *mp;
2269     void *save;
2270     int error;
2271
2272     mp = ap->a_head.a_ops->vv_mount;
2273     if (jreclist_init(mp, &jreclist, &jreccache, JTYPE_PUTPAGES) && 
2274         ap->a_count > 0
2275     ) {
2276         jreclist_undo_file(&jreclist, ap->a_vp, 
2277                            JRUNDO_FILEDATA|JRUNDO_SIZE|JRUNDO_MTIME, 
2278                            ap->a_offset, btoc(ap->a_count));
2279     }
2280     error = vop_journal_operate_ap(&ap->a_head);
2281     if (error == 0 && ap->a_count > 0) {
2282         TAILQ_FOREACH(jrec, &jreclist, user_entry) {
2283             jrecord_write_vnode_ref(jrec, ap->a_vp);
2284             save = jrecord_push(jrec, JTYPE_REDO);
2285             jrecord_write_pagelist(jrec, JLEAF_FILEDATA, ap->a_m, ap->a_rtvals, 
2286                                    btoc(ap->a_count), ap->a_offset);
2287             jrecord_pop(jrec, save);
2288         }
2289     }
2290     jreclist_done(&jreclist, error);
2291     return (error);
2292 }
2293
2294 /*
2295  * Journal vop_setacl { a_vp, a_type, a_aclp, a_cred, a_td }
2296  */
2297 static
2298 int
2299 journal_setacl(struct vop_setacl_args *ap)
2300 {
2301     struct jrecord_list jreclist;
2302     struct jrecord jreccache;
2303     struct jrecord *jrec;
2304     struct mount *mp;
2305     int error;
2306
2307     mp = ap->a_head.a_ops->vv_mount;
2308     jreclist_init(mp, &jreclist, &jreccache, JTYPE_SETACL);
2309     error = vop_journal_operate_ap(&ap->a_head);
2310     if (error == 0) {
2311         TAILQ_FOREACH(jrec, &jreclist, user_entry) {
2312 #if 0
2313             if ((jo->flags & MC_JOURNAL_WANT_REVERSABLE))
2314                 jrecord_undo_file(jrec, ap->a_vp, JRUNDO_XXX, 0, 0);
2315 #endif
2316             jrecord_write_cred(jrec, ap->a_td, ap->a_cred);
2317             jrecord_write_vnode_ref(jrec, ap->a_vp);
2318 #if 0
2319             save = jrecord_push(jrec, JTYPE_REDO);
2320             /* XXX type, aclp */
2321             jrecord_pop(jrec, save);
2322 #endif
2323         }
2324     }
2325     jreclist_done(&jreclist, error);
2326     return (error);
2327 }
2328
2329 /*
2330  * Journal vop_setextattr { a_vp, a_name, a_uio, a_cred, a_td }
2331  */
2332 static
2333 int
2334 journal_setextattr(struct vop_setextattr_args *ap)
2335 {
2336     struct jrecord_list jreclist;
2337     struct jrecord jreccache;
2338     struct jrecord *jrec;
2339     struct mount *mp;
2340     void *save;
2341     int error;
2342
2343     mp = ap->a_head.a_ops->vv_mount;
2344     jreclist_init(mp, &jreclist, &jreccache, JTYPE_SETEXTATTR);
2345     error = vop_journal_operate_ap(&ap->a_head);
2346     if (error == 0) {
2347         TAILQ_FOREACH(jrec, &jreclist, user_entry) {
2348 #if 0
2349             if ((jo->flags & MC_JOURNAL_WANT_REVERSABLE))
2350                 jrecord_undo_file(jrec, ap->a_vp, JRUNDO_XXX, 0, 0);
2351 #endif
2352             jrecord_write_cred(jrec, ap->a_td, ap->a_cred);
2353             jrecord_write_vnode_ref(jrec, ap->a_vp);
2354             jrecord_leaf(jrec, JLEAF_ATTRNAME, ap->a_name, strlen(ap->a_name));
2355             save = jrecord_push(jrec, JTYPE_REDO);
2356             jrecord_write_uio(jrec, JLEAF_FILEDATA, ap->a_uio);
2357             jrecord_pop(jrec, save);
2358         }
2359     }
2360     jreclist_done(&jreclist, error);
2361     return (error);
2362 }
2363
2364 /*
2365  * Journal vop_ncreate { a_ncp, a_vpp, a_cred, a_vap }
2366  */
2367 static
2368 int
2369 journal_ncreate(struct vop_ncreate_args *ap)
2370 {
2371     struct jrecord_list jreclist;
2372     struct jrecord jreccache;
2373     struct jrecord *jrec;
2374     struct mount *mp;
2375     void *save;
2376     int error;
2377
2378     mp = ap->a_head.a_ops->vv_mount;
2379     jreclist_init(mp, &jreclist, &jreccache, JTYPE_CREATE);
2380     error = vop_journal_operate_ap(&ap->a_head);
2381     if (error == 0) {
2382         TAILQ_FOREACH(jrec, &jreclist, user_entry) {
2383             jrecord_write_cred(jrec, NULL, ap->a_cred);
2384             jrecord_write_path(jrec, JLEAF_PATH1, ap->a_ncp);
2385             if (*ap->a_vpp)
2386                 jrecord_write_vnode_ref(jrec, *ap->a_vpp);
2387             save = jrecord_push(jrec, JTYPE_REDO);
2388             jrecord_write_vattr(jrec, ap->a_vap);
2389             jrecord_pop(jrec, save);
2390         }
2391     }
2392     jreclist_done(&jreclist, error);
2393     return (error);
2394 }
2395
2396 /*
2397  * Journal vop_nmknod { a_ncp, a_vpp, a_cred, a_vap }
2398  */
2399 static
2400 int
2401 journal_nmknod(struct vop_nmknod_args *ap)
2402 {
2403     struct jrecord_list jreclist;
2404     struct jrecord jreccache;
2405     struct jrecord *jrec;
2406     struct mount *mp;
2407     void *save;
2408     int error;
2409
2410     mp = ap->a_head.a_ops->vv_mount;
2411     jreclist_init(mp, &jreclist, &jreccache, JTYPE_MKNOD);
2412     error = vop_journal_operate_ap(&ap->a_head);
2413     if (error == 0) {
2414         TAILQ_FOREACH(jrec, &jreclist, user_entry) {
2415             jrecord_write_cred(jrec, NULL, ap->a_cred);
2416             jrecord_write_path(jrec, JLEAF_PATH1, ap->a_ncp);
2417             save = jrecord_push(jrec, JTYPE_REDO);
2418             jrecord_write_vattr(jrec, ap->a_vap);
2419             jrecord_pop(jrec, save);
2420             if (*ap->a_vpp)
2421                 jrecord_write_vnode_ref(jrec, *ap->a_vpp);
2422         }
2423     }
2424     jreclist_done(&jreclist, error);
2425     return (error);
2426 }
2427
2428 /*
2429  * Journal vop_nlink { a_ncp, a_vp, a_cred }
2430  */
2431 static
2432 int
2433 journal_nlink(struct vop_nlink_args *ap)
2434 {
2435     struct jrecord_list jreclist;
2436     struct jrecord jreccache;
2437     struct jrecord *jrec;
2438     struct mount *mp;
2439     void *save;
2440     int error;
2441
2442     mp = ap->a_head.a_ops->vv_mount;
2443     jreclist_init(mp, &jreclist, &jreccache, JTYPE_LINK);
2444     error = vop_journal_operate_ap(&ap->a_head);
2445     if (error == 0) {
2446         TAILQ_FOREACH(jrec, &jreclist, user_entry) {
2447             jrecord_write_cred(jrec, NULL, ap->a_cred);
2448             jrecord_write_path(jrec, JLEAF_PATH1, ap->a_ncp);
2449             /* XXX PATH to VP and inode number */
2450             /* XXX this call may not record the correct path when
2451              * multiple paths are available */
2452             save = jrecord_push(jrec, JTYPE_REDO);
2453             jrecord_write_vnode_link(jrec, ap->a_vp, ap->a_ncp);
2454             jrecord_pop(jrec, save);
2455         }
2456     }
2457     jreclist_done(&jreclist, error);
2458     return (error);
2459 }
2460
2461 /*
2462  * Journal vop_symlink { a_ncp, a_vpp, a_cred, a_vap, a_target }
2463  */
2464 static
2465 int
2466 journal_nsymlink(struct vop_nsymlink_args *ap)
2467 {
2468     struct jrecord_list jreclist;
2469     struct jrecord jreccache;
2470     struct jrecord *jrec;
2471     struct mount *mp;
2472     void *save;
2473     int error;
2474
2475     mp = ap->a_head.a_ops->vv_mount;
2476     jreclist_init(mp, &jreclist, &jreccache, JTYPE_SYMLINK);
2477     error = vop_journal_operate_ap(&ap->a_head);
2478     if (error == 0) {
2479         TAILQ_FOREACH(jrec, &jreclist, user_entry) {
2480             jrecord_write_cred(jrec, NULL, ap->a_cred);
2481             jrecord_write_path(jrec, JLEAF_PATH1, ap->a_ncp);
2482             save = jrecord_push(jrec, JTYPE_REDO);
2483             jrecord_leaf(jrec, JLEAF_SYMLINKDATA,
2484                         ap->a_target, strlen(ap->a_target));
2485             jrecord_pop(jrec, save);
2486             if (*ap->a_vpp)
2487                 jrecord_write_vnode_ref(jrec, *ap->a_vpp);
2488         }
2489     }
2490     jreclist_done(&jreclist, error);
2491     return (error);
2492 }
2493
2494 /*
2495  * Journal vop_nwhiteout { a_ncp, a_cred, a_flags }
2496  */
2497 static
2498 int
2499 journal_nwhiteout(struct vop_nwhiteout_args *ap)
2500 {
2501     struct jrecord_list jreclist;
2502     struct jrecord jreccache;
2503     struct jrecord *jrec;
2504     struct mount *mp;
2505     int error;
2506
2507     mp = ap->a_head.a_ops->vv_mount;
2508     jreclist_init(mp, &jreclist, &jreccache, JTYPE_WHITEOUT);
2509     error = vop_journal_operate_ap(&ap->a_head);
2510     if (error == 0) {
2511         TAILQ_FOREACH(jrec, &jreclist, user_entry) {
2512             jrecord_write_cred(jrec, NULL, ap->a_cred);
2513             jrecord_write_path(jrec, JLEAF_PATH1, ap->a_ncp);
2514         }
2515     }
2516     jreclist_done(&jreclist, error);
2517     return (error);
2518 }
2519
2520 /*
2521  * Journal vop_nremove { a_ncp, a_cred }
2522  */
2523 static
2524 int
2525 journal_nremove(struct vop_nremove_args *ap)
2526 {
2527     struct jrecord_list jreclist;
2528     struct jrecord jreccache;
2529     struct jrecord *jrec;
2530     struct mount *mp;
2531     int error;
2532
2533     mp = ap->a_head.a_ops->vv_mount;
2534     if (jreclist_init(mp, &jreclist, &jreccache, JTYPE_REMOVE) &&
2535         ap->a_ncp->nc_vp
2536     ) {
2537         jreclist_undo_file(&jreclist, ap->a_ncp->nc_vp, 
2538                            JRUNDO_ALL|JRUNDO_GETVP|JRUNDO_CONDLINK, 0, -1);
2539     }
2540     error = vop_journal_operate_ap(&ap->a_head);
2541     if (error == 0) {
2542         TAILQ_FOREACH(jrec, &jreclist, user_entry) {
2543             jrecord_write_cred(jrec, NULL, ap->a_cred);
2544             jrecord_write_path(jrec, JLEAF_PATH1, ap->a_ncp);
2545         }
2546     }
2547     jreclist_done(&jreclist, error);
2548     return (error);
2549 }
2550
2551 /*
2552  * Journal vop_nmkdir { a_ncp, a_vpp, a_cred, a_vap }
2553  */
2554 static
2555 int
2556 journal_nmkdir(struct vop_nmkdir_args *ap)
2557 {
2558     struct jrecord_list jreclist;
2559     struct jrecord jreccache;
2560     struct jrecord *jrec;
2561     struct mount *mp;
2562     int error;
2563
2564     mp = ap->a_head.a_ops->vv_mount;
2565     jreclist_init(mp, &jreclist, &jreccache, JTYPE_MKDIR);
2566     error = vop_journal_operate_ap(&ap->a_head);
2567     if (error == 0) {
2568         TAILQ_FOREACH(jrec, &jreclist, user_entry) {
2569 #if 0
2570             if (jo->flags & MC_JOURNAL_WANT_AUDIT) {
2571                 jrecord_write_audit(jrec);
2572             }
2573 #endif
2574             jrecord_write_path(jrec, JLEAF_PATH1, ap->a_ncp);
2575             jrecord_write_cred(jrec, NULL, ap->a_cred);
2576             jrecord_write_vattr(jrec, ap->a_vap);
2577             jrecord_write_path(jrec, JLEAF_PATH1, ap->a_ncp);
2578             if (*ap->a_vpp)
2579                 jrecord_write_vnode_ref(jrec, *ap->a_vpp);
2580         }
2581     }
2582     jreclist_done(&jreclist, error);
2583     return (error);
2584 }
2585
2586 /*
2587  * Journal vop_nrmdir { a_ncp, a_cred }
2588  */
2589 static
2590 int
2591 journal_nrmdir(struct vop_nrmdir_args *ap)
2592 {
2593     struct jrecord_list jreclist;
2594     struct jrecord jreccache;
2595     struct jrecord *jrec;
2596     struct mount *mp;
2597     int error;
2598
2599     mp = ap->a_head.a_ops->vv_mount;
2600     if (jreclist_init(mp, &jreclist, &jreccache, JTYPE_RMDIR)) {
2601         jreclist_undo_file(&jreclist, ap->a_ncp->nc_vp,
2602                            JRUNDO_VATTR|JRUNDO_GETVP, 0, 0);
2603     }
2604     error = vop_journal_operate_ap(&ap->a_head);
2605     if (error == 0) {
2606         TAILQ_FOREACH(jrec, &jreclist, user_entry) {
2607             jrecord_write_cred(jrec, NULL, ap->a_cred);
2608             jrecord_write_path(jrec, JLEAF_PATH1, ap->a_ncp);
2609         }
2610     }
2611     jreclist_done(&jreclist, error);
2612     return (error);
2613 }
2614
2615 /*
2616  * Journal vop_nrename { a_fncp, a_tncp, a_cred }
2617  */
2618 static
2619 int
2620 journal_nrename(struct vop_nrename_args *ap)
2621 {
2622     struct jrecord_list jreclist;
2623     struct jrecord jreccache;
2624     struct jrecord *jrec;
2625     struct mount *mp;
2626     int error;
2627
2628     mp = ap->a_head.a_ops->vv_mount;
2629     if (jreclist_init(mp, &jreclist, &jreccache, JTYPE_RENAME) &&
2630         ap->a_tncp->nc_vp
2631     ) {
2632         jreclist_undo_file(&jreclist, ap->a_tncp->nc_vp, 
2633                            JRUNDO_ALL|JRUNDO_GETVP|JRUNDO_CONDLINK, 0, -1);
2634     }
2635     error = vop_journal_operate_ap(&ap->a_head);
2636     if (error == 0) {
2637         TAILQ_FOREACH(jrec, &jreclist, user_entry) {
2638             jrecord_write_cred(jrec, NULL, ap->a_cred);
2639             jrecord_write_path(jrec, JLEAF_PATH1, ap->a_fncp);
2640             jrecord_write_path(jrec, JLEAF_PATH2, ap->a_tncp);
2641         }
2642     }
2643     jreclist_done(&jreclist, error);
2644     return (error);
2645 }
2646