* (such as VFS logic) that will not compile easily in userland.
*/
#ifdef _KERNEL
-#ifdef HAVE_ZPL
/*
* Needed to close a small window in zfs_znode_move() that allows the zfsvfs to
* be freed before it can be safely accessed.
static kmem_cache_t *znode_cache = NULL;
/*ARGSUSED*/
-static void
-znode_evict_error(dmu_buf_t *dbuf, void *user_ptr)
-{
- /*
- * We should never drop all dbuf refs without first clearing
- * the eviction callback.
- */
- panic("evicting znode %p\n", user_ptr);
-}
-
-/*ARGSUSED*/
static int
zfs_znode_cache_constructor(void *buf, void *arg, int kmflags)
{
zfs_znode_fini(void)
{
/*
- * Cleanup vfs & vnode ops
- */
- zfs_remove_op_tables();
-
- /*
* Cleanup zcache
*/
if (znode_cache)
rw_destroy(&zfsvfs_lock);
}
-struct vnodeops *zfs_dvnodeops;
-struct vnodeops *zfs_fvnodeops;
-struct vnodeops *zfs_symvnodeops;
-struct vnodeops *zfs_xdvnodeops;
-struct vnodeops *zfs_evnodeops;
-struct vnodeops *zfs_sharevnodeops;
-
-void
-zfs_remove_op_tables()
-{
- /*
- * Remove vfs ops
- */
- ASSERT(zfsfstype);
- (void) vfs_freevfsops_by_type(zfsfstype);
- zfsfstype = 0;
-
- /*
- * Remove vnode ops
- */
- if (zfs_dvnodeops)
- vn_freevnodeops(zfs_dvnodeops);
- if (zfs_fvnodeops)
- vn_freevnodeops(zfs_fvnodeops);
- if (zfs_symvnodeops)
- vn_freevnodeops(zfs_symvnodeops);
- if (zfs_xdvnodeops)
- vn_freevnodeops(zfs_xdvnodeops);
- if (zfs_evnodeops)
- vn_freevnodeops(zfs_evnodeops);
- if (zfs_sharevnodeops)
- vn_freevnodeops(zfs_sharevnodeops);
-
- zfs_dvnodeops = NULL;
- zfs_fvnodeops = NULL;
- zfs_symvnodeops = NULL;
- zfs_xdvnodeops = NULL;
- zfs_evnodeops = NULL;
- zfs_sharevnodeops = NULL;
-}
-
-extern const fs_operation_def_t zfs_dvnodeops_template[];
-extern const fs_operation_def_t zfs_fvnodeops_template[];
-extern const fs_operation_def_t zfs_xdvnodeops_template[];
-extern const fs_operation_def_t zfs_symvnodeops_template[];
-extern const fs_operation_def_t zfs_evnodeops_template[];
-extern const fs_operation_def_t zfs_sharevnodeops_template[];
-
-int
-zfs_create_op_tables()
-{
- int error;
-
- /*
- * zfs_dvnodeops can be set if mod_remove() calls mod_installfs()
- * due to a failure to remove the the 2nd modlinkage (zfs_modldrv).
- * In this case we just return as the ops vectors are already set up.
- */
- if (zfs_dvnodeops)
- return (0);
-
- error = vn_make_ops(MNTTYPE_ZFS, zfs_dvnodeops_template,
- &zfs_dvnodeops);
- if (error)
- return (error);
-
- error = vn_make_ops(MNTTYPE_ZFS, zfs_fvnodeops_template,
- &zfs_fvnodeops);
- if (error)
- return (error);
-
- error = vn_make_ops(MNTTYPE_ZFS, zfs_symvnodeops_template,
- &zfs_symvnodeops);
- if (error)
- return (error);
-
- error = vn_make_ops(MNTTYPE_ZFS, zfs_xdvnodeops_template,
- &zfs_xdvnodeops);
- if (error)
- return (error);
-
- error = vn_make_ops(MNTTYPE_ZFS, zfs_evnodeops_template,
- &zfs_evnodeops);
- if (error)
- return (error);
-
- error = vn_make_ops(MNTTYPE_ZFS, zfs_sharevnodeops_template,
- &zfs_sharevnodeops);
-
- return (error);
-}
-
+#ifdef HAVE_ZPL
int
zfs_create_share_dir(zfsvfs_t *zfsvfs, dmu_tx_t *tx)
{
+#ifdef HAVE_SHARE
zfs_acl_ids_t acl_ids;
vattr_t vattr;
znode_t *sharezp;
kmem_cache_free(znode_cache, sharezp);
return (error);
+#else
+ return (0);
+#endif /* HAVE_SHARE */
}
/*
#define MAXMIN64 0xffffffffUL
#endif
+#endif /* HAVE_ZPL */
+
/*
* Create special expldev for ZFS private use.
* Can't use standard expldev since it doesn't do
}
/*
- * Construct a new znode/vnode and intialize.
+ * Construct a new znode+inode and initialize.
*
* This does not do a call to dmu_set_user() that is
* up to the caller to do, in case you don't want to
dmu_object_type_t obj_type, sa_handle_t *hdl)
{
znode_t *zp;
- vnode_t *vp;
- uint64_t mode;
+ struct inode *inode;
uint64_t parent;
sa_bulk_attr_t bulk[9];
int count = 0;
- zp = kmem_cache_alloc(znode_cache, KM_SLEEP);
+ ASSERT(zfsvfs != NULL);
+ ASSERT(zfsvfs->z_vfs != NULL);
+ ASSERT(zfsvfs->z_vfs->mnt_sb != NULL);
+
+ inode = iget_locked(zfsvfs->z_vfs->mnt_sb, db->db_object);
+ zp = ITOZ(inode);
+ ASSERT(inode->i_state & I_NEW);
ASSERT(zp->z_dirlocks == NULL);
ASSERT(!POINTER_IS_VALID(zp->z_zfsvfs));
zp->z_moved = 0;
zp->z_seq = 0x7A4653;
zp->z_sync_cnt = 0;
- vp = ZTOV(zp);
- vn_reinit(vp);
-
zfs_znode_sa_init(zfsvfs, zp, db, obj_type, hdl);
- SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MODE(zfsvfs), NULL, &mode, 8);
- SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_GEN(zfsvfs), NULL, &zp->z_gen, 8);
+ SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MODE(zfsvfs), NULL,
+ &zp->z_mode, 8);
+ SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_GEN(zfsvfs), NULL,
+ &zp->z_gen, 8);
SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_SIZE(zfsvfs), NULL,
&zp->z_size, 8);
SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_LINKS(zfsvfs), NULL,
&zp->z_links, 8);
SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_FLAGS(zfsvfs), NULL,
&zp->z_pflags, 8);
- SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_PARENT(zfsvfs), NULL, &parent, 8);
+ SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_PARENT(zfsvfs), NULL,
+ &parent, 8);
SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_ATIME(zfsvfs), NULL,
&zp->z_atime, 16);
SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_UID(zfsvfs), NULL,
if (sa_bulk_lookup(zp->z_sa_hdl, bulk, count) != 0 || zp->z_gen == 0) {
if (hdl == NULL)
sa_handle_destroy(zp->z_sa_hdl);
- kmem_cache_free(znode_cache, zp);
+ iput(inode);
return (NULL);
}
- zp->z_mode = mode;
- vp->v_vfsp = zfsvfs->z_parent->z_vfs;
-
- vp->v_type = IFTOVT((mode_t)mode);
-
- switch (vp->v_type) {
- case VDIR:
- if (zp->z_pflags & ZFS_XATTR) {
- vn_setops(vp, zfs_xdvnodeops);
- vp->v_flag |= V_XATTRDIR;
- } else {
- vn_setops(vp, zfs_dvnodeops);
- }
- zp->z_zn_prefetch = B_TRUE; /* z_prefetch default is enabled */
- break;
- case VBLK:
- case VCHR:
- {
- uint64_t rdev;
- VERIFY(sa_lookup(zp->z_sa_hdl, SA_ZPL_RDEV(zfsvfs),
- &rdev, sizeof (rdev)) == 0);
-
- vp->v_rdev = zfs_cmpldev(rdev);
- }
- /*FALLTHROUGH*/
- case VFIFO:
- case VSOCK:
- case VDOOR:
- vn_setops(vp, zfs_fvnodeops);
- break;
- case VREG:
- vp->v_flag |= VMODSORT;
- if (parent == zfsvfs->z_shares_dir) {
- ASSERT(zp->z_uid == 0 && zp->z_gid == 0);
- vn_setops(vp, zfs_sharevnodeops);
- } else {
- vn_setops(vp, zfs_fvnodeops);
- }
- break;
- case VLNK:
- vn_setops(vp, zfs_symvnodeops);
- break;
- default:
- vn_setops(vp, zfs_evnodeops);
- break;
+ inode->i_mode = (umode_t)zp->z_mode;
+ if ((S_ISCHR(inode->i_mode)) || (S_ISBLK(inode->i_mode))) {
+ uint64_t rdev;
+ VERIFY(sa_lookup(zp->z_sa_hdl, SA_ZPL_RDEV(zfsvfs),
+ &rdev, sizeof (rdev)) == 0);
+ inode->i_rdev = zfs_cmpldev(rdev);
}
+ /* zp->z_set_ops_inode() must be set in sb->alloc_inode() */
+ ASSERT(zp->z_set_ops_inode != NULL);
+ zp->z_set_ops_inode(inode);
+ unlock_new_inode(inode);
+
mutex_enter(&zfsvfs->z_znodes_lock);
list_insert_tail(&zfsvfs->z_all_znodes, zp);
membar_producer();
return (zp);
}
+/*
+ * 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.
+ */
+void
+zfs_inode_update(znode_t *zp)
+{
+ zfsvfs_t *zfsvfs;
+ struct inode *inode;
+ uint32_t blksize;
+ uint64_t atime[2], mtime[2], ctime[2];
+
+ ASSERT(zp != NULL);
+ zfsvfs = zp->z_zfsvfs;
+ inode = ZTOI(zp);
+
+ sa_lookup(zp->z_sa_hdl, SA_ZPL_ATIME(zfsvfs), &atime, 16);
+ sa_lookup(zp->z_sa_hdl, SA_ZPL_MTIME(zfsvfs), &mtime, 16);
+ sa_lookup(zp->z_sa_hdl, SA_ZPL_CTIME(zfsvfs), &ctime, 16);
+
+ spin_lock(&inode->i_lock);
+ inode->i_generation = zp->z_gen;
+ inode->i_uid = zp->z_uid;
+ inode->i_gid = zp->z_gid;
+ inode->i_nlink = zp->z_links;
+ inode->i_mode = zp->z_mode;
+ inode->i_blkbits = SPA_MINBLOCKSHIFT;
+ dmu_object_size_from_db(sa_get_db(zp->z_sa_hdl), &blksize,
+ (u_longlong_t *)&inode->i_blocks);
+
+ ZFS_TIME_DECODE(&inode->i_atime, atime);
+ ZFS_TIME_DECODE(&inode->i_mtime, mtime);
+ ZFS_TIME_DECODE(&inode->i_ctime, ctime);
+
+ i_size_write(inode, zp->z_size);
+ spin_unlock(&inode->i_lock);
+}
+
static uint64_t empty_xattr;
static uint64_t pad[4];
static zfs_acl_phys_t acl_phys;
void
zfs_xvattr_set(znode_t *zp, xvattr_t *xvap, dmu_tx_t *tx)
{
+#ifdef HAVE_XVATTR
xoptattr_t *xoap;
xoap = xva_getxoptattr(xvap);
zp->z_pflags, tx);
XVA_SET_RTN(xvap, XAT_SPARSE);
}
+#endif /* HAVE_XVATTR */
}
int
dmu_object_size_from_db(sa_get_db(zp->z_sa_hdl), &zp->z_blksz, &dummy);
}
+#ifdef HAVE_ZPL
/*
* This is a dummy interface used when pvn_vplist_dirty() should *not*
* be calling back into the fs for a putpage(). E.g.: when truncating
ASSERT(0);
return (0);
}
+#endif /* HAVE_ZPL */
/*
* Increase the file length
zfs_trunc(znode_t *zp, uint64_t end)
{
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
+#ifdef HAVE_ZPL
vnode_t *vp = ZTOV(zp);
+#endif /* HAVE_ZPL */
dmu_tx_t *tx;
rl_t *rl;
int error;
dmu_tx_commit(tx);
+#ifdef HAVE_ZPL
/*
* Clear any mapped pages in the truncated region. This has to
* happen outside of the transaction to avoid the possibility of
B_INVAL | B_TRUNC, NULL);
ASSERT(error == 0);
}
+#endif /* HAVE_ZPL */
zfs_range_unlock(rl);
int
zfs_freesp(znode_t *zp, uint64_t off, uint64_t len, int flag, boolean_t log)
{
+#ifdef HAVE_ZPL
vnode_t *vp = ZTOV(zp);
+#endif /* HAVE_ZPL */
dmu_tx_t *tx;
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
zilog_t *zilog = zfsvfs->z_log;
return (error);
}
+#ifdef HAVE_ZPL
/*
* Check for any locks in the region to be freed.
*/
if (error = chklock(vp, FWRITE, off, length, flag, NULL))
return (error);
}
+#endif /* HAVE_ZPL */
if (len == 0) {
error = zfs_trunc(zp, off);
zfs_log_truncate(zilog, tx, TX_TRUNCATE, zp, off, len);
dmu_tx_commit(tx);
+ zfs_inode_update(zp);
return (0);
}
-#endif /* HAVE_ZPL */
void
zfs_create_fs(objset_t *os, cred_t *cr, nvlist_t *zplprops, dmu_tx_t *tx)