zfs_acl_chmod(vtype_t vtype, uint64_t mode, boolean_t split, boolean_t trim,
    zfs_acl_t *aclp)
{
	void		*acep = NULL;
	uint64_t	who;
	int		new_count, new_bytes;
	int		ace_size;
	int 		entry_type;
	uint16_t	iflags, type;
	uint32_t	access_mask;
	zfs_acl_node_t	*newnode;
	size_t 		abstract_size = aclp->z_ops->ace_abstract_size();
	void 		*zacep;
	boolean_t	isdir;
	trivial_acl_t	masks;

	new_count = new_bytes = 0;

	isdir = (vtype == VDIR);

	acl_trivial_access_masks((mode_t)mode, isdir, &masks);

	newnode = zfs_acl_node_alloc((abstract_size * 6) + aclp->z_acl_bytes);

	zacep = newnode->z_acldata;
	if (masks.allow0) {
		zfs_set_ace(aclp, zacep, masks.allow0, ALLOW, -1, ACE_OWNER);
		zacep = (void *)((uintptr_t)zacep + abstract_size);
		new_count++;
		new_bytes += abstract_size;
	}
	if (masks.deny1) {
		zfs_set_ace(aclp, zacep, masks.deny1, DENY, -1, ACE_OWNER);
		zacep = (void *)((uintptr_t)zacep + abstract_size);
		new_count++;
		new_bytes += abstract_size;
	}
	if (masks.deny2) {
		zfs_set_ace(aclp, zacep, masks.deny2, DENY, -1, OWNING_GROUP);
		zacep = (void *)((uintptr_t)zacep + abstract_size);
		new_count++;
		new_bytes += abstract_size;
	}

	while ((acep = zfs_acl_next_ace(aclp, acep, &who, &access_mask,
	    &iflags, &type))) {
		entry_type = (iflags & ACE_TYPE_FLAGS);
		/*
		 * ACEs used to represent the file mode may be divided
		 * into an equivalent pair of inherit-only and regular
		 * ACEs, if they are inheritable.
		 * Skip regular ACEs, which are replaced by the new mode.
		 */
		if (split && (entry_type == ACE_OWNER ||
		    entry_type == OWNING_GROUP ||
		    entry_type == ACE_EVERYONE)) {
			if (!isdir || !(iflags &
			    (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE)))
				continue;
			/*
			 * We preserve owner@, group@, or @everyone
			 * permissions, if they are inheritable, by
			 * copying them to inherit_only ACEs. This
			 * prevents inheritable permissions from being
			 * altered along with the file mode.
			 */
			iflags |= ACE_INHERIT_ONLY_ACE;
		}

		/*
		 * If this ACL has any inheritable ACEs, mark that in
		 * the hints (which are later masked into the pflags)
		 * so create knows to do inheritance.
		 */
		if (isdir && (iflags &
		    (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE)))
			aclp->z_hints |= ZFS_INHERIT_ACE;

		if ((type != ALLOW && type != DENY) ||
		    (iflags & ACE_INHERIT_ONLY_ACE)) {
			switch (type) {
			case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
			case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
			case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
			case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
				aclp->z_hints |= ZFS_ACL_OBJ_ACE;
				break;
			}
		} else {
			/*
			 * Limit permissions granted by ACEs to be no greater
			 * than permissions of the requested group mode.
			 * Applies when the "aclmode" property is set to
			 * "groupmask".
			 */
			if ((type == ALLOW) && trim)
				access_mask &= masks.group;
		}
		zfs_set_ace(aclp, zacep, access_mask, type, who, iflags);
		ace_size = aclp->z_ops->ace_size(acep);
		zacep = (void *)((uintptr_t)zacep + ace_size);
		new_count++;
		new_bytes += ace_size;
	}
	zfs_set_ace(aclp, zacep, masks.owner, ALLOW, -1, ACE_OWNER);
	zacep = (void *)((uintptr_t)zacep + abstract_size);
	zfs_set_ace(aclp, zacep, masks.group, ALLOW, -1, OWNING_GROUP);
	zacep = (void *)((uintptr_t)zacep + abstract_size);
	zfs_set_ace(aclp, zacep, masks.everyone, ALLOW, -1, ACE_EVERYONE);

	new_count += 3;
	new_bytes += abstract_size * 3;
	zfs_acl_release_nodes(aclp);
	aclp->z_acl_count = new_count;
	aclp->z_acl_bytes = new_bytes;
	newnode->z_ace_count = new_count;
	newnode->z_size = new_bytes;
	list_insert_tail(&aclp->z_acl, newnode);
}