]> git.proxmox.com Git - mirror_zfs.git/blobdiff - module/os/linux/zfs/zfs_znode.c
Linux 6.7 compat: use inode atime/mtime accessors
[mirror_zfs.git] / module / os / linux / zfs / zfs_znode.c
index ebfaae67bac1643240cd48f8b39b2fd3f926f51b..b99df188c64b4ab400151e58db75016a506d7413 100644 (file)
@@ -6,7 +6,7 @@
  * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
+ * or https://opensource.org/licenses/CDDL-1.0.
  * See the License for the specific language governing permissions
  * and limitations under the License.
  *
@@ -38,7 +38,6 @@
 #include <sys/file.h>
 #include <sys/kmem.h>
 #include <sys/errno.h>
-#include <sys/mode.h>
 #include <sys/atomic.h>
 #include <sys/zfs_dir.h>
 #include <sys/zfs_acl.h>
@@ -55,7 +54,7 @@
 #include <sys/dmu.h>
 #include <sys/dmu_objset.h>
 #include <sys/dmu_tx.h>
-#include <sys/refcount.h>
+#include <sys/zfs_refcount.h>
 #include <sys/stat.h>
 #include <sys/zap.h>
 #include <sys/zfs_znode.h>
@@ -81,7 +80,7 @@ unsigned int zfs_object_mutex_size = ZFS_OBJ_MTX_SZ;
  * This is used by the test suite so that it can delay znodes from being
  * freed in order to inspect the unlinked set.
  */
-int zfs_unlink_suspend_progress = 0;
+static int zfs_unlink_suspend_progress = 0;
 
 /*
  * This callback is invoked when acquiring a RL_WRITER or RL_APPEND lock on
@@ -90,7 +89,7 @@ int zfs_unlink_suspend_progress = 0;
  * called with the rangelock_t's rl_lock held, which avoids races.
  */
 static void
-zfs_rangelock_cb(locked_range_t *new, void *arg)
+zfs_rangelock_cb(zfs_locked_range_t *new, void *arg)
 {
        znode_t *zp = arg;
 
@@ -114,10 +113,10 @@ zfs_rangelock_cb(locked_range_t *new, void *arg)
        }
 }
 
-/*ARGSUSED*/
 static int
 zfs_znode_cache_constructor(void *buf, void *arg, int kmflags)
 {
+       (void) arg, (void) kmflags;
        znode_t *zp = buf;
 
        inode_init_once(ZTOI(zp));
@@ -135,14 +134,16 @@ zfs_znode_cache_constructor(void *buf, void *arg, int kmflags)
        zp->z_acl_cached = NULL;
        zp->z_xattr_cached = NULL;
        zp->z_xattr_parent = 0;
-       zp->z_moved = B_FALSE;
+       zp->z_sync_writes_cnt = 0;
+       zp->z_async_writes_cnt = 0;
+
        return (0);
 }
 
-/*ARGSUSED*/
 static void
 zfs_znode_cache_destructor(void *buf, void *arg)
 {
+       (void) arg;
        znode_t *zp = buf;
 
        ASSERT(!list_link_active(&zp->z_link_node));
@@ -153,19 +154,22 @@ zfs_znode_cache_destructor(void *buf, void *arg)
        rw_destroy(&zp->z_xattr_lock);
        zfs_rangelock_fini(&zp->z_rangelock);
 
-       ASSERT(zp->z_dirlocks == NULL);
-       ASSERT(zp->z_acl_cached == NULL);
-       ASSERT(zp->z_xattr_cached == NULL);
+       ASSERT3P(zp->z_dirlocks, ==, NULL);
+       ASSERT3P(zp->z_acl_cached, ==, NULL);
+       ASSERT3P(zp->z_xattr_cached, ==, NULL);
+
+       ASSERT0(atomic_load_32(&zp->z_sync_writes_cnt));
+       ASSERT0(atomic_load_32(&zp->z_async_writes_cnt));
 }
 
 static int
 zfs_znode_hold_cache_constructor(void *buf, void *arg, int kmflags)
 {
+       (void) arg, (void) kmflags;
        znode_hold_t *zh = buf;
 
        mutex_init(&zh->zh_lock, NULL, MUTEX_DEFAULT, NULL);
-       zfs_refcount_create(&zh->zh_refcount);
-       zh->zh_obj = ZFS_NO_OBJECT;
+       zh->zh_refcount = 0;
 
        return (0);
 }
