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

Commit b28b8b8b authored by Sumukh Hallymysore Ravindra's avatar Sumukh Hallymysore Ravindra
Browse files

msm: synx: fix synx handle/s mapping to synx object



Multiple synx integer handles can me mapped to the same synx object
metadata (synx_table_row) due to sharing across processes. However,
the synx metadata has memory to save only single handle.
This results in failure to clean all the handles mapped to the synx
obj during clean up resulting in exhaustion of available handles for
future uses.
Change fixes this issue by saving the mapped synx handles in a list
and iterates the list to remove the hanldes during clean up.

Change-Id: Ia1aa791743f63dfd79804f235edd379623896727
Signed-off-by: default avatarSumukh Hallymysore Ravindra <shallymy@codeaurora.org>
parent fb6de081
Loading
Loading
Loading
Loading
+64 −42
Original line number Diff line number Diff line
@@ -18,10 +18,12 @@ struct synx_device *synx_dev;

void synx_external_callback(s32 sync_obj, int status, void *data)
{
	s32 synx_obj;
	struct synx_table_row *row = NULL;
	struct synx_external_data *bind_data = data;

	if (bind_data) {
		synx_obj = bind_data->synx_obj;
		row = synx_from_key(bind_data->synx_obj, bind_data->secure_key);
		kfree(bind_data);
	}
@@ -32,7 +34,7 @@ void synx_external_callback(s32 sync_obj, int status, void *data)
		spin_unlock_bh(&synx_dev->row_spinlocks[row->index]);

		pr_debug("signaling synx 0x%x from external callback %d\n",
			row->synx_obj, sync_obj);
			synx_obj, sync_obj);
		synx_signal_core(row, status);
	} else {
		pr_err("invalid callback from sync external obj %d\n",
@@ -115,10 +117,10 @@ int synx_create(s32 *synx_obj, const char *name)
		return -EINVAL;
	}

	*synx_obj = row->synx_obj;
	*synx_obj = id;

	pr_debug("row: synx id: 0x%x, index: %d\n",
		row->synx_obj, row->index);
		id, row->index);
	pr_debug("Exit %s\n", __func__);

	return rc;
@@ -144,7 +146,7 @@ int synx_register_callback(s32 synx_obj,
		if (temp_cb_info->callback_func == cb_func &&
			temp_cb_info->cb_data == userdata) {
			pr_err("duplicate registration for synx 0x%x\n",
				row->synx_obj);
				synx_obj);
			spin_unlock_bh(&synx_dev->row_spinlocks[row->index]);
			return -EALREADY;
		}
@@ -198,7 +200,7 @@ int synx_deregister_callback(s32 synx_obj,

	state = synx_status_locked(row);
	pr_debug("de-registering callback for synx 0x%x\n",
		row->synx_obj);
		synx_obj);
	list_for_each_entry_safe(synx_cb, temp, &row->callback_list, list) {
		if (synx_cb->callback_func == cb_func &&
			synx_cb->cb_data == userdata) {
@@ -243,8 +245,8 @@ int synx_signal_core(struct synx_table_row *row, u32 status)
	}

	if (is_merged_synx(row)) {
		pr_err("signaling a composite synx object 0x%x\n",
			row->synx_obj);
		pr_err("signaling a composite synx object at %d\n",
			row->index);
		return -EINVAL;
	}

@@ -252,8 +254,8 @@ int synx_signal_core(struct synx_table_row *row, u32 status)

	if (synx_status_locked(row) != SYNX_STATE_ACTIVE) {
		spin_unlock_bh(&synx_dev->row_spinlocks[row->index]);
		pr_err("object already signaled synx = 0x%x\n",
			row->synx_obj);
		pr_err("object already signaled synx at %d\n",
			row->index);
		return -EALREADY;
	}

@@ -263,8 +265,8 @@ int synx_signal_core(struct synx_table_row *row, u32 status)

	rc = dma_fence_signal_locked(row->fence);
	if (rc < 0) {
		pr_err("unable to signal synx 0x%x, err: %d\n",
			row->synx_obj, rc);
		pr_err("unable to signal synx at %d, err: %d\n",
			row->index, rc);
		if (status != SYNX_STATE_SIGNALED_ERROR) {
			dma_fence_set_error(row->fence, -EINVAL);
			status = SYNX_STATE_SIGNALED_ERROR;
@@ -414,10 +416,10 @@ int synx_merge(s32 *synx_objs, u32 num_objs, s32 *synx_merged)
		goto clear;
	}

	*synx_merged = row->synx_obj;
	*synx_merged = id;

	pr_debug("row (merged): synx 0x%x, index: %d\n",
		row->synx_obj, row->index);
		id, row->index);
	pr_debug("Exit %s\n", __func__);

	return 0;
@@ -431,19 +433,10 @@ int synx_merge(s32 *synx_objs, u32 num_objs, s32 *synx_merged)
	return rc;
}

