Example #1
0
/*
 * zfs_log_create() is used to handle TX_CREATE, TX_CREATE_ATTR, TX_MKDIR,
 * TX_MKDIR_ATTR and TX_MKXATTR
 * transactions.
 *
 * TX_CREATE and TX_MKDIR are standard creates, but they may have FUID
 * domain information appended prior to the name.  In this case the
 * uid/gid in the log record will be a log centric FUID.
 *
 * TX_CREATE_ACL_ATTR and TX_MKDIR_ACL_ATTR handle special creates that
 * may contain attributes, ACL and optional fuid information.
 *
 * TX_CREATE_ACL and TX_MKDIR_ACL handle special creates that specify
 * and ACL and normal users/groups in the ACEs.
 *
 * There may be an optional xvattr attribute information similar
 * to zfs_log_setattr.
 *
 * Also, after the file name "domain" strings may be appended.
 */
void
zfs_log_create(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype,
               znode_t *dzp, znode_t *zp, char *name, vsecattr_t *vsecp,
               zfs_fuid_info_t *fuidp, vattr_t *vap)
{
    itx_t *itx;
    uint64_t seq;
    lr_create_t *lr;
#ifdef HAVE_ZPL
    lr_acl_create_t *lracl;
#endif
    size_t aclsize;
    size_t xvatsize = 0;
    size_t txsize;
    xvattr_t *xvap = (xvattr_t *)vap;
    void *end;
    size_t lrsize;
    size_t namesize = strlen(name) + 1;
    size_t fuidsz = 0;

    if (zilog == NULL)
        return;

    ZFS_HANDLE_REPLAY(zilog, tx); /* exits if replay */

    /*
     * If we have FUIDs present then add in space for
     * domains and ACE fuid's if any.
     */
    if (fuidp) {
        fuidsz += fuidp->z_domain_str_sz;
        fuidsz += fuidp->z_fuid_cnt * sizeof (uint64_t);
    }

    if (vap->va_mask & AT_XVATTR)
        xvatsize = ZIL_XVAT_SIZE(xvap->xva_mapsize);

    if ((int)txtype == TX_CREATE_ATTR || (int)txtype == TX_MKDIR_ATTR ||
            (int)txtype == TX_CREATE || (int)txtype == TX_MKDIR ||
            (int)txtype == TX_MKXATTR) {
        txsize = sizeof (*lr) + namesize + fuidsz + xvatsize;
        lrsize = sizeof (*lr);
    } else {
        aclsize = (vsecp) ? vsecp->vsa_aclentsz : 0;
        txsize =
            sizeof (lr_acl_create_t) + namesize + fuidsz +
            ZIL_ACE_LENGTH(aclsize) + xvatsize;
        lrsize = sizeof (lr_acl_create_t);
    }

    itx = zil_itx_create(txtype, txsize);

    lr = (lr_create_t *)&itx->itx_lr;
    lr->lr_doid = dzp->z_id;
    lr->lr_foid = zp->z_id;
    lr->lr_mode = zp->z_phys->zp_mode;
    if (!IS_EPHEMERAL(zp->z_phys->zp_uid)) {
        lr->lr_uid = (uint64_t)zp->z_phys->zp_uid;
    } else {
        lr->lr_uid = fuidp->z_fuid_owner;
    }
    if (!IS_EPHEMERAL(zp->z_phys->zp_gid)) {
        lr->lr_gid = (uint64_t)zp->z_phys->zp_gid;
    } else {
        lr->lr_gid = fuidp->z_fuid_group;
    }
    lr->lr_gen = zp->z_phys->zp_gen;
    lr->lr_crtime[0] = zp->z_phys->zp_crtime[0];
    lr->lr_crtime[1] = zp->z_phys->zp_crtime[1];
    lr->lr_rdev = zp->z_phys->zp_rdev;

    /*
     * Fill in xvattr info if any
     */
#ifdef HAVE_ZPL
    if (vap->va_mask & AT_XVATTR) {
        zfs_log_xvattr((lr_attr_t *)((caddr_t)lr + lrsize), xvap);
        end = (caddr_t)lr + lrsize + xvatsize;
    } else {
        end = (caddr_t)lr + lrsize;
    }
#else
    end = (caddr_t)lr + lrsize;
#endif /* HAVE_ZPL */


    /* Now fill in any ACL info */

#ifdef HAVE_ZPL
    if (vsecp) {
        lracl = (lr_acl_create_t *)&itx->itx_lr;
        lracl->lr_aclcnt = vsecp->vsa_aclcnt;
        lracl->lr_acl_bytes = aclsize;
        lracl->lr_domcnt = fuidp ? fuidp->z_domain_cnt : 0;
        lracl->lr_fuidcnt  = fuidp ? fuidp->z_fuid_cnt : 0;
        if (vsecp->vsa_aclflags & VSA_ACE_ACLFLAGS)
            lracl->lr_acl_flags = (uint64_t)vsecp->vsa_aclflags;
        else
            lracl->lr_acl_flags = 0;

        bcopy(vsecp->vsa_aclentp, end, aclsize);
        end = (caddr_t)end + ZIL_ACE_LENGTH(aclsize);
    }

    /* drop in FUID info */
    if (fuidp) {
        end = zfs_log_fuid_ids(fuidp, end);
        end = zfs_log_fuid_domains(fuidp, end);
    }
#endif
    /*
     * Now place file name in log record
     */
    bcopy(name, end, namesize);

    seq = zil_itx_assign(zilog, itx, tx);
    dzp->z_last_itx = seq;
    zp->z_last_itx = seq;
}
Example #2
0
/*
 * 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);
        }

        error = VOP_CREATE(ZTOV(dzp), name, &xva.xva_vattr,
                           0, 0, &vp, kcred, vflg, NULL, &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 = VOP_MKDIR(ZTOV(dzp), name, &xva.xva_vattr,
                          &vp, kcred, NULL, vflg, &vsec);
        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);
}
Example #3
0
/*
 * Replay file create with optional ACL, xvattr information as well
 * as option FUID information.
 */
static int
zfs_replay_create_acl(zfs_sb_t *zsb, 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(zsb, 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(zsb->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);
		zsb->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 (zsb->z_fuid_replay == NULL) {
			fuidstart = (caddr_t)(lracl + 1) + xvatlen +
			    ZIL_ACE_LENGTH(lracl->lr_acl_bytes);
			zsb->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);
		zsb->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 (zsb->z_fuid_replay == NULL) {
			fuidstart = (caddr_t)(lracl + 1) + xvatlen +
			    ZIL_ACE_LENGTH(lracl->lr_acl_bytes);
			zsb->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 (zsb->z_fuid_replay)
		zfs_fuid_info_free(zsb->z_fuid_replay);
	zsb->z_fuid_replay = NULL;

	return (error);
}