@@ -173,10 +177,10 @@ zfs_znode_hold_cache_constructor(void *buf, void *arg, int kmflags)
 static void
 zfs_znode_hold_cache_destructor(void *buf, void *arg)
 {
+       (void) arg;
        znode_hold_t *zh = buf;
 
        mutex_destroy(&zh->zh_lock);
-       zfs_refcount_destroy(&zh->zh_refcount);
 }
 
 void
@@ -219,7 +223,7 @@ zfs_znode_fini(void)
  * created or destroyed.  This kind of locking would normally reside in the
  * znode itself but in this case that's impossible because the znode and SA
  * buffer may not yet exist.  Therefore the locking is handled externally
- * with an array of mutexs and AVLs trees which contain per-object locks.
+ * with an array of mutexes and AVLs trees which contain per-object locks.
  *
  * In zfs_znode_hold_enter() a per-object lock is created as needed, inserted
  * in to the correct AVL tree and finally the per-object lock is held.  In
@@ -250,7 +254,7 @@ zfs_znode_hold_compare(const void *a, const void *b)
        return (TREE_CMP(zh_a->zh_obj, zh_b->zh_obj));
 }
 
-boolean_t
+static boolean_t __maybe_unused
 zfs_znode_held(zfsvfs_t *zfsvfs, uint64_t obj)
 {
        znode_hold_t *zh, search;
@@ -267,7 +271,7 @@ zfs_znode_held(zfsvfs_t *zfsvfs, uint64_t obj)
        return (held);
 }
 
-static znode_hold_t *
+znode_hold_t *
 zfs_znode_hold_enter(zfsvfs_t *zfsvfs, uint64_t obj)
 {
        znode_hold_t *zh, *zh_new, search;
@@ -275,43 +279,43 @@ zfs_znode_hold_enter(zfsvfs_t *zfsvfs, uint64_t obj)
        boolean_t found = B_FALSE;
 
        zh_new = kmem_cache_alloc(znode_hold_cache, KM_SLEEP);
-       zh_new->zh_obj = obj;
        search.zh_obj = obj;
 
        mutex_enter(&zfsvfs->z_hold_locks[i]);
        zh = avl_find(&zfsvfs->z_hold_trees[i], &search, NULL);
        if (likely(zh == NULL)) {
                zh = zh_new;
+               zh->zh_obj = obj;
                avl_add(&zfsvfs->z_hold_trees[i], zh);
        } else {
                ASSERT3U(zh->zh_obj, ==, obj);
                found = B_TRUE;
        }
-       zfs_refcount_add(&zh->zh_refcount, NULL);
+       zh->zh_refcount++;
+       ASSERT3S(zh->zh_refcount, >, 0);
        mutex_exit(&zfsvfs->z_hold_locks[i]);
 
        if (found == B_TRUE)
                kmem_cache_free(znode_hold_cache, zh_new);
 
        ASSERT(MUTEX_NOT_HELD(&zh->zh_lock));
-       ASSERT3S(zfs_refcount_count(&zh->zh_refcount), >, 0);
        mutex_enter(&zh->zh_lock);
 
        return (zh);
 }
 
