xref: /dragonfly/sys/kern/vfs_jops.c (revision df0b0ead)
16ddb7618SMatthew Dillon /*
2f56dc967SMatthew Dillon  * Copyright (c) 2004-2006 The DragonFly Project.  All rights reserved.
36ddb7618SMatthew Dillon  *
46ddb7618SMatthew Dillon  * This code is derived from software contributed to The DragonFly Project
56ddb7618SMatthew Dillon  * by Matthew Dillon <dillon@backplane.com>
66ddb7618SMatthew Dillon  *
76ddb7618SMatthew Dillon  * Redistribution and use in source and binary forms, with or without
86ddb7618SMatthew Dillon  * modification, are permitted provided that the following conditions
96ddb7618SMatthew Dillon  * are met:
106ddb7618SMatthew Dillon  *
116ddb7618SMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
126ddb7618SMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
136ddb7618SMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
146ddb7618SMatthew Dillon  *    notice, this list of conditions and the following disclaimer in
156ddb7618SMatthew Dillon  *    the documentation and/or other materials provided with the
166ddb7618SMatthew Dillon  *    distribution.
176ddb7618SMatthew Dillon  * 3. Neither the name of The DragonFly Project nor the names of its
186ddb7618SMatthew Dillon  *    contributors may be used to endorse or promote products derived
196ddb7618SMatthew Dillon  *    from this software without specific, prior written permission.
206ddb7618SMatthew Dillon  *
216ddb7618SMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
226ddb7618SMatthew Dillon  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
236ddb7618SMatthew Dillon  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
246ddb7618SMatthew Dillon  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
256ddb7618SMatthew Dillon  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
266ddb7618SMatthew Dillon  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
276ddb7618SMatthew Dillon  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
286ddb7618SMatthew Dillon  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
296ddb7618SMatthew Dillon  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
306ddb7618SMatthew Dillon  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
316ddb7618SMatthew Dillon  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
326ddb7618SMatthew Dillon  * SUCH DAMAGE.
332281065eSMatthew Dillon  */
342281065eSMatthew Dillon /*
352281065eSMatthew Dillon  * Each mount point may have zero or more independantly configured journals
362281065eSMatthew Dillon  * attached to it.  Each journal is represented by a memory FIFO and worker
372281065eSMatthew Dillon  * thread.  Journal events are streamed through the FIFO to the thread,
382281065eSMatthew Dillon  * batched up (typically on one-second intervals), and written out by the
392281065eSMatthew Dillon  * thread.
402281065eSMatthew Dillon  *
412281065eSMatthew Dillon  * Journal vnode ops are executed instead of mnt_vn_norm_ops when one or
422281065eSMatthew Dillon  * more journals have been installed on a mount point.  It becomes the
432281065eSMatthew Dillon  * responsibility of the journal op to call the underlying normal op as
442281065eSMatthew Dillon  * appropriate.
456ddb7618SMatthew Dillon  */
466ddb7618SMatthew Dillon #include <sys/param.h>
476ddb7618SMatthew Dillon #include <sys/systm.h>
486ddb7618SMatthew Dillon #include <sys/buf.h>
496ddb7618SMatthew Dillon #include <sys/conf.h>
506ddb7618SMatthew Dillon #include <sys/kernel.h>
5182eaef15SMatthew Dillon #include <sys/queue.h>
526ddb7618SMatthew Dillon #include <sys/lock.h>
536ddb7618SMatthew Dillon #include <sys/malloc.h>
546ddb7618SMatthew Dillon #include <sys/mount.h>
556ddb7618SMatthew Dillon #include <sys/unistd.h>
566ddb7618SMatthew Dillon #include <sys/vnode.h>
576ddb7618SMatthew Dillon #include <sys/poll.h>
582281065eSMatthew Dillon #include <sys/mountctl.h>
59b2f7ec6cSMatthew Dillon #include <sys/journal.h>
602281065eSMatthew Dillon #include <sys/file.h>
61b2f7ec6cSMatthew Dillon #include <sys/proc.h>
62500b6a22SMatthew Dillon #include <sys/socket.h>
63500b6a22SMatthew Dillon #include <sys/socketvar.h>
646ddb7618SMatthew Dillon 
656ddb7618SMatthew Dillon #include <machine/limits.h>
666ddb7618SMatthew Dillon 
676ddb7618SMatthew Dillon #include <vm/vm.h>
686ddb7618SMatthew Dillon #include <vm/vm_object.h>
696ddb7618SMatthew Dillon #include <vm/vm_page.h>
706ddb7618SMatthew Dillon #include <vm/vm_pager.h>
716ddb7618SMatthew Dillon #include <vm/vnode_pager.h>
726ddb7618SMatthew Dillon 
732281065eSMatthew Dillon #include <sys/file2.h>
742281065eSMatthew Dillon 
752281065eSMatthew Dillon static int journal_attach(struct mount *mp);
762281065eSMatthew Dillon static void journal_detach(struct mount *mp);
772281065eSMatthew Dillon static int journal_install_vfs_journal(struct mount *mp, struct file *fp,
782281065eSMatthew Dillon 			    const struct mountctl_install_journal *info);
79500b6a22SMatthew Dillon static int journal_restart_vfs_journal(struct mount *mp, struct file *fp,
80500b6a22SMatthew Dillon 			    const struct mountctl_restart_journal *info);
812281065eSMatthew Dillon static int journal_remove_vfs_journal(struct mount *mp,
822281065eSMatthew Dillon 			    const struct mountctl_remove_journal *info);
83500b6a22SMatthew Dillon static int journal_restart(struct mount *mp, struct file *fp,
84500b6a22SMatthew Dillon 			    struct journal *jo, int flags);
85432b8263SMatthew Dillon static int journal_destroy(struct mount *mp, struct journal *jo, int flags);
862281065eSMatthew Dillon static int journal_resync_vfs_journal(struct mount *mp, const void *ctl);
8739b13188SMatthew Dillon static int journal_status_vfs_journal(struct mount *mp,
8839b13188SMatthew Dillon 		       const struct mountctl_status_journal *info,
8939b13188SMatthew Dillon 		       struct mountctl_journal_ret_status *rstat,
9039b13188SMatthew Dillon 		       int buflen, int *res);
9182eaef15SMatthew Dillon 
9226e603edSMatthew Dillon static void jrecord_undo_file(struct jrecord *jrec, struct vnode *vp,
9326e603edSMatthew Dillon 			     int jrflags, off_t off, off_t bytes);
9482eaef15SMatthew Dillon 
95558b8e00SMatthew Dillon static int journal_setattr(struct vop_setattr_args *ap);
96558b8e00SMatthew Dillon static int journal_write(struct vop_write_args *ap);
97558b8e00SMatthew Dillon static int journal_fsync(struct vop_fsync_args *ap);
98558b8e00SMatthew Dillon static int journal_putpages(struct vop_putpages_args *ap);
99558b8e00SMatthew Dillon static int journal_setacl(struct vop_setacl_args *ap);
100558b8e00SMatthew Dillon static int journal_setextattr(struct vop_setextattr_args *ap);
101558b8e00SMatthew Dillon static int journal_ncreate(struct vop_ncreate_args *ap);
102558b8e00SMatthew Dillon static int journal_nmknod(struct vop_nmknod_args *ap);
103558b8e00SMatthew Dillon static int journal_nlink(struct vop_nlink_args *ap);
104558b8e00SMatthew Dillon static int journal_nsymlink(struct vop_nsymlink_args *ap);
105558b8e00SMatthew Dillon static int journal_nwhiteout(struct vop_nwhiteout_args *ap);
106558b8e00SMatthew Dillon static int journal_nremove(struct vop_nremove_args *ap);
1072281065eSMatthew Dillon static int journal_nmkdir(struct vop_nmkdir_args *ap);
108558b8e00SMatthew Dillon static int journal_nrmdir(struct vop_nrmdir_args *ap);
109558b8e00SMatthew Dillon static int journal_nrename(struct vop_nrename_args *ap);
1102281065eSMatthew Dillon 
11126e603edSMatthew Dillon #define JRUNDO_SIZE	0x00000001
11226e603edSMatthew Dillon #define JRUNDO_UID	0x00000002
11326e603edSMatthew Dillon #define JRUNDO_GID	0x00000004
11426e603edSMatthew Dillon #define JRUNDO_FSID	0x00000008
11526e603edSMatthew Dillon #define JRUNDO_MODES	0x00000010
11626e603edSMatthew Dillon #define JRUNDO_INUM	0x00000020
11726e603edSMatthew Dillon #define JRUNDO_ATIME	0x00000040
11826e603edSMatthew Dillon #define JRUNDO_MTIME	0x00000080
11926e603edSMatthew Dillon #define JRUNDO_CTIME	0x00000100
12026e603edSMatthew Dillon #define JRUNDO_GEN	0x00000200
12126e603edSMatthew Dillon #define JRUNDO_FLAGS	0x00000400
12226e603edSMatthew Dillon #define JRUNDO_UDEV	0x00000800
123aa159335SMatthew Dillon #define JRUNDO_NLINK	0x00001000
12426e603edSMatthew Dillon #define JRUNDO_FILEDATA	0x00010000
12526e603edSMatthew Dillon #define JRUNDO_GETVP	0x00020000
12626e603edSMatthew Dillon #define JRUNDO_CONDLINK	0x00040000	/* write file data if link count 1 */
12726e603edSMatthew Dillon #define JRUNDO_VATTR	(JRUNDO_SIZE|JRUNDO_UID|JRUNDO_GID|JRUNDO_FSID|\
12826e603edSMatthew Dillon 			 JRUNDO_MODES|JRUNDO_INUM|JRUNDO_ATIME|JRUNDO_MTIME|\
129aa159335SMatthew Dillon 			 JRUNDO_CTIME|JRUNDO_GEN|JRUNDO_FLAGS|JRUNDO_UDEV|\
130aa159335SMatthew Dillon 			 JRUNDO_NLINK)
13126e603edSMatthew Dillon #define JRUNDO_ALL	(JRUNDO_VATTR|JRUNDO_FILEDATA)
13226e603edSMatthew Dillon 
13366a1ddf5SMatthew Dillon static struct vop_ops journal_vnode_vops = {
13466a1ddf5SMatthew Dillon     .vop_default =	vop_journal_operate_ap,
13566a1ddf5SMatthew Dillon     .vop_mountctl =	journal_mountctl,
13666a1ddf5SMatthew Dillon     .vop_setattr =	journal_setattr,
13766a1ddf5SMatthew Dillon     .vop_write =	journal_write,
13866a1ddf5SMatthew Dillon     .vop_fsync =	journal_fsync,
13966a1ddf5SMatthew Dillon     .vop_putpages =	journal_putpages,
14066a1ddf5SMatthew Dillon     .vop_setacl =	journal_setacl,
14166a1ddf5SMatthew Dillon     .vop_setextattr =	journal_setextattr,
14266a1ddf5SMatthew Dillon     .vop_ncreate =	journal_ncreate,
14366a1ddf5SMatthew Dillon     .vop_nmknod =	journal_nmknod,
14466a1ddf5SMatthew Dillon     .vop_nlink =	journal_nlink,
14566a1ddf5SMatthew Dillon     .vop_nsymlink =	journal_nsymlink,
14666a1ddf5SMatthew Dillon     .vop_nwhiteout =	journal_nwhiteout,
14766a1ddf5SMatthew Dillon     .vop_nremove =	journal_nremove,
14866a1ddf5SMatthew Dillon     .vop_nmkdir =	journal_nmkdir,
14966a1ddf5SMatthew Dillon     .vop_nrmdir =	journal_nrmdir,
15066a1ddf5SMatthew Dillon     .vop_nrename =	journal_nrename
1516ddb7618SMatthew Dillon };
1526ddb7618SMatthew Dillon 
1536ddb7618SMatthew Dillon int
journal_mountctl(struct vop_mountctl_args * ap)1542281065eSMatthew Dillon journal_mountctl(struct vop_mountctl_args *ap)
1552281065eSMatthew Dillon {
1562281065eSMatthew Dillon     struct mount *mp;
1572281065eSMatthew Dillon     int error = 0;
1582281065eSMatthew Dillon 
15966a1ddf5SMatthew Dillon     mp = ap->a_head.a_ops->head.vv_mount;
1602281065eSMatthew Dillon     KKASSERT(mp);
1612281065eSMatthew Dillon 
1622281065eSMatthew Dillon     if (mp->mnt_vn_journal_ops == NULL) {
1632281065eSMatthew Dillon 	switch(ap->a_op) {
1642281065eSMatthew Dillon 	case MOUNTCTL_INSTALL_VFS_JOURNAL:
1652281065eSMatthew Dillon 	    error = journal_attach(mp);
1662281065eSMatthew Dillon 	    if (error == 0 && ap->a_ctllen != sizeof(struct mountctl_install_journal))
1672281065eSMatthew Dillon 		error = EINVAL;
1682281065eSMatthew Dillon 	    if (error == 0 && ap->a_fp == NULL)
1692281065eSMatthew Dillon 		error = EBADF;
1702281065eSMatthew Dillon 	    if (error == 0)
1712281065eSMatthew Dillon 		error = journal_install_vfs_journal(mp, ap->a_fp, ap->a_ctl);
1722281065eSMatthew Dillon 	    if (TAILQ_EMPTY(&mp->mnt_jlist))
1732281065eSMatthew Dillon 		journal_detach(mp);
1742281065eSMatthew Dillon 	    break;
175500b6a22SMatthew Dillon 	case MOUNTCTL_RESTART_VFS_JOURNAL:
1762281065eSMatthew Dillon 	case MOUNTCTL_REMOVE_VFS_JOURNAL:
1772281065eSMatthew Dillon 	case MOUNTCTL_RESYNC_VFS_JOURNAL:
17839b13188SMatthew Dillon 	case MOUNTCTL_STATUS_VFS_JOURNAL:
17939b13188SMatthew Dillon 	    error = ENOENT;
1802281065eSMatthew Dillon 	    break;
1812281065eSMatthew Dillon 	default:
1822281065eSMatthew Dillon 	    error = EOPNOTSUPP;
1832281065eSMatthew Dillon 	    break;
1842281065eSMatthew Dillon 	}
1852281065eSMatthew Dillon     } else {
1862281065eSMatthew Dillon 	switch(ap->a_op) {
1872281065eSMatthew Dillon 	case MOUNTCTL_INSTALL_VFS_JOURNAL:
1882281065eSMatthew Dillon 	    if (ap->a_ctllen != sizeof(struct mountctl_install_journal))
1892281065eSMatthew Dillon 		error = EINVAL;
1902281065eSMatthew Dillon 	    if (error == 0 && ap->a_fp == NULL)
1912281065eSMatthew Dillon 		error = EBADF;
1922281065eSMatthew Dillon 	    if (error == 0)
1932281065eSMatthew Dillon 		error = journal_install_vfs_journal(mp, ap->a_fp, ap->a_ctl);
1942281065eSMatthew Dillon 	    break;
195500b6a22SMatthew Dillon 	case MOUNTCTL_RESTART_VFS_JOURNAL:
196500b6a22SMatthew Dillon 	    if (ap->a_ctllen != sizeof(struct mountctl_restart_journal))
197500b6a22SMatthew Dillon 		error = EINVAL;
198500b6a22SMatthew Dillon 	    if (error == 0 && ap->a_fp == NULL)
199500b6a22SMatthew Dillon 		error = EBADF;
200500b6a22SMatthew Dillon 	    if (error == 0)
201500b6a22SMatthew Dillon 		error = journal_restart_vfs_journal(mp, ap->a_fp, ap->a_ctl);
202500b6a22SMatthew Dillon 	    break;
2032281065eSMatthew Dillon 	case MOUNTCTL_REMOVE_VFS_JOURNAL:
2042281065eSMatthew Dillon 	    if (ap->a_ctllen != sizeof(struct mountctl_remove_journal))
2052281065eSMatthew Dillon 		error = EINVAL;
2062281065eSMatthew Dillon 	    if (error == 0)
2072281065eSMatthew Dillon 		error = journal_remove_vfs_journal(mp, ap->a_ctl);
2082281065eSMatthew Dillon 	    if (TAILQ_EMPTY(&mp->mnt_jlist))
2092281065eSMatthew Dillon 		journal_detach(mp);
2102281065eSMatthew Dillon 	    break;
2112281065eSMatthew Dillon 	case MOUNTCTL_RESYNC_VFS_JOURNAL:
2122281065eSMatthew Dillon 	    if (ap->a_ctllen != 0)
2132281065eSMatthew Dillon 		error = EINVAL;
2142281065eSMatthew Dillon 	    error = journal_resync_vfs_journal(mp, ap->a_ctl);
2152281065eSMatthew Dillon 	    break;
21639b13188SMatthew Dillon 	case MOUNTCTL_STATUS_VFS_JOURNAL:
21739b13188SMatthew Dillon 	    if (ap->a_ctllen != sizeof(struct mountctl_status_journal))
21839b13188SMatthew Dillon 		error = EINVAL;
21939b13188SMatthew Dillon 	    if (error == 0) {
22039b13188SMatthew Dillon 		error = journal_status_vfs_journal(mp, ap->a_ctl,
22139b13188SMatthew Dillon 					ap->a_buf, ap->a_buflen, ap->a_res);
22239b13188SMatthew Dillon 	    }
22339b13188SMatthew Dillon 	    break;
2242281065eSMatthew Dillon 	default:
2252281065eSMatthew Dillon 	    error = EOPNOTSUPP;
2262281065eSMatthew Dillon 	    break;
2272281065eSMatthew Dillon 	}
2282281065eSMatthew Dillon     }
2292281065eSMatthew Dillon     return (error);
2302281065eSMatthew Dillon }
2312281065eSMatthew Dillon 
2322281065eSMatthew Dillon /*
2332281065eSMatthew Dillon  * High level mount point setup.  When a
2342281065eSMatthew Dillon  */
2352281065eSMatthew Dillon static int
journal_attach(struct mount * mp)2366ddb7618SMatthew Dillon journal_attach(struct mount *mp)
2376ddb7618SMatthew Dillon {
238797e4fe9SMatthew Dillon     KKASSERT(mp->mnt_jbitmap == NULL);
23966a1ddf5SMatthew Dillon     vfs_add_vnodeops(mp, &journal_vnode_vops, &mp->mnt_vn_journal_ops);
240efda3bd0SMatthew Dillon     mp->mnt_jbitmap = kmalloc(JREC_STREAMID_JMAX/8, M_JOURNAL, M_WAITOK|M_ZERO);
241797e4fe9SMatthew Dillon     mp->mnt_streamid = JREC_STREAMID_JMIN;
2426ddb7618SMatthew Dillon     return(0);
2436ddb7618SMatthew Dillon }
2446ddb7618SMatthew Dillon 
2452281065eSMatthew Dillon static void
journal_detach(struct mount * mp)2466ddb7618SMatthew Dillon journal_detach(struct mount *mp)
2476ddb7618SMatthew Dillon {
248797e4fe9SMatthew Dillon     KKASSERT(mp->mnt_jbitmap != NULL);
2496ddb7618SMatthew Dillon     if (mp->mnt_vn_journal_ops)
25066a1ddf5SMatthew Dillon 	vfs_rm_vnodeops(mp, &journal_vnode_vops, &mp->mnt_vn_journal_ops);
251efda3bd0SMatthew Dillon     kfree(mp->mnt_jbitmap, M_JOURNAL);
252797e4fe9SMatthew Dillon     mp->mnt_jbitmap = NULL;
2536ddb7618SMatthew Dillon }
2546ddb7618SMatthew Dillon 
2552281065eSMatthew Dillon /*
25682eaef15SMatthew Dillon  * Install a journal on a mount point.  Each journal has an associated worker
25782eaef15SMatthew Dillon  * thread which is responsible for buffering and spooling the data to the
25882eaef15SMatthew Dillon  * target.  A mount point may have multiple journals attached to it.  An
25982eaef15SMatthew Dillon  * initial start record is generated when the journal is associated.
2602281065eSMatthew Dillon  */
2612281065eSMatthew Dillon static int
journal_install_vfs_journal(struct mount * mp,struct file * fp,const struct mountctl_install_journal * info)2622281065eSMatthew Dillon journal_install_vfs_journal(struct mount *mp, struct file *fp,
2632281065eSMatthew Dillon 			    const struct mountctl_install_journal *info)
2642281065eSMatthew Dillon {
2652281065eSMatthew Dillon     struct journal *jo;
26682eaef15SMatthew Dillon     struct jrecord jrec;
2672281065eSMatthew Dillon     int error = 0;
2682281065eSMatthew Dillon     int size;
2692281065eSMatthew Dillon 
270efda3bd0SMatthew Dillon     jo = kmalloc(sizeof(struct journal), M_JOURNAL, M_WAITOK|M_ZERO);
2712281065eSMatthew Dillon     bcopy(info->id, jo->id, sizeof(jo->id));
272432b8263SMatthew Dillon     jo->flags = info->flags & ~(MC_JOURNAL_WACTIVE | MC_JOURNAL_RACTIVE |
273432b8263SMatthew Dillon 				MC_JOURNAL_STOP_REQ);
2742281065eSMatthew Dillon 
2752281065eSMatthew Dillon     /*
2762281065eSMatthew Dillon      * Memory FIFO size, round to nearest power of 2
2772281065eSMatthew Dillon      */
27882eaef15SMatthew Dillon     if (info->membufsize) {
2792281065eSMatthew Dillon 	if (info->membufsize < 65536)
2802281065eSMatthew Dillon 	    size = 65536;
2812281065eSMatthew Dillon 	else if (info->membufsize > 128 * 1024 * 1024)
2822281065eSMatthew Dillon 	    size = 128 * 1024 * 1024;
2832281065eSMatthew Dillon 	else
2842281065eSMatthew Dillon 	    size = (int)info->membufsize;
2852281065eSMatthew Dillon     } else {
2862281065eSMatthew Dillon 	size = 1024 * 1024;
2872281065eSMatthew Dillon     }
2882281065eSMatthew Dillon     jo->fifo.size = 1;
2892281065eSMatthew Dillon     while (jo->fifo.size < size)
2902281065eSMatthew Dillon 	jo->fifo.size <<= 1;
2912281065eSMatthew Dillon 
2922281065eSMatthew Dillon     /*
2932281065eSMatthew Dillon      * Other parameters.  If not specified the starting transaction id
2942281065eSMatthew Dillon      * will be the current date.
2952281065eSMatthew Dillon      */
29682eaef15SMatthew Dillon     if (info->transid) {
2972281065eSMatthew Dillon 	jo->transid = info->transid;
2982281065eSMatthew Dillon     } else {
2992281065eSMatthew Dillon 	struct timespec ts;
3002281065eSMatthew Dillon 	getnanotime(&ts);
3012281065eSMatthew Dillon 	jo->transid = ((int64_t)ts.tv_sec << 30) | ts.tv_nsec;
3022281065eSMatthew Dillon     }
3032281065eSMatthew Dillon 
3042281065eSMatthew Dillon     jo->fp = fp;
3052281065eSMatthew Dillon 
3062281065eSMatthew Dillon     /*
3072281065eSMatthew Dillon      * Allocate the memory FIFO
3082281065eSMatthew Dillon      */
3092281065eSMatthew Dillon     jo->fifo.mask = jo->fifo.size - 1;
310efda3bd0SMatthew Dillon     jo->fifo.membase = kmalloc(jo->fifo.size, M_JFIFO, M_WAITOK|M_ZERO|M_NULLOK);
3112281065eSMatthew Dillon     if (jo->fifo.membase == NULL)
3122281065eSMatthew Dillon 	error = ENOMEM;
3132281065eSMatthew Dillon 
31482eaef15SMatthew Dillon     /*
3153119bac5SMatthew Dillon      * Create the worker threads and generate the association record.
31682eaef15SMatthew Dillon      */
3172281065eSMatthew Dillon     if (error) {
318efda3bd0SMatthew Dillon 	kfree(jo, M_JOURNAL);
3192281065eSMatthew Dillon     } else {
3202281065eSMatthew Dillon 	fhold(fp);
321500b6a22SMatthew Dillon 	journal_create_threads(jo);
32282eaef15SMatthew Dillon 	jrecord_init(jo, &jrec, JREC_STREAMID_DISCONT);
32382eaef15SMatthew Dillon 	jrecord_write(&jrec, JTYPE_ASSOCIATE, 0);
32482eaef15SMatthew Dillon 	jrecord_done(&jrec, 0);
3252281065eSMatthew Dillon 	TAILQ_INSERT_TAIL(&mp->mnt_jlist, jo, jentry);
3262281065eSMatthew Dillon     }
3272281065eSMatthew Dillon     return(error);
3282281065eSMatthew Dillon }
3292281065eSMatthew Dillon 
33082eaef15SMatthew Dillon /*
331500b6a22SMatthew Dillon  * Restart a journal with a new descriptor.   The existing reader and writer
332500b6a22SMatthew Dillon  * threads are terminated and a new descriptor is associated with the
333500b6a22SMatthew Dillon  * journal.  The FIFO rindex is reset to xindex and the threads are then
334500b6a22SMatthew Dillon  * restarted.
335500b6a22SMatthew Dillon  */
336500b6a22SMatthew Dillon static int
journal_restart_vfs_journal(struct mount * mp,struct file * fp,const struct mountctl_restart_journal * info)337500b6a22SMatthew Dillon journal_restart_vfs_journal(struct mount *mp, struct file *fp,
338500b6a22SMatthew Dillon 			   const struct mountctl_restart_journal *info)
339500b6a22SMatthew Dillon {
340500b6a22SMatthew Dillon     struct journal *jo;
341500b6a22SMatthew Dillon     int error;
342500b6a22SMatthew Dillon 
343500b6a22SMatthew Dillon     TAILQ_FOREACH(jo, &mp->mnt_jlist, jentry) {
344500b6a22SMatthew Dillon 	if (bcmp(jo->id, info->id, sizeof(jo->id)) == 0)
345500b6a22SMatthew Dillon 	    break;
346500b6a22SMatthew Dillon     }
347500b6a22SMatthew Dillon     if (jo)
348500b6a22SMatthew Dillon 	error = journal_restart(mp, fp, jo, info->flags);
349500b6a22SMatthew Dillon     else
350500b6a22SMatthew Dillon 	error = EINVAL;
351500b6a22SMatthew Dillon     return (error);
352500b6a22SMatthew Dillon }
353500b6a22SMatthew Dillon 
354500b6a22SMatthew Dillon static int
journal_restart(struct mount * mp,struct file * fp,struct journal * jo,int flags)355500b6a22SMatthew Dillon journal_restart(struct mount *mp, struct file *fp,
356500b6a22SMatthew Dillon 		struct journal *jo, int flags)
357500b6a22SMatthew Dillon {
358500b6a22SMatthew Dillon     /*
359500b6a22SMatthew Dillon      * XXX lock the jo
360500b6a22SMatthew Dillon      */
361500b6a22SMatthew Dillon 
362500b6a22SMatthew Dillon #if 0
363500b6a22SMatthew Dillon     /*
364500b6a22SMatthew Dillon      * Record the fact that we are doing a restart in the journal.
365500b6a22SMatthew Dillon      * XXX it isn't safe to do this if the journal is being restarted
366500b6a22SMatthew Dillon      * because it was locked up and the writer thread has already exited.
367500b6a22SMatthew Dillon      */
368500b6a22SMatthew Dillon     jrecord_init(jo, &jrec, JREC_STREAMID_RESTART);
369500b6a22SMatthew Dillon     jrecord_write(&jrec, JTYPE_DISASSOCIATE, 0);
370500b6a22SMatthew Dillon     jrecord_done(&jrec, 0);
371500b6a22SMatthew Dillon #endif
372500b6a22SMatthew Dillon 
373500b6a22SMatthew Dillon     /*
374500b6a22SMatthew Dillon      * Stop the reader and writer threads and clean up the current
375500b6a22SMatthew Dillon      * descriptor.
376500b6a22SMatthew Dillon      */
3776ea70f76SSascha Wildner     kprintf("RESTART WITH FP %p KILLING %p\n", fp, jo->fp);
378500b6a22SMatthew Dillon     journal_destroy_threads(jo, flags);
379500b6a22SMatthew Dillon 
380500b6a22SMatthew Dillon     if (jo->fp)
3819f87144fSMatthew Dillon 	fdrop(jo->fp);
382500b6a22SMatthew Dillon 
383500b6a22SMatthew Dillon     /*
384500b6a22SMatthew Dillon      * Associate the new descriptor, reset the FIFO index, and recreate
385500b6a22SMatthew Dillon      * the threads.
386500b6a22SMatthew Dillon      */
387500b6a22SMatthew Dillon     fhold(fp);
388500b6a22SMatthew Dillon     jo->fp = fp;
389500b6a22SMatthew Dillon     jo->fifo.rindex = jo->fifo.xindex;
390500b6a22SMatthew Dillon     journal_create_threads(jo);
391500b6a22SMatthew Dillon 
392500b6a22SMatthew Dillon     return(0);
393500b6a22SMatthew Dillon }
394500b6a22SMatthew Dillon 
395500b6a22SMatthew Dillon /*
39682eaef15SMatthew Dillon  * Disassociate a journal from a mount point and terminate its worker thread.
39782eaef15SMatthew Dillon  * A final termination record is written out before the file pointer is
39882eaef15SMatthew Dillon  * dropped.
39982eaef15SMatthew Dillon  */
4002281065eSMatthew Dillon static int
journal_remove_vfs_journal(struct mount * mp,const struct mountctl_remove_journal * info)40182eaef15SMatthew Dillon journal_remove_vfs_journal(struct mount *mp,
40282eaef15SMatthew Dillon 			   const struct mountctl_remove_journal *info)
4032281065eSMatthew Dillon {
4042281065eSMatthew Dillon     struct journal *jo;
4052281065eSMatthew Dillon     int error;
4062281065eSMatthew Dillon 
4072281065eSMatthew Dillon     TAILQ_FOREACH(jo, &mp->mnt_jlist, jentry) {
4082281065eSMatthew Dillon 	if (bcmp(jo->id, info->id, sizeof(jo->id)) == 0)
4092281065eSMatthew Dillon 	    break;
4102281065eSMatthew Dillon     }
411432b8263SMatthew Dillon     if (jo)
412432b8263SMatthew Dillon 	error = journal_destroy(mp, jo, info->flags);
413432b8263SMatthew Dillon     else
414432b8263SMatthew Dillon 	error = EINVAL;
415432b8263SMatthew Dillon     return (error);
416432b8263SMatthew Dillon }
417432b8263SMatthew Dillon 
418432b8263SMatthew Dillon /*
419432b8263SMatthew Dillon  * Remove all journals associated with a mount point.  Usually called
420432b8263SMatthew Dillon  * by the umount code.
421432b8263SMatthew Dillon  */
422432b8263SMatthew Dillon void
journal_remove_all_journals(struct mount * mp,int flags)423432b8263SMatthew Dillon journal_remove_all_journals(struct mount *mp, int flags)
424432b8263SMatthew Dillon {
425432b8263SMatthew Dillon     struct journal *jo;
426432b8263SMatthew Dillon 
427432b8263SMatthew Dillon     while ((jo = TAILQ_FIRST(&mp->mnt_jlist)) != NULL) {
428432b8263SMatthew Dillon 	journal_destroy(mp, jo, flags);
429432b8263SMatthew Dillon     }
430432b8263SMatthew Dillon }
431432b8263SMatthew Dillon 
432432b8263SMatthew Dillon static int
journal_destroy(struct mount * mp,struct journal * jo,int flags)433432b8263SMatthew Dillon journal_destroy(struct mount *mp, struct journal *jo, int flags)
434432b8263SMatthew Dillon {
435432b8263SMatthew Dillon     struct jrecord jrec;
436432b8263SMatthew Dillon 
4372281065eSMatthew Dillon     TAILQ_REMOVE(&mp->mnt_jlist, jo, jentry);
43882eaef15SMatthew Dillon 
43982eaef15SMatthew Dillon     jrecord_init(jo, &jrec, JREC_STREAMID_DISCONT);
44082eaef15SMatthew Dillon     jrecord_write(&jrec, JTYPE_DISASSOCIATE, 0);
44182eaef15SMatthew Dillon     jrecord_done(&jrec, 0);
44282eaef15SMatthew Dillon 
443500b6a22SMatthew Dillon     journal_destroy_threads(jo, flags);
444500b6a22SMatthew Dillon 
4452281065eSMatthew Dillon     if (jo->fp)
4469f87144fSMatthew Dillon 	fdrop(jo->fp);
4472281065eSMatthew Dillon     if (jo->fifo.membase)
448efda3bd0SMatthew Dillon 	kfree(jo->fifo.membase, M_JFIFO);
449efda3bd0SMatthew Dillon     kfree(jo, M_JOURNAL);
450797e4fe9SMatthew Dillon 
451432b8263SMatthew Dillon     return(0);
4522281065eSMatthew Dillon }
4532281065eSMatthew Dillon 
4542281065eSMatthew Dillon static int
journal_resync_vfs_journal(struct mount * mp,const void * ctl)4552281065eSMatthew Dillon journal_resync_vfs_journal(struct mount *mp, const void *ctl)
4562281065eSMatthew Dillon {
4572281065eSMatthew Dillon     return(EINVAL);
4582281065eSMatthew Dillon }
4592281065eSMatthew Dillon 
46039b13188SMatthew Dillon static int
journal_status_vfs_journal(struct mount * mp,const struct mountctl_status_journal * info,struct mountctl_journal_ret_status * rstat,int buflen,int * res)46139b13188SMatthew Dillon journal_status_vfs_journal(struct mount *mp,
46239b13188SMatthew Dillon 		       const struct mountctl_status_journal *info,
46339b13188SMatthew Dillon 		       struct mountctl_journal_ret_status *rstat,
46439b13188SMatthew Dillon 		       int buflen, int *res)
46539b13188SMatthew Dillon {
46639b13188SMatthew Dillon     struct journal *jo;
46739b13188SMatthew Dillon     int error = 0;
46839b13188SMatthew Dillon     int index;
46939b13188SMatthew Dillon 
47039b13188SMatthew Dillon     index = 0;
47139b13188SMatthew Dillon     *res = 0;
47239b13188SMatthew Dillon     TAILQ_FOREACH(jo, &mp->mnt_jlist, jentry) {
47339b13188SMatthew Dillon 	if (info->index == MC_JOURNAL_INDEX_ID) {
47439b13188SMatthew Dillon 	    if (bcmp(jo->id, info->id, sizeof(jo->id)) != 0)
47539b13188SMatthew Dillon 		continue;
47639b13188SMatthew Dillon 	} else if (info->index >= 0) {
47739b13188SMatthew Dillon 	    if (info->index < index)
47839b13188SMatthew Dillon 		continue;
47939b13188SMatthew Dillon 	} else if (info->index != MC_JOURNAL_INDEX_ALL) {
48039b13188SMatthew Dillon 	    continue;
48139b13188SMatthew Dillon 	}
48239b13188SMatthew Dillon 	if (buflen < sizeof(*rstat)) {
48339b13188SMatthew Dillon 	    if (*res)
48439b13188SMatthew Dillon 		rstat[-1].flags |= MC_JOURNAL_STATUS_MORETOCOME;
48539b13188SMatthew Dillon 	    else
48639b13188SMatthew Dillon 		error = EINVAL;
48739b13188SMatthew Dillon 	    break;
48839b13188SMatthew Dillon 	}
48939b13188SMatthew Dillon 	bzero(rstat, sizeof(*rstat));
49039b13188SMatthew Dillon 	rstat->recsize = sizeof(*rstat);
49139b13188SMatthew Dillon 	bcopy(jo->id, rstat->id, sizeof(jo->id));
49239b13188SMatthew Dillon 	rstat->index = index;
49339b13188SMatthew Dillon 	rstat->membufsize = jo->fifo.size;
4943119bac5SMatthew Dillon 	rstat->membufused = jo->fifo.windex - jo->fifo.xindex;
4953119bac5SMatthew Dillon 	rstat->membufunacked = jo->fifo.rindex - jo->fifo.xindex;
49639b13188SMatthew Dillon 	rstat->bytessent = jo->total_acked;
4973119bac5SMatthew Dillon 	rstat->fifostalls = jo->fifostalls;
49839b13188SMatthew Dillon 	++rstat;
49939b13188SMatthew Dillon 	++index;
50039b13188SMatthew Dillon 	*res += sizeof(*rstat);
50139b13188SMatthew Dillon 	buflen -= sizeof(*rstat);
50239b13188SMatthew Dillon     }
50339b13188SMatthew Dillon     return(error);
50439b13188SMatthew Dillon }
505432b8263SMatthew Dillon 
50682eaef15SMatthew Dillon /************************************************************************
50726e603edSMatthew Dillon  *			PARALLEL TRANSACTION SUPPORT ROUTINES		*
50826e603edSMatthew Dillon  ************************************************************************
50926e603edSMatthew Dillon  *
51026e603edSMatthew Dillon  * JRECLIST_*() - routines which create and iterate over jrecord structures,
51126e603edSMatthew Dillon  *		  because a mount point may have multiple attached journals.
51226e603edSMatthew Dillon  */
51326e603edSMatthew Dillon 
51426e603edSMatthew Dillon /*
51526e603edSMatthew Dillon  * Initialize the passed jrecord_list and create a jrecord for each
51626e603edSMatthew Dillon  * journal we need to write to.  Unnecessary mallocs are avoided by
51726e603edSMatthew Dillon  * using the passed jrecord structure as the first jrecord in the list.
51826e603edSMatthew Dillon  * A starting transaction is pushed for each jrecord.
51926e603edSMatthew Dillon  *
52026e603edSMatthew Dillon  * Returns non-zero if any of the journals require undo records.
52126e603edSMatthew Dillon  */
52226e603edSMatthew Dillon static
52326e603edSMatthew Dillon int
jreclist_init(struct mount * mp,struct jrecord_list * jreclist,struct jrecord * jreccache,int16_t rectype)52426e603edSMatthew Dillon jreclist_init(struct mount *mp, struct jrecord_list *jreclist,
52526e603edSMatthew Dillon 	      struct jrecord *jreccache, int16_t rectype)
52626e603edSMatthew Dillon {
52726e603edSMatthew Dillon     struct journal *jo;
52826e603edSMatthew Dillon     struct jrecord *jrec;
529797e4fe9SMatthew Dillon     int wantrev;
530797e4fe9SMatthew Dillon     int count;
531797e4fe9SMatthew Dillon     int16_t streamid;
53226e603edSMatthew Dillon 
533797e4fe9SMatthew Dillon     TAILQ_INIT(&jreclist->list);
534797e4fe9SMatthew Dillon 
535797e4fe9SMatthew Dillon     /*
536797e4fe9SMatthew Dillon      * Select the stream ID to use for the transaction.  We must select
537797e4fe9SMatthew Dillon      * a stream ID that is not currently in use by some other parallel
538797e4fe9SMatthew Dillon      * transaction.
539797e4fe9SMatthew Dillon      *
540797e4fe9SMatthew Dillon      * Don't bother calculating the next streamid when reassigning
541797e4fe9SMatthew Dillon      * mnt_streamid, since parallel transactions are fairly rare.  This
542797e4fe9SMatthew Dillon      * also allows someone observing the raw records to clearly see
543797e4fe9SMatthew Dillon      * when parallel transactions occur.
544797e4fe9SMatthew Dillon      */
545797e4fe9SMatthew Dillon     streamid = mp->mnt_streamid;
546797e4fe9SMatthew Dillon     count = 0;
547797e4fe9SMatthew Dillon     while (mp->mnt_jbitmap[streamid >> 3] & (1 << (streamid & 7))) {
548797e4fe9SMatthew Dillon 	if (++streamid == JREC_STREAMID_JMAX)
549797e4fe9SMatthew Dillon 		streamid = JREC_STREAMID_JMIN;
550797e4fe9SMatthew Dillon 	if (++count == JREC_STREAMID_JMAX - JREC_STREAMID_JMIN) {
5516ea70f76SSascha Wildner 		kprintf("jreclist_init: all streamid's in use! sleeping\n");
552797e4fe9SMatthew Dillon 		tsleep(jreclist, 0, "jsidfl", hz * 10);
553797e4fe9SMatthew Dillon 		count = 0;
554797e4fe9SMatthew Dillon 	}
555797e4fe9SMatthew Dillon     }
556797e4fe9SMatthew Dillon     mp->mnt_jbitmap[streamid >> 3] |= 1 << (streamid & 7);
557797e4fe9SMatthew Dillon     mp->mnt_streamid = streamid;
558797e4fe9SMatthew Dillon     jreclist->streamid = streamid;
559797e4fe9SMatthew Dillon 
560797e4fe9SMatthew Dillon     /*
561797e4fe9SMatthew Dillon      * Now initialize a stream on each journal.
562797e4fe9SMatthew Dillon      */
563797e4fe9SMatthew Dillon     count = 0;
564797e4fe9SMatthew Dillon     wantrev = 0;
56526e603edSMatthew Dillon     TAILQ_FOREACH(jo, &mp->mnt_jlist, jentry) {
56626e603edSMatthew Dillon 	if (count == 0)
56726e603edSMatthew Dillon 	    jrec = jreccache;
56826e603edSMatthew Dillon 	else
569efda3bd0SMatthew Dillon 	    jrec = kmalloc(sizeof(*jrec), M_JOURNAL, M_WAITOK);
570797e4fe9SMatthew Dillon 	jrecord_init(jo, jrec, streamid);
57126e603edSMatthew Dillon 	jrec->user_save = jrecord_push(jrec, rectype);
572797e4fe9SMatthew Dillon 	TAILQ_INSERT_TAIL(&jreclist->list, jrec, user_entry);
57326e603edSMatthew Dillon 	if (jo->flags & MC_JOURNAL_WANT_REVERSABLE)
57426e603edSMatthew Dillon 	    wantrev = 1;
57526e603edSMatthew Dillon 	++count;
57626e603edSMatthew Dillon     }
57726e603edSMatthew Dillon     return(wantrev);
57826e603edSMatthew Dillon }
57926e603edSMatthew Dillon 
58026e603edSMatthew Dillon /*
58126e603edSMatthew Dillon  * Terminate the journaled transactions started by jreclist_init().  If
58226e603edSMatthew Dillon  * an error occured, the transaction records will be aborted.
58326e603edSMatthew Dillon  */
58426e603edSMatthew Dillon static
58526e603edSMatthew Dillon void
jreclist_done(struct mount * mp,struct jrecord_list * jreclist,int error)586797e4fe9SMatthew Dillon jreclist_done(struct mount *mp, struct jrecord_list *jreclist, int error)
58726e603edSMatthew Dillon {
58826e603edSMatthew Dillon     struct jrecord *jrec;
58926e603edSMatthew Dillon     int count;
59026e603edSMatthew Dillon 
591797e4fe9SMatthew Dillon     /*
592797e4fe9SMatthew Dillon      * Cleanup the jrecord state on each journal.
593797e4fe9SMatthew Dillon      */
594797e4fe9SMatthew Dillon     TAILQ_FOREACH(jrec, &jreclist->list, user_entry) {
59526e603edSMatthew Dillon 	jrecord_pop(jrec, jrec->user_save);
59626e603edSMatthew Dillon 	jrecord_done(jrec, error);
59726e603edSMatthew Dillon     }
598797e4fe9SMatthew Dillon 
599797e4fe9SMatthew Dillon     /*
600797e4fe9SMatthew Dillon      * Free allocated jrec's (the first is always supplied)
601797e4fe9SMatthew Dillon      */
60226e603edSMatthew Dillon     count = 0;
603797e4fe9SMatthew Dillon     while ((jrec = TAILQ_FIRST(&jreclist->list)) != NULL) {
604797e4fe9SMatthew Dillon 	TAILQ_REMOVE(&jreclist->list, jrec, user_entry);
60526e603edSMatthew Dillon 	if (count)
606efda3bd0SMatthew Dillon 	    kfree(jrec, M_JOURNAL);
60726e603edSMatthew Dillon 	++count;
60826e603edSMatthew Dillon     }
609797e4fe9SMatthew Dillon 
610797e4fe9SMatthew Dillon     /*
611797e4fe9SMatthew Dillon      * Clear the streamid so it can be reused.
612797e4fe9SMatthew Dillon      */
613797e4fe9SMatthew Dillon     mp->mnt_jbitmap[jreclist->streamid >> 3] &= ~(1 << (jreclist->streamid & 7));
61426e603edSMatthew Dillon }
61526e603edSMatthew Dillon 
61626e603edSMatthew Dillon /*
61726e603edSMatthew Dillon  * This procedure writes out UNDO records for available reversable
61826e603edSMatthew Dillon  * journals.
61926e603edSMatthew Dillon  *
62026e603edSMatthew Dillon  * XXX could use improvement.  There is no need to re-read the file
62126e603edSMatthew Dillon  * for each journal.
62226e603edSMatthew Dillon  */
62326e603edSMatthew Dillon static
62426e603edSMatthew Dillon void
jreclist_undo_file(struct jrecord_list * jreclist,struct vnode * vp,int jrflags,off_t off,off_t bytes)62526e603edSMatthew Dillon jreclist_undo_file(struct jrecord_list *jreclist, struct vnode *vp,
62626e603edSMatthew Dillon 		   int jrflags, off_t off, off_t bytes)
62726e603edSMatthew Dillon {
62826e603edSMatthew Dillon     struct jrecord *jrec;
62926e603edSMatthew Dillon     int error;
63026e603edSMatthew Dillon 
63126e603edSMatthew Dillon     error = 0;
63226e603edSMatthew Dillon     if (jrflags & JRUNDO_GETVP)
63387de5057SMatthew Dillon 	error = vget(vp, LK_SHARED);
63426e603edSMatthew Dillon     if (error == 0) {
635797e4fe9SMatthew Dillon 	TAILQ_FOREACH(jrec, &jreclist->list, user_entry) {
63626e603edSMatthew Dillon 	    if (jrec->jo->flags & MC_JOURNAL_WANT_REVERSABLE) {
63726e603edSMatthew Dillon 		jrecord_undo_file(jrec, vp, jrflags, off, bytes);
63826e603edSMatthew Dillon 	    }
63926e603edSMatthew Dillon 	}
64026e603edSMatthew Dillon     }
64126e603edSMatthew Dillon     if (error == 0 && jrflags & JRUNDO_GETVP)
64226e603edSMatthew Dillon 	vput(vp);
64326e603edSMatthew Dillon }
64426e603edSMatthew Dillon 
64526e603edSMatthew Dillon /************************************************************************
64626e603edSMatthew Dillon  *			LOW LEVEL UNDO SUPPORT ROUTINE			*
64726e603edSMatthew Dillon  ************************************************************************
64826e603edSMatthew Dillon  *
64926e603edSMatthew Dillon  * This function is used to support UNDO records.  It will generate an
65026e603edSMatthew Dillon  * appropriate record with the requested portion of the file data.  Note
65126e603edSMatthew Dillon  * that file data is only recorded if JRUNDO_FILEDATA is passed.  If bytes
65226e603edSMatthew Dillon  * is -1, it will be set to the size of the file.
65326e603edSMatthew Dillon  */
65426e603edSMatthew Dillon static void
jrecord_undo_file(struct jrecord * jrec,struct vnode * vp,int jrflags,off_t off,off_t bytes)65526e603edSMatthew Dillon jrecord_undo_file(struct jrecord *jrec, struct vnode *vp, int jrflags,
65626e603edSMatthew Dillon 		  off_t off, off_t bytes)
65726e603edSMatthew Dillon {
65826e603edSMatthew Dillon     struct vattr attr;
65926e603edSMatthew Dillon     void *save1; /* warning, save pointers do not always remain valid */
66026e603edSMatthew Dillon     void *save2;
66126e603edSMatthew Dillon     int error;
66226e603edSMatthew Dillon 
66326e603edSMatthew Dillon     /*
66426e603edSMatthew Dillon      * Setup.  Start the UNDO record, obtain a shared lock on the vnode,
66526e603edSMatthew Dillon      * and retrieve attribute info.
66626e603edSMatthew Dillon      */
66726e603edSMatthew Dillon     save1 = jrecord_push(jrec, JTYPE_UNDO);
66887de5057SMatthew Dillon     error = VOP_GETATTR(vp, &attr);
66926e603edSMatthew Dillon     if (error)
67026e603edSMatthew Dillon 	goto done;
67126e603edSMatthew Dillon 
67226e603edSMatthew Dillon     /*
67326e603edSMatthew Dillon      * Generate UNDO records as requested.
67426e603edSMatthew Dillon      */
67526e603edSMatthew Dillon     if (jrflags & JRUNDO_VATTR) {
67626e603edSMatthew Dillon 	save2 = jrecord_push(jrec, JTYPE_VATTR);
67726e603edSMatthew Dillon 	jrecord_leaf(jrec, JLEAF_VTYPE, &attr.va_type, sizeof(attr.va_type));
678aa159335SMatthew Dillon 	if ((jrflags & JRUNDO_NLINK) && attr.va_nlink != VNOVAL)
679aa159335SMatthew Dillon 	    jrecord_leaf(jrec, JLEAF_NLINK, &attr.va_nlink, sizeof(attr.va_nlink));
68026e603edSMatthew Dillon 	if ((jrflags & JRUNDO_SIZE) && attr.va_size != VNOVAL)
68126e603edSMatthew Dillon 	    jrecord_leaf(jrec, JLEAF_SIZE, &attr.va_size, sizeof(attr.va_size));
68226e603edSMatthew Dillon 	if ((jrflags & JRUNDO_UID) && attr.va_uid != VNOVAL)
68326e603edSMatthew Dillon 	    jrecord_leaf(jrec, JLEAF_UID, &attr.va_uid, sizeof(attr.va_uid));
68426e603edSMatthew Dillon 	if ((jrflags & JRUNDO_GID) && attr.va_gid != VNOVAL)
68526e603edSMatthew Dillon 	    jrecord_leaf(jrec, JLEAF_GID, &attr.va_gid, sizeof(attr.va_gid));
68626e603edSMatthew Dillon 	if ((jrflags & JRUNDO_FSID) && attr.va_fsid != VNOVAL)
68726e603edSMatthew Dillon 	    jrecord_leaf(jrec, JLEAF_FSID, &attr.va_fsid, sizeof(attr.va_fsid));
68826e603edSMatthew Dillon 	if ((jrflags & JRUNDO_MODES) && attr.va_mode != (mode_t)VNOVAL)
68926e603edSMatthew Dillon 	    jrecord_leaf(jrec, JLEAF_MODES, &attr.va_mode, sizeof(attr.va_mode));
69026e603edSMatthew Dillon 	if ((jrflags & JRUNDO_INUM) && attr.va_fileid != VNOVAL)
69126e603edSMatthew Dillon 	    jrecord_leaf(jrec, JLEAF_INUM, &attr.va_fileid, sizeof(attr.va_fileid));
69226e603edSMatthew Dillon 	if ((jrflags & JRUNDO_ATIME) && attr.va_atime.tv_sec != VNOVAL)
69326e603edSMatthew Dillon 	    jrecord_leaf(jrec, JLEAF_ATIME, &attr.va_atime, sizeof(attr.va_atime));
69426e603edSMatthew Dillon 	if ((jrflags & JRUNDO_MTIME) && attr.va_mtime.tv_sec != VNOVAL)
69526e603edSMatthew Dillon 	    jrecord_leaf(jrec, JLEAF_MTIME, &attr.va_mtime, sizeof(attr.va_mtime));
69626e603edSMatthew Dillon 	if ((jrflags & JRUNDO_CTIME) && attr.va_ctime.tv_sec != VNOVAL)
69726e603edSMatthew Dillon 	    jrecord_leaf(jrec, JLEAF_CTIME, &attr.va_ctime, sizeof(attr.va_ctime));
69826e603edSMatthew Dillon 	if ((jrflags & JRUNDO_GEN) && attr.va_gen != VNOVAL)
69926e603edSMatthew Dillon 	    jrecord_leaf(jrec, JLEAF_GEN, &attr.va_gen, sizeof(attr.va_gen));
70026e603edSMatthew Dillon 	if ((jrflags & JRUNDO_FLAGS) && attr.va_flags != VNOVAL)
70126e603edSMatthew Dillon 	    jrecord_leaf(jrec, JLEAF_FLAGS, &attr.va_flags, sizeof(attr.va_flags));
7020e9b9130SMatthew Dillon 	if ((jrflags & JRUNDO_UDEV) && attr.va_rmajor != VNOVAL) {
70391ffdfc5SSascha Wildner 	    dev_t rdev = makeudev(attr.va_rmajor, attr.va_rminor);
7040e9b9130SMatthew Dillon 	    jrecord_leaf(jrec, JLEAF_UDEV, &rdev, sizeof(rdev));
7050e9b9130SMatthew Dillon 	    jrecord_leaf(jrec, JLEAF_UMAJOR, &attr.va_rmajor, sizeof(attr.va_rmajor));
7060e9b9130SMatthew Dillon 	    jrecord_leaf(jrec, JLEAF_UMINOR, &attr.va_rminor, sizeof(attr.va_rminor));
7070e9b9130SMatthew Dillon 	}
70826e603edSMatthew Dillon 	jrecord_pop(jrec, save2);
70926e603edSMatthew Dillon     }
71026e603edSMatthew Dillon 
71126e603edSMatthew Dillon     /*
71226e603edSMatthew Dillon      * Output the file data being overwritten by reading the file and
71326e603edSMatthew Dillon      * writing it out to the journal prior to the write operation.  We
71426e603edSMatthew Dillon      * do not need to write out data past the current file EOF.
71526e603edSMatthew Dillon      *
71626e603edSMatthew Dillon      * XXX support JRUNDO_CONDLINK - do not write out file data for files
71726e603edSMatthew Dillon      * with a link count > 1.  The undo code needs to locate the inode and
71826e603edSMatthew Dillon      * regenerate the hardlink.
71926e603edSMatthew Dillon      */
72025bae9ceSMatthew Dillon     if ((jrflags & JRUNDO_FILEDATA) && attr.va_type == VREG) {
72126e603edSMatthew Dillon 	if (attr.va_size != VNOVAL) {
72226e603edSMatthew Dillon 	    if (bytes == -1)
72326e603edSMatthew Dillon 		bytes = attr.va_size - off;
72426e603edSMatthew Dillon 	    if (off + bytes > attr.va_size)
72526e603edSMatthew Dillon 		bytes = attr.va_size - off;
72626e603edSMatthew Dillon 	    if (bytes > 0)
72726e603edSMatthew Dillon 		jrecord_file_data(jrec, vp, off, bytes);
72826e603edSMatthew Dillon 	} else {
72926e603edSMatthew Dillon 	    error = EINVAL;
73026e603edSMatthew Dillon 	}
73126e603edSMatthew Dillon     }
73225bae9ceSMatthew Dillon     if ((jrflags & JRUNDO_FILEDATA) && attr.va_type == VLNK) {
73325bae9ceSMatthew Dillon 	struct iovec aiov;
73425bae9ceSMatthew Dillon 	struct uio auio;
73525bae9ceSMatthew Dillon 	char *buf;
73625bae9ceSMatthew Dillon 
737efda3bd0SMatthew Dillon 	buf = kmalloc(PATH_MAX, M_JOURNAL, M_WAITOK);
73825bae9ceSMatthew Dillon 	aiov.iov_base = buf;
73925bae9ceSMatthew Dillon 	aiov.iov_len = PATH_MAX;
74025bae9ceSMatthew Dillon 	auio.uio_iov = &aiov;
74125bae9ceSMatthew Dillon 	auio.uio_iovcnt = 1;
74225bae9ceSMatthew Dillon 	auio.uio_offset = 0;
74325bae9ceSMatthew Dillon 	auio.uio_rw = UIO_READ;
74425bae9ceSMatthew Dillon 	auio.uio_segflg = UIO_SYSSPACE;
74525bae9ceSMatthew Dillon 	auio.uio_td = curthread;
74625bae9ceSMatthew Dillon 	auio.uio_resid = PATH_MAX;
74725bae9ceSMatthew Dillon 	error = VOP_READLINK(vp, &auio, proc0.p_ucred);
74825bae9ceSMatthew Dillon 	if (error == 0) {
74925bae9ceSMatthew Dillon 		jrecord_leaf(jrec, JLEAF_SYMLINKDATA, buf,
75025bae9ceSMatthew Dillon 				PATH_MAX - auio.uio_resid);
75125bae9ceSMatthew Dillon 	}
752efda3bd0SMatthew Dillon 	kfree(buf, M_JOURNAL);
75325bae9ceSMatthew Dillon     }
75426e603edSMatthew Dillon done:
75526e603edSMatthew Dillon     if (error)
75626e603edSMatthew Dillon 	jrecord_leaf(jrec, JLEAF_ERROR, &error, sizeof(error));
75726e603edSMatthew Dillon     jrecord_pop(jrec, save1);
75826e603edSMatthew Dillon }
75926e603edSMatthew Dillon 
7602281065eSMatthew Dillon /************************************************************************
7612281065eSMatthew Dillon  *			JOURNAL VNOPS					*
762558b8e00SMatthew Dillon  ************************************************************************
763558b8e00SMatthew Dillon  *
764558b8e00SMatthew Dillon  * These are function shims replacing the normal filesystem ops.  We become
765558b8e00SMatthew Dillon  * responsible for calling the underlying filesystem ops.  We have the choice
766558b8e00SMatthew Dillon  * of executing the underlying op first and then generating the journal entry,
767558b8e00SMatthew Dillon  * or starting the journal entry, executing the underlying op, and then
768558b8e00SMatthew Dillon  * either completing or aborting it.
769558b8e00SMatthew Dillon  *
770558b8e00SMatthew Dillon  * The journal is supposed to be a high-level entity, which generally means
771558b8e00SMatthew Dillon  * identifying files by name rather then by inode.  Supplying both allows
772558b8e00SMatthew Dillon  * the journal to be used both for inode-number-compatible 'mirrors' and
773558b8e00SMatthew Dillon  * for simple filesystem replication.
774558b8e00SMatthew Dillon  *
775558b8e00SMatthew Dillon  * Writes are particularly difficult to deal with because a single write may
776558b8e00SMatthew Dillon  * represent a hundred megabyte buffer or more, and both writes and truncations
777558b8e00SMatthew Dillon  * require the 'old' data to be written out as well as the new data if the
778558b8e00SMatthew Dillon  * log is reversable.  Other issues:
779558b8e00SMatthew Dillon  *
780558b8e00SMatthew Dillon  * - How to deal with operations on unlinked files (no path available),
781558b8e00SMatthew Dillon  *   but which may still be filesystem visible due to hard links.
782558b8e00SMatthew Dillon  *
783558b8e00SMatthew Dillon  * - How to deal with modifications made via a memory map.
784558b8e00SMatthew Dillon  *
785558b8e00SMatthew Dillon  * - Future cache coherency support will require cache coherency API calls
786558b8e00SMatthew Dillon  *   both prior to and after the call to the underlying VFS.
787558b8e00SMatthew Dillon  *
788558b8e00SMatthew Dillon  * ALSO NOTE: We do not have to shim compatibility VOPs like MKDIR which have
789558b8e00SMatthew Dillon  * new VFS equivalents (NMKDIR).
790558b8e00SMatthew Dillon  */
791558b8e00SMatthew Dillon 
792b2f7ec6cSMatthew Dillon /*
793b478fdceSSascha Wildner  * Journal vop_setattr { a_vp, a_vap, a_cred }
794b2f7ec6cSMatthew Dillon  */
795558b8e00SMatthew Dillon static
796558b8e00SMatthew Dillon int
journal_setattr(struct vop_setattr_args * ap)797558b8e00SMatthew Dillon journal_setattr(struct vop_setattr_args *ap)
798558b8e00SMatthew Dillon {
79926e603edSMatthew Dillon     struct jrecord_list jreclist;
80026e603edSMatthew Dillon     struct jrecord jreccache;
80126e603edSMatthew Dillon     struct jrecord *jrec;
802558b8e00SMatthew Dillon     struct mount *mp;
803aa159335SMatthew Dillon     void *save;
804558b8e00SMatthew Dillon     int error;
805558b8e00SMatthew Dillon 
80666a1ddf5SMatthew Dillon     mp = ap->a_head.a_ops->head.vv_mount;
80726e603edSMatthew Dillon     if (jreclist_init(mp, &jreclist, &jreccache, JTYPE_SETATTR)) {
80826e603edSMatthew Dillon 	jreclist_undo_file(&jreclist, ap->a_vp, JRUNDO_VATTR, 0, 0);
80926e603edSMatthew Dillon     }
81026e603edSMatthew Dillon     error = vop_journal_operate_ap(&ap->a_head);
811558b8e00SMatthew Dillon     if (error == 0) {
812797e4fe9SMatthew Dillon 	TAILQ_FOREACH(jrec, &jreclist.list, user_entry) {
81387de5057SMatthew Dillon 	    jrecord_write_cred(jrec, curthread, ap->a_cred);
81426e603edSMatthew Dillon 	    jrecord_write_vnode_ref(jrec, ap->a_vp);
815aa159335SMatthew Dillon 	    save = jrecord_push(jrec, JTYPE_REDO);
81626e603edSMatthew Dillon 	    jrecord_write_vattr(jrec, ap->a_vap);
817aa159335SMatthew Dillon 	    jrecord_pop(jrec, save);
818558b8e00SMatthew Dillon 	}
819558b8e00SMatthew Dillon     }
820797e4fe9SMatthew Dillon     jreclist_done(mp, &jreclist, error);
821558b8e00SMatthew Dillon     return (error);
822558b8e00SMatthew Dillon }
823558b8e00SMatthew Dillon 
824b2f7ec6cSMatthew Dillon /*
825b2f7ec6cSMatthew Dillon  * Journal vop_write { a_vp, a_uio, a_ioflag, a_cred }
826b2f7ec6cSMatthew Dillon  */
827558b8e00SMatthew Dillon static
828558b8e00SMatthew Dillon int
journal_write(struct vop_write_args * ap)829558b8e00SMatthew Dillon journal_write(struct vop_write_args *ap)
830558b8e00SMatthew Dillon {
83126e603edSMatthew Dillon     struct jrecord_list jreclist;
83226e603edSMatthew Dillon     struct jrecord jreccache;
83326e603edSMatthew Dillon     struct jrecord *jrec;
834558b8e00SMatthew Dillon     struct mount *mp;
8359578bde0SMatthew Dillon     struct uio uio_copy;
8369578bde0SMatthew Dillon     struct iovec uio_one_iovec;
837aa159335SMatthew Dillon     void *save;
838558b8e00SMatthew Dillon     int error;
839558b8e00SMatthew Dillon 
8409578bde0SMatthew Dillon     /*
841cfb7e99aSMatthew Dillon      * Special synchronizing writes for VM backing store do not supply any
842cfb7e99aSMatthew Dillon      * real data
843cfb7e99aSMatthew Dillon      */
844cfb7e99aSMatthew Dillon     if (ap->a_uio->uio_segflg == UIO_NOCOPY) {
845cfb7e99aSMatthew Dillon 	    error = vop_journal_operate_ap(&ap->a_head);
846cfb7e99aSMatthew Dillon 	    return (error);
847cfb7e99aSMatthew Dillon     }
848cfb7e99aSMatthew Dillon 
849cfb7e99aSMatthew Dillon     /*
8509578bde0SMatthew Dillon      * This is really nasty.  UIO's don't retain sufficient information to
8519578bde0SMatthew Dillon      * be reusable once they've gone through the VOP chain.  The iovecs get
8529578bde0SMatthew Dillon      * cleared, so we have to copy the UIO.
8539578bde0SMatthew Dillon      *
8549578bde0SMatthew Dillon      * XXX fix the UIO code to not destroy iov's during a scan so we can
8559578bde0SMatthew Dillon      *     reuse the uio over and over again.
856d0887c34SMatthew Dillon      *
857d0887c34SMatthew Dillon      * XXX UNDO code needs to journal the old data prior to the write.
8589578bde0SMatthew Dillon      */
8599578bde0SMatthew Dillon     uio_copy = *ap->a_uio;
8609578bde0SMatthew Dillon     if (uio_copy.uio_iovcnt == 1) {
8619578bde0SMatthew Dillon 	uio_one_iovec = ap->a_uio->uio_iov[0];
8629578bde0SMatthew Dillon 	uio_copy.uio_iov = &uio_one_iovec;
8639578bde0SMatthew Dillon     } else {
86477652cadSMatthew Dillon 	uio_copy.uio_iov = kmalloc(uio_copy.uio_iovcnt * sizeof(struct iovec),
8659578bde0SMatthew Dillon 				    M_JOURNAL, M_WAITOK);
8669578bde0SMatthew Dillon 	bcopy(ap->a_uio->uio_iov, uio_copy.uio_iov,
8679578bde0SMatthew Dillon 		uio_copy.uio_iovcnt * sizeof(struct iovec));
8689578bde0SMatthew Dillon     }
8699578bde0SMatthew Dillon 
87026e603edSMatthew Dillon     /*
87126e603edSMatthew Dillon      * Write out undo data.  Note that uio_offset is incorrect if
87226e603edSMatthew Dillon      * IO_APPEND is set, but fortunately we have no undo file data to
87326e603edSMatthew Dillon      * write out in that case.
87426e603edSMatthew Dillon      */
87566a1ddf5SMatthew Dillon     mp = ap->a_head.a_ops->head.vv_mount;
87626e603edSMatthew Dillon     if (jreclist_init(mp, &jreclist, &jreccache, JTYPE_WRITE)) {
87726e603edSMatthew Dillon 	if (ap->a_ioflag & IO_APPEND) {
87826e603edSMatthew Dillon 	    jreclist_undo_file(&jreclist, ap->a_vp, JRUNDO_SIZE|JRUNDO_MTIME, 0, 0);
87926e603edSMatthew Dillon 	} else {
88026e603edSMatthew Dillon 	    jreclist_undo_file(&jreclist, ap->a_vp,
88126e603edSMatthew Dillon 			       JRUNDO_FILEDATA|JRUNDO_SIZE|JRUNDO_MTIME,
88226e603edSMatthew Dillon 			       uio_copy.uio_offset, uio_copy.uio_resid);
88326e603edSMatthew Dillon 	}
88426e603edSMatthew Dillon     }
885558b8e00SMatthew Dillon     error = vop_journal_operate_ap(&ap->a_head);
886d0887c34SMatthew Dillon 
887d0887c34SMatthew Dillon     /*
888d0887c34SMatthew Dillon      * XXX bad hack to figure out the offset for O_APPEND writes (note:
889d0887c34SMatthew Dillon      * uio field state after the VFS operation).
890d0887c34SMatthew Dillon      */
891d0887c34SMatthew Dillon     uio_copy.uio_offset = ap->a_uio->uio_offset -
892d0887c34SMatthew Dillon 			  (uio_copy.uio_resid - ap->a_uio->uio_resid);
893d0887c34SMatthew Dillon 
89426e603edSMatthew Dillon     /*
89526e603edSMatthew Dillon      * Output the write data to the journal.
89626e603edSMatthew Dillon      */
897558b8e00SMatthew Dillon     if (error == 0) {
898797e4fe9SMatthew Dillon 	TAILQ_FOREACH(jrec, &jreclist.list, user_entry) {
89926e603edSMatthew Dillon 	    jrecord_write_cred(jrec, NULL, ap->a_cred);
90026e603edSMatthew Dillon 	    jrecord_write_vnode_ref(jrec, ap->a_vp);
901aa159335SMatthew Dillon 	    save = jrecord_push(jrec, JTYPE_REDO);
90226e603edSMatthew Dillon 	    jrecord_write_uio(jrec, JLEAF_FILEDATA, &uio_copy);
903aa159335SMatthew Dillon 	    jrecord_pop(jrec, save);
904558b8e00SMatthew Dillon 	}
905558b8e00SMatthew Dillon     }
906797e4fe9SMatthew Dillon     jreclist_done(mp, &jreclist, error);
9079578bde0SMatthew Dillon 
9089578bde0SMatthew Dillon     if (uio_copy.uio_iov != &uio_one_iovec)
909efda3bd0SMatthew Dillon 	kfree(uio_copy.uio_iov, M_JOURNAL);
910558b8e00SMatthew Dillon     return (error);
911558b8e00SMatthew Dillon }
912558b8e00SMatthew Dillon 
913b2f7ec6cSMatthew Dillon /*
914b478fdceSSascha Wildner  * Journal vop_fsync { a_vp, a_waitfor }
915b2f7ec6cSMatthew Dillon  */
916558b8e00SMatthew Dillon static
917558b8e00SMatthew Dillon int
journal_fsync(struct vop_fsync_args * ap)918558b8e00SMatthew Dillon journal_fsync(struct vop_fsync_args *ap)
919558b8e00SMatthew Dillon {
92026e603edSMatthew Dillon #if 0
921558b8e00SMatthew Dillon     struct mount *mp;
922558b8e00SMatthew Dillon     struct journal *jo;
92326e603edSMatthew Dillon #endif
924558b8e00SMatthew Dillon     int error;
925558b8e00SMatthew Dillon 
926558b8e00SMatthew Dillon     error = vop_journal_operate_ap(&ap->a_head);
92726e603edSMatthew Dillon #if 0
92866a1ddf5SMatthew Dillon     mp = ap->a_head.a_ops->head.vv_mount;
929558b8e00SMatthew Dillon     if (error == 0) {
930558b8e00SMatthew Dillon 	TAILQ_FOREACH(jo, &mp->mnt_jlist, jentry) {
931558b8e00SMatthew Dillon 	    /* XXX synchronize pending journal records */
932558b8e00SMatthew Dillon 	}
933558b8e00SMatthew Dillon     }
93426e603edSMatthew Dillon #endif
935558b8e00SMatthew Dillon     return (error);
936558b8e00SMatthew Dillon }
937558b8e00SMatthew Dillon 
938b2f7ec6cSMatthew Dillon /*
939*df0b0eadSSascha Wildner  * Journal vop_putpages { a_vp, a_m, a_count, a_flags, a_rtvals, a_offset }
940143c4f15SMatthew Dillon  *
941143c4f15SMatthew Dillon  * note: a_count is in bytes.
942b2f7ec6cSMatthew Dillon  */
943558b8e00SMatthew Dillon static
944558b8e00SMatthew Dillon int
journal_putpages(struct vop_putpages_args * ap)945558b8e00SMatthew Dillon journal_putpages(struct vop_putpages_args *ap)
946558b8e00SMatthew Dillon {
94726e603edSMatthew Dillon     struct jrecord_list jreclist;
94826e603edSMatthew Dillon     struct jrecord jreccache;
94926e603edSMatthew Dillon     struct jrecord *jrec;
950558b8e00SMatthew Dillon     struct mount *mp;
951aa159335SMatthew Dillon     void *save;
952558b8e00SMatthew Dillon     int error;
953558b8e00SMatthew Dillon 
95466a1ddf5SMatthew Dillon     mp = ap->a_head.a_ops->head.vv_mount;
95526e603edSMatthew Dillon     if (jreclist_init(mp, &jreclist, &jreccache, JTYPE_PUTPAGES) &&
95626e603edSMatthew Dillon 	ap->a_count > 0
95726e603edSMatthew Dillon     ) {
95826e603edSMatthew Dillon 	jreclist_undo_file(&jreclist, ap->a_vp,
95926e603edSMatthew Dillon 			   JRUNDO_FILEDATA|JRUNDO_SIZE|JRUNDO_MTIME,
96026e603edSMatthew Dillon 			   ap->a_offset, btoc(ap->a_count));
96126e603edSMatthew Dillon     }
96226e603edSMatthew Dillon     error = vop_journal_operate_ap(&ap->a_head);
963143c4f15SMatthew Dillon     if (error == 0 && ap->a_count > 0) {
964797e4fe9SMatthew Dillon 	TAILQ_FOREACH(jrec, &jreclist.list, user_entry) {
96526e603edSMatthew Dillon 	    jrecord_write_vnode_ref(jrec, ap->a_vp);
966aa159335SMatthew Dillon 	    save = jrecord_push(jrec, JTYPE_REDO);
96726e603edSMatthew Dillon 	    jrecord_write_pagelist(jrec, JLEAF_FILEDATA, ap->a_m, ap->a_rtvals,
96826e603edSMatthew Dillon 				   btoc(ap->a_count), ap->a_offset);
969aa159335SMatthew Dillon 	    jrecord_pop(jrec, save);
970558b8e00SMatthew Dillon 	}
971558b8e00SMatthew Dillon     }
972797e4fe9SMatthew Dillon     jreclist_done(mp, &jreclist, error);
973558b8e00SMatthew Dillon     return (error);
974558b8e00SMatthew Dillon }
975558b8e00SMatthew Dillon 
976b2f7ec6cSMatthew Dillon /*
977b478fdceSSascha Wildner  * Journal vop_setacl { a_vp, a_type, a_aclp, a_cred }
978b2f7ec6cSMatthew Dillon  */
979558b8e00SMatthew Dillon static
980558b8e00SMatthew Dillon int
journal_setacl(struct vop_setacl_args * ap)981558b8e00SMatthew Dillon journal_setacl(struct vop_setacl_args *ap)
982558b8e00SMatthew Dillon {
98326e603edSMatthew Dillon     struct jrecord_list jreclist;
98426e603edSMatthew Dillon     struct jrecord jreccache;
98526e603edSMatthew Dillon     struct jrecord *jrec;
986558b8e00SMatthew Dillon     struct mount *mp;
987558b8e00SMatthew Dillon     int error;
988558b8e00SMatthew Dillon 
98966a1ddf5SMatthew Dillon     mp = ap->a_head.a_ops->head.vv_mount;
99026e603edSMatthew Dillon     jreclist_init(mp, &jreclist, &jreccache, JTYPE_SETACL);
99126e603edSMatthew Dillon     error = vop_journal_operate_ap(&ap->a_head);
992558b8e00SMatthew Dillon     if (error == 0) {
993797e4fe9SMatthew Dillon 	TAILQ_FOREACH(jrec, &jreclist.list, user_entry) {
99426e603edSMatthew Dillon #if 0
99526e603edSMatthew Dillon 	    if ((jo->flags & MC_JOURNAL_WANT_REVERSABLE))
99626e603edSMatthew Dillon 		jrecord_undo_file(jrec, ap->a_vp, JRUNDO_XXX, 0, 0);
99726e603edSMatthew Dillon #endif
99887de5057SMatthew Dillon 	    jrecord_write_cred(jrec, curthread, ap->a_cred);
99926e603edSMatthew Dillon 	    jrecord_write_vnode_ref(jrec, ap->a_vp);
1000aa159335SMatthew Dillon #if 0
1001aa159335SMatthew Dillon 	    save = jrecord_push(jrec, JTYPE_REDO);
1002b2f7ec6cSMatthew Dillon 	    /* XXX type, aclp */
1003aa159335SMatthew Dillon 	    jrecord_pop(jrec, save);
1004aa159335SMatthew Dillon #endif
1005558b8e00SMatthew Dillon 	}
1006558b8e00SMatthew Dillon     }
1007797e4fe9SMatthew Dillon     jreclist_done(mp, &jreclist, error);
1008558b8e00SMatthew Dillon     return (error);
1009558b8e00SMatthew Dillon }
1010558b8e00SMatthew Dillon 
1011b2f7ec6cSMatthew Dillon /*
1012b478fdceSSascha Wildner  * Journal vop_setextattr { a_vp, a_name, a_uio, a_cred }
1013b2f7ec6cSMatthew Dillon  */
1014558b8e00SMatthew Dillon static
1015558b8e00SMatthew Dillon int
journal_setextattr(struct vop_setextattr_args * ap)1016558b8e00SMatthew Dillon journal_setextattr(struct vop_setextattr_args *ap)
1017558b8e00SMatthew Dillon {
101826e603edSMatthew Dillon     struct jrecord_list jreclist;
101926e603edSMatthew Dillon     struct jrecord jreccache;
102026e603edSMatthew Dillon     struct jrecord *jrec;
1021558b8e00SMatthew Dillon     struct mount *mp;
1022aa159335SMatthew Dillon     void *save;
1023558b8e00SMatthew Dillon     int error;
1024558b8e00SMatthew Dillon 
102566a1ddf5SMatthew Dillon     mp = ap->a_head.a_ops->head.vv_mount;
102626e603edSMatthew Dillon     jreclist_init(mp, &jreclist, &jreccache, JTYPE_SETEXTATTR);
102726e603edSMatthew Dillon     error = vop_journal_operate_ap(&ap->a_head);
1028558b8e00SMatthew Dillon     if (error == 0) {
1029797e4fe9SMatthew Dillon 	TAILQ_FOREACH(jrec, &jreclist.list, user_entry) {
103026e603edSMatthew Dillon #if 0
103126e603edSMatthew Dillon 	    if ((jo->flags & MC_JOURNAL_WANT_REVERSABLE))
103226e603edSMatthew Dillon 		jrecord_undo_file(jrec, ap->a_vp, JRUNDO_XXX, 0, 0);
103326e603edSMatthew Dillon #endif
103487de5057SMatthew Dillon 	    jrecord_write_cred(jrec, curthread, ap->a_cred);
103526e603edSMatthew Dillon 	    jrecord_write_vnode_ref(jrec, ap->a_vp);
10360f6997f9SMatthew Dillon 	    jrecord_leaf(jrec, JLEAF_ATTRNAME, ap->a_attrname,
10370f6997f9SMatthew Dillon 			strlen(ap->a_attrname));
1038aa159335SMatthew Dillon 	    save = jrecord_push(jrec, JTYPE_REDO);
103926e603edSMatthew Dillon 	    jrecord_write_uio(jrec, JLEAF_FILEDATA, ap->a_uio);
1040aa159335SMatthew Dillon 	    jrecord_pop(jrec, save);
1041558b8e00SMatthew Dillon 	}
1042558b8e00SMatthew Dillon     }
1043797e4fe9SMatthew Dillon     jreclist_done(mp, &jreclist, error);
1044558b8e00SMatthew Dillon     return (error);
1045558b8e00SMatthew Dillon }
1046558b8e00SMatthew Dillon 
1047b2f7ec6cSMatthew Dillon /*
104828623bf9SMatthew Dillon  * Journal vop_ncreate { a_nch, a_vpp, a_cred, a_vap }
1049b2f7ec6cSMatthew Dillon  */
1050558b8e00SMatthew Dillon static
1051558b8e00SMatthew Dillon int
journal_ncreate(struct vop_ncreate_args * ap)1052558b8e00SMatthew Dillon journal_ncreate(struct vop_ncreate_args *ap)
1053558b8e00SMatthew Dillon {
105426e603edSMatthew Dillon     struct jrecord_list jreclist;
105526e603edSMatthew Dillon     struct jrecord jreccache;
105626e603edSMatthew Dillon     struct jrecord *jrec;
1057558b8e00SMatthew Dillon     struct mount *mp;
1058aa159335SMatthew Dillon     void *save;
1059558b8e00SMatthew Dillon     int error;
1060558b8e00SMatthew Dillon 
106166a1ddf5SMatthew Dillon     mp = ap->a_head.a_ops->head.vv_mount;
106226e603edSMatthew Dillon     jreclist_init(mp, &jreclist, &jreccache, JTYPE_CREATE);
106326e603edSMatthew Dillon     error = vop_journal_operate_ap(&ap->a_head);
1064558b8e00SMatthew Dillon     if (error == 0) {
1065797e4fe9SMatthew Dillon 	TAILQ_FOREACH(jrec, &jreclist.list, user_entry) {
106626e603edSMatthew Dillon 	    jrecord_write_cred(jrec, NULL, ap->a_cred);
106728623bf9SMatthew Dillon 	    jrecord_write_path(jrec, JLEAF_PATH1, ap->a_nch->ncp);
1068b2f7ec6cSMatthew Dillon 	    if (*ap->a_vpp)
106926e603edSMatthew Dillon 		jrecord_write_vnode_ref(jrec, *ap->a_vpp);
1070aa159335SMatthew Dillon 	    save = jrecord_push(jrec, JTYPE_REDO);
107126e603edSMatthew Dillon 	    jrecord_write_vattr(jrec, ap->a_vap);
1072aa159335SMatthew Dillon 	    jrecord_pop(jrec, save);
1073558b8e00SMatthew Dillon 	}
1074558b8e00SMatthew Dillon     }
1075797e4fe9SMatthew Dillon     jreclist_done(mp, &jreclist, error);
1076558b8e00SMatthew Dillon     return (error);
1077558b8e00SMatthew Dillon }
1078558b8e00SMatthew Dillon 
1079b2f7ec6cSMatthew Dillon /*
108028623bf9SMatthew Dillon  * Journal vop_nmknod { a_nch, a_vpp, a_cred, a_vap }
1081b2f7ec6cSMatthew Dillon  */
1082558b8e00SMatthew Dillon static
1083558b8e00SMatthew Dillon int
journal_nmknod(struct vop_nmknod_args * ap)1084558b8e00SMatthew Dillon journal_nmknod(struct vop_nmknod_args *ap)
1085558b8e00SMatthew Dillon {
108626e603edSMatthew Dillon     struct jrecord_list jreclist;
108726e603edSMatthew Dillon     struct jrecord jreccache;
108826e603edSMatthew Dillon     struct jrecord *jrec;
1089558b8e00SMatthew Dillon     struct mount *mp;
1090aa159335SMatthew Dillon     void *save;
1091558b8e00SMatthew Dillon     int error;
1092558b8e00SMatthew Dillon 
109366a1ddf5SMatthew Dillon     mp = ap->a_head.a_ops->head.vv_mount;
109426e603edSMatthew Dillon     jreclist_init(mp, &jreclist, &jreccache, JTYPE_MKNOD);
109526e603edSMatthew Dillon     error = vop_journal_operate_ap(&ap->a_head);
1096558b8e00SMatthew Dillon     if (error == 0) {
1097797e4fe9SMatthew Dillon 	TAILQ_FOREACH(jrec, &jreclist.list, user_entry) {
109826e603edSMatthew Dillon 	    jrecord_write_cred(jrec, NULL, ap->a_cred);
109928623bf9SMatthew Dillon 	    jrecord_write_path(jrec, JLEAF_PATH1, ap->a_nch->ncp);
1100aa159335SMatthew Dillon 	    save = jrecord_push(jrec, JTYPE_REDO);
110126e603edSMatthew Dillon 	    jrecord_write_vattr(jrec, ap->a_vap);
1102aa159335SMatthew Dillon 	    jrecord_pop(jrec, save);
1103b2f7ec6cSMatthew Dillon 	    if (*ap->a_vpp)
110426e603edSMatthew Dillon 		jrecord_write_vnode_ref(jrec, *ap->a_vpp);
1105558b8e00SMatthew Dillon 	}
1106558b8e00SMatthew Dillon     }
1107797e4fe9SMatthew Dillon     jreclist_done(mp, &jreclist, error);
1108558b8e00SMatthew Dillon     return (error);
1109558b8e00SMatthew Dillon }
1110558b8e00SMatthew Dillon 
1111b2f7ec6cSMatthew Dillon /*
111228623bf9SMatthew Dillon  * Journal vop_nlink { a_nch, a_vp, a_cred }
1113b2f7ec6cSMatthew Dillon  */
1114558b8e00SMatthew Dillon static
1115558b8e00SMatthew Dillon int
journal_nlink(struct vop_nlink_args * ap)1116558b8e00SMatthew Dillon journal_nlink(struct vop_nlink_args *ap)
1117558b8e00SMatthew Dillon {
111826e603edSMatthew Dillon     struct jrecord_list jreclist;
111926e603edSMatthew Dillon     struct jrecord jreccache;
112026e603edSMatthew Dillon     struct jrecord *jrec;
1121558b8e00SMatthew Dillon     struct mount *mp;
1122aa159335SMatthew Dillon     void *save;
1123558b8e00SMatthew Dillon     int error;
1124558b8e00SMatthew Dillon 
112566a1ddf5SMatthew Dillon     mp = ap->a_head.a_ops->head.vv_mount;
112626e603edSMatthew Dillon     jreclist_init(mp, &jreclist, &jreccache, JTYPE_LINK);
112726e603edSMatthew Dillon     error = vop_journal_operate_ap(&ap->a_head);
1128558b8e00SMatthew Dillon     if (error == 0) {
1129797e4fe9SMatthew Dillon 	TAILQ_FOREACH(jrec, &jreclist.list, user_entry) {
113026e603edSMatthew Dillon 	    jrecord_write_cred(jrec, NULL, ap->a_cred);
113128623bf9SMatthew Dillon 	    jrecord_write_path(jrec, JLEAF_PATH1, ap->a_nch->ncp);
1132b2f7ec6cSMatthew Dillon 	    /* XXX PATH to VP and inode number */
1133f4659a6cSMatthew Dillon 	    /* XXX this call may not record the correct path when
1134f4659a6cSMatthew Dillon 	     * multiple paths are available */
1135aa159335SMatthew Dillon 	    save = jrecord_push(jrec, JTYPE_REDO);
113628623bf9SMatthew Dillon 	    jrecord_write_vnode_link(jrec, ap->a_vp, ap->a_nch->ncp);
1137aa159335SMatthew Dillon 	    jrecord_pop(jrec, save);
1138558b8e00SMatthew Dillon 	}
1139558b8e00SMatthew Dillon     }
1140797e4fe9SMatthew Dillon     jreclist_done(mp, &jreclist, error);
1141558b8e00SMatthew Dillon     return (error);
1142558b8e00SMatthew Dillon }
1143558b8e00SMatthew Dillon 
1144b2f7ec6cSMatthew Dillon /*
114528623bf9SMatthew Dillon  * Journal vop_symlink { a_nch, a_vpp, a_cred, a_vap, a_target }
1146b2f7ec6cSMatthew Dillon  */
1147558b8e00SMatthew Dillon static
1148558b8e00SMatthew Dillon int
journal_nsymlink(struct vop_nsymlink_args * ap)1149558b8e00SMatthew Dillon journal_nsymlink(struct vop_nsymlink_args *ap)
1150558b8e00SMatthew Dillon {
115126e603edSMatthew Dillon     struct jrecord_list jreclist;
115226e603edSMatthew Dillon     struct jrecord jreccache;
115326e603edSMatthew Dillon     struct jrecord *jrec;
1154558b8e00SMatthew Dillon     struct mount *mp;
1155aa159335SMatthew Dillon     void *save;
1156558b8e00SMatthew Dillon     int error;
1157558b8e00SMatthew Dillon 
115866a1ddf5SMatthew Dillon     mp = ap->a_head.a_ops->head.vv_mount;
115926e603edSMatthew Dillon     jreclist_init(mp, &jreclist, &jreccache, JTYPE_SYMLINK);
116026e603edSMatthew Dillon     error = vop_journal_operate_ap(&ap->a_head);
1161558b8e00SMatthew Dillon     if (error == 0) {
1162797e4fe9SMatthew Dillon 	TAILQ_FOREACH(jrec, &jreclist.list, user_entry) {
116326e603edSMatthew Dillon 	    jrecord_write_cred(jrec, NULL, ap->a_cred);
116428623bf9SMatthew Dillon 	    jrecord_write_path(jrec, JLEAF_PATH1, ap->a_nch->ncp);
1165aa159335SMatthew Dillon 	    save = jrecord_push(jrec, JTYPE_REDO);
116626e603edSMatthew Dillon 	    jrecord_leaf(jrec, JLEAF_SYMLINKDATA,
1167b2f7ec6cSMatthew Dillon 			ap->a_target, strlen(ap->a_target));
1168aa159335SMatthew Dillon 	    jrecord_pop(jrec, save);
1169b2f7ec6cSMatthew Dillon 	    if (*ap->a_vpp)
117026e603edSMatthew Dillon 		jrecord_write_vnode_ref(jrec, *ap->a_vpp);
1171558b8e00SMatthew Dillon 	}
1172558b8e00SMatthew Dillon     }
1173797e4fe9SMatthew Dillon     jreclist_done(mp, &jreclist, error);
1174558b8e00SMatthew Dillon     return (error);
1175558b8e00SMatthew Dillon }
1176558b8e00SMatthew Dillon 
1177b2f7ec6cSMatthew Dillon /*
117828623bf9SMatthew Dillon  * Journal vop_nwhiteout { a_nch, a_cred, a_flags }
1179b2f7ec6cSMatthew Dillon  */
1180558b8e00SMatthew Dillon static
1181558b8e00SMatthew Dillon int
journal_nwhiteout(struct vop_nwhiteout_args * ap)1182558b8e00SMatthew Dillon journal_nwhiteout(struct vop_nwhiteout_args *ap)
1183558b8e00SMatthew Dillon {
118426e603edSMatthew Dillon     struct jrecord_list jreclist;
118526e603edSMatthew Dillon     struct jrecord jreccache;
118626e603edSMatthew Dillon     struct jrecord *jrec;
1187558b8e00SMatthew Dillon     struct mount *mp;
1188558b8e00SMatthew Dillon     int error;
1189558b8e00SMatthew Dillon 
119066a1ddf5SMatthew Dillon     mp = ap->a_head.a_ops->head.vv_mount;
119126e603edSMatthew Dillon     jreclist_init(mp, &jreclist, &jreccache, JTYPE_WHITEOUT);
119226e603edSMatthew Dillon     error = vop_journal_operate_ap(&ap->a_head);
1193558b8e00SMatthew Dillon     if (error == 0) {
1194797e4fe9SMatthew Dillon 	TAILQ_FOREACH(jrec, &jreclist.list, user_entry) {
119526e603edSMatthew Dillon 	    jrecord_write_cred(jrec, NULL, ap->a_cred);
119628623bf9SMatthew Dillon 	    jrecord_write_path(jrec, JLEAF_PATH1, ap->a_nch->ncp);
1197558b8e00SMatthew Dillon 	}
1198558b8e00SMatthew Dillon     }
1199797e4fe9SMatthew Dillon     jreclist_done(mp, &jreclist, error);
1200558b8e00SMatthew Dillon     return (error);
1201558b8e00SMatthew Dillon }
1202558b8e00SMatthew Dillon 
1203b2f7ec6cSMatthew Dillon /*
120428623bf9SMatthew Dillon  * Journal vop_nremove { a_nch, a_cred }
1205b2f7ec6cSMatthew Dillon  */
1206558b8e00SMatthew Dillon static
1207558b8e00SMatthew Dillon int
journal_nremove(struct vop_nremove_args * ap)1208558b8e00SMatthew Dillon journal_nremove(struct vop_nremove_args *ap)
1209558b8e00SMatthew Dillon {
121026e603edSMatthew Dillon     struct jrecord_list jreclist;
121126e603edSMatthew Dillon     struct jrecord jreccache;
121226e603edSMatthew Dillon     struct jrecord *jrec;
1213558b8e00SMatthew Dillon     struct mount *mp;
1214558b8e00SMatthew Dillon     int error;
1215558b8e00SMatthew Dillon 
121666a1ddf5SMatthew Dillon     mp = ap->a_head.a_ops->head.vv_mount;
121726e603edSMatthew Dillon     if (jreclist_init(mp, &jreclist, &jreccache, JTYPE_REMOVE) &&
121828623bf9SMatthew Dillon 	ap->a_nch->ncp->nc_vp
121926e603edSMatthew Dillon     ) {
122028623bf9SMatthew Dillon 	jreclist_undo_file(&jreclist, ap->a_nch->ncp->nc_vp,
122126e603edSMatthew Dillon 			   JRUNDO_ALL|JRUNDO_GETVP|JRUNDO_CONDLINK, 0, -1);
122226e603edSMatthew Dillon     }
122326e603edSMatthew Dillon     error = vop_journal_operate_ap(&ap->a_head);
1224558b8e00SMatthew Dillon     if (error == 0) {
1225797e4fe9SMatthew Dillon 	TAILQ_FOREACH(jrec, &jreclist.list, user_entry) {
122626e603edSMatthew Dillon 	    jrecord_write_cred(jrec, NULL, ap->a_cred);
122728623bf9SMatthew Dillon 	    jrecord_write_path(jrec, JLEAF_PATH1, ap->a_nch->ncp);
1228558b8e00SMatthew Dillon 	}
1229558b8e00SMatthew Dillon     }
1230797e4fe9SMatthew Dillon     jreclist_done(mp, &jreclist, error);
1231558b8e00SMatthew Dillon     return (error);
1232558b8e00SMatthew Dillon }
12332281065eSMatthew Dillon 
1234b2f7ec6cSMatthew Dillon /*
123528623bf9SMatthew Dillon  * Journal vop_nmkdir { a_nch, a_vpp, a_cred, a_vap }
1236b2f7ec6cSMatthew Dillon  */
12372281065eSMatthew Dillon static
12382281065eSMatthew Dillon int
journal_nmkdir(struct vop_nmkdir_args * ap)12392281065eSMatthew Dillon journal_nmkdir(struct vop_nmkdir_args *ap)
12402281065eSMatthew Dillon {
124126e603edSMatthew Dillon     struct jrecord_list jreclist;
124226e603edSMatthew Dillon     struct jrecord jreccache;
124326e603edSMatthew Dillon     struct jrecord *jrec;
124482eaef15SMatthew Dillon     struct mount *mp;
12452281065eSMatthew Dillon     int error;
12462281065eSMatthew Dillon 
124766a1ddf5SMatthew Dillon     mp = ap->a_head.a_ops->head.vv_mount;
124826e603edSMatthew Dillon     jreclist_init(mp, &jreclist, &jreccache, JTYPE_MKDIR);
124926e603edSMatthew Dillon     error = vop_journal_operate_ap(&ap->a_head);
125082eaef15SMatthew Dillon     if (error == 0) {
1251797e4fe9SMatthew Dillon 	TAILQ_FOREACH(jrec, &jreclist.list, user_entry) {
125282eaef15SMatthew Dillon #if 0
125382eaef15SMatthew Dillon 	    if (jo->flags & MC_JOURNAL_WANT_AUDIT) {
125426e603edSMatthew Dillon 		jrecord_write_audit(jrec);
125582eaef15SMatthew Dillon 	    }
125682eaef15SMatthew Dillon #endif
125728623bf9SMatthew Dillon 	    jrecord_write_path(jrec, JLEAF_PATH1, ap->a_nch->ncp);
125826e603edSMatthew Dillon 	    jrecord_write_cred(jrec, NULL, ap->a_cred);
125926e603edSMatthew Dillon 	    jrecord_write_vattr(jrec, ap->a_vap);
126028623bf9SMatthew Dillon 	    jrecord_write_path(jrec, JLEAF_PATH1, ap->a_nch->ncp);
1261b2f7ec6cSMatthew Dillon 	    if (*ap->a_vpp)
126226e603edSMatthew Dillon 		jrecord_write_vnode_ref(jrec, *ap->a_vpp);
126382eaef15SMatthew Dillon 	}
126482eaef15SMatthew Dillon     }
1265797e4fe9SMatthew Dillon     jreclist_done(mp, &jreclist, error);
12662281065eSMatthew Dillon     return (error);
12672281065eSMatthew Dillon }
12682281065eSMatthew Dillon 
1269b2f7ec6cSMatthew Dillon /*
127028623bf9SMatthew Dillon  * Journal vop_nrmdir { a_nch, a_cred }
1271b2f7ec6cSMatthew Dillon  */
1272558b8e00SMatthew Dillon static
1273558b8e00SMatthew Dillon int
journal_nrmdir(struct vop_nrmdir_args * ap)1274558b8e00SMatthew Dillon journal_nrmdir(struct vop_nrmdir_args *ap)
1275558b8e00SMatthew Dillon {
127626e603edSMatthew Dillon     struct jrecord_list jreclist;
127726e603edSMatthew Dillon     struct jrecord jreccache;
127826e603edSMatthew Dillon     struct jrecord *jrec;
1279558b8e00SMatthew Dillon     struct mount *mp;
1280558b8e00SMatthew Dillon     int error;
1281558b8e00SMatthew Dillon 
128266a1ddf5SMatthew Dillon     mp = ap->a_head.a_ops->head.vv_mount;
128326e603edSMatthew Dillon     if (jreclist_init(mp, &jreclist, &jreccache, JTYPE_RMDIR)) {
128428623bf9SMatthew Dillon 	jreclist_undo_file(&jreclist, ap->a_nch->ncp->nc_vp,
128526e603edSMatthew Dillon 			   JRUNDO_VATTR|JRUNDO_GETVP, 0, 0);
128626e603edSMatthew Dillon     }
128726e603edSMatthew Dillon     error = vop_journal_operate_ap(&ap->a_head);
1288558b8e00SMatthew Dillon     if (error == 0) {
1289797e4fe9SMatthew Dillon 	TAILQ_FOREACH(jrec, &jreclist.list, user_entry) {
129026e603edSMatthew Dillon 	    jrecord_write_cred(jrec, NULL, ap->a_cred);
129128623bf9SMatthew Dillon 	    jrecord_write_path(jrec, JLEAF_PATH1, ap->a_nch->ncp);
1292558b8e00SMatthew Dillon 	}
1293558b8e00SMatthew Dillon     }
1294797e4fe9SMatthew Dillon     jreclist_done(mp, &jreclist, error);
1295558b8e00SMatthew Dillon     return (error);
1296558b8e00SMatthew Dillon }
1297558b8e00SMatthew Dillon 
1298b2f7ec6cSMatthew Dillon /*
129928623bf9SMatthew Dillon  * Journal vop_nrename { a_fnch, a_tnch, a_cred }
1300b2f7ec6cSMatthew Dillon  */
1301558b8e00SMatthew Dillon static
1302558b8e00SMatthew Dillon int
journal_nrename(struct vop_nrename_args * ap)1303558b8e00SMatthew Dillon journal_nrename(struct vop_nrename_args *ap)
1304558b8e00SMatthew Dillon {
130526e603edSMatthew Dillon     struct jrecord_list jreclist;
130626e603edSMatthew Dillon     struct jrecord jreccache;
130726e603edSMatthew Dillon     struct jrecord *jrec;
1308558b8e00SMatthew Dillon     struct mount *mp;
1309558b8e00SMatthew Dillon     int error;
1310558b8e00SMatthew Dillon 
131166a1ddf5SMatthew Dillon     mp = ap->a_head.a_ops->head.vv_mount;
131226e603edSMatthew Dillon     if (jreclist_init(mp, &jreclist, &jreccache, JTYPE_RENAME) &&
131328623bf9SMatthew Dillon 	ap->a_tnch->ncp->nc_vp
131426e603edSMatthew Dillon     ) {
131528623bf9SMatthew Dillon 	jreclist_undo_file(&jreclist, ap->a_tnch->ncp->nc_vp,
131626e603edSMatthew Dillon 			   JRUNDO_ALL|JRUNDO_GETVP|JRUNDO_CONDLINK, 0, -1);
131726e603edSMatthew Dillon     }
131826e603edSMatthew Dillon     error = vop_journal_operate_ap(&ap->a_head);
1319558b8e00SMatthew Dillon     if (error == 0) {
1320797e4fe9SMatthew Dillon 	TAILQ_FOREACH(jrec, &jreclist.list, user_entry) {
132126e603edSMatthew Dillon 	    jrecord_write_cred(jrec, NULL, ap->a_cred);
132228623bf9SMatthew Dillon 	    jrecord_write_path(jrec, JLEAF_PATH1, ap->a_fnch->ncp);
132328623bf9SMatthew Dillon 	    jrecord_write_path(jrec, JLEAF_PATH2, ap->a_tnch->ncp);
1324558b8e00SMatthew Dillon 	}
1325558b8e00SMatthew Dillon     }
1326797e4fe9SMatthew Dillon     jreclist_done(mp, &jreclist, error);
1327558b8e00SMatthew Dillon     return (error);
1328558b8e00SMatthew Dillon }
1329558b8e00SMatthew Dillon 
1330