static int zfs_replay_setattr(zfsvfs_t *zfsvfs, lr_setattr_t *lr, boolean_t byteswap) { znode_t *zp; xvattr_t xva; vattr_t *vap = &xva.xva_vattr; int error; void *start; xva_init(&xva); if (byteswap) { byteswap_uint64_array(lr, sizeof (*lr)); if ((lr->lr_mask & AT_XVATTR) && zfsvfs->z_version >= ZPL_VERSION_INITIAL) zfs_replay_swap_attrs((lr_attr_t *)(lr + 1)); } if ((error = zfs_zget(zfsvfs, lr->lr_foid, &zp)) != 0) { /* * As we can log setattrs out of order, it's possible the * file has been removed. In this case just drop the setattr * and return success. */ if (error == ENOENT) error = 0; return (error); } zfs_init_vattr(vap, lr->lr_mask, lr->lr_mode, lr->lr_uid, lr->lr_gid, 0, lr->lr_foid); vap->va_size = lr->lr_size; ZFS_TIME_DECODE(&vap->va_atime, lr->lr_atime); ZFS_TIME_DECODE(&vap->va_mtime, lr->lr_mtime); /* * Fill in xvattr_t portions if necessary. */ start = (lr_setattr_t *)(lr + 1); if (vap->va_mask & AT_XVATTR) { zfs_replay_xvattr((lr_attr_t *)start, &xva); start = (caddr_t)start + ZIL_XVAT_SIZE(((lr_attr_t *)start)->lr_attr_masksize); } else xva.xva_vattr.va_mask &= ~AT_XVATTR; zfsvfs->z_fuid_replay = zfs_replay_fuid_domain(start, &start, lr->lr_uid, lr->lr_gid); error = VOP_SETATTR(ZTOV(zp), vap, 0, kcred, NULL); zfs_fuid_info_free(zfsvfs->z_fuid_replay); zfsvfs->z_fuid_replay = NULL; VN_RELE(ZTOV(zp)); return (error); }
static int zfs_replay_setattr(void *arg1, void *arg2, boolean_t byteswap) { zfsvfs_t *zfsvfs = arg1; lr_setattr_t *lr = arg2; znode_t *zp; xvattr_t xva; vattr_t *vap = &xva.xva_vattr; vnode_t *vp; int error; void *start; xva_init(&xva); if (byteswap) { byteswap_uint64_array(lr, sizeof (*lr)); if ((lr->lr_mask & AT_XVATTR) && zfsvfs->z_version >= ZPL_VERSION_INITIAL) zfs_replay_swap_attrs((lr_attr_t *)(lr + 1)); } if ((error = zfs_zget(zfsvfs, lr->lr_foid, &zp)) != 0) return (error); zfs_init_vattr(vap, lr->lr_mask, lr->lr_mode, lr->lr_uid, lr->lr_gid, 0, lr->lr_foid); vap->va_size = lr->lr_size; ZFS_TIME_DECODE(&vap->va_atime, lr->lr_atime); ZFS_TIME_DECODE(&vap->va_mtime, lr->lr_mtime); /* * Fill in xvattr_t portions if necessary. */ start = (lr_setattr_t *)(lr + 1); if (vap->va_mask & AT_XVATTR) { zfs_replay_xvattr((lr_attr_t *)start, &xva); start = (caddr_t)start + ZIL_XVAT_SIZE(((lr_attr_t *)start)->lr_attr_masksize); } else xva.xva_vattr.va_mask &= ~AT_XVATTR; zfsvfs->z_fuid_replay = zfs_replay_fuid_domain(start, &start, lr->lr_uid, lr->lr_gid); vp = ZTOV(zp); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); error = VOP_SETATTR(vp, vap, kcred); VOP_UNLOCK(vp, 0); zfs_fuid_info_free(zfsvfs->z_fuid_replay); zfsvfs->z_fuid_replay = NULL; VN_RELE(vp); return (error); }
static int zfs_replay_setattr(zfsvfs_t *zfsvfs, lr_setattr_t *lr, boolean_t byteswap) { znode_t *zp; xvattr_t xva; vattr_t *vap = &xva.xva_vattr; int error; void *start; xva_init(&xva); if (byteswap) { byteswap_uint64_array(lr, sizeof (*lr)); if ((lr->lr_mask & ATTR_XVATTR) && zfsvfs->z_version >= ZPL_VERSION_INITIAL) zfs_replay_swap_attrs((lr_attr_t *)(lr + 1)); } if ((error = zfs_zget(zfsvfs, lr->lr_foid, &zp)) != 0) return (error); zfs_init_vattr(vap, lr->lr_mask, lr->lr_mode, lr->lr_uid, lr->lr_gid, 0, lr->lr_foid); vap->va_size = lr->lr_size; ZFS_TIME_DECODE(&vap->va_atime, lr->lr_atime); ZFS_TIME_DECODE(&vap->va_mtime, lr->lr_mtime); gethrestime(&vap->va_ctime); vap->va_mask |= ATTR_CTIME; /* * Fill in xvattr_t portions if necessary. */ start = (lr_setattr_t *)(lr + 1); if (vap->va_mask & ATTR_XVATTR) { zfs_replay_xvattr((lr_attr_t *)start, &xva); start = (caddr_t)start + ZIL_XVAT_SIZE(((lr_attr_t *)start)->lr_attr_masksize); } else xva.xva_vattr.va_mask &= ~ATTR_XVATTR; zfsvfs->z_fuid_replay = zfs_replay_fuid_domain(start, &start, lr->lr_uid, lr->lr_gid); error = zfs_setattr(ZTOI(zp), vap, 0, kcred); zfs_fuid_info_free(zfsvfs->z_fuid_replay); zfsvfs->z_fuid_replay = NULL; iput(ZTOI(zp)); return (error); }
static void zfs_replay_xvattr(lr_attr_t *lrattr, xvattr_t *xvap) { xoptattr_t *xoap = NULL; uint64_t *attrs; uint64_t *crtime; uint32_t *bitmap; void *scanstamp; int i; xvap->xva_vattr.va_mask |= AT_XVATTR; if ((xoap = xva_getxoptattr(xvap)) == NULL) { xvap->xva_vattr.va_mask &= ~AT_XVATTR; /* shouldn't happen */ return; } ASSERT(lrattr->lr_attr_masksize == xvap->xva_mapsize); bitmap = &lrattr->lr_attr_bitmap; for (i = 0; i != lrattr->lr_attr_masksize; i++, bitmap++) xvap->xva_reqattrmap[i] = *bitmap; attrs = (uint64_t *)(lrattr + lrattr->lr_attr_masksize - 1); crtime = attrs + 1; scanstamp = (caddr_t)(crtime + 2); if (XVA_ISSET_REQ(xvap, XAT_HIDDEN)) xoap->xoa_hidden = ((*attrs & XAT0_HIDDEN) != 0); if (XVA_ISSET_REQ(xvap, XAT_SYSTEM)) xoap->xoa_system = ((*attrs & XAT0_SYSTEM) != 0); if (XVA_ISSET_REQ(xvap, XAT_ARCHIVE)) xoap->xoa_archive = ((*attrs & XAT0_ARCHIVE) != 0); if (XVA_ISSET_REQ(xvap, XAT_READONLY)) xoap->xoa_readonly = ((*attrs & XAT0_READONLY) != 0); if (XVA_ISSET_REQ(xvap, XAT_IMMUTABLE)) xoap->xoa_immutable = ((*attrs & XAT0_IMMUTABLE) != 0); if (XVA_ISSET_REQ(xvap, XAT_NOUNLINK)) xoap->xoa_nounlink = ((*attrs & XAT0_NOUNLINK) != 0); if (XVA_ISSET_REQ(xvap, XAT_APPENDONLY)) xoap->xoa_appendonly = ((*attrs & XAT0_APPENDONLY) != 0); if (XVA_ISSET_REQ(xvap, XAT_NODUMP)) xoap->xoa_nodump = ((*attrs & XAT0_NODUMP) != 0); if (XVA_ISSET_REQ(xvap, XAT_OPAQUE)) xoap->xoa_opaque = ((*attrs & XAT0_OPAQUE) != 0); if (XVA_ISSET_REQ(xvap, XAT_AV_MODIFIED)) xoap->xoa_av_modified = ((*attrs & XAT0_AV_MODIFIED) != 0); if (XVA_ISSET_REQ(xvap, XAT_AV_QUARANTINED)) xoap->xoa_av_quarantined = ((*attrs & XAT0_AV_QUARANTINED) != 0); if (XVA_ISSET_REQ(xvap, XAT_CREATETIME)) ZFS_TIME_DECODE(&xoap->xoa_createtime, crtime); if (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP)) bcopy(scanstamp, xoap->xoa_av_scanstamp, AV_SCANSTAMP_SZ); if (XVA_ISSET_REQ(xvap, XAT_REPARSE)) xoap->xoa_reparse = ((*attrs & XAT0_REPARSE) != 0); if (XVA_ISSET_REQ(xvap, XAT_OFFLINE)) xoap->xoa_offline = ((*attrs & XAT0_OFFLINE) != 0); if (XVA_ISSET_REQ(xvap, XAT_SPARSE)) xoap->xoa_sparse = ((*attrs & XAT0_SPARSE) != 0); }
/* * Create the '.zfs' directory. This directory is cached as part of the VFS * structure. This results in a hold on the vfs_t. The code in zfs_umount() * therefore checks against a vfs_count of 2 instead of 1. This reference * is removed when the ctldir is destroyed in the unmount. */ void zfsctl_create(zfsvfs_t *zfsvfs) { vnode_t *vp, *rvp; zfsctl_node_t *zcp; uint64_t crtime[2]; ASSERT(zfsvfs->z_ctldir == NULL); vp = gfs_root_create(sizeof (zfsctl_node_t), zfsvfs->z_vfs, &zfsctl_ops_root, ZFSCTL_INO_ROOT, zfsctl_root_entries, zfsctl_root_inode_cb, MAXNAMELEN, NULL, NULL); zcp = vp->v_data; zcp->zc_id = ZFSCTL_INO_ROOT; VERIFY(VFS_ROOT(zfsvfs->z_vfs, LK_EXCLUSIVE, &rvp) == 0); VERIFY(0 == sa_lookup(VTOZ(rvp)->z_sa_hdl, SA_ZPL_CRTIME(zfsvfs), &crtime, sizeof (crtime))); ZFS_TIME_DECODE(&zcp->zc_cmtime, crtime); VN_URELE(rvp); /* * We're only faking the fact that we have a root of a filesystem for * the sake of the GFS interfaces. Undo the flag manipulation it did * for us. */ vp->v_vflag &= ~VV_ROOT; zfsvfs->z_ctldir = vp; VOP_UNLOCK(vp, 0); }
/* * Create the '.zfs' directory. This directory is cached as part of the VFS * structure. This results in a hold on the vfs_t. The code in zfs_umount() * therefore checks against a vfs_count of 2 instead of 1. This reference * is removed when the ctldir is destroyed in the unmount. */ void zfsctl_create(zfsvfs_t *zfsvfs) { vnode_t *vp, *rvp; zfsctl_node_t *zcp; ASSERT(zfsvfs->z_ctldir == NULL); vp = gfs_root_create(sizeof (zfsctl_node_t), zfsvfs->z_vfs, zfsctl_ops_root, ZFSCTL_INO_ROOT, zfsctl_root_entries, zfsctl_root_inode_cb, MAXNAMELEN, NULL, NULL); zcp = vp->v_data; zcp->zc_id = ZFSCTL_INO_ROOT; VERIFY(VFS_ROOT(zfsvfs->z_vfs, &rvp) == 0); ZFS_TIME_DECODE(&zcp->zc_cmtime, VTOZ(rvp)->z_phys->zp_crtime); VN_RELE(rvp); /* * We're only faking the fact that we have a root of a filesystem for * the sake of the GFS interfaces. Undo the flag manipulation it did * for us. */ vp->v_flag &= ~(VROOT | VNOCACHE | VNOMAP | VNOSWAP | VNOMOUNT); zfsvfs->z_ctldir = vp; }
static int zfs_vfs_sync(struct mount *mp, __unused int waitfor, __unused vfs_context_t context) { zfsvfs_t *zfsvfs = vfs_fsprivate(mp); ZFS_ENTER(zfsvfs); /* * Mac OS X needs a file system modify time * * We use the mtime of the "com.apple.system.mtime" * extended attribute, which is associated with the * file system root directory. * * Here we sync any mtime changes to this attribute. */ if (zfsvfs->z_mtime_vp != NULL) { timestruc_t mtime; znode_t *zp; top: zp = VTOZ(zfsvfs->z_mtime_vp); ZFS_TIME_DECODE(&mtime, zp->z_phys->zp_mtime); if (zfsvfs->z_last_mtime_synced < mtime.tv_sec) { dmu_tx_t *tx; int error; tx = dmu_tx_create(zfsvfs->z_os); dmu_tx_hold_bonus(tx, zp->z_id); error = dmu_tx_assign(tx, zfsvfs->z_assign); if (error) { if (error == ERESTART && zfsvfs->z_assign == TXG_NOWAIT) { dmu_tx_wait(tx); dmu_tx_abort(tx); goto top; } dmu_tx_abort(tx); } else { dmu_buf_will_dirty(zp->z_dbuf, tx); dmu_tx_commit(tx); zfsvfs->z_last_mtime_synced = mtime.tv_sec; } } } if (zfsvfs->z_log != NULL) zil_commit(zfsvfs->z_log, UINT64_MAX, 0); else txg_wait_synced(dmu_objset_pool(zfsvfs->z_os), 0); ZFS_EXIT(zfsvfs); return (0); }
/* * 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) { zfs_sb_t *zsb; struct inode *ip; uint32_t blksize; uint64_t atime[2], mtime[2], ctime[2]; ASSERT(zp != NULL); zsb = ZTOZSB(zp); ip = ZTOI(zp); /* Skip .zfs control nodes which do not exist on disk. */ if (zfsctl_is_node(ip)) return; sa_lookup(zp->z_sa_hdl, SA_ZPL_ATIME(zsb), &atime, 16); sa_lookup(zp->z_sa_hdl, SA_ZPL_MTIME(zsb), &mtime, 16); sa_lookup(zp->z_sa_hdl, SA_ZPL_CTIME(zsb), &ctime, 16); spin_lock(&ip->i_lock); ip->i_generation = zp->z_gen; ip->i_uid = SUID_TO_KUID(zp->z_uid); ip->i_gid = SGID_TO_KGID(zp->z_gid); set_nlink(ip, zp->z_links); ip->i_mode = zp->z_mode; zfs_set_inode_flags(zp, ip); ip->i_blkbits = SPA_MINBLOCKSHIFT; dmu_object_size_from_db(sa_get_db(zp->z_sa_hdl), &blksize, (u_longlong_t *)&ip->i_blocks); ZFS_TIME_DECODE(&ip->i_atime, atime); ZFS_TIME_DECODE(&ip->i_mtime, mtime); ZFS_TIME_DECODE(&ip->i_ctime, ctime); i_size_write(ip, zp->z_size); spin_unlock(&ip->i_lock); }
/* * Create the '.zfs' directory. */ void zfsctl_create(zfsvfs_t *zfsvfs) { zfsctl_root_t *dot_zfs; sfs_node_t *snapdir; vnode_t *rvp; uint64_t crtime[2]; ASSERT(zfsvfs->z_ctldir == NULL); snapdir = sfs_alloc_node(sizeof(*snapdir), "snapshot", ZFSCTL_INO_ROOT, ZFSCTL_INO_SNAPDIR); dot_zfs = (zfsctl_root_t *)sfs_alloc_node(sizeof(*dot_zfs), ".zfs", 0, ZFSCTL_INO_ROOT); dot_zfs->snapdir = snapdir; VERIFY(VFS_ROOT(zfsvfs->z_vfs, LK_EXCLUSIVE, &rvp) == 0); VERIFY(0 == sa_lookup(VTOZ(rvp)->z_sa_hdl, SA_ZPL_CRTIME(zfsvfs), &crtime, sizeof(crtime))); ZFS_TIME_DECODE(&dot_zfs->cmtime, crtime); vput(rvp); zfsvfs->z_ctldir = dot_zfs; }
static int zfs_replay_create(zfsvfs_t *zfsvfs, lr_create_t *lr, boolean_t byteswap) { char *name = NULL; /* location determined later */ char *link; /* symlink content follows name */ znode_t *dzp; vnode_t *vp = NULL; xvattr_t xva; int vflg = 0; size_t lrsize = sizeof (lr_create_t); lr_attr_t *lrattr; void *start; size_t xvatlen; uint64_t txtype; struct componentname cn; int error; txtype = (lr->lr_common.lrc_txtype & ~TX_CI); if (byteswap) { byteswap_uint64_array(lr, sizeof (*lr)); if (txtype == TX_CREATE_ATTR || txtype == TX_MKDIR_ATTR) zfs_replay_swap_attrs((lr_attr_t *)(lr + 1)); } if ((error = zfs_zget(zfsvfs, lr->lr_doid, &dzp)) != 0) return (error); xva_init(&xva); zfs_init_vattr(&xva.xva_vattr, AT_TYPE | AT_MODE | AT_UID | AT_GID, lr->lr_mode, lr->lr_uid, lr->lr_gid, lr->lr_rdev, lr->lr_foid); /* * All forms of zfs create (create, mkdir, mkxattrdir, symlink) * eventually end up in zfs_mknode(), which assigns the object's * creation time and generation number. The generic VOP_CREATE() * doesn't have either concept, so we smuggle the values inside * the vattr's otherwise unused va_ctime and va_nblocks fields. */ ZFS_TIME_DECODE(&xva.xva_vattr.va_ctime, lr->lr_crtime); xva.xva_vattr.va_nblocks = lr->lr_gen; error = dmu_object_info(zfsvfs->z_os, lr->lr_foid, NULL); if (error != ENOENT) goto out; if (lr->lr_common.lrc_txtype & TX_CI) vflg |= FIGNORECASE; /* * Symlinks don't have fuid info, and CIFS never creates * symlinks. * * The _ATTR versions will grab the fuid info in their subcases. */ if ((int)lr->lr_common.lrc_txtype != TX_SYMLINK && (int)lr->lr_common.lrc_txtype != TX_MKDIR_ATTR && (int)lr->lr_common.lrc_txtype != TX_CREATE_ATTR) { start = (lr + 1); zfsvfs->z_fuid_replay = zfs_replay_fuid_domain(start, &start, lr->lr_uid, lr->lr_gid); } cn.cn_cred = kcred; cn.cn_thread = curthread; cn.cn_flags = SAVENAME; vn_lock(ZTOV(dzp), LK_EXCLUSIVE | LK_RETRY); switch (txtype) { case TX_CREATE_ATTR: lrattr = (lr_attr_t *)(caddr_t)(lr + 1); xvatlen = ZIL_XVAT_SIZE(lrattr->lr_attr_masksize); zfs_replay_xvattr((lr_attr_t *)((caddr_t)lr + lrsize), &xva); start = (caddr_t)(lr + 1) + xvatlen; zfsvfs->z_fuid_replay = zfs_replay_fuid_domain(start, &start, lr->lr_uid, lr->lr_gid); name = (char *)start; /*FALLTHROUGH*/ case TX_CREATE: if (name == NULL) name = (char *)start; cn.cn_nameptr = name; error = VOP_CREATE(ZTOV(dzp), &vp, &cn, &xva.xva_vattr /*,vflg*/); break; case TX_MKDIR_ATTR: lrattr = (lr_attr_t *)(caddr_t)(lr + 1); xvatlen = ZIL_XVAT_SIZE(lrattr->lr_attr_masksize); zfs_replay_xvattr((lr_attr_t *)((caddr_t)lr + lrsize), &xva); start = (caddr_t)(lr + 1) + xvatlen; zfsvfs->z_fuid_replay = zfs_replay_fuid_domain(start, &start, lr->lr_uid, lr->lr_gid); name = (char *)start; /*FALLTHROUGH*/ case TX_MKDIR: if (name == NULL) name = (char *)(lr + 1); cn.cn_nameptr = name; error = VOP_MKDIR(ZTOV(dzp), &vp, &cn, &xva.xva_vattr /*,vflg*/); break; case TX_MKXATTR: error = zfs_make_xattrdir(dzp, &xva.xva_vattr, &vp, kcred); break; case TX_SYMLINK: name = (char *)(lr + 1); link = name + strlen(name) + 1; cn.cn_nameptr = name; error = VOP_SYMLINK(ZTOV(dzp), &vp, &cn, &xva.xva_vattr, link /*,vflg*/); break; default: error = ENOTSUP; } VOP_UNLOCK(ZTOV(dzp), 0); out: if (error == 0 && vp != NULL) VN_URELE(vp); VN_RELE(ZTOV(dzp)); if (zfsvfs->z_fuid_replay) zfs_fuid_info_free(zfsvfs->z_fuid_replay); zfsvfs->z_fuid_replay = NULL; return (error); }
/* * Replay file create with optional ACL, xvattr information as well * as option FUID information. */ static int zfs_replay_create_acl(zfsvfs_t *zfsvfs, lr_acl_create_t *lracl, boolean_t byteswap) { char *name = NULL; /* location determined later */ lr_create_t *lr = (lr_create_t *)lracl; znode_t *dzp; vnode_t *vp = NULL; xvattr_t xva; int vflg = 0; vsecattr_t vsec = { 0 }; lr_attr_t *lrattr; void *aclstart; void *fuidstart; size_t xvatlen = 0; uint64_t txtype; int error; txtype = (lr->lr_common.lrc_txtype & ~TX_CI); if (byteswap) { byteswap_uint64_array(lracl, sizeof (*lracl)); if (txtype == TX_CREATE_ACL_ATTR || txtype == TX_MKDIR_ACL_ATTR) { lrattr = (lr_attr_t *)(caddr_t)(lracl + 1); zfs_replay_swap_attrs(lrattr); xvatlen = ZIL_XVAT_SIZE(lrattr->lr_attr_masksize); } aclstart = (caddr_t)(lracl + 1) + xvatlen; zfs_ace_byteswap(aclstart, lracl->lr_acl_bytes, B_FALSE); /* swap fuids */ if (lracl->lr_fuidcnt) { byteswap_uint64_array((caddr_t)aclstart + ZIL_ACE_LENGTH(lracl->lr_acl_bytes), lracl->lr_fuidcnt * sizeof (uint64_t)); } } if ((error = zfs_zget(zfsvfs, lr->lr_doid, &dzp)) != 0) return (error); xva_init(&xva); zfs_init_vattr(&xva.xva_vattr, AT_TYPE | AT_MODE | AT_UID | AT_GID, lr->lr_mode, lr->lr_uid, lr->lr_gid, lr->lr_rdev, lr->lr_foid); /* * All forms of zfs create (create, mkdir, mkxattrdir, symlink) * eventually end up in zfs_mknode(), which assigns the object's * creation time and generation number. The generic VOP_CREATE() * doesn't have either concept, so we smuggle the values inside * the vattr's otherwise unused va_ctime and va_nblocks fields. */ ZFS_TIME_DECODE(&xva.xva_vattr.va_ctime, lr->lr_crtime); xva.xva_vattr.va_nblocks = lr->lr_gen; error = dmu_object_info(zfsvfs->z_os, lr->lr_foid, NULL); if (error != ENOENT) goto bail; if (lr->lr_common.lrc_txtype & TX_CI) vflg |= FIGNORECASE; switch (txtype) { case TX_CREATE_ACL: aclstart = (caddr_t)(lracl + 1); fuidstart = (caddr_t)aclstart + ZIL_ACE_LENGTH(lracl->lr_acl_bytes); zfsvfs->z_fuid_replay = zfs_replay_fuids(fuidstart, (void *)&name, lracl->lr_fuidcnt, lracl->lr_domcnt, lr->lr_uid, lr->lr_gid); /*FALLTHROUGH*/ case TX_CREATE_ACL_ATTR: if (name == NULL) { lrattr = (lr_attr_t *)(caddr_t)(lracl + 1); xvatlen = ZIL_XVAT_SIZE(lrattr->lr_attr_masksize); xva.xva_vattr.va_mask |= AT_XVATTR; zfs_replay_xvattr(lrattr, &xva); } vsec.vsa_mask = VSA_ACE | VSA_ACE_ACLFLAGS; vsec.vsa_aclentp = (caddr_t)(lracl + 1) + xvatlen; vsec.vsa_aclcnt = lracl->lr_aclcnt; vsec.vsa_aclentsz = lracl->lr_acl_bytes; vsec.vsa_aclflags = lracl->lr_acl_flags; if (zfsvfs->z_fuid_replay == NULL) { fuidstart = (caddr_t)(lracl + 1) + xvatlen + ZIL_ACE_LENGTH(lracl->lr_acl_bytes); zfsvfs->z_fuid_replay = zfs_replay_fuids(fuidstart, (void *)&name, lracl->lr_fuidcnt, lracl->lr_domcnt, lr->lr_uid, lr->lr_gid); } #ifdef TODO error = VOP_CREATE(ZTOV(dzp), name, &xva.xva_vattr, 0, 0, &vp, kcred, vflg, NULL, &vsec); #else panic("%s:%u: unsupported condition", __func__, __LINE__); #endif break; case TX_MKDIR_ACL: aclstart = (caddr_t)(lracl + 1); fuidstart = (caddr_t)aclstart + ZIL_ACE_LENGTH(lracl->lr_acl_bytes); zfsvfs->z_fuid_replay = zfs_replay_fuids(fuidstart, (void *)&name, lracl->lr_fuidcnt, lracl->lr_domcnt, lr->lr_uid, lr->lr_gid); /*FALLTHROUGH*/ case TX_MKDIR_ACL_ATTR: if (name == NULL) { lrattr = (lr_attr_t *)(caddr_t)(lracl + 1); xvatlen = ZIL_XVAT_SIZE(lrattr->lr_attr_masksize); zfs_replay_xvattr(lrattr, &xva); } vsec.vsa_mask = VSA_ACE | VSA_ACE_ACLFLAGS; vsec.vsa_aclentp = (caddr_t)(lracl + 1) + xvatlen; vsec.vsa_aclcnt = lracl->lr_aclcnt; vsec.vsa_aclentsz = lracl->lr_acl_bytes; vsec.vsa_aclflags = lracl->lr_acl_flags; if (zfsvfs->z_fuid_replay == NULL) { fuidstart = (caddr_t)(lracl + 1) + xvatlen + ZIL_ACE_LENGTH(lracl->lr_acl_bytes); zfsvfs->z_fuid_replay = zfs_replay_fuids(fuidstart, (void *)&name, lracl->lr_fuidcnt, lracl->lr_domcnt, lr->lr_uid, lr->lr_gid); } #ifdef TODO error = VOP_MKDIR(ZTOV(dzp), name, &xva.xva_vattr, &vp, kcred, NULL, vflg, &vsec); #else panic("%s:%u: unsupported condition", __func__, __LINE__); #endif break; default: error = ENOTSUP; } bail: if (error == 0 && vp != NULL) VN_RELE(vp); VN_RELE(ZTOV(dzp)); if (zfsvfs->z_fuid_replay) zfs_fuid_info_free(zfsvfs->z_fuid_replay); zfsvfs->z_fuid_replay = NULL; return (error); }
void commonattrpack(attrinfo_t *aip, zfsvfs_t *zfsvfs, znode_t *zp, const char *name, ino64_t objnum, enum vtype vtype, boolean_t user64) { attrgroup_t commonattr = aip->ai_attrlist->commonattr; void *attrbufptr = *aip->ai_attrbufpp; void *varbufptr = *aip->ai_varbufpp; struct mount *mp = zfsvfs->z_vfs; cred_t *cr = (cred_t *)vfs_context_ucred(aip->ai_context); finderinfo_t finderinfo; /* * We should probably combine all the sa_lookup into a bulk * lookup operand. */ finderinfo.fi_flags = 0; if (ATTR_CMN_NAME & commonattr) { nameattrpack(aip, name, strlen(name)); attrbufptr = *aip->ai_attrbufpp; varbufptr = *aip->ai_varbufpp; } if (ATTR_CMN_DEVID & commonattr) { *((dev_t *)attrbufptr) = vfs_statfs(mp)->f_fsid.val[0]; attrbufptr = ((dev_t *)attrbufptr) + 1; } if (ATTR_CMN_FSID & commonattr) { *((fsid_t *)attrbufptr) = vfs_statfs(mp)->f_fsid; attrbufptr = ((fsid_t *)attrbufptr) + 1; } if (ATTR_CMN_OBJTYPE & commonattr) { *((fsobj_type_t *)attrbufptr) = vtype; attrbufptr = ((fsobj_type_t *)attrbufptr) + 1; } if (ATTR_CMN_OBJTAG & commonattr) { *((fsobj_tag_t *)attrbufptr) = VT_ZFS; attrbufptr = ((fsobj_tag_t *)attrbufptr) + 1; } /* * Note: ATTR_CMN_OBJID is lossy (only 32 bits). */ if ((ATTR_CMN_OBJID | ATTR_CMN_OBJPERMANENTID) & commonattr) { u_int32_t fileid; /* * On Mac OS X we always export the root directory id as 2 */ fileid = (objnum == zfsvfs->z_root) ? 2 : objnum; if (ATTR_CMN_OBJID & commonattr) { ((fsobj_id_t *)attrbufptr)->fid_objno = fileid; ((fsobj_id_t *)attrbufptr)->fid_generation = 0; attrbufptr = ((fsobj_id_t *)attrbufptr) + 1; } if (ATTR_CMN_OBJPERMANENTID & commonattr) { ((fsobj_id_t *)attrbufptr)->fid_objno = fileid; ((fsobj_id_t *)attrbufptr)->fid_generation = 0; attrbufptr = ((fsobj_id_t *)attrbufptr) + 1; } } /* * Note: ATTR_CMN_PAROBJID is lossy (only 32 bits). */ if (ATTR_CMN_PAROBJID & commonattr) { uint64_t parentid; VERIFY(sa_lookup(zp->z_sa_hdl, SA_ZPL_PARENT(zfsvfs), &parentid, sizeof (parentid)) == 0); /* * On Mac OS X we always export the root * directory id as 2 and its parent as 1 */ if (zp && zp->z_id == zfsvfs->z_root) parentid = 1; else if (parentid == zfsvfs->z_root) parentid = 2; ASSERT(parentid != 0); ((fsobj_id_t *)attrbufptr)->fid_objno = (uint32_t)parentid; ((fsobj_id_t *)attrbufptr)->fid_generation = 0; attrbufptr = ((fsobj_id_t *)attrbufptr) + 1; } if (ATTR_CMN_SCRIPT & commonattr) { *((text_encoding_t *)attrbufptr) = kTextEncodingMacUnicode; attrbufptr = ((text_encoding_t *)attrbufptr) + 1; } if (ATTR_CMN_CRTIME & commonattr) { uint64_t times[2]; VERIFY(sa_lookup(zp->z_sa_hdl, SA_ZPL_CRTIME(zfsvfs), times, sizeof(times)) == 0); if (user64) { ZFS_TIME_DECODE((timespec_user64_t *)attrbufptr, times); attrbufptr = ((timespec_user64_t *)attrbufptr) + 1; } else { ZFS_TIME_DECODE((timespec_user32_t *)attrbufptr, times); attrbufptr = ((timespec_user32_t *)attrbufptr) + 1; } } if (ATTR_CMN_MODTIME & commonattr) { uint64_t times[2]; VERIFY(sa_lookup(zp->z_sa_hdl, SA_ZPL_MTIME(zfsvfs), times, sizeof(times)) == 0); if (user64) { ZFS_TIME_DECODE((timespec_user64_t *)attrbufptr, times); attrbufptr = ((timespec_user64_t *)attrbufptr) + 1; } else { ZFS_TIME_DECODE((timespec_user32_t *)attrbufptr, times); attrbufptr = ((timespec_user32_t *)attrbufptr) + 1; } } if (ATTR_CMN_CHGTIME & commonattr) { uint64_t times[2]; VERIFY(sa_lookup(zp->z_sa_hdl, SA_ZPL_CTIME(zfsvfs), times, sizeof(times)) == 0); if (user64) { ZFS_TIME_DECODE((timespec_user64_t *)attrbufptr, times); attrbufptr = ((timespec_user64_t *)attrbufptr) + 1; } else { ZFS_TIME_DECODE((timespec_user32_t *)attrbufptr, times); attrbufptr = ((timespec_user32_t *)attrbufptr) + 1; } } if (ATTR_CMN_ACCTIME & commonattr) { uint64_t times[2]; VERIFY(sa_lookup(zp->z_sa_hdl, SA_ZPL_ATIME(zfsvfs), times, sizeof(times)) == 0); if (user64) { ZFS_TIME_DECODE((timespec_user64_t *)attrbufptr, times); attrbufptr = ((timespec_user64_t *)attrbufptr) + 1; } else { ZFS_TIME_DECODE((timespec_user32_t *)attrbufptr, times); attrbufptr = ((timespec_user32_t *)attrbufptr) + 1; } } if (ATTR_CMN_BKUPTIME & commonattr) { /* legacy attribute -- just pass zero */ if (user64) { ((timespec_user64_t *)attrbufptr)->tv_sec = 0; ((timespec_user64_t *)attrbufptr)->tv_nsec = 0; attrbufptr = ((timespec_user64_t *)attrbufptr) + 1; } else { ((timespec_user32_t *)attrbufptr)->tv_sec = 0; ((timespec_user32_t *)attrbufptr)->tv_nsec = 0; attrbufptr = ((timespec_user32_t *)attrbufptr) + 1; } } if (ATTR_CMN_FNDRINFO & commonattr) { uint64_t val; VERIFY(sa_lookup(zp->z_sa_hdl, SA_ZPL_FLAGS(zfsvfs), &val, sizeof(val)) == 0); getfinderinfo(zp, cr, &finderinfo); /* Shadow ZFS_HIDDEN to Finder Info's invisible bit */ if (val & ZFS_HIDDEN) { finderinfo.fi_flags |= OSSwapHostToBigConstInt16(kIsInvisible); } bcopy(&finderinfo, attrbufptr, sizeof (finderinfo)); attrbufptr = (char *)attrbufptr + 32; } if (ATTR_CMN_OWNERID & commonattr) { uint64_t val; VERIFY(sa_lookup(zp->z_sa_hdl, SA_ZPL_UID(zfsvfs), &val, sizeof(val)) == 0); *((uid_t *)attrbufptr) = val; attrbufptr = ((uid_t *)attrbufptr) + 1; } if (ATTR_CMN_GRPID & commonattr) { uint64_t val; VERIFY(sa_lookup(zp->z_sa_hdl, SA_ZPL_GID(zfsvfs), &val, sizeof(val)) == 0); *((gid_t *)attrbufptr) = val; attrbufptr = ((gid_t *)attrbufptr) + 1; } if (ATTR_CMN_ACCESSMASK & commonattr) { uint64_t val; VERIFY(sa_lookup(zp->z_sa_hdl, SA_ZPL_MODE(zfsvfs), &val, sizeof(val)) == 0); *((u_int32_t *)attrbufptr) = val; attrbufptr = ((u_int32_t *)attrbufptr) + 1; } if (ATTR_CMN_FLAGS & commonattr) { u_int32_t flags = zfs_getbsdflags(zp); /* Shadow Finder Info's invisible bit to UF_HIDDEN */ if ((ATTR_CMN_FNDRINFO & commonattr) && (OSSwapBigToHostInt16(finderinfo.fi_flags) & kIsInvisible)) flags |= UF_HIDDEN; *((u_int32_t *)attrbufptr) = flags; attrbufptr = ((u_int32_t *)attrbufptr) + 1; } if (ATTR_CMN_USERACCESS & commonattr) { u_int32_t user_access = 0; uint64_t val; VERIFY(sa_lookup(zp->z_sa_hdl, SA_ZPL_FLAGS(zfsvfs), &val, sizeof(val)) == 0); user_access = getuseraccess(zp, aip->ai_context); /* Also consider READ-ONLY file system. */ if (vfs_flags(mp) & MNT_RDONLY) { user_access &= ~W_OK; } /* Locked objects are not writable either */ if ((val & ZFS_IMMUTABLE) && (vfs_context_suser(aip->ai_context) != 0)) { user_access &= ~W_OK; } *((u_int32_t *)attrbufptr) = user_access; attrbufptr = ((u_int32_t *)attrbufptr) + 1; } if (ATTR_CMN_FILEID & commonattr) { /* * On Mac OS X we always export the root directory id as 2 */ if (objnum == zfsvfs->z_root) objnum = 2; *((u_int64_t *)attrbufptr) = objnum; attrbufptr = ((u_int64_t *)attrbufptr) + 1; } if (ATTR_CMN_PARENTID & commonattr) { uint64_t parentid; VERIFY(sa_lookup(zp->z_sa_hdl, SA_ZPL_PARENT(zfsvfs), &parentid, sizeof (parentid)) == 0); /* * On Mac OS X we always export the root * directory id as 2 and its parent as 1 */ if (zp && zp->z_id == zfsvfs->z_root) parentid = 1; else if (parentid == zfsvfs->z_root) parentid = 2; ASSERT(parentid != 0); *((u_int64_t *)attrbufptr) = parentid; attrbufptr = ((u_int64_t *)attrbufptr) + 1; } *aip->ai_attrbufpp = attrbufptr; *aip->ai_varbufpp = varbufptr; }
static int zfs_vfs_getattr(struct mount *mp, struct vfs_attr *fsap, __unused vfs_context_t context) { zfsvfs_t *zfsvfs = vfs_fsprivate(mp); uint64_t refdbytes, availbytes, usedobjs, availobjs; ZFS_ENTER(zfsvfs); dmu_objset_space(zfsvfs->z_os, &refdbytes, &availbytes, &usedobjs, &availobjs); VFSATTR_RETURN(fsap, f_objcount, usedobjs); VFSATTR_RETURN(fsap, f_maxobjcount, 0x7fffffffffffffff); /* * Carbon depends on f_filecount and f_dircount so * make up some values based on total objects. */ VFSATTR_RETURN(fsap, f_filecount, usedobjs - (usedobjs / 4)); VFSATTR_RETURN(fsap, f_dircount, usedobjs / 4); /* * The underlying storage pool actually uses multiple block sizes. * We report the fragsize as the smallest block size we support, * and we report our blocksize as the filesystem's maximum blocksize. */ VFSATTR_RETURN(fsap, f_bsize, 1UL << SPA_MINBLOCKSHIFT); VFSATTR_RETURN(fsap, f_iosize, zfsvfs->z_max_blksz); /* * The following report "total" blocks of various kinds in the * file system, but reported in terms of f_frsize - the * "fragment" size. */ VFSATTR_RETURN(fsap, f_blocks, (u_int64_t)((refdbytes + availbytes) >> SPA_MINBLOCKSHIFT)); VFSATTR_RETURN(fsap, f_bfree, (u_int64_t)(availbytes >> SPA_MINBLOCKSHIFT)); VFSATTR_RETURN(fsap, f_bavail, fsap->f_bfree); /* no root reservation */ VFSATTR_RETURN(fsap, f_bused, fsap->f_blocks - fsap->f_bfree); /* * statvfs() should really be called statufs(), because it assumes * static metadata. ZFS doesn't preallocate files, so the best * we can do is report the max that could possibly fit in f_files, * and that minus the number actually used in f_ffree. * For f_ffree, report the smaller of the number of object available * and the number of blocks (each object will take at least a block). */ VFSATTR_RETURN(fsap, f_ffree, (u_int64_t)MIN(availobjs, fsap->f_bfree)); VFSATTR_RETURN(fsap, f_files, fsap->f_ffree + usedobjs); #if 0 statp->f_flag = vf_to_stf(vfsp->vfs_flag); #endif if (VFSATTR_IS_ACTIVE(fsap, f_fsid)) { VFSATTR_RETURN(fsap, f_fsid, vfs_statfs(mp)->f_fsid); } if (VFSATTR_IS_ACTIVE(fsap, f_capabilities)) { bcopy(&zfs_capabilities, &fsap->f_capabilities, sizeof (zfs_capabilities)); VFSATTR_SET_SUPPORTED(fsap, f_capabilities); } if (VFSATTR_IS_ACTIVE(fsap, f_attributes)) { bcopy(&zfs_attributes, &fsap->f_attributes.validattr, sizeof (zfs_attributes)); bcopy(&zfs_attributes, &fsap->f_attributes.nativeattr, sizeof (zfs_attributes)); VFSATTR_SET_SUPPORTED(fsap, f_attributes); } if (VFSATTR_IS_ACTIVE(fsap, f_create_time)) { dmu_objset_stats_t dmu_stat; dmu_objset_fast_stat(zfsvfs->z_os, &dmu_stat); fsap->f_create_time.tv_sec = dmu_stat.dds_creation_time; fsap->f_create_time.tv_nsec = 0; VFSATTR_SET_SUPPORTED(fsap, f_create_time); } if (VFSATTR_IS_ACTIVE(fsap, f_modify_time)) { if (zfsvfs->z_mtime_vp != NULL) { znode_t *mzp; mzp = VTOZ(zfsvfs->z_mtime_vp); ZFS_TIME_DECODE(&fsap->f_modify_time, mzp->z_phys->zp_mtime); } else { fsap->f_modify_time.tv_sec = 0; fsap->f_modify_time.tv_nsec = 0; } VFSATTR_SET_SUPPORTED(fsap, f_modify_time); } /* * For Carbon compatibility, pretend to support this legacy/unused * attribute */ if (VFSATTR_IS_ACTIVE(fsap, f_backup_time)) { fsap->f_backup_time.tv_sec = 0; fsap->f_backup_time.tv_nsec = 0; VFSATTR_SET_SUPPORTED(fsap, f_backup_time); } if (VFSATTR_IS_ACTIVE(fsap, f_vol_name)) { spa_t *spa = dmu_objset_spa(zfsvfs->z_os); spa_config_enter(spa, RW_READER, FTAG); strlcpy(fsap->f_vol_name, spa_name(spa), MAXPATHLEN); spa_config_exit(spa, FTAG); VFSATTR_SET_SUPPORTED(fsap, f_vol_name); } VFSATTR_RETURN(fsap, f_fssubtype, 0); VFSATTR_RETURN(fsap, f_signature, 0x5a21); /* 'Z!' */ VFSATTR_RETURN(fsap, f_carbon_fsid, 0); ZFS_EXIT(zfsvfs); return (0); }
static int zfs_vfs_mount(struct mount *mp, vnode_t devvp, user_addr_t data, vfs_context_t context) { char *osname = NULL; size_t osnamelen = 0; int error = 0; int canwrite; /* * Get the objset name (the "special" mount argument). * The filesystem that we mount as root is defined in the * "zfs-bootfs" property. */ if (data) { user_addr_t fspec = USER_ADDR_NULL; #ifndef __APPLE__ if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(), DDI_PROP_DONTPASS, "zfs-bootfs", &zfs_bootpath) != DDI_SUCCESS) return (EIO); error = parse_bootpath(zfs_bootpath, rootfs.bo_name); ddi_prop_free(zfs_bootpath); #endif osname = kmem_alloc(MAXPATHLEN, KM_SLEEP); if (vfs_context_is64bit(context)) { if ( (error = copyin(data, (caddr_t)&fspec, sizeof(fspec))) ) goto out; } else { #ifdef ZFS_LEOPARD_ONLY char *tmp; #else user32_addr_t tmp; #endif if ( (error = copyin(data, (caddr_t)&tmp, sizeof(tmp))) ) goto out; /* munge into LP64 addr */ fspec = CAST_USER_ADDR_T(tmp); } if ( (error = copyinstr(fspec, osname, MAXPATHLEN, &osnamelen)) ) goto out; } #if 0 if (mvp->v_type != VDIR) return (ENOTDIR); mutex_enter(&mvp->v_lock); if ((uap->flags & MS_REMOUNT) == 0 && (uap->flags & MS_OVERLAY) == 0 && (mvp->v_count != 1 || (mvp->v_flag & VROOT))) { mutex_exit(&mvp->v_lock); return (EBUSY); } mutex_exit(&mvp->v_lock); /* * ZFS does not support passing unparsed data in via MS_DATA. * Users should use the MS_OPTIONSTR interface; this means * that all option parsing is already done and the options struct * can be interrogated. */ if ((uap->flags & MS_DATA) && uap->datalen > 0) return (EINVAL); /* * Get the objset name (the "special" mount argument). */ if (error = pn_get(uap->spec, fromspace, &spn)) return (error); osname = spn.pn_path; #endif /* * Check for mount privilege? * * If we don't have privilege then see if * we have local permission to allow it */ #ifndef __APPLE__ error = secpolicy_fs_mount(cr, mvp, vfsp); if (error) { error = dsl_deleg_access(osname, ZFS_DELEG_PERM_MOUNT, cr); if (error == 0) { vattr_t vattr; /* * Make sure user is the owner of the mount point * or has sufficient privileges. */ vattr.va_mask = AT_UID; if (error = VOP_GETATTR(mvp, &vattr, 0, cr)) { goto out; } if (error = secpolicy_vnode_owner(cr, vattr.va_uid)) { goto out; } if (error = VOP_ACCESS(mvp, VWRITE, 0, cr)) { goto out; } secpolicy_fs_mount_clearopts(cr, vfsp); } else { goto out; } } #endif error = zfs_domount(mp, 0, osname, context); if (error) printf("zfs_vfs_mount: error %d\n", error); if (error == 0) { zfsvfs_t *zfsvfs = NULL; /* Make the Finder treat sub file systems just like a folder */ if (strpbrk(osname, "/")) vfs_setflags(mp, (u_int64_t)((unsigned int)MNT_DONTBROWSE)); /* Indicate to VFS that we support ACLs. */ vfs_setextendedsecurity(mp); /* Advisory locking should be handled at the VFS layer */ vfs_setlocklocal(mp); /* * Mac OS X needs a file system modify time * * We use the mtime of the "com.apple.system.mtime" * extended attribute, which is associated with the * file system root directory. * * Here we need to take a ref on z_mtime_vp to keep it around. * If the attribute isn't there, attempt to create it. */ zfsvfs = vfs_fsprivate(mp); if (zfsvfs->z_mtime_vp == NULL) { struct vnode * rvp; struct vnode *xdvp = NULLVP; struct vnode *xvp = NULLVP; znode_t *rootzp; timestruc_t modify_time; cred_t *cr; timestruc_t now; int flag; int result; if (zfs_zget(zfsvfs, zfsvfs->z_root, &rootzp) != 0) { goto out; } rvp = ZTOV(rootzp); cr = (cred_t *)vfs_context_ucred(context); /* Grab the hidden attribute directory vnode. */ result = zfs_get_xattrdir(rootzp, &xdvp, cr, CREATE_XATTR_DIR); vnode_put(rvp); /* all done with root vnode */ rvp = NULL; if (result) { goto out; } /* * HACK - workaround missing vnode_setnoflush() KPI... * * We tag zfsvfs so that zfs_attach_vnode() can then set * vnfs_marksystem when the vnode gets created. */ zfsvfs->z_last_unmount_time = 0xBADC0DE; zfsvfs->z_last_mtime_synced = VTOZ(xdvp)->z_id; flag = vfs_isrdonly(mp) ? 0 : ZEXISTS; /* Lookup or create the named attribute. */ if ( zfs_obtain_xattr(VTOZ(xdvp), ZFS_MTIME_XATTR, S_IRUSR | S_IWUSR, cr, &xvp, flag) ) { zfsvfs->z_last_unmount_time = 0; zfsvfs->z_last_mtime_synced = 0; vnode_put(xdvp); goto out; } gethrestime(&now); ZFS_TIME_ENCODE(&now, VTOZ(xvp)->z_phys->zp_mtime); vnode_put(xdvp); vnode_ref(xvp); zfsvfs->z_mtime_vp = xvp; ZFS_TIME_DECODE(&modify_time, VTOZ(xvp)->z_phys->zp_mtime); zfsvfs->z_last_unmount_time = modify_time.tv_sec; zfsvfs->z_last_mtime_synced = modify_time.tv_sec; /* * Keep this referenced vnode from impeding an unmount. * * XXX vnode_setnoflush() is MIA from KPI (see workaround above). */ #if 0 vnode_setnoflush(xvp); #endif vnode_put(xvp); } } out: if (osname) { kmem_free(osname, MAXPATHLEN); } return (error); }
/* For part 1 of zfs_getattr() */ int zfs_getattr_znode_locked(vattr_t *vap, znode_t *zp, cred_t *cr) { zfsvfs_t *zfsvfs = zp->z_zfsvfs; int error; uint64_t times[2]; uint64_t val; VERIFY(sa_lookup(zp->z_sa_hdl, SA_ZPL_MODE(zfsvfs), &val, sizeof (val)) == 0); vap->va_mode = val & MODEMASK; VERIFY(sa_lookup(zp->z_sa_hdl, SA_ZPL_UID(zfsvfs), &val, sizeof (val)) == 0); vap->va_uid = val; VERIFY(sa_lookup(zp->z_sa_hdl, SA_ZPL_GID(zfsvfs), &val, sizeof (val)) == 0); vap->va_gid = val; //vap->va_fsid = zp->z_zfsvfs->z_vfs->vfs_dev; /* On OS X, the root directory id is always 2 */ vap->va_fileid = (zp->z_id == zfsvfs->z_root) ? 2 : zp->z_id; VERIFY(sa_lookup(zp->z_sa_hdl, SA_ZPL_LINKS(zfsvfs), &val, sizeof (val)) == 0); vap->va_nlink = val; VERIFY(sa_lookup(zp->z_sa_hdl, SA_ZPL_SIZE(zfsvfs), &val, sizeof (val)) == 0); vap->va_data_size = val; vap->va_total_size = val; VERIFY(sa_lookup(zp->z_sa_hdl, SA_ZPL_RDEV(zfsvfs), &val, sizeof (val)) == 0); vap->va_rdev = val; VERIFY(sa_lookup(zp->z_sa_hdl, SA_ZPL_GEN(zfsvfs), &val, sizeof (val)) == 0); vap->va_gen = val; (void) sa_lookup(zp->z_sa_hdl, SA_ZPL_CRTIME(zfsvfs), times, sizeof (times)); ZFS_TIME_DECODE(&vap->va_create_time, times); (void) sa_lookup(zp->z_sa_hdl, SA_ZPL_ATIME(zfsvfs), times, sizeof (times)); ZFS_TIME_DECODE(&vap->va_access_time, times); (void) sa_lookup(zp->z_sa_hdl, SA_ZPL_MTIME(zfsvfs), times, sizeof (times)); ZFS_TIME_DECODE(&vap->va_modify_time, times); (void) sa_lookup(zp->z_sa_hdl, SA_ZPL_CTIME(zfsvfs), times, sizeof (times)); ZFS_TIME_DECODE(&vap->va_change_time, times); if (VATTR_IS_ACTIVE(vap, va_backup_time)) { vap->va_backup_time.tv_sec = 0; vap->va_backup_time.tv_nsec = 0; VATTR_SET_SUPPORTED(vap, va_backup_time); } vap->va_flags = zfs_getbsdflags(zp); /* On OS X, the root directory id is always 2 and its parent is 1 */ VERIFY(sa_lookup(zp->z_sa_hdl, SA_ZPL_PARENT(zfsvfs), &val, sizeof (val)) == 0); if (zp->z_id == zfsvfs->z_root) vap->va_parentid = 1; else if (val == zfsvfs->z_root) vap->va_parentid = 2; else vap->va_parentid = val; vap->va_iosize = zp->z_blksz ? zp->z_blksz : zfsvfs->z_max_blksz; VATTR_SET_SUPPORTED(vap, va_iosize); printf("stat blksize set to %d\n", vap->va_iosize); vap->va_supported |= ZFS_SUPPORTED_VATTRS; if (VATTR_IS_ACTIVE(vap, va_nchildren) && vnode_isdir(ZTOV(zp))) VATTR_RETURN(vap, va_nchildren, vap->va_nlink - 2); if (VATTR_IS_ACTIVE(vap, va_acl)) { if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_ZNODE_ACL(zfsvfs), times, sizeof (times)))) { // if (zp->z_phys->zp_acl.z_acl_count == 0) { vap->va_acl = (kauth_acl_t) KAUTH_FILESEC_NONE; } else { error = zfs_getacl(zp, &vap->va_acl, B_TRUE, cr); if (error) return (error); VATTR_SET_SUPPORTED(vap, va_acl); /* * va_acl implies that va_uuuid and va_guuid are * also supported. */ VATTR_RETURN(vap, va_uuuid, kauth_null_guid); VATTR_RETURN(vap, va_guuid, kauth_null_guid); } } return (0); }
static int zfs_replay_create(zfsvfs_t *zfsvfs, lr_create_t *lr, boolean_t byteswap) { char *name = NULL; /* location determined later */ char *link; /* symlink content follows name */ znode_t *dzp; struct inode *ip = NULL; xvattr_t xva; int vflg = 0; size_t lrsize = sizeof (lr_create_t); lr_attr_t *lrattr; void *start; size_t xvatlen; uint64_t txtype; uint64_t objid; uint64_t dnodesize; int error; txtype = (lr->lr_common.lrc_txtype & ~TX_CI); if (byteswap) { byteswap_uint64_array(lr, sizeof (*lr)); if (txtype == TX_CREATE_ATTR || txtype == TX_MKDIR_ATTR) zfs_replay_swap_attrs((lr_attr_t *)(lr + 1)); } if ((error = zfs_zget(zfsvfs, lr->lr_doid, &dzp)) != 0) return (error); objid = LR_FOID_GET_OBJ(lr->lr_foid); dnodesize = LR_FOID_GET_SLOTS(lr->lr_foid) << DNODE_SHIFT; xva_init(&xva); zfs_init_vattr(&xva.xva_vattr, ATTR_MODE | ATTR_UID | ATTR_GID, lr->lr_mode, lr->lr_uid, lr->lr_gid, lr->lr_rdev, objid); /* * All forms of zfs create (create, mkdir, mkxattrdir, symlink) * eventually end up in zfs_mknode(), which assigns the object's * creation time, generation number, and dnode slot count. The * generic zfs_create() has no concept of these attributes, so * we smuggle the values inside * the vattr's otherwise unused * va_ctime, va_nblocks, and va_nlink fields. */ ZFS_TIME_DECODE(&xva.xva_vattr.va_ctime, lr->lr_crtime); xva.xva_vattr.va_nblocks = lr->lr_gen; xva.xva_vattr.va_fsid = dnodesize; error = dmu_object_info(zfsvfs->z_os, objid, NULL); if (error != ENOENT) goto out; if (lr->lr_common.lrc_txtype & TX_CI) vflg |= FIGNORECASE; /* * Symlinks don't have fuid info, and CIFS never creates * symlinks. * * The _ATTR versions will grab the fuid info in their subcases. */ if ((int)lr->lr_common.lrc_txtype != TX_SYMLINK && (int)lr->lr_common.lrc_txtype != TX_MKDIR_ATTR && (int)lr->lr_common.lrc_txtype != TX_CREATE_ATTR) { start = (lr + 1); zfsvfs->z_fuid_replay = zfs_replay_fuid_domain(start, &start, lr->lr_uid, lr->lr_gid); } switch (txtype) { case TX_CREATE_ATTR: lrattr = (lr_attr_t *)(caddr_t)(lr + 1); xvatlen = ZIL_XVAT_SIZE(lrattr->lr_attr_masksize); zfs_replay_xvattr((lr_attr_t *)((caddr_t)lr + lrsize), &xva); start = (caddr_t)(lr + 1) + xvatlen; zfsvfs->z_fuid_replay = zfs_replay_fuid_domain(start, &start, lr->lr_uid, lr->lr_gid); name = (char *)start; /*FALLTHROUGH*/ case TX_CREATE: if (name == NULL) name = (char *)start; error = zfs_create(ZTOI(dzp), name, &xva.xva_vattr, 0, 0, &ip, kcred, vflg, NULL); break; case TX_MKDIR_ATTR: lrattr = (lr_attr_t *)(caddr_t)(lr + 1); xvatlen = ZIL_XVAT_SIZE(lrattr->lr_attr_masksize); zfs_replay_xvattr((lr_attr_t *)((caddr_t)lr + lrsize), &xva); start = (caddr_t)(lr + 1) + xvatlen; zfsvfs->z_fuid_replay = zfs_replay_fuid_domain(start, &start, lr->lr_uid, lr->lr_gid); name = (char *)start; /*FALLTHROUGH*/ case TX_MKDIR: if (name == NULL) name = (char *)(lr + 1); error = zfs_mkdir(ZTOI(dzp), name, &xva.xva_vattr, &ip, kcred, vflg, NULL); break; case TX_MKXATTR: error = zfs_make_xattrdir(dzp, &xva.xva_vattr, &ip, kcred); break; case TX_SYMLINK: name = (char *)(lr + 1); link = name + strlen(name) + 1; error = zfs_symlink(ZTOI(dzp), name, &xva.xva_vattr, link, &ip, kcred, vflg); break; default: error = SET_ERROR(ENOTSUP); } out: if (error == 0 && ip != NULL) iput(ip); iput(ZTOI(dzp)); if (zfsvfs->z_fuid_replay) zfs_fuid_info_free(zfsvfs->z_fuid_replay); zfsvfs->z_fuid_replay = NULL; return (error); }
/* * Replay file create with optional ACL, xvattr information as well * as option FUID information. */ static int zfs_replay_create_acl(zfsvfs_t *zfsvfs, lr_acl_create_t *lracl, boolean_t byteswap) { char *name = NULL; /* location determined later */ lr_create_t *lr = (lr_create_t *)lracl; znode_t *dzp; struct inode *ip = NULL; xvattr_t xva; int vflg = 0; vsecattr_t vsec = { 0 }; lr_attr_t *lrattr; void *aclstart; void *fuidstart; size_t xvatlen = 0; uint64_t txtype; uint64_t objid; uint64_t dnodesize; int error; txtype = (lr->lr_common.lrc_txtype & ~TX_CI); if (byteswap) { byteswap_uint64_array(lracl, sizeof (*lracl)); if (txtype == TX_CREATE_ACL_ATTR || txtype == TX_MKDIR_ACL_ATTR) { lrattr = (lr_attr_t *)(caddr_t)(lracl + 1); zfs_replay_swap_attrs(lrattr); xvatlen = ZIL_XVAT_SIZE(lrattr->lr_attr_masksize); } aclstart = (caddr_t)(lracl + 1) + xvatlen; zfs_ace_byteswap(aclstart, lracl->lr_acl_bytes, B_FALSE); /* swap fuids */ if (lracl->lr_fuidcnt) { byteswap_uint64_array((caddr_t)aclstart + ZIL_ACE_LENGTH(lracl->lr_acl_bytes), lracl->lr_fuidcnt * sizeof (uint64_t)); } } if ((error = zfs_zget(zfsvfs, lr->lr_doid, &dzp)) != 0) return (error); objid = LR_FOID_GET_OBJ(lr->lr_foid); dnodesize = LR_FOID_GET_SLOTS(lr->lr_foid) << DNODE_SHIFT; xva_init(&xva); zfs_init_vattr(&xva.xva_vattr, ATTR_MODE | ATTR_UID | ATTR_GID, lr->lr_mode, lr->lr_uid, lr->lr_gid, lr->lr_rdev, objid); /* * All forms of zfs create (create, mkdir, mkxattrdir, symlink) * eventually end up in zfs_mknode(), which assigns the object's * creation time, generation number, and dnode size. The generic * zfs_create() has no concept of these attributes, so we smuggle * the values inside the vattr's otherwise unused va_ctime, * va_nblocks, and va_fsid fields. */ ZFS_TIME_DECODE(&xva.xva_vattr.va_ctime, lr->lr_crtime); xva.xva_vattr.va_nblocks = lr->lr_gen; xva.xva_vattr.va_fsid = dnodesize; error = dmu_object_info(zfsvfs->z_os, lr->lr_foid, NULL); if (error != ENOENT) goto bail; if (lr->lr_common.lrc_txtype & TX_CI) vflg |= FIGNORECASE; switch (txtype) { case TX_CREATE_ACL: aclstart = (caddr_t)(lracl + 1); fuidstart = (caddr_t)aclstart + ZIL_ACE_LENGTH(lracl->lr_acl_bytes); zfsvfs->z_fuid_replay = zfs_replay_fuids(fuidstart, (void *)&name, lracl->lr_fuidcnt, lracl->lr_domcnt, lr->lr_uid, lr->lr_gid); /*FALLTHROUGH*/ case TX_CREATE_ACL_ATTR: if (name == NULL) { lrattr = (lr_attr_t *)(caddr_t)(lracl + 1); xvatlen = ZIL_XVAT_SIZE(lrattr->lr_attr_masksize); xva.xva_vattr.va_mask |= ATTR_XVATTR; zfs_replay_xvattr(lrattr, &xva); } vsec.vsa_mask = VSA_ACE | VSA_ACE_ACLFLAGS; vsec.vsa_aclentp = (caddr_t)(lracl + 1) + xvatlen; vsec.vsa_aclcnt = lracl->lr_aclcnt; vsec.vsa_aclentsz = lracl->lr_acl_bytes; vsec.vsa_aclflags = lracl->lr_acl_flags; if (zfsvfs->z_fuid_replay == NULL) { fuidstart = (caddr_t)(lracl + 1) + xvatlen + ZIL_ACE_LENGTH(lracl->lr_acl_bytes); zfsvfs->z_fuid_replay = zfs_replay_fuids(fuidstart, (void *)&name, lracl->lr_fuidcnt, lracl->lr_domcnt, lr->lr_uid, lr->lr_gid); } error = zfs_create(ZTOI(dzp), name, &xva.xva_vattr, 0, 0, &ip, kcred, vflg, &vsec); break; case TX_MKDIR_ACL: aclstart = (caddr_t)(lracl + 1); fuidstart = (caddr_t)aclstart + ZIL_ACE_LENGTH(lracl->lr_acl_bytes); zfsvfs->z_fuid_replay = zfs_replay_fuids(fuidstart, (void *)&name, lracl->lr_fuidcnt, lracl->lr_domcnt, lr->lr_uid, lr->lr_gid); /*FALLTHROUGH*/ case TX_MKDIR_ACL_ATTR: if (name == NULL) { lrattr = (lr_attr_t *)(caddr_t)(lracl + 1); xvatlen = ZIL_XVAT_SIZE(lrattr->lr_attr_masksize); zfs_replay_xvattr(lrattr, &xva); } vsec.vsa_mask = VSA_ACE | VSA_ACE_ACLFLAGS; vsec.vsa_aclentp = (caddr_t)(lracl + 1) + xvatlen; vsec.vsa_aclcnt = lracl->lr_aclcnt; vsec.vsa_aclentsz = lracl->lr_acl_bytes; vsec.vsa_aclflags = lracl->lr_acl_flags; if (zfsvfs->z_fuid_replay == NULL) { fuidstart = (caddr_t)(lracl + 1) + xvatlen + ZIL_ACE_LENGTH(lracl->lr_acl_bytes); zfsvfs->z_fuid_replay = zfs_replay_fuids(fuidstart, (void *)&name, lracl->lr_fuidcnt, lracl->lr_domcnt, lr->lr_uid, lr->lr_gid); } error = zfs_mkdir(ZTOI(dzp), name, &xva.xva_vattr, &ip, kcred, vflg, &vsec); break; default: error = SET_ERROR(ENOTSUP); } bail: if (error == 0 && ip != NULL) iput(ip); iput(ZTOI(dzp)); if (zfsvfs->z_fuid_replay) zfs_fuid_info_free(zfsvfs->z_fuid_replay); zfsvfs->z_fuid_replay = NULL; return (error); }