Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9e0b6978 authored by Sumukh Hallymysore Ravindra's avatar Sumukh Hallymysore Ravindra
Browse files

msm: synx: fix merged synx sharing across processes



Import of merged synx obj will fail if the release on merged
synx obj by the exporting process finishes before import.
Even though the backed dma fence is reference counted, synx
metadata for the merged obj is not. So release would remove
synx data resulting in failure of import function.
This change saves information of exported synx handles in
a list (this would work for both merged and individual synxs)
which wont be cleared until successfully imported.

Change-Id: I18007112d469db55667b7604423d78a2febc706a
Signed-off-by: default avatarSumukh Hallymysore Ravindra <shallymy@codeaurora.org>
parent b482dc81
Loading
Loading
Loading
Loading
+25 −40
Original line number Diff line number Diff line
@@ -633,74 +633,57 @@ int synx_addrefcount(s32 synx_obj, s32 count)
	return 0;
}

int synx_import(s32 synx_obj, u32 secure_key, s32 *new_synx_obj)
int synx_import(s32 synx_obj, u32 import_key, s32 *new_synx_obj)
{
	bool bit;
	s32 id;
	long idx = 0;
	struct dma_fence *fence;
	struct synx_table_row *row = NULL;
	struct synx_table_row *new_row = NULL;

	pr_debug("Enter %s\n", __func__);

	if (!new_synx_obj)
		return -EINVAL;

	row = synx_from_key(synx_obj, secure_key);
	row = synx_from_import_key(synx_obj, import_key);
	if (!row)
		return -EINVAL;

	/*
	 * Reason for separate metadata (for merged synx) being
	 * dma fence array has separate release func registed with
	 * dma fence ops, which doesn't invoke release func registered
	 * by the framework to clear metadata when all refs are released.
	 * Hence we need to clear the metadata for merged synx obj
	 * upon synx_release itself. But this creates a problem if
	 * the synx obj is exported. Thus we need separate metadata
	 * structures even though they represent same synx obj.
	 * Note, only the metadata is released, and the fence reference
	 * count is decremented still.
	 */
	if (is_merged_synx(row)) {
		do {
			idx = find_first_zero_bit(synx_dev->bitmap,
					SYNX_MAX_OBJS);
			if (idx >= SYNX_MAX_OBJS)
				return -ENOMEM;
			bit = test_and_set_bit(idx, synx_dev->bitmap);
		} while (bit);

		new_row = synx_dev->synx_table + idx;
	/* new global synx id */
		id = synx_create_handle(new_row);

		/* both metadata points to same dma fence */
		new_row->fence = row->fence;
		new_row->index = idx;
		new_row->synx_obj = id;
	} else {
		/* new global synx id. Imported synx points to same metadata */
	id = synx_create_handle(row);
	if (id < 0) {
		fence = row->fence;
		if (is_merged_synx(row)) {
			clear_bit(row->index, synx_dev->bitmap);
			memset(row, 0, sizeof(*row));
		}
		/* release the reference obtained during export */
		dma_fence_put(fence);
		return -EINVAL;
	}

	row->synx_obj = id;
	*new_synx_obj = id;
	pr_debug("Exit %s\n", __func__);

	return 0;
}

int synx_export(s32 synx_obj, u32 *key)
int synx_export(s32 synx_obj, u32 *import_key)
{
	int rc;
	struct synx_table_row *row = NULL;

	pr_debug("Enter %s\n", __func__);

	row = synx_from_handle(synx_obj);
	if (!row)
		return -EINVAL;

	spin_lock_bh(&synx_dev->row_spinlocks[row->index]);
	*key = synx_generate_secure_key(row);
	rc = synx_generate_import_key(row, import_key);
	if (rc < 0)
		return rc;

	spin_lock_bh(&synx_dev->row_spinlocks[row->index]);
	/*
	 * to make sure the synx is not lost if the process dies or
	 * synx is released before any other process gets a chance to
@@ -710,6 +693,7 @@ int synx_export(s32 synx_obj, u32 *key)
	 */
	dma_fence_get(row->fence);
	spin_unlock_bh(&synx_dev->row_spinlocks[row->index]);
	pr_debug("Exit %s\n", __func__);

	return 0;
}
@@ -1489,6 +1473,7 @@ static int __init synx_init(void)
	}

	INIT_LIST_HEAD(&synx_dev->client_list);
	INIT_LIST_HEAD(&synx_dev->import_list);
	synx_dev->dma_context = dma_fence_context_alloc(1);

	synx_dev->debugfs_root = init_synx_debug_dir(synx_dev);
+18 −0
Original line number Diff line number Diff line
@@ -155,6 +155,22 @@ struct synx_registered_ops {
	u32 type;
};

/**
 * struct synx_import_data - Import metadata for sharing synx handles
 * with processes
 *
 * @key      : Import key for sharing synx handle
 * @synx_obj : Synx handle being exported
 * @row      : Pointer to synx object
 * @list     : List member used to append the node to import list
 */