int synx_release(s32 synx_obj)
static int synx_release_core(struct synx_table_row *row)
{
	s32 idx;
	struct dma_fence *fence = NULL;
	struct synx_table_row *row  = NULL;

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

	row = synx_from_handle(synx_obj);
	if (!row) {
		pr_err("invalid synx: 0x%x\n", synx_obj);
		return -EINVAL;
	}

	/*
	 * metadata might be cleared after invoking dma_fence_put
@@ -469,6 +462,21 @@ int synx_release(s32 synx_obj)
	return 0;
}

int synx_release(s32 synx_obj)
{
	struct synx_table_row *row  = NULL;

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

	row = synx_from_handle(synx_obj);
	if (!row) {
		pr_err("invalid synx: 0x%x\n", synx_obj);
		return -EINVAL;
	}

	return synx_release_core(row);
}

int synx_wait(s32 synx_obj, u64 timeout_ms)
{
	unsigned long timeleft;
@@ -561,7 +569,7 @@ int synx_bind(s32 synx_obj, struct synx_external_desc external_sync)
	}

	/* data passed to external callback */
	data->synx_obj = row->synx_obj;
	data->synx_obj = synx_obj;
	data->secure_key = synx_generate_secure_key(row);

	rc = bind_ops->register_callback(synx_external_callback,
@@ -630,6 +638,7 @@ int synx_import(s32 synx_obj, u32 import_key, s32 *new_synx_obj)
{
	s32 id;
	struct dma_fence *fence;
	struct synx_obj_node *obj_node;
	struct synx_table_row *row = NULL;

	pr_debug("Enter %s\n", __func__);
@@ -641,6 +650,10 @@ int synx_import(s32 synx_obj, u32 import_key, s32 *new_synx_obj)
	if (!row)
		return -EINVAL;

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

	/* new global synx id */
	id = synx_create_handle(row);
	if (id < 0) {
@@ -651,10 +664,15 @@ int synx_import(s32 synx_obj, u32 import_key, s32 *new_synx_obj)
		}
		/* release the reference obtained during export */
		dma_fence_put(fence);
		kfree(obj_node);
		return -EINVAL;
	}

	row->synx_obj = id;
	spin_lock_bh(&synx_dev->row_spinlocks[row->index]);
	obj_node->synx_obj = id;
	list_add(&obj_node->list, &row->synx_obj_list);
	spin_unlock_bh(&synx_dev->row_spinlocks[row->index]);

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

@@ -672,7 +690,7 @@ int synx_export(s32 synx_obj, u32 *import_key)
	if (!row)
		return -EINVAL;

	rc = synx_generate_import_key(row, import_key);
	rc = synx_generate_import_key(row, synx_obj, import_key);
	if (rc < 0)
		return rc;

@@ -874,6 +892,7 @@ static int synx_handle_wait(struct synx_private_ioctl_arg *k_ioctl)
static int synx_handle_register_user_payload(
	struct synx_private_ioctl_arg *k_ioctl)
{
	s32 synx_obj;
	u32 state = SYNX_STATE_INVALID;
	struct synx_userpayload_info userpayload_info;
	struct synx_cb_data *user_payload_kernel;
@@ -891,9 +910,10 @@ static int synx_handle_register_user_payload(
		k_ioctl->size))
		return -EFAULT;

	row = synx_from_handle(userpayload_info.synx_obj);
	synx_obj = userpayload_info.synx_obj;
	row = synx_from_handle(synx_obj);
	if (!row) {
		pr_err("invalid synx: 0x%x\n", userpayload_info.synx_obj);
		pr_err("invalid synx: 0x%x\n", synx_obj);
		return -EINVAL;
	}

@@ -911,7 +931,7 @@ static int synx_handle_register_user_payload(
		return -ENOMEM;

	user_payload_kernel->client = client;
	user_payload_kernel->data.synx_obj = row->synx_obj;
	user_payload_kernel->data.synx_obj = synx_obj;
	memcpy(user_payload_kernel->data.payload_data,
		userpayload_info.payload,
		SYNX_PAYLOAD_WORDS * sizeof(__u64));
@@ -937,7 +957,7 @@ static int synx_handle_register_user_payload(
			user_payload_iter->data.payload_data[1] ==
				user_payload_kernel->data.payload_data[1]) {
			pr_err("callback already registered on 0x%x\n",
				row->synx_obj);
				synx_obj);
			spin_unlock_bh(&synx_dev->row_spinlocks[row->index]);
			kfree(user_payload_kernel);
			return -EALREADY;
@@ -954,6 +974,7 @@ static int synx_handle_register_user_payload(
static int synx_handle_deregister_user_payload(
	struct synx_private_ioctl_arg *k_ioctl)
{
	s32 synx_obj;
	u32 state = SYNX_STATE_INVALID;
	struct synx_client *client = NULL;
	struct synx_userpayload_info userpayload_info;
@@ -971,9 +992,10 @@ static int synx_handle_deregister_user_payload(
		k_ioctl->size))
		return -EFAULT;

	row = synx_from_handle(userpayload_info.synx_obj);
	synx_obj = userpayload_info.synx_obj;
	row = synx_from_handle(synx_obj);
	if (!row) {
		pr_err("invalid synx: 0x%x\n", userpayload_info.synx_obj);
		pr_err("invalid synx: 0x%x\n", synx_obj);
		return -EINVAL;
	}

@@ -1021,7 +1043,7 @@ static int synx_handle_deregister_user_payload(
			SYNX_PAYLOAD_WORDS * sizeof(__u64));

		user_payload_kernel->client = client;
		data->synx_obj = row->synx_obj;
		data->synx_obj = synx_obj;
		data->status = SYNX_CALLBACK_RESULT_CANCELED;

		spin_lock_bh(&client->eventq_lock);
@@ -1292,15 +1314,15 @@ static int synx_close(struct inode *inode, struct file *filep)
			 * signal all ACTIVE objects as ERR, but we don't care
			 * about the return status here apart from logging it.
			 */
			if (row->synx_obj && !is_merged_synx(row) &&
			if (row->index && !is_merged_synx(row) &&
				(synx_status(row) == SYNX_STATE_ACTIVE)) {
				pr_debug("synx 0x%x still active at shutdown\n",
					row->synx_obj);
				pr_debug("synx still active at shutdown at %d\n",
					row->index);
				rc = synx_signal_core(row,
						SYNX_STATE_SIGNALED_ERROR);
				if (rc < 0)
					pr_err("cleanup signal fail idx:0x%x\n",
						row->synx_obj);
					pr_err("cleanup signal fail at %d\n",
						row->index);
			}
		}

@@ -1318,11 +1340,11 @@ static int synx_close(struct inode *inode, struct file *filep)
			struct synx_table_row *row =
				synx_dev->synx_table + i;

			if (row->synx_obj) {
				rc = synx_release(row->synx_obj);
			if (row->index) {
				rc = synx_release_core(row);
				if (rc < 0) {
					pr_err("cleanup destroy fail idx:0x%x\n",
						row->synx_obj);
					pr_err("cleanup destroy fail at %d\n",
						row->index);
				}
			}
		}
+11 −6
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@ static ssize_t synx_table_read(struct file *file,
	struct error_node *err_node, *err_node_tmp;
	struct synx_table_row *row;
	char *dbuf, *cur, *end;
	struct synx_obj_node *obj_node;

	int i = 0;
	int state = SYNX_STATE_INVALID;
@@ -60,26 +61,23 @@ static ssize_t synx_table_read(struct file *file,
	end = cur + MAX_DBG_BUF_SIZE;
	if (columns & NAME_COLUMN)
		cur += scnprintf(cur, end - cur, "|   Name   |");
	if (columns & ID_COLUMN)
		cur += scnprintf(cur, end - cur, "|    ID    |");
	if (columns & BOUND_COLUMN)
		cur += scnprintf(cur, end - cur, "|   Bound   |");
	if (columns & STATE_COLUMN)
		cur += scnprintf(cur, end - cur, "|  Status  |");
	if (columns & ID_COLUMN)
		cur += scnprintf(cur, end - cur, "|    ID    |");
	cur += scnprintf(cur, end - cur, "\n");
	for (i = 0; i < SYNX_MAX_OBJS; i++) {
		row = &dev->synx_table[i];

		if (!row || !row->synx_obj)
		if (!row->index)
			continue;

		spin_lock_bh(&dev->row_spinlocks[row->index]);
		if (columns & NAME_COLUMN)
			cur += scnprintf(cur, end - cur,
				"|%10s|", row->name);
		if (columns & ID_COLUMN)
			cur += scnprintf(cur, end - cur,
				"|%10d|", row->synx_obj);
		if (columns & BOUND_COLUMN)
			cur += scnprintf(cur, end - cur,
				"|%11d|", row->num_bound_synxs);
@@ -96,6 +94,13 @@ static ssize_t synx_table_read(struct file *file,
				cur,
				end);
		}
		if (columns & ID_COLUMN) {
			list_for_each_entry(obj_node,
				&row->synx_obj_list, list) {
				cur += scnprintf(cur, end - cur,
					"|0x%8x|", obj_node->synx_obj);
				}
		}
		spin_unlock_bh(&dev->row_spinlocks[row->index]);
		cur += scnprintf(cur, end - cur, "\n");
	}
+14 −2
Original line number Diff line number Diff line
@@ -111,13 +111,25 @@ struct synx_cb_data {
	struct list_head list;
};

/**
 * struct synx_obj_node - Single node of info for the synx handle
 * mapped to synx object metadata
 *
 * @synx_obj : Synx integer handle
 * @list     : List member used to append to synx handle list
 */
struct synx_obj_node {
	s32 synx_obj;
	struct list_head list;
};

/**
 * struct synx_table_row - Single row of information about a synx object, used
 * for internal book keeping in the synx driver
 *
 * @name              : Optional string representation of the synx object
 * @fence             : dma fence backing the synx object
 * @synx_obj          : Integer id representing this synx object
 * @synx_obj_list     : List of synx integer handles mapped
 * @index             : Index of the spin lock table associated with synx obj
 * @num_bound_synxs   : Number of external bound synx objects
 * @signaling_id      : ID of the external sync object invoking the callback
@@ -129,7 +141,7 @@ struct synx_cb_data {
struct synx_table_row {
	char name[SYNX_OBJ_NAME_LEN];
	struct dma_fence *fence;
	s32 synx_obj;
	struct list_head synx_obj_list;
	s32 index;
	u32 num_bound_synxs;
	s32 signaling_id;
+44 −19
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ int synx_init_object(struct synx_table_row *table,
{
	struct dma_fence *fence = NULL;
	struct synx_table_row *row = table + idx;
	struct synx_obj_node *obj_node;

	if (!table || idx <= 0 || idx >= SYNX_MAX_OBJS)
		return -EINVAL;
@@ -39,20 +40,28 @@ int synx_init_object(struct synx_table_row *table,
	if (!fence)
		return -ENOMEM;

	obj_node = kzalloc(sizeof(*obj_node), GFP_KERNEL);
	if (!obj_node) {
		kfree(fence);
		return -ENOMEM;
	}

	dma_fence_init(fence, ops, &synx_dev->row_spinlocks[idx],
		synx_dev->dma_context, 1);

	row->fence = fence;
	row->synx_obj = id;
	obj_node->synx_obj = id;
	row->index = idx;
	INIT_LIST_HEAD(&row->synx_obj_list);
	INIT_LIST_HEAD(&row->callback_list);
	INIT_LIST_HEAD(&row->user_payload_list);

	list_add(&obj_node->list, &row->synx_obj_list);
	if (name)
		strlcpy(row->name, name, sizeof(row->name));

	pr_debug("synx obj init: id:0x%x state:%u fence: 0x%pK\n",
		row->synx_obj, synx_status_locked(row), fence);
		synx_status_locked(row), fence);

	return 0;
}
@@ -65,20 +74,27 @@ int synx_init_group_object(struct synx_table_row *table,
{
	struct synx_table_row *row = table + idx;
	struct dma_fence_array *array;
	struct synx_obj_node *obj_node;

	array = dma_fence_array_create(num_objs,
				fences, synx_dev->dma_context, 1, false);
	if (!array)
		return -EINVAL;

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

	row->fence = &array->base;
	row->synx_obj = id;
	obj_node->synx_obj = id;
	row->index = idx;
	INIT_LIST_HEAD(&row->synx_obj_list);
	INIT_LIST_HEAD(&row->callback_list);
	INIT_LIST_HEAD(&row->user_payload_list);

	pr_debug("synx group obj init: id:0x%x state:%u fence: 0x%pK\n",
		row->synx_obj, synx_status_locked(row), row->fence);
	list_add(&obj_node->list, &row->synx_obj_list);
	pr_debug("synx group obj init: id:%d state:%u fence: 0x%pK\n",
		id, synx_status_locked(row), row->fence);

	return 0;
}
@@ -139,24 +155,31 @@ int synx_activate(struct synx_table_row *row)

int synx_deinit_object(struct synx_table_row *row)
{
	s32 synx_obj;
	s32 index;
	struct synx_client *client;
	struct synx_callback_info *synx_cb, *temp_cb;
	struct synx_cb_data  *upayload_info, *temp_upayload;
	struct synx_obj_node *obj_node, *temp_obj_node;

	if (!row || !synx_dev)
		return -EINVAL;

	synx_obj = row->synx_obj;

	index = row->index;
	spin_lock_bh(&synx_dev->idr_lock);
	list_for_each_entry_safe(obj_node,
		temp_obj_node, &row->synx_obj_list, list) {
		if ((struct synx_table_row *)idr_remove(&synx_dev->synx_ids,
			row->synx_obj) != row) {
				obj_node->synx_obj) != row) {
			pr_err("removing data in idr table failed 0x%x\n",
			row->synx_obj);
				obj_node->synx_obj);
			spin_unlock_bh(&synx_dev->idr_lock);
			return -EINVAL;
		}
		pr_debug("removed synx obj at 0x%x successful\n",
			obj_node->synx_obj);
		list_del_init(&obj_node->list);
		kfree(obj_node);
	}
	spin_unlock_bh(&synx_dev->idr_lock);

	/*
@@ -208,7 +231,7 @@ int synx_deinit_object(struct synx_table_row *row)
	clear_bit(row->index, synx_dev->bitmap);
	memset(row, 0, sizeof(*row));

	pr_debug("destroying synx obj: 0x%x successful\n", synx_obj);
	pr_debug("destroying synx obj at %d successful\n", index);
	return 0;
}

@@ -595,8 +618,8 @@ struct synx_table_row *synx_from_fence(struct dma_fence *fence)
	for (idx = 0; idx < SYNX_MAX_OBJS; idx++) {
		if (table[idx].fence == fence) {
			row = table + idx;
			pr_debug("synx global data found for 0x%x\n",
				row->synx_obj);
			pr_debug("synx global data found at %d\n",
				row->index);
			break;
		}
	}
@@ -627,6 +650,7 @@ struct synx_table_row *synx_from_import_key(s32 synx_obj, u32 key)
}

int synx_generate_import_key(struct synx_table_row *row,
	s32 synx_obj,
	u32 *key)
{
	bool bit;
@@ -648,7 +672,7 @@ int synx_generate_import_key(struct synx_table_row *row,
	} while (!*key);

	data->key = *key;
	data->synx_obj = row->synx_obj;
	data->synx_obj = synx_obj;
	/*
	 * Reason for separate metadata (for merged synx)
	 * being dma fence array has separate release func
@@ -682,6 +706,7 @@ int synx_generate_import_key(struct synx_table_row *row,
		/* both metadata points to same dma fence */
		new_row->fence = row->fence;
		new_row->index = idx;
		INIT_LIST_HEAD(&new_row->synx_obj_list);
		INIT_LIST_HEAD(&new_row->callback_list);
		INIT_LIST_HEAD(&new_row->user_payload_list);
		data->row = new_row;
@@ -690,7 +715,7 @@ int synx_generate_import_key(struct synx_table_row *row,
	}
	list_add(&data->list, &synx_dev->import_list);
	pr_debug("allocated import key for 0x%x\n",
		row->synx_obj);
		synx_obj);
	mutex_unlock(&synx_dev->table_lock);

	return 0;
+4 −2
Original line number Diff line number Diff line
@@ -234,11 +234,13 @@ int synx_generate_secure_key(struct synx_table_row *row);
 *         verified during import.
 *
 * @param row      : Pointer to the synx object row
 * @param synx_obj : Synx handle
 * @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,
	s32 synx_obj,
	u32 *key);

/**