-static void
+void
 zfs_znode_hold_exit(zfsvfs_t *zfsvfs, znode_hold_t *zh)
 {
        int i = ZFS_OBJ_HASH(zfsvfs, zh->zh_obj);
        boolean_t remove = B_FALSE;
 
        ASSERT(zfs_znode_held(zfsvfs, zh->zh_obj));
-       ASSERT3S(zfs_refcount_count(&zh->zh_refcount), >, 0);
        mutex_exit(&zh->zh_lock);
 
        mutex_enter(&zfsvfs->z_hold_locks[i]);
-       if (zfs_refcount_remove(&zh->zh_refcount, NULL) == 0) {
+       ASSERT3S(zh->zh_refcount, >, 0);
+       if (--zh->zh_refcount == 0) {
                avl_remove(&zfsvfs->z_hold_trees[i], zh);
                remove = B_TRUE;
        }
@@ -321,6 +325,12 @@ zfs_znode_hold_exit(zfsvfs_t *zfsvfs, znode_hold_t *zh)
                kmem_cache_free(znode_hold_cache, zh);
 }
 
+dev_t
+zfs_cmpldev(uint64_t dev)
+{
+       return (dev);
+}
+
 static void
 zfs_znode_sa_init(zfsvfs_t *zfsvfs, znode_t *zp,
     dmu_buf_t *db, dmu_object_type_t obj_type, sa_handle_t *sa_hdl)
@@ -347,7 +357,7 @@ zfs_znode_sa_init(zfsvfs_t *zfsvfs, znode_t *zp,
 void
 zfs_znode_dmu_fini(znode_t *zp)
 {
-       ASSERT(zfs_znode_held(ZTOZSB(zp), zp->z_id) || zp->z_unlinked ||
+       ASSERT(zfs_znode_held(ZTOZSB(zp), zp->z_id) ||
            RW_WRITE_HELD(&ZTOZSB(zp)->z_teardown_inactive_lock));
 
        sa_handle_destroy(zp->z_sa_hdl);
@@ -380,7 +390,6 @@ zfs_inode_destroy(struct inode *ip)
        mutex_enter(&zfsvfs->z_znodes_lock);
        if (list_link_active(&zp->z_link_node)) {
                list_remove(&zfsvfs->z_all_znodes, zp);
-               zfsvfs->z_nr_znodes--;
        }
        mutex_exit(&zfsvfs->z_znodes_lock);
 
@@ -405,12 +414,21 @@ zfs_inode_set_ops(zfsvfs_t *zfsvfs, struct inode *ip)
        switch (ip->i_mode & S_IFMT) {
        case S_IFREG:
                ip->i_op = &zpl_inode_operations;
+#ifdef HAVE_VFS_FILE_OPERATIONS_EXTEND
+               ip->i_fop = &zpl_file_operations.kabi_fops;
+#else
                ip->i_fop = &zpl_file_operations;
+#endif
                ip->i_mapping->a_ops = &zpl_address_space_operations;
                break;
 
        case S_IFDIR:
+#ifdef HAVE_RENAME2_OPERATIONS_WRAPPER
+               ip->i_flags |= S_IOPS_WRAPPER;
+               ip->i_op = &zpl_dir_inode_operations.ops;
+#else
                ip->i_op = &zpl_dir_inode_operations;
+#endif
                ip->i_fop = &zpl_dir_file_operations;
                ITOZ(ip)->z_zn_prefetch = B_TRUE;
                break;
@@ -426,7 +444,7 @@ zfs_inode_set_ops(zfsvfs_t *zfsvfs, struct inode *ip)
        case S_IFBLK:
                (void) sa_lookup(ITOZ(ip)->z_sa_hdl, SA_ZPL_RDEV(zfsvfs), &rdev,
                    sizeof (rdev));
-               /*FALLTHROUGH*/
+               zfs_fallthrough;
        case S_IFIFO:
        case S_IFSOCK:
                init_special_inode(ip, ip->i_mode, rdev);
@@ -440,13 +458,17 @@ zfs_inode_set_ops(zfsvfs_t *zfsvfs, struct inode *ip)
                /* Assume the inode is a file and attempt to continue */
                ip->i_mode = S_IFREG | 0644;
                ip->i_op = &zpl_inode_operations;
+#ifdef HAVE_VFS_FILE_OPERATIONS_EXTEND
+               ip->i_fop = &zpl_file_operations.kabi_fops;
+#else
                ip->i_fop = &zpl_file_operations;
+#endif
                ip->i_mapping->a_ops = &zpl_address_space_operations;
                break;
        }
 }
 
-void
+static void
 zfs_set_inode_flags(znode_t *zp, struct inode *ip)
 {
        /*
@@ -475,22 +497,16 @@ zfs_set_inode_flags(znode_t *zp, struct inode *ip)
 }
 
 /*
- * Update the embedded inode given the znode.  We should work toward
- * eliminating this function as soon as possible by removing values
- * which are duplicated between the znode and inode.  If the generic
- * inode has the correct field it should be used, and the ZFS code
- * updated to access the inode.  This can be done incrementally.
+ * Update the embedded inode given the znode.
  */
 void
-zfs_inode_update(znode_t *zp)
+zfs_znode_update_vfs(znode_t *zp)
 {
-       zfsvfs_t        *zfsvfs;
        struct inode    *ip;
        uint32_t        blksize;
        u_longlong_t    i_blocks;
 
        ASSERT(zp != NULL);
-       zfsvfs = ZTOZSB(zp);
        ip = ZTOI(zp);
 
        /* Skip .zfs control nodes which do not exist on disk. */
@@ -500,6 +516,7 @@ zfs_inode_update(znode_t *zp)
        dmu_object_size_from_db(sa_get_db(zp->z_sa_hdl), &blksize, &i_blocks);
 
        spin_lock(&ip->i_lock);
+       ip->i_mode = zp->z_mode;
        ip->i_blocks = i_blocks;
        i_size_write(ip, zp->z_size);
        spin_unlock(&ip->i_lock);
@@ -524,9 +541,10 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_buf_t *db, int blksz,
        uint64_t tmp_gen;
        uint64_t links;
        uint64_t z_uid, z_gid;
-       uint64_t atime[2], mtime[2], ctime[2];
+       uint64_t atime[2], mtime[2], ctime[2], btime[2];
+       inode_timespec_t tmp_ts;
        uint64_t projid = ZFS_DEFAULT_PROJID;
-       sa_bulk_attr_t bulk[11];
+       sa_bulk_attr_t bulk[12];
        int count = 0;
 
        ASSERT(zfsvfs != NULL);
@@ -541,10 +559,10 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_buf_t *db, int blksz,
        ASSERT3P(zp->z_xattr_cached, ==, NULL);
        zp->z_unlinked = B_FALSE;
        zp->z_atime_dirty = B_FALSE;
-       zp->z_moved = B_FALSE;
+#if !defined(HAVE_FILEMAP_RANGE_HAS_PAGE)
        zp->z_is_mapped = B_FALSE;
+#endif
        zp->z_is_ctldir = B_FALSE;
-       zp->z_is_stale = B_FALSE;
        zp->z_suspended = B_FALSE;
        zp->z_sa_hdl = NULL;
        zp->z_mapcnt = 0;
@@ -552,6 +570,8 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_buf_t *db, int blksz,
        zp->z_blksz = blksz;
        zp->z_seq = 0x7A4653;
        zp->z_sync_cnt = 0;
+       zp->z_sync_writes_cnt = 0;
+       zp->z_async_writes_cnt = 0;
 
        zfs_znode_sa_init(zfsvfs, zp, db, obj_type, hdl);
 
@@ -569,6 +589,7 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_buf_t *db, int blksz,
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_ATIME(zfsvfs), NULL, &atime, 16);
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MTIME(zfsvfs), NULL, &mtime, 16);
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zfsvfs), NULL, &ctime, 16);
+       SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CRTIME(zfsvfs), NULL, &btime, 16);
 
        if (sa_bulk_lookup(zp->z_sa_hdl, bulk, count) != 0 || tmp_gen == 0 ||
            (dmu_objset_projectquota_enabled(zfsvfs->z_os) &&
@@ -593,12 +614,16 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_buf_t *db, int blksz,
        if (zp->z_pflags & ZFS_XATTR)
                zp->z_xattr_parent = parent;
 
-       ZFS_TIME_DECODE(&ip->i_atime, atime);
-       ZFS_TIME_DECODE(&ip->i_mtime, mtime);
-       ZFS_TIME_DECODE(&ip->i_ctime, ctime);
+       ZFS_TIME_DECODE(&tmp_ts, atime);
+       zpl_inode_set_atime_to_ts(ip, tmp_ts);
+       ZFS_TIME_DECODE(&tmp_ts, mtime);
+       zpl_inode_set_mtime_to_ts(ip, tmp_ts);
+       ZFS_TIME_DECODE(&tmp_ts, ctime);
+       zpl_inode_set_ctime_to_ts(ip, tmp_ts);
+       ZFS_TIME_DECODE(&zp->z_btime, btime);
 
        ip->i_ino = zp->z_id;
-       zfs_inode_update(zp);
+       zfs_znode_update_vfs(zp);
        zfs_inode_set_ops(zfsvfs, ip);
 
        /*
@@ -606,18 +631,23 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_buf_t *db, int blksz,
         * number is already hashed for this super block.  This can never
         * happen because the inode numbers map 1:1 with the object numbers.
         *
-        * The one exception is rolling back a mounted file system, but in
-        * this case all the active inode are unhashed during the rollback.
+        * Exceptions include rolling back a mounted file system, either
+        * from the zfs rollback or zfs recv command.
+        *
+        * Active inodes are unhashed during the rollback, but since zrele
+        * can happen asynchronously, we can't guarantee they've been
+        * unhashed.  This can cause hash collisions in unlinked drain
+        * processing so do not hash unlinked znodes.
         */
-       VERIFY3S(insert_inode_locked(ip), ==, 0);
+       if (links > 0)
+               VERIFY3S(insert_inode_locked(ip), ==, 0);
 
        mutex_enter(&zfsvfs->z_znodes_lock);
        list_insert_tail(&zfsvfs->z_all_znodes, zp);
-       zfsvfs->z_nr_znodes++;
-       membar_producer();
        mutex_exit(&zfsvfs->z_znodes_lock);
 
-       unlock_new_inode(ip);
+       if (links > 0)
+               unlock_new_inode(ip);
        return (zp);
 
 error:
@@ -1094,6 +1124,10 @@ again:
                mutex_enter(&zp->z_lock);
                ASSERT3U(zp->z_id, ==, obj_num);
                /*
+                * If zp->z_unlinked is set, the znode is already marked
+                * for deletion and should not be discovered. Check this
+                * after checking igrab() due to fsetxattr() & O_TMPFILE.
+                *
                 * If igrab() returns NULL the VFS has independently
                 * determined the inode should be evicted and has
                 * called iput_final() to start the eviction process.
@@ -1108,18 +1142,24 @@ again:
                 * the VFS that this inode should not be evicted.
                 */
                if (igrab(ZTOI(zp)) == NULL) {
-                       mutex_exit(&zp->z_lock);
-                       sa_buf_rele(db, NULL);
-                       zfs_znode_hold_exit(zfsvfs, zh);
-                       /* inode might need this to finish evict */
-                       cond_resched();
-                       goto again;
+                       if (zp->z_unlinked)
+                               err = SET_ERROR(ENOENT);
+                       else
+                               err = SET_ERROR(EAGAIN);
+               } else {
+                       *zpp = zp;
+                       err = 0;
                }
-               *zpp = zp;
-               err = 0;
+
                mutex_exit(&zp->z_lock);
                sa_buf_rele(db, NULL);
                zfs_znode_hold_exit(zfsvfs, zh);
+
+               if (err == EAGAIN) {
+                       /* inode might need this to finish evict */
+                       cond_resched();
+                       goto again;
+               }
                return (err);
        }
 
@@ -1153,12 +1193,13 @@ zfs_rezget(znode_t *zp)
        uint64_t obj_num = zp->z_id;
        uint64_t mode;
        uint64_t links;
-       sa_bulk_attr_t bulk[10];
+       sa_bulk_attr_t bulk[11];
        int err;
        int count = 0;
        uint64_t gen;
        uint64_t z_uid, z_gid;
-       uint64_t atime[2], mtime[2], ctime[2];
+       uint64_t atime[2], mtime[2], ctime[2], btime[2];
+       inode_timespec_t tmp_ts;
        uint64_t projid = ZFS_DEFAULT_PROJID;
        znode_hold_t *zh;
 
@@ -1228,6 +1269,7 @@ zfs_rezget(znode_t *zp)
            &mtime, 16);
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zfsvfs), NULL,
            &ctime, 16);