struct synx_import_data {
	u32 key;
	s32 synx_obj;
	struct synx_table_row *row;
	struct list_head list;
};

/**
 * struct synx_device - Internal struct to book keep synx driver details
 *
@@ -175,6 +191,7 @@ struct synx_registered_ops {
 * debugfs_root   : Root directory for debugfs
 * synx_node_head : list head for synx nodes
 * synx_node_list_lock : Spinlock for synx nodes
 * import_list    : List to validate synx import requests
 */
struct synx_device {
	struct cdev cdev;
@@ -194,6 +211,7 @@ struct synx_device {
	struct dentry *debugfs_root;
	struct list_head synx_debug_head;
	spinlock_t synx_node_list_lock;
	struct list_head import_list;
};

/**
+92 −0
Original line number Diff line number Diff line
@@ -579,6 +579,98 @@ struct synx_table_row *synx_from_fence(struct dma_fence *fence)
	return row;
}

struct synx_table_row *synx_from_import_key(s32 synx_obj, u32 key)
{
	struct synx_import_data *data, *tmp_data;
	struct synx_table_row *row = NULL;

	mutex_lock(&synx_dev->table_lock);
	list_for_each_entry_safe(data, tmp_data,
		&synx_dev->import_list, list) {
		if (data->key == key && data->synx_obj == synx_obj) {
			pr_debug("found synx handle, importing 0x%x\n",
				synx_obj);
			row = data->row;
			list_del_init(&data->list);
			kfree(data);
			break;
		}
	}
	mutex_unlock(&synx_dev->table_lock);

	return row;
}

int synx_generate_import_key(struct synx_table_row *row,
	u32 *key)
{
	bool bit;
	long idx = 0;
	struct synx_import_data *data;
	struct synx_table_row *new_row;

	if (!row)
		return -EINVAL;

	data = kzalloc(sizeof(*data), GFP_KERNEL);
	if (!data)
		return -ENOMEM;

	mutex_lock(&synx_dev->table_lock);
	do {
		/* obtain a random non-zero key */
		get_random_bytes(key, sizeof(*key));
	} while (!*key);

	data->key = *key;
	data->synx_obj = row->synx_obj;
	/*
	 * Reason for separate metadata (for merged synx)
	 * being dma fence array has separate release func
	 * registed with dma fence ops, which doesn't invoke
	 * release func registered by the framework to clear
	 * metadata when all refs are released.
	 * Hence we need to clear the metadata for merged synx
	 * obj upon synx_release itself. But this creates a
	 * problem if synx obj is exported. Thus need separate
	 * metadata structures even though they represent same
	 * synx obj.
	 * Note, only the metadata is released, and the fence
	 * reference count is decremented still.
	 */
	if (is_merged_synx(row)) {
		do {
			idx = find_first_zero_bit(
					synx_dev->bitmap,
					SYNX_MAX_OBJS);
			if (idx >= SYNX_MAX_OBJS) {
				kfree(data);
				mutex_unlock(
					&synx_dev->table_lock);
				return -ENOMEM;
			}
			bit = test_and_set_bit(idx,
					synx_dev->bitmap);
		} while (bit);

		new_row = synx_dev->synx_table + idx;
		/* both metadata points to same dma fence */
		new_row->fence = row->fence;
		new_row->index = idx;
		INIT_LIST_HEAD(&new_row->callback_list);
		INIT_LIST_HEAD(&new_row->user_payload_list);
		data->row = new_row;
	} else {
		data->row = row;
	}
	list_add(&data->list, &synx_dev->import_list);
	pr_debug("allocated import key for 0x%x\n",
		row->synx_obj);
	mutex_unlock(&synx_dev->table_lock);

	return 0;
}

void *synx_from_key(s32 id, u32 secure_key)
{
	struct synx_table_row *row = NULL;
+25 −0
Original line number Diff line number Diff line
@@ -228,6 +228,31 @@ struct bind_operations *synx_get_bind_ops(u32 type);
 */
int synx_generate_secure_key(struct synx_table_row *row);

/**
 * @brief: Function to generate a key for authenticating requests
 *         Generated key for synx object being exported is
 *         verified during import.
 *
 * @param row : Pointer to the synx object row
 * @param key : Pointer to key (filled by the function)
 *
 * @return Status of operation. Negative in case of error. Zero otherwise.
 */
int synx_generate_import_key(struct synx_table_row *row,
	u32 *key);

/**
 * @brief: Function to authenticate requests for importing synx handle
 *         Used to verify the requests generated on synx object
 *         being imported.
 *
 * @param synx_obj : Synx handle being imported
 * @param key      : Key to authenticate import request
 *
 * @return Pointer to the synx object row for valid request. NULL otherwise.
 */
struct synx_table_row *synx_from_import_key(s32 synx_obj, u32 key);

/**
 * @brief: Function to handle adding an error
 *         code to a synx