FreeBSD/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_acl.c
/*
 * Set a file's ACL
 */
Set a file's ACL
Set a file ' s ACL
int
zfs_setacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr)
{
	zfsvfs_t	*zfsvfs = zp->z_zfsvfs;
	zilog_t		*zilog = zfsvfs->z_log;
	ulong_t		mask = vsecp->vsa_mask & (VSA_ACE | VSA_ACECNT);
	dmu_tx_t	*tx;
	int		error;
	zfs_acl_t	*aclp;
	zfs_fuid_info_t	*fuidp = NULL;
	boolean_t	fuid_dirtied;
	uint64_t	acl_obj;
	ASSERT_VOP_ELOCKED(ZTOV(zp), __func__);
	if (mask == 0)
		return (SET_ERROR(ENOSYS));
	if (zp->z_pflags & ZFS_IMMUTABLE)
		return (SET_ERROR(EPERM));
	if (error = zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr))
		return (error);
	error = zfs_vsec_2_aclp(zfsvfs, ZTOV(zp)->v_type, vsecp, cr, &fuidp,
	    &aclp);
	if (error)
		return (error);
	if (!(vsecp->vsa_mask & VSA_ACE_ACLFLAGS)) {
		aclp->z_hints |=
		    (zp->z_pflags & V4_ACL_WIDE_FLAGS);
	}
top:
	mutex_enter(&zp->z_acl_lock);
	tx = dmu_tx_create(zfsvfs->z_os);
	dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_TRUE);
	fuid_dirtied = zfsvfs->z_fuid_dirty;
	if (fuid_dirtied)
		zfs_fuid_txhold(zfsvfs, tx);
	if ((acl_obj = zfs_external_acl(zp)) != 0) {
		if (zfsvfs->z_version >= ZPL_VERSION_FUID &&
		    zfs_znode_acl_version(zp) <= ZFS_ACL_VERSION_INITIAL) {
			dmu_tx_hold_free(tx, acl_obj, 0,
			    DMU_OBJECT_END);
			dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0,
			    aclp->z_acl_bytes);
		} else {
			dmu_tx_hold_write(tx, acl_obj, 0, aclp->z_acl_bytes);
		}
	} else if (!zp->z_is_sa && aclp->z_acl_bytes > ZFS_ACE_SPACE) {
		dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, aclp->z_acl_bytes);
	}
	zfs_sa_upgrade_txholds(tx, zp);
	error = dmu_tx_assign(tx, TXG_NOWAIT);
	if (error) {
		mutex_exit(&zp->z_acl_lock);
		if (error == ERESTART) {
			dmu_tx_wait(tx);
			dmu_tx_abort(tx);
			goto top;
		}
		dmu_tx_abort(tx);
		zfs_acl_free(aclp);
		return (error);
	}
	error = zfs_aclset_common(zp, aclp, cr, tx);
	ASSERT(error == 0);
	ASSERT(zp->z_acl_cached == NULL);
	zp->z_acl_cached = aclp;
	if (fuid_dirtied)
		zfs_fuid_sync(zfsvfs, tx);
	zfs_log_acl(zilog, tx, zp, vsecp, fuidp);
	if (fuidp)
		zfs_fuid_info_free(fuidp);
	dmu_tx_commit(tx);
	mutex_exit(&zp->z_acl_lock);
	return (error);
}
int zfs_setacl ( znode_t * zp , vsecattr_t * vsecp , boolean_t skipaclchk , cred_t * cr ) { zfsvfs_t * zfsvfs = zp -> z_zfsvfs ; zilog_t * zilog = zfsvfs -> z_log ; ulong_t mask = vsecp -> vsa_mask & ( VSA_ACE | VSA_ACECNT ) ; dmu_tx_t * tx ; int error ; zfs_acl_t * aclp ; zfs_fuid_info_t * fuidp = NULL ; boolean_t fuid_dirtied ; uint64_t acl_obj ; ASSERT_VOP_ELOCKED ( ZTOV ( zp ) , __func__ ) ; if ( mask == 0 ) return ( SET_ERROR ( ENOSYS ) ) ; if ( zp -> z_pflags & ZFS_IMMUTABLE ) return ( SET_ERROR ( EPERM ) ) ; if ( error = zfs_zaccess ( zp , ACE_WRITE_ACL , 0 , skipaclchk , cr ) ) return ( error ) ; error = zfs_vsec_2_aclp ( zfsvfs , ZTOV ( zp ) -> v_type , vsecp , cr , & fuidp , & aclp ) ; if ( error ) return ( error ) ; if ( ! ( vsecp -> vsa_mask & VSA_ACE_ACLFLAGS ) ) { aclp -> z_hints |= ( zp -> z_pflags & V4_ACL_WIDE_FLAGS ) ; } top : mutex_enter ( & zp -> z_acl_lock ) ; tx = dmu_tx_create ( zfsvfs -> z_os ) ; dmu_tx_hold_sa ( tx , zp -> z_sa_hdl , B_TRUE ) ; fuid_dirtied = zfsvfs -> z_fuid_dirty ; if ( fuid_dirtied ) zfs_fuid_txhold ( zfsvfs , tx ) ; if ( ( acl_obj = zfs_external_acl ( zp ) ) != 0 ) { if ( zfsvfs -> z_version >= ZPL_VERSION_FUID && zfs_znode_acl_version ( zp ) <= ZFS_ACL_VERSION_INITIAL ) { dmu_tx_hold_free ( tx , acl_obj , 0 , DMU_OBJECT_END ) ; dmu_tx_hold_write ( tx , DMU_NEW_OBJECT , 0 , aclp -> z_acl_bytes ) ; } else { dmu_tx_hold_write ( tx , acl_obj , 0 , aclp -> z_acl_bytes ) ; } } else if ( ! zp -> z_is_sa && aclp -> z_acl_bytes > ZFS_ACE_SPACE ) { dmu_tx_hold_write ( tx , DMU_NEW_OBJECT , 0 , aclp -> z_acl_bytes ) ; } zfs_sa_upgrade_txholds ( tx , zp ) ; error = dmu_tx_assign ( tx , TXG_NOWAIT ) ; if ( error ) { mutex_exit ( & zp -> z_acl_lock ) ; if ( error == ERESTART ) { dmu_tx_wait ( tx ) ; dmu_tx_abort ( tx ) ; goto top ; } dmu_tx_abort ( tx ) ; zfs_acl_free ( aclp ) ; return ( error ) ; } error = zfs_aclset_common ( zp , aclp , cr , tx ) ; ASSERT ( error == 0 ) ; ASSERT ( zp -> z_acl_cached == NULL ) ; zp -> z_acl_cached = aclp ; if ( fuid_dirtied ) zfs_fuid_sync ( zfsvfs , tx ) ; zfs_log_acl ( zilog , tx , zp , vsecp , fuidp ) ; if ( fuidp ) zfs_fuid_info_free ( fuidp ) ; dmu_tx_commit ( tx ) ; mutex_exit ( & zp -> z_acl_lock ) ; return ( error ) ; }
Set a file's ACL
Set a file ' s ACL
/*
	 * If ACL wide flags aren't being set then preserve any
	 * existing flags.
	 */ /*
	 * If old version and ACL won't fit in bonus and we aren't
	 * upgrading then take out necessary DMU holds
	 */