hammer2 - cluster API, preliminary implementation of multi-chain updates
authorMatthew Dillon <dillon@apollo.backplane.com>
Thu, 20 Mar 2014 00:28:42 +0000 (17:28 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Sat, 22 Mar 2014 01:02:45 +0000 (18:02 -0700)
* Separate out read-only from read-write access to cluster data.

* Implement hammer2_cluster_modsync() and call in appropriate places.

* Clean up some media inode fields not currently in-use.

sys/vfs/hammer2/hammer2.h
sys/vfs/hammer2/hammer2_cluster.c
sys/vfs/hammer2/hammer2_disk.h
sys/vfs/hammer2/hammer2_inode.c
sys/vfs/hammer2/hammer2_ioctl.c
sys/vfs/hammer2/hammer2_subr.c
sys/vfs/hammer2/hammer2_vfsops.c
sys/vfs/hammer2/hammer2_vnops.c

index 1c5f274..12d2c30 100644 (file)
@@ -757,12 +757,12 @@ void hammer2_mount_exlock(hammer2_mount_t *hmp);
 void hammer2_mount_shlock(hammer2_mount_t *hmp);
 void hammer2_mount_unlock(hammer2_mount_t *hmp);
 
-int hammer2_get_dtype(hammer2_inode_data_t *ipdata);
-int hammer2_get_vtype(hammer2_inode_data_t *ipdata);
+int hammer2_get_dtype(const hammer2_inode_data_t *ipdata);
+int hammer2_get_vtype(const hammer2_inode_data_t *ipdata);
 u_int8_t hammer2_get_obj_type(enum vtype vtype);
 void hammer2_time_to_timespec(u_int64_t xtime, struct timespec *ts);
-u_int64_t hammer2_timespec_to_time(struct timespec *ts);
-u_int32_t hammer2_to_unix_xid(uuid_t *uuid);
+u_int64_t hammer2_timespec_to_time(const struct timespec *ts);
+u_int32_t hammer2_to_unix_xid(const uuid_t *uuid);
 void hammer2_guid_to_uuid(uuid_t *uuid, u_int32_t guid);
 
 hammer2_key_t hammer2_dirhash(const unsigned char *name, size_t len);
@@ -770,7 +770,8 @@ int hammer2_getradix(size_t bytes);
 
 int hammer2_calc_logical(hammer2_inode_t *ip, hammer2_off_t uoff,
                        hammer2_key_t *lbasep, hammer2_key_t *leofp);
-int hammer2_calc_physical(hammer2_inode_t *ip, hammer2_inode_data_t *ipdata,
+int hammer2_calc_physical(hammer2_inode_t *ip,
+                       const hammer2_inode_data_t *ipdata,
                        hammer2_key_t lbase);
 void hammer2_update_time(uint64_t *timep);
 void hammer2_adjreadcounter(hammer2_blockref_t *bref, size_t bytes);
@@ -980,7 +981,8 @@ void hammer2_freemap_adjust(hammer2_trans_t *trans, hammer2_mount_t *hmp,
  */
 u_int hammer2_cluster_bytes(hammer2_cluster_t *cluster);
 uint8_t hammer2_cluster_type(hammer2_cluster_t *cluster);
-hammer2_media_data_t *hammer2_cluster_data(hammer2_cluster_t *cluster);
+const hammer2_media_data_t *hammer2_cluster_data(hammer2_cluster_t *cluster);
+hammer2_media_data_t *hammer2_cluster_wdata(hammer2_cluster_t *cluster);
 hammer2_cluster_t *hammer2_cluster_from_chain(hammer2_chain_t *chain);
 int hammer2_cluster_modified(hammer2_cluster_t *cluster);
 int hammer2_cluster_unlinked(hammer2_cluster_t *cluster);
@@ -1014,6 +1016,7 @@ hammer2_inode_data_t *hammer2_cluster_modify_ip(hammer2_trans_t *trans,
                        int flags);
 void hammer2_cluster_modify(hammer2_trans_t *trans, hammer2_cluster_t *cluster,
                        int flags);
+void hammer2_cluster_modsync(hammer2_cluster_t *cluster);
 hammer2_cluster_t *hammer2_cluster_lookup_init(hammer2_cluster_t *cparent,
                        int flags);
 void hammer2_cluster_lookup_done(hammer2_cluster_t *cparent);
index 15caffe..744d209 100644 (file)
@@ -66,12 +66,23 @@ hammer2_cluster_type(hammer2_cluster_t *cluster)
        return(cluster->focus->bref.type);
 }
 
-hammer2_media_data_t *
+/*
+ * NOTE: When modifying a cluster object via hammer2_cluster_wdata()
+ *      and hammer2_cluster_modsync(), remember that block array
+ *      entries are not copied to the elements of the cluster.
+ */
+const hammer2_media_data_t *
 hammer2_cluster_data(hammer2_cluster_t *cluster)
 {
        return(cluster->focus->data);
 }
 
+hammer2_media_data_t *
+hammer2_cluster_wdata(hammer2_cluster_t *cluster)
+{
+       return(cluster->focus->data);
+}
+
 int
 hammer2_cluster_modified(hammer2_cluster_t *cluster)
 {
@@ -539,7 +550,7 @@ hammer2_cluster_modify_ip(hammer2_trans_t *trans, hammer2_inode_t *ip,
        hammer2_inode_repoint(ip, NULL, cluster);
        if (ip->vp)
                vsetisdirty(ip->vp);
-       return (&hammer2_cluster_data(cluster)->ipdata);
+       return (&hammer2_cluster_wdata(cluster)->ipdata);
 }
 
 /*
@@ -570,6 +581,53 @@ hammer2_cluster_modify(hammer2_trans_t *trans, hammer2_cluster_t *cluster,
  */
 /* hammer2_cluster_modsync() */
 
+void
+hammer2_cluster_modsync(hammer2_cluster_t *cluster)
+{
+       hammer2_chain_t *focus;
+       hammer2_chain_t *scan;
+       const hammer2_inode_data_t *ripdata;
+       hammer2_inode_data_t *wipdata;
+       int i;
+
+       focus = cluster->focus;
+       KKASSERT(focus->flags & HAMMER2_CHAIN_MODIFIED);
+
+       for (i = 0; i < cluster->nchains; ++i) {
+               scan = cluster->array[i];
+               if (scan == NULL || scan == focus)
+                       continue;
+               KKASSERT(scan->flags & HAMMER2_CHAIN_MODIFIED);
+               KKASSERT(focus->bytes == scan->bytes &&
+                        focus->bref.type == scan->bref.type);
+               switch(focus->bref.type) {
+               case HAMMER2_BREF_TYPE_INODE:
+                       ripdata = &focus->data->ipdata;
+                       wipdata = &scan->data->ipdata;
+                       if ((ripdata->op_flags &
+                           HAMMER2_OPFLAG_DIRECTDATA) == 0) {
+                               bcopy(ripdata, wipdata,
+                                     offsetof(hammer2_inode_data_t, u));
+                               break;
+                       }
+                       /* fall through */
+               case HAMMER2_BREF_TYPE_DATA:
+                       bcopy(focus->data, scan->data, focus->bytes);
+                       break;
+               case HAMMER2_BREF_TYPE_FREEMAP_NODE:
+               case HAMMER2_BREF_TYPE_FREEMAP_LEAF:
+               case HAMMER2_BREF_TYPE_FREEMAP:
+               case HAMMER2_BREF_TYPE_VOLUME:
+                       panic("hammer2_cluster_modsync: illegal node type");
+                       /* NOT REACHED */
+                       break;
+               default:
+                       panic("hammer2_cluster_modsync: unknown node type");
+                       break;
+               }
+       }
+}
+
 /*
  * Lookup initialization/completion API
  */
@@ -947,7 +1005,8 @@ hammer2_cluster_snapshot(hammer2_trans_t *trans, hammer2_cluster_t *ocluster,
 {
        hammer2_mount_t *hmp;
        hammer2_cluster_t *ncluster;
-       hammer2_inode_data_t *ipdata;
+       const hammer2_inode_data_t *ipdata;
+       hammer2_inode_data_t *wipdata;
        hammer2_inode_t *nip;
        size_t name_len;
        hammer2_key_t lhc;
@@ -984,17 +1043,19 @@ hammer2_cluster_snapshot(hammer2_trans_t *trans, hammer2_cluster_t *ocluster,
                                   pfs->name, name_len, &ncluster, &error);
 
        if (nip) {
-               ipdata = hammer2_cluster_modify_ip(trans, nip, ncluster, 0);
-               ipdata->pfs_type = HAMMER2_PFSTYPE_SNAPSHOT;
-               kern_uuidgen(&ipdata->pfs_fsid, 1);
+               wipdata = hammer2_cluster_modify_ip(trans, nip, ncluster, 0);
+               wipdata->pfs_type = HAMMER2_PFSTYPE_SNAPSHOT;
+               kern_uuidgen(&wipdata->pfs_fsid, 1);
                if (ocluster->focus->flags & HAMMER2_CHAIN_PFSROOT)
-                       ipdata->pfs_clid = opfs_clid;
+                       wipdata->pfs_clid = opfs_clid;
                else
-                       kern_uuidgen(&ipdata->pfs_clid, 1);
+                       kern_uuidgen(&wipdata->pfs_clid, 1);
                hammer2_cluster_set_chainflags(ncluster, HAMMER2_CHAIN_PFSROOT);
 
                /* XXX hack blockset copy */
-               ipdata->u.blockset = ocluster->focus->data->ipdata.u.blockset;
+               /* XXX doesn't work with real cluster */
+               KKASSERT(ocluster->nchains == 1);
+               wipdata->u.blockset = ocluster->focus->data->ipdata.u.blockset;
 
                hammer2_inode_unlock_ex(nip, ncluster);
        }
index 558f0ab..e65fbd9 100644 (file)
@@ -752,7 +752,7 @@ struct hammer2_inode_data {
         * allocations under inode, not counting the inode itself.
         * 0/0 indicates empty entry.  fully set-associative.
         */
-       hammer2_off_t   freezones[4];   /* 00E0/E8/F0/F8 base|radix */
+       hammer2_off_t   reservedE0[4];  /* 00E0/E8/F0/F8 */
 
        unsigned char   filename[HAMMER2_INODE_MAXNAME];
                                        /* 0100-01FF (256 char, unterminated) */
index feb2fe2..9d295dd 100644 (file)
@@ -81,7 +81,7 @@ hammer2_inode_cmp(hammer2_inode_t *ip1, hammer2_inode_t *ip2)
 hammer2_cluster_t *
 hammer2_inode_lock_ex(hammer2_inode_t *ip)
 {
-       hammer2_inode_data_t *ipdata;
+       const hammer2_inode_data_t *ipdata;
        hammer2_cluster_t *cluster;
        hammer2_chain_t *chain;
        hammer2_chain_t *ochain;
@@ -158,7 +158,7 @@ hammer2_inode_unlock_ex(hammer2_inode_t *ip, hammer2_cluster_t *cluster)
 hammer2_cluster_t *
 hammer2_inode_lock_sh(hammer2_inode_t *ip)
 {
-       hammer2_inode_data_t *ipdata;
+       const hammer2_inode_data_t *ipdata;
        hammer2_cluster_t *cluster;
        hammer2_chain_core_t *core;
        hammer2_chain_t *chain;
@@ -369,7 +369,7 @@ hammer2_inode_drop(hammer2_inode_t *ip)
 struct vnode *
 hammer2_igetv(hammer2_inode_t *ip, hammer2_cluster_t *cparent, int *errorp)
 {
-       hammer2_inode_data_t *ipdata;
+       const hammer2_inode_data_t *ipdata;
        hammer2_pfsmount_t *pmp;
        struct vnode *vp;
        ccms_state_t ostate;
@@ -520,8 +520,8 @@ hammer2_inode_get(hammer2_pfsmount_t *pmp, hammer2_inode_t *dip,
                  hammer2_cluster_t *cluster)
 {
        hammer2_inode_t *nip;
-       hammer2_inode_data_t *iptmp;
-       hammer2_inode_data_t *nipdata;
+       const hammer2_inode_data_t *iptmp;
+       const hammer2_inode_data_t *nipdata;
 
        KKASSERT(hammer2_cluster_type(cluster) == HAMMER2_BREF_TYPE_INODE);
 
@@ -626,7 +626,7 @@ hammer2_inode_create(hammer2_trans_t *trans, hammer2_inode_t *dip,
                     const uint8_t *name, size_t name_len,
                     hammer2_cluster_t **clusterp, int *errorp)
 {
-       hammer2_inode_data_t *dipdata;
+       const hammer2_inode_data_t *dipdata;
        hammer2_inode_data_t *nipdata;
        hammer2_cluster_t *cluster;
        hammer2_cluster_t *cparent;
@@ -716,10 +716,11 @@ retry:
         *
         * NOTE: nipdata will have chain's blockset data.
         */
-       nipdata = &hammer2_cluster_data(cluster)->ipdata;
+       KKASSERT(cluster->focus->flags & HAMMER2_CHAIN_MODIFIED);
+       nipdata = &hammer2_cluster_wdata(cluster)->ipdata;
        nipdata->inum = trans->inode_tid;
        nip = hammer2_inode_get(dip->pmp, dip, cluster);
-       nipdata = &hammer2_cluster_data(cluster)->ipdata;
+       nipdata = &hammer2_cluster_wdata(cluster)->ipdata;
 
        if (vap) {
                KKASSERT(trans->inodes_created == 0);
@@ -809,7 +810,7 @@ hammer2_hardlink_shiftup(hammer2_trans_t *trans, hammer2_cluster_t *cluster,
                        hammer2_inode_t *dip, hammer2_cluster_t *dcluster,
                        int nlinks, int *errorp)
 {
-       hammer2_inode_data_t *iptmp;
+       const hammer2_inode_data_t *iptmp;
        hammer2_inode_data_t *nipdata;
        hammer2_cluster_t *xcluster;
        hammer2_key_t key_dummy;
@@ -909,12 +910,13 @@ retry:
         * a name after its inode number.
         */
        hammer2_cluster_modify(trans, cluster, 0);
-       nipdata = &hammer2_cluster_data(cluster)->ipdata;
+       nipdata = &hammer2_cluster_wdata(cluster)->ipdata;
        ksnprintf(nipdata->filename, sizeof(nipdata->filename),
                  "0x%016jx", (intmax_t)nipdata->inum);
        nipdata->name_len = strlen(nipdata->filename);
        nipdata->name_key = lhc;
        nipdata->nlinks += nlinks;
+       hammer2_cluster_modsync(cluster);
 }
 
 /*
@@ -937,7 +939,7 @@ hammer2_inode_connect(hammer2_trans_t *trans,
                      const uint8_t *name, size_t name_len,
                      hammer2_key_t lhc)
 {
-       hammer2_inode_data_t *ipdata;
+       hammer2_inode_data_t *wipdata;
        hammer2_cluster_t *ocluster;
        hammer2_cluster_t *ncluster;
        hammer2_key_t key_dummy;
@@ -1070,15 +1072,16 @@ hammer2_inode_connect(hammer2_trans_t *trans,
                 */
                hammer2_cluster_modify(trans, ncluster, 0);
                KKASSERT(name_len < HAMMER2_INODE_MAXNAME);
-               ipdata = &hammer2_cluster_data(ncluster)->ipdata;
-               bcopy(name, ipdata->filename, name_len);
-               ipdata->name_key = lhc;
-               ipdata->name_len = name_len;
-               ipdata->target_type =
+               wipdata = &hammer2_cluster_wdata(ncluster)->ipdata;
+               bcopy(name, wipdata->filename, name_len);
+               wipdata->name_key = lhc;
+               wipdata->name_len = name_len;
+               wipdata->target_type =
                                hammer2_cluster_data(ocluster)->ipdata.type;
-               ipdata->type = HAMMER2_OBJTYPE_HARDLINK;
-               ipdata->inum = hammer2_cluster_data(ocluster)->ipdata.inum;
-               ipdata->nlinks = 1;
+               wipdata->type = HAMMER2_OBJTYPE_HARDLINK;
+               wipdata->inum = hammer2_cluster_data(ocluster)->ipdata.inum;
+               wipdata->nlinks = 1;
+               hammer2_cluster_modsync(ncluster);
                hammer2_cluster_unlock(ncluster);
                ncluster = ocluster;
                ocluster = NULL;
@@ -1089,13 +1092,14 @@ hammer2_inode_connect(hammer2_trans_t *trans,
                 * has already been set up.
                 */
                hammer2_cluster_modify(trans, ncluster, 0);
-               ipdata = &hammer2_cluster_data(ncluster)->ipdata;
+               wipdata = &hammer2_cluster_wdata(ncluster)->ipdata;
 
                KKASSERT(name_len < HAMMER2_INODE_MAXNAME);
-               bcopy(name, ipdata->filename, name_len);
-               ipdata->name_key = lhc;
-               ipdata->name_len = name_len;
-               ipdata->nlinks = 1;
+               bcopy(name, wipdata->filename, name_len);
+               wipdata->name_key = lhc;
+               wipdata->name_len = name_len;
+               wipdata->nlinks = 1;
+               hammer2_cluster_modsync(ncluster);
        }
 
        /*
@@ -1205,7 +1209,8 @@ hammer2_unlink_file(hammer2_trans_t *trans, hammer2_inode_t *dip,
                    const uint8_t *name, size_t name_len,
                    int isdir, int *hlinkp, struct nchandle *nch)
 {
-       hammer2_inode_data_t *ipdata;
+       const hammer2_inode_data_t *ripdata;
+       hammer2_inode_data_t *wipdata;
        hammer2_cluster_t *cparent;
        hammer2_cluster_t *ocluster;
        hammer2_cluster_t *cluster;
@@ -1233,9 +1238,9 @@ hammer2_unlink_file(hammer2_trans_t *trans, hammer2_inode_t *dip,
                                     0, &ddflag);
        while (cluster) {
                if (hammer2_cluster_type(cluster) == HAMMER2_BREF_TYPE_INODE) {
-                       ipdata = &hammer2_cluster_data(cluster)->ipdata;
-                       if (ipdata->name_len == name_len &&
-                           bcmp(ipdata->filename, name, name_len) == 0) {
+                       ripdata = &hammer2_cluster_data(cluster)->ipdata;
+                       if (ripdata->name_len == name_len &&
+                           bcmp(ripdata->filename, name, name_len) == 0) {
                                break;
                        }
                }
@@ -1254,12 +1259,12 @@ hammer2_unlink_file(hammer2_trans_t *trans, hammer2_inode_t *dip,
                error = ENOENT;
                goto done;
        }
-       ipdata = &hammer2_cluster_data(cluster)->ipdata;
-       type = ipdata->type;
+       ripdata = &hammer2_cluster_data(cluster)->ipdata;
+       type = ripdata->type;
        if (type == HAMMER2_OBJTYPE_HARDLINK) {
                if (hlinkp)
                        *hlinkp = 1;
-               type = ipdata->target_type;
+               type = ripdata->target_type;
        }
 
        if (type == HAMMER2_OBJTYPE_DIRECTORY && isdir == 0) {
@@ -1282,7 +1287,7 @@ hammer2_unlink_file(hammer2_trans_t *trans, hammer2_inode_t *dip,
         * Lock ownership is transfered to cluster.  ocluster is merely
         * referenced.
         */
-       if (ipdata->type == HAMMER2_OBJTYPE_HARDLINK) {
+       if (ripdata->type == HAMMER2_OBJTYPE_HARDLINK) {
                hammer2_cluster_unlock(cparent);
                cparent = NULL;
 
@@ -1364,17 +1369,21 @@ hammer2_unlink_file(hammer2_trans_t *trans, hammer2_inode_t *dip,
         */
        KKASSERT(cluster != NULL);
        hammer2_cluster_modify(trans, cluster, 0);
-       ipdata = &hammer2_cluster_data(cluster)->ipdata;
-       --ipdata->nlinks;
-       if ((int64_t)ipdata->nlinks < 0)        /* XXX debugging */
-               ipdata->nlinks = 0;
-       if (ipdata->nlinks == 0) {
+       wipdata = &hammer2_cluster_wdata(cluster)->ipdata;
+       ripdata = wipdata;
+       --wipdata->nlinks;
+       if ((int64_t)wipdata->nlinks < 0) {     /* XXX debugging */
+               wipdata->nlinks = 0;
+       }
+       hammer2_cluster_modsync(cluster);
+
+       if (wipdata->nlinks == 0) {
                if ((cluster->focus->flags & HAMMER2_CHAIN_PFSROOT) &&
                    cluster->pmp) {
                        error = EINVAL;
                        kprintf("hammer2: PFS \"%s\" cannot be deleted "
                                "while still mounted\n",
-                               ipdata->filename);
+                               wipdata->filename);
                        goto done;
                }
                if (nch && cache_isopen(nch)) {
@@ -1382,7 +1391,7 @@ hammer2_unlink_file(hammer2_trans_t *trans, hammer2_inode_t *dip,
                        hammer2_cluster_set_chainflags(cluster,
                                                        HAMMER2_CHAIN_UNLINKED);
                        hammer2_inode_move_to_hidden(trans, &cluster,
-                                                    ipdata->inum);
+                                                    wipdata->inum);
                } else {
                        hammer2_cluster_delete(trans, cluster, 0);
                }
@@ -1410,7 +1419,7 @@ hammer2_inode_install_hidden(hammer2_pfsmount_t *pmp)
        hammer2_cluster_t *cparent;
        hammer2_cluster_t *cluster;
        hammer2_cluster_t *scan;
-       hammer2_inode_data_t *ipdata;
+       hammer2_inode_data_t *wipdata;
        hammer2_key_t key_dummy;
        hammer2_key_t key_next;
        int ddflag;
@@ -1470,11 +1479,13 @@ hammer2_inode_install_hidden(hammer2_pfsmount_t *pmp)
                                       HAMMER2_BREF_TYPE_INODE,
                                       HAMMER2_INODE_BYTES);
        hammer2_inode_unlock_ex(pmp->iroot, cparent);
+
        hammer2_cluster_modify(&trans, cluster, 0);
-       ipdata = &hammer2_cluster_data(cluster)->ipdata;
-       ipdata->type = HAMMER2_OBJTYPE_DIRECTORY;
-       ipdata->inum = HAMMER2_INODE_HIDDENDIR;
-       ipdata->nlinks = 1;
+       wipdata = &hammer2_cluster_wdata(cluster)->ipdata;
+       wipdata->type = HAMMER2_OBJTYPE_DIRECTORY;
+       wipdata->inum = HAMMER2_INODE_HIDDENDIR;
+       wipdata->nlinks = 1;
+       hammer2_cluster_modsync(cluster);
        kprintf("hammer2: PFS root missing hidden directory, creating\n");
 
        pmp->ihidden = hammer2_inode_get(pmp, pmp->iroot, cluster);
@@ -1531,15 +1542,16 @@ hammer2_hardlink_consolidate(hammer2_trans_t *trans,
                             hammer2_cluster_t *cdcluster,
                             int nlinks)
 {
-       hammer2_inode_data_t *ipdata;
+       const hammer2_inode_data_t *ripdata;
+       hammer2_inode_data_t *wipdata;
        hammer2_cluster_t *cluster;
        hammer2_cluster_t *ncluster;
        int error;
 
        cluster = *clusterp;
-       ipdata = &hammer2_cluster_data(cluster)->ipdata;
+       ripdata = &hammer2_cluster_data(cluster)->ipdata;
        if (nlinks == 0 &&                      /* no hardlink needed */
-           (ipdata->name_key & HAMMER2_DIRHASH_VISIBLE)) {
+           (ripdata->name_key & HAMMER2_DIRHASH_VISIBLE)) {
                return (0);
        }
 
@@ -1554,13 +1566,15 @@ hammer2_hardlink_consolidate(hammer2_trans_t *trans,
         * this is already a hardlink target, all we need to do is adjust
         * the link count.
         */
-       ipdata = &hammer2_cluster_data(cluster)->ipdata;
+       ripdata = &hammer2_cluster_data(cluster)->ipdata;
        if (cdip == ip->pip &&
-           (ipdata->name_key & HAMMER2_DIRHASH_VISIBLE) == 0) {
+           (ripdata->name_key & HAMMER2_DIRHASH_VISIBLE) == 0) {
                if (nlinks) {
                        hammer2_cluster_modify(trans, cluster, 0);
-                       ipdata = &hammer2_cluster_data(cluster)->ipdata;
-                       ipdata->nlinks += nlinks;
+                       wipdata = &hammer2_cluster_wdata(cluster)->ipdata;
+                       wipdata->nlinks += nlinks;
+                       hammer2_cluster_modsync(cluster);
+                       ripdata = wipdata;
                }
                error = 0;
                goto done;
@@ -1573,9 +1587,9 @@ hammer2_hardlink_consolidate(hammer2_trans_t *trans,
         * a hardlink target and only needs to be deleted.
         */
        KKASSERT((cluster->focus->flags & HAMMER2_CHAIN_DELETED) == 0);
-       ipdata = &hammer2_cluster_data(cluster)->ipdata;
-       KKASSERT(ipdata->type != HAMMER2_OBJTYPE_HARDLINK);
-       if (ipdata->name_key & HAMMER2_DIRHASH_VISIBLE) {
+       ripdata = &hammer2_cluster_data(cluster)->ipdata;
+       KKASSERT(ripdata->type != HAMMER2_OBJTYPE_HARDLINK);
+       if (ripdata->name_key & HAMMER2_DIRHASH_VISIBLE) {
                /*
                 * We are going to duplicate cluster later, causing its
                 * media block to be shifted to the duplicate.  Even though
@@ -1592,40 +1606,42 @@ hammer2_hardlink_consolidate(hammer2_trans_t *trans,
                                                 HAMMER2_DELDUP_RECORE);
                KKASSERT((ncluster->focus->flags &
                         HAMMER2_CHAIN_DUPLICATED) == 0);
-               ipdata = &hammer2_cluster_data(ncluster)->ipdata;
-               ipdata->target_type = ipdata->type;
-               ipdata->type = HAMMER2_OBJTYPE_HARDLINK;
-               ipdata->uflags = 0;
-               ipdata->rmajor = 0;
-               ipdata->rminor = 0;
-               ipdata->ctime = 0;
-               ipdata->mtime = 0;
-               ipdata->atime = 0;
-               ipdata->btime = 0;
-               bzero(&ipdata->uid, sizeof(ipdata->uid));
-               bzero(&ipdata->gid, sizeof(ipdata->gid));
-               ipdata->op_flags = HAMMER2_OPFLAG_DIRECTDATA;
-               ipdata->cap_flags = 0;
-               ipdata->mode = 0;
-               ipdata->size = 0;
-               ipdata->nlinks = 1;
-               ipdata->iparent = 0;    /* XXX */
-               ipdata->pfs_type = 0;
-               ipdata->pfs_inum = 0;
-               bzero(&ipdata->pfs_clid, sizeof(ipdata->pfs_clid));
-               bzero(&ipdata->pfs_fsid, sizeof(ipdata->pfs_fsid));
-               ipdata->data_quota = 0;
-               ipdata->data_count = 0;
-               ipdata->inode_quota = 0;
-               ipdata->inode_count = 0;
-               ipdata->attr_tid = 0;
-               ipdata->dirent_tid = 0;
-               bzero(&ipdata->u, sizeof(ipdata->u));
+               wipdata = &hammer2_cluster_wdata(ncluster)->ipdata;
+               wipdata->target_type = wipdata->type;
+               wipdata->type = HAMMER2_OBJTYPE_HARDLINK;
+               wipdata->uflags = 0;
+               wipdata->rmajor = 0;
+               wipdata->rminor = 0;
+               wipdata->ctime = 0;
+               wipdata->mtime = 0;
+               wipdata->atime = 0;
+               wipdata->btime = 0;
+               bzero(&wipdata->uid, sizeof(wipdata->uid));
+               bzero(&wipdata->gid, sizeof(wipdata->gid));
+               wipdata->op_flags = HAMMER2_OPFLAG_DIRECTDATA;
+               wipdata->cap_flags = 0;
+               wipdata->mode = 0;
+               wipdata->size = 0;
+               wipdata->nlinks = 1;
+               wipdata->iparent = 0;   /* XXX */
+               wipdata->pfs_type = 0;
+               wipdata->pfs_inum = 0;
+               bzero(&wipdata->pfs_clid, sizeof(wipdata->pfs_clid));
+               bzero(&wipdata->pfs_fsid, sizeof(wipdata->pfs_fsid));
+               wipdata->data_quota = 0;
+               wipdata->data_count = 0;
+               wipdata->inode_quota = 0;
+               wipdata->inode_count = 0;
+               wipdata->attr_tid = 0;
+               wipdata->dirent_tid = 0;
+               bzero(&wipdata->u, sizeof(wipdata->u));
                /* XXX transaction ids */
+               hammer2_cluster_modsync(ncluster);
        } else {
                hammer2_cluster_delete(trans, cluster, 0);
                ncluster = NULL;
        }
+       ripdata = wipdata;
 
        /*
         * cluster represents the hardlink target and is now flagged deleted.
@@ -1694,7 +1710,7 @@ hammer2_hardlink_deconsolidate(hammer2_trans_t *trans,
 int
 hammer2_hardlink_find(hammer2_inode_t *dip, hammer2_cluster_t *cluster)
 {
-       hammer2_inode_data_t *ipdata;
+       const hammer2_inode_data_t *ipdata;
        hammer2_cluster_t *cparent;
        hammer2_cluster_t *rcluster;
        hammer2_inode_t *ip;
@@ -1815,30 +1831,36 @@ void
 hammer2_inode_fsync(hammer2_trans_t *trans, hammer2_inode_t *ip, 
                    hammer2_cluster_t *cparent)
 {
-       hammer2_inode_data_t *ipdata;
+       const hammer2_inode_data_t *ripdata;
+       hammer2_inode_data_t *wipdata;
        hammer2_cluster_t *dparent;
        hammer2_cluster_t *cluster;
        hammer2_key_t lbase;
        hammer2_key_t key_next;
+       int dosync = 0;
        int ddflag;
 
-       ipdata = &hammer2_cluster_data(cparent)->ipdata;    /* target file */
+       ripdata = &hammer2_cluster_data(cparent)->ipdata;    /* target file */
 
        if (ip->flags & HAMMER2_INODE_MTIME) {
-               ipdata = hammer2_cluster_modify_ip(trans, ip, cparent, 0);
+               wipdata = hammer2_cluster_modify_ip(trans, ip, cparent, 0);
                atomic_clear_int(&ip->flags, HAMMER2_INODE_MTIME);
-               ipdata->mtime = ip->mtime;
+               wipdata->mtime = ip->mtime;
+               dosync = 1;
+               ripdata = wipdata;
        }
-       if ((ip->flags & HAMMER2_INODE_RESIZED) && ip->size < ipdata->size) {
-               ipdata = hammer2_cluster_modify_ip(trans, ip, cparent, 0);
-               ipdata->size = ip->size;
+       if ((ip->flags & HAMMER2_INODE_RESIZED) && ip->size < ripdata->size) {
+               wipdata = hammer2_cluster_modify_ip(trans, ip, cparent, 0);
+               wipdata->size = ip->size;
+               dosync = 1;
+               ripdata = wipdata;
                atomic_clear_int(&ip->flags, HAMMER2_INODE_RESIZED);
 
                /*
                 * We must delete any chains beyond the EOF.  The chain
                 * straddling the EOF will be pending in the bioq.
                 */
-               lbase = (ipdata->size + HAMMER2_PBUFMASK64) &
+               lbase = (ripdata->size + HAMMER2_PBUFMASK64) &
                        ~HAMMER2_PBUFMASK64;
                dparent = hammer2_cluster_lookup_init(&ip->cluster, 0);
                cluster = hammer2_cluster_lookup(dparent, &key_next,
@@ -1867,19 +1889,24 @@ hammer2_inode_fsync(hammer2_trans_t *trans, hammer2_inode_t *ip,
                }
                hammer2_cluster_lookup_done(dparent);
        } else
-       if ((ip->flags & HAMMER2_INODE_RESIZED) && ip->size > ipdata->size) {
-               ipdata = hammer2_cluster_modify_ip(trans, ip, cparent, 0);
-               ipdata->size = ip->size;
+       if ((ip->flags & HAMMER2_INODE_RESIZED) && ip->size > ripdata->size) {
+               wipdata = hammer2_cluster_modify_ip(trans, ip, cparent, 0);
+               wipdata->size = ip->size;
                atomic_clear_int(&ip->flags, HAMMER2_INODE_RESIZED);
 
                /*
                 * When resizing larger we may not have any direct-data
                 * available.
                 */
-               if ((ipdata->op_flags & HAMMER2_OPFLAG_DIRECTDATA) &&
+               if ((wipdata->op_flags & HAMMER2_OPFLAG_DIRECTDATA) &&
                    ip->size > HAMMER2_EMBEDDED_BYTES) {
-                       ipdata->op_flags &= ~HAMMER2_OPFLAG_DIRECTDATA;
-                       bzero(&ipdata->u.blockset, sizeof(ipdata->u.blockset));
+                       wipdata->op_flags &= ~HAMMER2_OPFLAG_DIRECTDATA;
+                       bzero(&wipdata->u.blockset,
+                             sizeof(wipdata->u.blockset));
                }
+               dosync = 1;
+               ripdata = wipdata;
        }
+       if (dosync)
+               hammer2_cluster_modsync(cparent);
 }
index 0a5c9bc..70bdd1d 100644 (file)
@@ -349,7 +349,7 @@ hammer2_ioctl_socket_set(hammer2_inode_t *ip, void *data)
 static int
 hammer2_ioctl_pfs_get(hammer2_inode_t *ip, void *data)
 {
-       hammer2_inode_data_t *ipdata;
+       const hammer2_inode_data_t *ipdata;
        hammer2_mount_t *hmp;
        hammer2_ioc_pfs_t *pfs;
        hammer2_cluster_t *cparent;
@@ -440,7 +440,7 @@ hammer2_ioctl_pfs_get(hammer2_inode_t *ip, void *data)
 static int
 hammer2_ioctl_pfs_lookup(hammer2_inode_t *ip, void *data)
 {
-       hammer2_inode_data_t *ipdata;
+       const hammer2_inode_data_t *ipdata;
        hammer2_mount_t *hmp;
        hammer2_ioc_pfs_t *pfs;
        hammer2_cluster_t *cparent;
@@ -537,6 +537,7 @@ hammer2_ioctl_pfs_create(hammer2_inode_t *ip, void *data)
                 */
                if (strcmp(pfs->name, "boot") == 0)
                        nipdata->comp_algo = HAMMER2_COMP_AUTOZERO;
+               hammer2_cluster_modsync(ncluster);
                hammer2_inode_unlock_ex(nip, ncluster);
        }
        hammer2_trans_done(&trans);
@@ -595,10 +596,12 @@ hammer2_ioctl_pfs_snapshot(hammer2_inode_t *ip, void *data)
 static int
 hammer2_ioctl_inode_get(hammer2_inode_t *ip, void *data)
 {
-       hammer2_ioc_inode_t *ino = data;
-       hammer2_inode_data_t *ipdata;
+       const hammer2_inode_data_t *ipdata;
+       hammer2_ioc_inode_t *ino;
        hammer2_cluster_t *cparent;
 
+       ino = data;
+
        cparent = hammer2_inode_lock_sh(ip);
        ipdata = &hammer2_cluster_data(cparent)->ipdata;
        ino->ip_data = *ipdata;
@@ -615,19 +618,23 @@ hammer2_ioctl_inode_get(hammer2_inode_t *ip, void *data)
 static int
 hammer2_ioctl_inode_set(hammer2_inode_t *ip, void *data)
 {
-       hammer2_inode_data_t *ipdata;
+       const hammer2_inode_data_t *ripdata;
+       hammer2_inode_data_t *wipdata;
        hammer2_ioc_inode_t *ino = data;
        hammer2_cluster_t *cparent;
        hammer2_trans_t trans;
        int error = 0;
+       int dosync = 0;
 
        hammer2_trans_init(&trans, ip->pmp, NULL, 0);
        cparent = hammer2_inode_lock_ex(ip);
-       ipdata = &hammer2_cluster_data(cparent)->ipdata;
+       ripdata = &hammer2_cluster_data(cparent)->ipdata;
 
-       if (ino->ip_data.comp_algo != ipdata->comp_algo) {
-               ipdata = hammer2_cluster_modify_ip(&trans, ip, cparent, 0);
-               ipdata->comp_algo = ino->ip_data.comp_algo;
+       if (ino->ip_data.comp_algo != ripdata->comp_algo) {
+               wipdata = hammer2_cluster_modify_ip(&trans, ip, cparent, 0);
+               wipdata->comp_algo = ino->ip_data.comp_algo;
+               ripdata = wipdata; /* safety */
+               dosync = 1;
        }
        ino->kdata = ip;
        
@@ -638,6 +645,8 @@ hammer2_ioctl_inode_set(hammer2_inode_t *ip, void *data)
        }
        if (ino->flags & HAMMER2IOC_INODE_FLAG_COPIES) {
        }
+       if (dosync)
+               hammer2_cluster_modsync(cparent);
        hammer2_trans_done(&trans);
        hammer2_inode_unlock_ex(ip, cparent);
 
index 0cb517a..09667ab 100644 (file)
@@ -87,7 +87,7 @@ hammer2_voldata_unlock(hammer2_mount_t *hmp, int modify)
  * ip must be locked sh/ex.
  */
 int
-hammer2_get_dtype(hammer2_inode_data_t *ipdata)
+hammer2_get_dtype(const hammer2_inode_data_t *ipdata)
 {
        uint8_t type;
 
@@ -125,7 +125,7 @@ hammer2_get_dtype(hammer2_inode_data_t *ipdata)
  * Return the directory entry type for an inode
  */
 int
-hammer2_get_vtype(hammer2_inode_data_t *ipdata)
+hammer2_get_vtype(const hammer2_inode_data_t *ipdata)
 {
        switch(ipdata->type) {
        case HAMMER2_OBJTYPE_UNKNOWN:
@@ -189,7 +189,7 @@ hammer2_time_to_timespec(u_int64_t xtime, struct timespec *ts)
 }
 
 u_int64_t
-hammer2_timespec_to_time(struct timespec *ts)
+hammer2_timespec_to_time(const struct timespec *ts)
 {
        u_int64_t xtime;
 
@@ -202,9 +202,9 @@ hammer2_timespec_to_time(struct timespec *ts)
  * Convert a uuid to a unix uid or gid
  */
 u_int32_t
-hammer2_to_unix_xid(uuid_t *uuid)
+hammer2_to_unix_xid(const uuid_t *uuid)
 {
-       return(*(u_int32_t *)&uuid->node[2]);
+       return(*(const u_int32_t *)&uuid->node[2]);
 }
 
 void
@@ -383,7 +383,8 @@ hammer2_calc_logical(hammer2_inode_t *ip, hammer2_off_t uoff,
  * Returns 0 if the requested base offset is beyond the file EOF.
  */
 int
-hammer2_calc_physical(hammer2_inode_t *ip, hammer2_inode_data_t *ipdata,
+hammer2_calc_physical(hammer2_inode_t *ip,
+                     const hammer2_inode_data_t *ipdata,
                      hammer2_key_t lbase)
 {
        int lblksize;
index 4983350..1b482fa 100644 (file)
@@ -211,20 +211,20 @@ static void hammer2_write_file_core(struct buf *bp, hammer2_trans_t *trans,
                                int *errorp);
 static void hammer2_compress_and_write(struct buf *bp, hammer2_trans_t *trans,
                                hammer2_inode_t *ip,
-                               hammer2_inode_data_t *ipdata,
+                               const hammer2_inode_data_t *ipdata,
                                hammer2_cluster_t *cparent,
                                hammer2_key_t lbase, int ioflag,
                                int pblksize, int *errorp, int comp_algo);
 static void hammer2_zero_check_and_write(struct buf *bp,
                                hammer2_trans_t *trans, hammer2_inode_t *ip,
-                               hammer2_inode_data_t *ipdata,
+                               const hammer2_inode_data_t *ipdata,
                                hammer2_cluster_t *cparent,
                                hammer2_key_t lbase,
                                int ioflag, int pblksize, int *errorp);
 static int test_block_zeros(const char *buf, size_t bytes);
 static void zero_write(struct buf *bp, hammer2_trans_t *trans,
                                hammer2_inode_t *ip,
-                               hammer2_inode_data_t *ipdata,
+                               const hammer2_inode_data_t *ipdata,
                                hammer2_cluster_t *cparent,
                                hammer2_key_t lbase,
                                int *errorp);
@@ -769,7 +769,7 @@ hammer2_write_thread(void *arg)
        struct vnode *vp;
        hammer2_inode_t *ip;
        hammer2_cluster_t *cparent;
-       hammer2_inode_data_t *ipdata;
+       hammer2_inode_data_t *wipdata;
        hammer2_key_t lbase;
        int lblksize;
        int pblksize;
@@ -827,15 +827,16 @@ hammer2_write_thread(void *arg)
                                         HAMMER2_INODE_MTIME)) {
                                hammer2_inode_fsync(&trans, ip, cparent);
                        }
-                       ipdata = hammer2_cluster_modify_ip(&trans, ip,
+                       wipdata = hammer2_cluster_modify_ip(&trans, ip,
                                                         cparent, 0);
                        lblksize = hammer2_calc_logical(ip, bio->bio_offset,
                                                        &lbase, NULL);
-                       pblksize = hammer2_calc_physical(ip, ipdata, lbase);
-                       hammer2_write_file_core(bp, &trans, ip, ipdata,
+                       pblksize = hammer2_calc_physical(ip, wipdata, lbase);
+                       hammer2_write_file_core(bp, &trans, ip, wipdata,
                                                cparent,
                                                lbase, IO_ASYNC,
                                                pblksize, &error);
+                       hammer2_cluster_modsync(cparent);
                        hammer2_inode_unlock_ex(ip, cparent);
                        if (error) {
                                kprintf("hammer2: error in buffer write\n");
@@ -1019,7 +1020,7 @@ hammer2_write_file_core(struct buf *bp, hammer2_trans_t *trans,
 static
 void
 hammer2_compress_and_write(struct buf *bp, hammer2_trans_t *trans,
-       hammer2_inode_t *ip, hammer2_inode_data_t *ipdata,
+       hammer2_inode_t *ip, const hammer2_inode_data_t *ipdata,
        hammer2_cluster_t *cparent,
        hammer2_key_t lbase, int ioflag, int pblksize,
        int *errorp, int comp_algo)
@@ -1244,7 +1245,7 @@ done:
 static
 void
 hammer2_zero_check_and_write(struct buf *bp, hammer2_trans_t *trans,
-       hammer2_inode_t *ip, hammer2_inode_data_t *ipdata,
+       hammer2_inode_t *ip, const hammer2_inode_data_t *ipdata,
        hammer2_cluster_t *cparent,
        hammer2_key_t lbase, int ioflag, int pblksize, int *errorp)
 {
@@ -1283,8 +1284,9 @@ test_block_zeros(const char *buf, size_t bytes)
  */
 static
 void
-zero_write(struct buf *bp, hammer2_trans_t *trans, hammer2_inode_t *ip,
-       hammer2_inode_data_t *ipdata, hammer2_cluster_t *cparent,
+zero_write(struct buf *bp, hammer2_trans_t *trans,
+       hammer2_inode_t *ip, const hammer2_inode_data_t *ipdata,
+       hammer2_cluster_t *cparent,
        hammer2_key_t lbase, int *errorp __unused)
 {
        hammer2_cluster_t *cluster;
@@ -1296,10 +1298,13 @@ zero_write(struct buf *bp, hammer2_trans_t *trans, hammer2_inode_t *ip,
        cluster = hammer2_cluster_lookup(cparent, &key_dummy, lbase, lbase,
                                     HAMMER2_LOOKUP_NODATA, &ddflag);
        if (cluster) {
-               data = hammer2_cluster_data(cluster);
+               data = hammer2_cluster_wdata(cluster);
 
                if (ddflag) {
+                       KKASSERT(cluster->focus->flags &
+                                HAMMER2_CHAIN_MODIFIED);
                        bzero(data->ipdata.u.data, HAMMER2_EMBEDDED_BYTES);
+                       hammer2_cluster_modsync(cluster);
                } else {
                        hammer2_cluster_delete(trans, cluster, 0);
                }
@@ -2262,7 +2267,7 @@ hammer2_install_volume_header(hammer2_mount_t *hmp)
 void
 hammer2_cluster_reconnect(hammer2_pfsmount_t *pmp, struct file *fp)
 {
-       hammer2_inode_data_t *ipdata;
+       const hammer2_inode_data_t *ipdata;
        hammer2_cluster_t *cparent;
        hammer2_mount_t *hmp;
        size_t name_len;
index fa7dab6..24f0278 100644 (file)
@@ -347,7 +347,7 @@ int
 hammer2_vop_access(struct vop_access_args *ap)
 {
        hammer2_inode_t *ip = VTOI(ap->a_vp);
-       hammer2_inode_data_t *ipdata;
+       const hammer2_inode_data_t *ipdata;
        hammer2_cluster_t *cluster;
        uid_t uid;
        gid_t gid;
@@ -367,7 +367,7 @@ static
 int
 hammer2_vop_getattr(struct vop_getattr_args *ap)
 {
-       hammer2_inode_data_t *ipdata;
+       const hammer2_inode_data_t *ipdata;
        hammer2_cluster_t *cluster;
        hammer2_pfsmount_t *pmp;
        hammer2_inode_t *ip;
@@ -416,7 +416,8 @@ static
 int
 hammer2_vop_setattr(struct vop_setattr_args *ap)
 {
-       hammer2_inode_data_t *ipdata;
+       const hammer2_inode_data_t *ripdata;
+       hammer2_inode_data_t *wipdata;
        hammer2_inode_t *ip;
        hammer2_cluster_t *cluster;
        hammer2_trans_t trans;
@@ -425,6 +426,7 @@ hammer2_vop_setattr(struct vop_setattr_args *ap)
        int error;
        int kflags = 0;
        int domtime = 0;
+       int dosync = 0;
        uint64_t ctime;
 
        vp = ap->a_vp;
@@ -439,39 +441,41 @@ hammer2_vop_setattr(struct vop_setattr_args *ap)
        hammer2_pfs_memory_wait(ip->pmp);
        hammer2_trans_init(&trans, ip->pmp, NULL, 0);
        cluster = hammer2_inode_lock_ex(ip);
-       ipdata = &hammer2_cluster_data(cluster)->ipdata;
+       ripdata = &hammer2_cluster_data(cluster)->ipdata;
        error = 0;
 
        if (vap->va_flags != VNOVAL) {
                u_int32_t flags;
 
-               flags = ipdata->uflags;
+               flags = ripdata->uflags;
                error = vop_helper_setattr_flags(&flags, vap->va_flags,
-                                        hammer2_to_unix_xid(&ipdata->uid),
+                                        hammer2_to_unix_xid(&ripdata->uid),
                                         ap->a_cred);
                if (error == 0) {
-                       if (ipdata->uflags != flags) {
-                               ipdata = hammer2_cluster_modify_ip(&trans, ip,
-                                                                cluster, 0);
-                               ipdata->uflags = flags;
-                               ipdata->ctime = ctime;
+                       if (ripdata->uflags != flags) {
+                               wipdata = hammer2_cluster_modify_ip(&trans, ip,
+                                                                   cluster, 0);
+                               wipdata->uflags = flags;
+                               wipdata->ctime = ctime;
                                kflags |= NOTE_ATTRIB;
+                               dosync = 1;
+                               ripdata = wipdata;
                        }
-                       if (ipdata->uflags & (IMMUTABLE | APPEND)) {
+                       if (ripdata->uflags & (IMMUTABLE | APPEND)) {
                                error = 0;
                                goto done;
                        }
                }
                goto done;
        }
-       if (ipdata->uflags & (IMMUTABLE | APPEND)) {
+       if (ripdata->uflags & (IMMUTABLE | APPEND)) {
                error = EPERM;
                goto done;
        }
        if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
-               mode_t cur_mode = ipdata->mode;
-               uid_t cur_uid = hammer2_to_unix_xid(&ipdata->uid);
-               gid_t cur_gid = hammer2_to_unix_xid(&ipdata->gid);
+               mode_t cur_mode = ripdata->mode;
+               uid_t cur_uid = hammer2_to_unix_xid(&ripdata->uid);
+               gid_t cur_gid = hammer2_to_unix_xid(&ripdata->gid);
                uuid_t uuid_uid;
                uuid_t uuid_gid;
 
@@ -481,16 +485,18 @@ hammer2_vop_setattr(struct vop_setattr_args *ap)
                if (error == 0) {
                        hammer2_guid_to_uuid(&uuid_uid, cur_uid);
                        hammer2_guid_to_uuid(&uuid_gid, cur_gid);
-                       if (bcmp(&uuid_uid, &ipdata->uid, sizeof(uuid_uid)) ||
-                           bcmp(&uuid_gid, &ipdata->gid, sizeof(uuid_gid)) ||
-                           ipdata->mode != cur_mode
+                       if (bcmp(&uuid_uid, &ripdata->uid, sizeof(uuid_uid)) ||
+                           bcmp(&uuid_gid, &ripdata->gid, sizeof(uuid_gid)) ||
+                           ripdata->mode != cur_mode
                        ) {
-                               ipdata = hammer2_cluster_modify_ip(&trans, ip,
-                                                                cluster, 0);
-                               ipdata->uid = uuid_uid;
-                               ipdata->gid = uuid_gid;
-                               ipdata->mode = cur_mode;
-                               ipdata->ctime = ctime;
+                               wipdata = hammer2_cluster_modify_ip(&trans, ip,
+                                                                   cluster, 0);
+                               wipdata->uid = uuid_uid;
+                               wipdata->gid = uuid_gid;
+                               wipdata->mode = cur_mode;
+                               wipdata->ctime = ctime;
+                               dosync = 1;
+                               ripdata = wipdata;
                        }
                        kflags |= NOTE_ATTRIB;
                }
@@ -512,7 +518,7 @@ hammer2_vop_setattr(struct vop_setattr_args *ap)
                        }
                        cluster = hammer2_inode_lock_ex(ip);
                        /* RELOAD */
-                       ipdata = &hammer2_cluster_data(cluster)->ipdata;
+                       ripdata = &hammer2_cluster_data(cluster)->ipdata;
                        domtime = 1;
                        break;
                default:
@@ -523,30 +529,36 @@ hammer2_vop_setattr(struct vop_setattr_args *ap)
 #if 0
        /* atime not supported */
        if (vap->va_atime.tv_sec != VNOVAL) {
-               ipdata = hammer2_cluster_modify_ip(&trans, ip, cluster, 0);
-               ipdata->atime = hammer2_timespec_to_time(&vap->va_atime);
+               wipdata = hammer2_cluster_modify_ip(&trans, ip, cluster, 0);
+               wipdata->atime = hammer2_timespec_to_time(&vap->va_atime);
                kflags |= NOTE_ATTRIB;
+               dosync = 1;
+               ripdata = wipdata;
        }
 #endif
        if (vap->va_mtime.tv_sec != VNOVAL) {
-               ipdata = hammer2_cluster_modify_ip(&trans, ip, cluster, 0);
-               ipdata->mtime = hammer2_timespec_to_time(&vap->va_mtime);
+               wipdata = hammer2_cluster_modify_ip(&trans, ip, cluster, 0);
+               wipdata->mtime = hammer2_timespec_to_time(&vap->va_mtime);
                kflags |= NOTE_ATTRIB;
                domtime = 0;
+               dosync = 1;
+               ripdata = wipdata;
        }
        if (vap->va_mode != (mode_t)VNOVAL) {
-               mode_t cur_mode = ipdata->mode;
-               uid_t cur_uid = hammer2_to_unix_xid(&ipdata->uid);
-               gid_t cur_gid = hammer2_to_unix_xid(&ipdata->gid);
+               mode_t cur_mode = ripdata->mode;
+               uid_t cur_uid = hammer2_to_unix_xid(&ripdata->uid);
+               gid_t cur_gid = hammer2_to_unix_xid(&ripdata->gid);
 
                error = vop_helper_chmod(ap->a_vp, vap->va_mode, ap->a_cred,
                                         cur_uid, cur_gid, &cur_mode);
-               if (error == 0 && ipdata->mode != cur_mode) {
-                       ipdata = hammer2_cluster_modify_ip(&trans, ip,
-                                                          cluster, 0);
-                       ipdata->mode = cur_mode;
-                       ipdata->ctime = ctime;
+               if (error == 0 && ripdata->mode != cur_mode) {
+                       wipdata = hammer2_cluster_modify_ip(&trans, ip,
+                                                           cluster, 0);
+                       wipdata->mode = cur_mode;
+                       wipdata->ctime = ctime;
                        kflags |= NOTE_ATTRIB;
+                       dosync = 1;
+                       ripdata = wipdata;
                }
        }
 
@@ -555,6 +567,10 @@ hammer2_vop_setattr(struct vop_setattr_args *ap)
         * to trim the related data chains, otherwise a later expansion can
         * cause havoc.
         */
+       if (dosync) {
+               hammer2_cluster_modsync(cluster);
+               dosync = 0;
+       }
        hammer2_inode_fsync(&trans, ip, cluster);
 
        /*
@@ -568,6 +584,8 @@ done:
                                           HAMMER2_INODE_MTIME);
                vsetisdirty(ip->vp);
        }
+       if (dosync)
+               hammer2_cluster_modsync(cluster);
        hammer2_inode_unlock_ex(ip, cluster);
        hammer2_trans_done(&trans);
        hammer2_knote(ip->vp, kflags);
@@ -579,7 +597,7 @@ static
 int
 hammer2_vop_readdir(struct vop_readdir_args *ap)
 {
-       hammer2_inode_data_t *ipdata;
+       const hammer2_inode_data_t *ipdata;
        hammer2_inode_t *ip;
        hammer2_inode_t *xip;
        hammer2_cluster_t *cparent;
@@ -1171,7 +1189,7 @@ hammer2_vop_nresolve(struct vop_nresolve_args *ap)
        hammer2_inode_t *dip;
        hammer2_cluster_t *cparent;
        hammer2_cluster_t *cluster;
-       hammer2_inode_data_t *ipdata;
+       const hammer2_inode_data_t *ipdata;
        hammer2_key_t key_next;
        hammer2_key_t lhc;
        struct namecache *ncp;
@@ -1408,7 +1426,7 @@ int
 hammer2_vop_advlock(struct vop_advlock_args *ap)
 {
        hammer2_inode_t *ip = VTOI(ap->a_vp);
-       hammer2_inode_data_t *ipdata;
+       const hammer2_inode_data_t *ipdata;
        hammer2_cluster_t *cparent;
        hammer2_off_t size;
 
@@ -1655,7 +1673,7 @@ hammer2_vop_nsymlink(struct vop_nsymlink_args *ap)
                struct iovec aiov;
                hammer2_inode_data_t *nipdata;
 
-               nipdata = &hammer2_cluster_data(ncparent)->ipdata;
+               nipdata = &hammer2_cluster_wdata(ncparent)->ipdata;
                /* nipdata = &nip->chain->data->ipdata;XXX */
                bytes = strlen(ap->a_target);