+       SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CRTIME(zfsvfs), NULL, &btime, 16);
 
        if (sa_bulk_lookup(zp->z_sa_hdl, bulk, count)) {
                zfs_znode_dmu_fini(zp);
@@ -1250,9 +1292,13 @@ zfs_rezget(znode_t *zp)
        zfs_uid_write(ZTOI(zp), z_uid);
        zfs_gid_write(ZTOI(zp), z_gid);
 
-       ZFS_TIME_DECODE(&ZTOI(zp)->i_atime, atime);
-       ZFS_TIME_DECODE(&ZTOI(zp)->i_mtime, mtime);
-       ZFS_TIME_DECODE(&ZTOI(zp)->i_ctime, ctime);
+       ZFS_TIME_DECODE(&tmp_ts, atime);
+       zpl_inode_set_atime_to_ts(ZTOI(zp), tmp_ts);
+       ZFS_TIME_DECODE(&tmp_ts, mtime);
+       zpl_inode_set_mtime_to_ts(ZTOI(zp), tmp_ts);
+       ZFS_TIME_DECODE(&tmp_ts, ctime);
+       zpl_inode_set_ctime_to_ts(ZTOI(zp), tmp_ts);
+       ZFS_TIME_DECODE(&zp->z_btime, btime);
 
        if ((uint32_t)gen != ZTOI(zp)->i_generation) {
                zfs_znode_dmu_fini(zp);
@@ -1265,7 +1311,7 @@ zfs_rezget(znode_t *zp)
 
        zp->z_blksz = doi.doi_data_block_size;
        zp->z_atime_dirty = B_FALSE;
-       zfs_inode_update(zp);
+       zfs_znode_update_vfs(zp);
 
        /*
         * If the file has zero links, then it has been unlinked on the send
@@ -1359,21 +1405,24 @@ zfs_zinactive(znode_t *zp)
 boolean_t
 zfs_relatime_need_update(const struct inode *ip)
 {
-       inode_timespec_t now;
+       inode_timespec_t now, tmp_atime, tmp_ts;
 
        gethrestime(&now);
+       tmp_atime = zpl_inode_get_atime(ip);
        /*
         * In relatime mode, only update the atime if the previous atime
         * is earlier than either the ctime or mtime or if at least a day
         * has passed since the last update of atime.
         */
-       if (zfs_compare_timespec(&ip->i_mtime, &ip->i_atime) >= 0)
+       tmp_ts = zpl_inode_get_mtime(ip);
+       if (zfs_compare_timespec(&tmp_ts, &tmp_atime) >= 0)
                return (B_TRUE);
 
-       if (zfs_compare_timespec(&ip->i_ctime, &ip->i_atime) >= 0)
+       tmp_ts = zpl_inode_get_ctime(ip);
+       if (zfs_compare_timespec(&tmp_ts, &tmp_atime) >= 0)
                return (B_TRUE);
 
-       if ((hrtime_t)now.tv_sec - (hrtime_t)ip->i_atime.tv_sec >= 24*60*60)
+       if ((hrtime_t)now.tv_sec - (hrtime_t)tmp_atime.tv_sec >= 24*60*60)
                return (B_TRUE);
 
        return (B_FALSE);
@@ -1396,7 +1445,7 @@ void
 zfs_tstamp_update_setup(znode_t *zp, uint_t flag, uint64_t mtime[2],
     uint64_t ctime[2])
 {
-       inode_timespec_t now;
+       inode_timespec_t now, tmp_ts;
 
        gethrestime(&now);
 
@@ -1404,7 +1453,8 @@ zfs_tstamp_update_setup(znode_t *zp, uint_t flag, uint64_t mtime[2],
 
        if (flag & ATTR_MTIME) {
                ZFS_TIME_ENCODE(&now, mtime);
-               ZFS_TIME_DECODE(&(ZTOI(zp)->i_mtime), mtime);
+               ZFS_TIME_DECODE(&tmp_ts, mtime);
+               zpl_inode_set_mtime_to_ts(ZTOI(zp), tmp_ts);
                if (ZTOZSB(zp)->z_use_fuids) {
                        zp->z_pflags |= (ZFS_ARCHIVE |
                            ZFS_AV_MODIFIED);
@@ -1413,7 +1463,8 @@ zfs_tstamp_update_setup(znode_t *zp, uint_t flag, uint64_t mtime[2],
 
        if (flag & ATTR_CTIME) {
                ZFS_TIME_ENCODE(&now, ctime);
-               ZFS_TIME_DECODE(&(ZTOI(zp)->i_ctime), ctime);
+               ZFS_TIME_DECODE(&tmp_ts, ctime);
+               zpl_inode_set_ctime_to_ts(ZTOI(zp), tmp_ts);
                if (ZTOZSB(zp)->z_use_fuids)
                        zp->z_pflags |= ZFS_ARCHIVE;
        }
@@ -1468,7 +1519,7 @@ zfs_extend(znode_t *zp, uint64_t end)
 {
        zfsvfs_t *zfsvfs = ZTOZSB(zp);
        dmu_tx_t *tx;
-       locked_range_t *lr;
+       zfs_locked_range_t *lr;
        uint64_t newblksz;
        int error;
 
@@ -1559,7 +1610,7 @@ zfs_zero_partial_page(znode_t *zp, uint64_t start, uint64_t len)
                        flush_dcache_page(pp);
 
                pb = kmap(pp);
-               bzero(pb + off, len);
+               memset(pb + off, 0, len);
                kunmap(pp);
 
                if (mapping_writably_mapped(mp))
@@ -1586,7 +1637,7 @@ static int
 zfs_free_range(znode_t *zp, uint64_t off, uint64_t len)
 {
        zfsvfs_t *zfsvfs = ZTOZSB(zp);
-       locked_range_t *lr;
+       zfs_locked_range_t *lr;
        int error;
 
        /*
@@ -1611,7 +1662,7 @@ zfs_free_range(znode_t *zp, uint64_t off, uint64_t len)
         * Zero partial page cache entries.  This must be done under a
         * range lock in order to keep the ARC and page cache in sync.
         */
-       if (zp->z_is_mapped) {
+       if (zn_has_cached_data(zp, off, off + len - 1)) {
                loff_t first_page, last_page, page_len;
                loff_t first_page_offset, last_page_offset;
 
@@ -1666,7 +1717,7 @@ zfs_trunc(znode_t *zp, uint64_t end)
 {
        zfsvfs_t *zfsvfs = ZTOZSB(zp);
        dmu_tx_t *tx;
-       locked_range_t *lr;
+       zfs_locked_range_t *lr;
        int error;
        sa_bulk_attr_t bulk[2];
        int count = 0;
@@ -1783,7 +1834,7 @@ log:
 
        dmu_tx_commit(tx);
 
-       zfs_inode_update(zp);
+       zfs_znode_update_vfs(zp);
        error = 0;
 
 out:
@@ -1834,7 +1885,7 @@ zfs_create_fs(objset_t *os, cred_t *cr, nvlist_t *zplprops, dmu_tx_t *tx)
        while ((elem = nvlist_next_nvpair(zplprops, elem)) != NULL) {
                /* For the moment we expect all zpl props to be uint64_ts */
                uint64_t val;
-               char *name;
+               const char *name;
 
                ASSERT(nvpair_type(elem) == DATA_TYPE_UINT64);
                VERIFY(nvpair_value_uint64(elem, &val) == 0);
@@ -1853,6 +1904,7 @@ zfs_create_fs(objset_t *os, cred_t *cr, nvlist_t *zplprops, dmu_tx_t *tx)
        }
        ASSERT(version != 0);
        error = zap_update(os, moid, ZPL_VERSION_STR, 8, 1, &version, tx);
+       ASSERT(error == 0);
 
        /*
         * Create zap object used for SA attribute registration
@@ -1886,7 +1938,6 @@ zfs_create_fs(objset_t *os, cred_t *cr, nvlist_t *zplprops, dmu_tx_t *tx)
        rootzp = kmem_cache_alloc(znode_cache, KM_SLEEP);
        rootzp->z_unlinked = B_FALSE;
        rootzp->z_atime_dirty = B_FALSE;
-       rootzp->z_moved = B_FALSE;
        rootzp->z_is_sa = USE_SA(version, os);
        rootzp->z_pflags = 0;
 
@@ -1931,7 +1982,7 @@ zfs_create_fs(objset_t *os, cred_t *cr, nvlist_t *zplprops, dmu_tx_t *tx)
        }
 
        VERIFY(0 == zfs_acl_ids_create(rootzp, IS_ROOT_NODE, &vattr,
-           cr, NULL, &acl_ids));
+           cr, NULL, &acl_ids, zfs_init_idmap));
        zfs_mknode(rootzp, &vattr, tx, cr, IS_ROOT_NODE, &zp, &acl_ids);
        ASSERT3P(zp, ==, rootzp);
        error = zap_add(os, moid, ZFS_ROOT_OBJ, 8, 1, &rootzp->z_id, tx);
@@ -1972,7 +2023,7 @@ zfs_sa_setup(objset_t *osp, sa_attr_type_t **sa_table)
 
 static int
 zfs_grab_sa_handle(objset_t *osp, uint64_t obj, sa_handle_t **hdlp,
-    dmu_buf_t **db, void *tag)
+    dmu_buf_t **db, const void *tag)
 {
        dmu_object_info_t doi;
        int error;
@@ -1998,8 +2049,8 @@ zfs_grab_sa_handle(objset_t *osp, uint64_t obj, sa_handle_t **hdlp,
        return (0);
 }
 
-void
-zfs_release_sa_handle(sa_handle_t *hdl, dmu_buf_t *db, void *tag)
+static void
+zfs_release_sa_handle(sa_handle_t *hdl, dmu_buf_t *db, const void *tag)
 {
        sa_handle_destroy(hdl);
        sa_buf_rele(db, tag);
@@ -2107,7 +2158,6 @@ zfs_obj_to_path_impl(objset_t *osp, uint64_t obj, sa_handle_t *hdl,
        } else if (error != ENOENT) {
                return (error);
        }
-       error = 0;
 
        for (;;) {
                uint64_t pobj = 0;
@@ -2115,8 +2165,10 @@ zfs_obj_to_path_impl(objset_t *osp, uint64_t obj, sa_handle_t *hdl,
                size_t complen;
                int is_xattrdir = 0;
 
-               if (prevdb)
+               if (prevdb) {
+                       ASSERT(prevhdl != NULL);
                        zfs_release_sa_handle(prevhdl, prevdb, FTAG);
+               }
 
                if ((error = zfs_obj_to_pobj(osp, sa_hdl, sa_table, &pobj,
                    &is_xattrdir)) != 0)
@@ -2130,7 +2182,7 @@ zfs_obj_to_path_impl(objset_t *osp, uint64_t obj, sa_handle_t *hdl,
 
                component[0] = '/';
                if (is_xattrdir) {
-                       (void) sprintf(component + 1, "<xattrdir>");
+                       strcpy(component + 1, "<xattrdir>");
                } else {
                        error = zap_value_search(osp, pobj, obj,
                            ZFS_DIRENT_OBJ(-1ULL), component + 1);
@@ -2141,7 +2193,7 @@ zfs_obj_to_path_impl(objset_t *osp, uint64_t obj, sa_handle_t *hdl,
                complen = strlen(component);
                path -= complen;
                ASSERT(path >= buf);
-               bcopy(component, path, complen);
+               memcpy(path, component, complen);
                obj = pobj;
 
                if (sa_hdl != hdl) {
@@ -2221,6 +2273,91 @@ zfs_obj_to_stats(objset_t *osp, uint64_t obj, zfs_stat_t *sb,
        return (error);
 }
 
+/*
+ * Read a property stored within the master node.
+ */
+int
+zfs_get_zplprop(objset_t *os, zfs_prop_t prop, uint64_t *value)
+{
+       uint64_t *cached_copy = NULL;
+
+       /*
+        * Figure out where in the objset_t the cached copy would live, if it
+        * is available for the requested property.
+        */
+       if (os != NULL) {
+               switch (prop) {
+               case ZFS_PROP_VERSION:
+                       cached_copy = &os->os_version;
+                       break;
+               case ZFS_PROP_NORMALIZE:
+                       cached_copy = &os->os_normalization;
+                       break;
+               case ZFS_PROP_UTF8ONLY:
+                       cached_copy = &os->os_utf8only;
+                       break;
+               case ZFS_PROP_CASE:
+                       cached_copy = &os->os_casesensitivity;
+                       break;
+               default:
+                       break;
+               }
+       }
+       if (cached_copy != NULL && *cached_copy != OBJSET_PROP_UNINITIALIZED) {
+               *value = *cached_copy;
+               return (0);
+       }
+
+       /*
+        * If the property wasn't cached, look up the file system's value for
+        * the property. For the version property, we look up a slightly
+        * different string.
+        */
+       const char *pname;
+       int error = ENOENT;
+       if (prop == ZFS_PROP_VERSION)
+               pname = ZPL_VERSION_STR;
+       else
+               pname = zfs_prop_to_name(prop);
+
+       if (os != NULL) {
+               ASSERT3U(os->os_phys->os_type, ==, DMU_OST_ZFS);
+               error = zap_lookup(os, MASTER_NODE_OBJ, pname, 8, 1, value);
+       }
+
+       if (error == ENOENT) {
+               /* No value set, use the default value */
+               switch (prop) {
+               case ZFS_PROP_VERSION:
+                       *value = ZPL_VERSION;
+                       break;
+               case ZFS_PROP_NORMALIZE:
+               case ZFS_PROP_UTF8ONLY:
+                       *value = 0;
+                       break;
+               case ZFS_PROP_CASE:
+                       *value = ZFS_CASE_SENSITIVE;
+                       break;
+               case ZFS_PROP_ACLTYPE:
+                       *value = ZFS_ACLTYPE_OFF;
+                       break;
+               default:
+                       return (error);
+               }
+               error = 0;
+       }
+
+       /*
+        * If one of the methods for getting the property value above worked,
+        * copy it into the objset_t's cache.
+        */
+       if (error == 0 && cached_copy != NULL) {
+               *cached_copy = *value;
+       }
+
+       return (error);
+}
+
 #if defined(_KERNEL)
 EXPORT_SYMBOL(zfs_create_fs);
 EXPORT_SYMBOL(zfs_obj_to_path);