mei: add a vtag map for each client

Vtag map is a list of tuples of vtag and file pointer (struct
mei_cl_vtag) associated with a particular me host client.

Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Link: https://lore.kernel.org/r/20200818115147.2567012-8-tomas.winkler@intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Alexander Usyskin
2020-08-18 14:51:41 +03:00
committed by Greg Kroah-Hartman
parent d1376f3d89
commit f35fe5f47e
4 changed files with 253 additions and 7 deletions

View File

@@ -80,6 +80,27 @@ err_unlock:
return err;
}
/**
* mei_cl_vtag_remove_by_fp - remove vtag that corresponds to fp from list
*
* @cl: host client
* @fp: pointer to file structure
*
*/
static void mei_cl_vtag_remove_by_fp(const struct mei_cl *cl,
const struct file *fp)
{
struct mei_cl_vtag *vtag_l, *next;
list_for_each_entry_safe(vtag_l, next, &cl->vtag_map, list) {
if (vtag_l->fp == fp) {
list_del(&vtag_l->list);
kfree(vtag_l);
return;
}
}
}
/**
* mei_release - the release function
*
@@ -101,17 +122,35 @@ static int mei_release(struct inode *inode, struct file *file)
mutex_lock(&dev->device_lock);
rets = mei_cl_disconnect(cl);
mei_cl_vtag_remove_by_fp(cl, file);
mei_cl_flush_queues(cl, file);
if (!list_empty(&cl->vtag_map)) {
cl_dbg(dev, cl, "not the last vtag\n");
mei_cl_flush_queues(cl, file);
rets = 0;
goto out;
}
rets = mei_cl_disconnect(cl);
/*
* Check again: This is necessary since disconnect releases the lock
* and another client can connect in the meantime.
*/
if (!list_empty(&cl->vtag_map)) {
cl_dbg(dev, cl, "not the last vtag after disconnect\n");
mei_cl_flush_queues(cl, file);
goto out;
}
mei_cl_flush_queues(cl, NULL);
cl_dbg(dev, cl, "removing\n");
mei_cl_unlink(cl);
file->private_data = NULL;
kfree(cl);
out:
file->private_data = NULL;
mutex_unlock(&dev->device_lock);
return rets;
}
@@ -237,6 +276,28 @@ out:
mutex_unlock(&dev->device_lock);
return rets;
}
/**
* mei_cl_vtag_by_fp - obtain the vtag by file pointer
*
* @cl: host client
* @fp: pointer to file structure
*
* Return: vtag value on success, otherwise 0
*/
static u8 mei_cl_vtag_by_fp(const struct mei_cl *cl, const struct file *fp)
{
struct mei_cl_vtag *cl_vtag;
if (!fp)
return 0;
list_for_each_entry(cl_vtag, &cl->vtag_map, list)
if (cl_vtag->fp == fp)
return cl_vtag->vtag;
return 0;
}
/**
* mei_write - the write function.
*
@@ -314,6 +375,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
rets = -ENOMEM;
goto out;
}
cb->vtag = mei_cl_vtag_by_fp(cl, file);
rets = copy_from_user(cb->buf.data, ubuf, length);
if (rets) {