--- a/sys/kern/vfs_jops.c +++ b/sys/kern/vfs_jops.c @@ -1021,6 +1021,24 @@ struct mount *mp; void *save; int error; + struct uio uio_copy; + struct iovec uio_one_iovec; + + /* + * The underlying VOP consumes the uio (uiomove advances the iovecs + * in place), so the attribute value must be snapshotted BEFORE the + * operation, exactly like journal_write() does. + */ + uio_copy = *ap->a_uio; + if (uio_copy.uio_iovcnt == 1) { + uio_one_iovec = ap->a_uio->uio_iov[0]; + uio_copy.uio_iov = &uio_one_iovec; + } else { + uio_copy.uio_iov = kmalloc(uio_copy.uio_iovcnt * sizeof(struct iovec), + M_JOURNAL, M_WAITOK); + bcopy(ap->a_uio->uio_iov, uio_copy.uio_iov, + uio_copy.uio_iovcnt * sizeof(struct iovec)); + } mp = ap->a_head.a_ops->head.vv_mount; jreclist_init(mp, &jreclist, &jreccache, JTYPE_SETEXTATTR); @@ -1036,11 +1054,14 @@ jrecord_leaf(jrec, JLEAF_ATTRNAME, ap->a_attrname, strlen(ap->a_attrname)); save = jrecord_push(jrec, JTYPE_REDO); - jrecord_write_uio(jrec, JLEAF_FILEDATA, ap->a_uio); + jrecord_write_uio(jrec, JLEAF_FILEDATA, &uio_copy); jrecord_pop(jrec, save); } } jreclist_done(mp, &jreclist, error); + + if (uio_copy.uio_iov != &uio_one_iovec) + kfree(uio_copy.uio_iov, M_JOURNAL); return (error); }