mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-29 23:24:11 +08:00
staging: unisys: visorhba: Convert module from IDR to XArray
Converted visorhba from IDR to XArray. The abstract data type XArray is more memory-efficient, parallelizable, and cache friendly. It takes advantage of RCU to perform lookups without locking. Furthermore, IDR is deprecated because XArray has a better (cleaner and more consistent) API. Reviewed-by: Dan Carpenter <dan.carpenter@oracle.com> Signed-off-by: Fabio M. De Francesco <fmdefrancesco@gmail.com> Link: https://lore.kernel.org/r/20210514081112.19542-1-fmdefrancesco@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
e02a3b9458
commit
6d400d7cee
@ -6,10 +6,10 @@
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/visorbus.h>
|
||||
#include <linux/xarray.h>
|
||||
#include <scsi/scsi.h>
|
||||
#include <scsi/scsi_host.h>
|
||||
#include <scsi/scsi_cmnd.h>
|
||||
@ -82,8 +82,7 @@ struct visorhba_devdata {
|
||||
* allows us to pass int handles back-and-forth between us and
|
||||
* iovm, instead of raw pointers
|
||||
*/
|
||||
struct idr idr;
|
||||
|
||||
struct xarray xa;
|
||||
struct dentry *debugfs_dir;
|
||||
struct dentry *debugfs_info;
|
||||
};
|
||||
@ -182,71 +181,48 @@ static struct uiscmdrsp *get_scsipending_cmdrsp(struct visorhba_devdata *ddata,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* simple_idr_get - Associate a provided pointer with an int value
|
||||
* 1 <= value <= INT_MAX, and return this int value;
|
||||
* the pointer value can be obtained later by passing
|
||||
* this int value to idr_find()
|
||||
* @idrtable: The data object maintaining the pointer<-->int mappings
|
||||
* @p: The pointer value to be remembered
|
||||
* @lock: A spinlock used when exclusive access to idrtable is needed
|
||||
*
|
||||
* Return: The id number mapped to pointer 'p', 0 on failure
|
||||
*/
|
||||
static unsigned int simple_idr_get(struct idr *idrtable, void *p,
|
||||
spinlock_t *lock)
|
||||
{
|
||||
int id;
|
||||
unsigned long flags;
|
||||
|
||||
idr_preload(GFP_KERNEL);
|
||||
spin_lock_irqsave(lock, flags);
|
||||
id = idr_alloc(idrtable, p, 1, INT_MAX, GFP_NOWAIT);
|
||||
spin_unlock_irqrestore(lock, flags);
|
||||
idr_preload_end();
|
||||
/* failure */
|
||||
if (id < 0)
|
||||
return 0;
|
||||
/* idr_alloc() guarantees > 0 */
|
||||
return (unsigned int)(id);
|
||||
}
|
||||
|
||||
/*
|
||||
* setup_scsitaskmgmt_handles - Stash the necessary handles so that the
|
||||
* completion processing logic for a taskmgmt
|
||||
* cmd will be able to find who to wake up
|
||||
* and where to stash the result
|
||||
* @idrtable: The data object maintaining the pointer<-->int mappings
|
||||
* @lock: A spinlock used when exclusive access to idrtable is needed
|
||||
* @xa: The data object maintaining the pointer<-->int mappings
|
||||
* @cmdrsp: Response from the IOVM
|
||||
* @event: The event handle to associate with an id
|
||||
* @result: The location to place the result of the event handle into
|
||||
*/
|
||||
static void setup_scsitaskmgmt_handles(struct idr *idrtable, spinlock_t *lock,
|
||||
struct uiscmdrsp *cmdrsp,
|
||||
static int setup_scsitaskmgmt_handles(struct xarray *xa, struct uiscmdrsp *cmdrsp,
|
||||
wait_queue_head_t *event, int *result)
|
||||
{
|
||||
/* specify the event that has to be triggered when this */
|
||||
/* cmd is complete */
|
||||
cmdrsp->scsitaskmgmt.notify_handle =
|
||||
simple_idr_get(idrtable, event, lock);
|
||||
cmdrsp->scsitaskmgmt.notifyresult_handle =
|
||||
simple_idr_get(idrtable, result, lock);
|
||||
int ret;
|
||||
u32 id;
|
||||
|
||||
/* specify the event that has to be triggered when this cmd is complete */
|
||||
ret = xa_alloc_irq(xa, &id, event, xa_limit_32b, GFP_KERNEL);
|
||||
if (ret)
|
||||
return ret;
|
||||
cmdrsp->scsitaskmgmt.notify_handle = id;
|
||||
ret = xa_alloc_irq(xa, &id, result, xa_limit_32b, GFP_KERNEL);
|
||||
if (ret) {
|
||||
xa_erase_irq(xa, cmdrsp->scsitaskmgmt.notify_handle);
|
||||
return ret;
|
||||
}
|
||||
cmdrsp->scsitaskmgmt.notifyresult_handle = id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* cleanup_scsitaskmgmt_handles - Forget handles created by
|
||||
* setup_scsitaskmgmt_handles()
|
||||
* @idrtable: The data object maintaining the pointer<-->int mappings
|
||||
* @xa: The data object maintaining the pointer<-->int mappings
|
||||
* @cmdrsp: Response from the IOVM
|
||||
*/
|
||||
static void cleanup_scsitaskmgmt_handles(struct idr *idrtable,
|
||||
static void cleanup_scsitaskmgmt_handles(struct xarray *xa,
|
||||
struct uiscmdrsp *cmdrsp)
|
||||
{
|
||||
if (cmdrsp->scsitaskmgmt.notify_handle)
|
||||
idr_remove(idrtable, cmdrsp->scsitaskmgmt.notify_handle);
|
||||
if (cmdrsp->scsitaskmgmt.notifyresult_handle)
|
||||
idr_remove(idrtable, cmdrsp->scsitaskmgmt.notifyresult_handle);
|
||||
xa_erase_irq(xa, cmdrsp->scsitaskmgmt.notify_handle);
|
||||
xa_erase_irq(xa, cmdrsp->scsitaskmgmt.notifyresult_handle);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -269,6 +245,7 @@ static int forward_taskmgmt_command(enum task_mgmt_types tasktype,
|
||||
int notifyresult = 0xffff;
|
||||
wait_queue_head_t notifyevent;
|
||||
int scsicmd_id;
|
||||
int ret;
|
||||
|
||||
if (devdata->serverdown || devdata->serverchangingstate)
|
||||
return FAILED;
|
||||
@ -284,8 +261,14 @@ static int forward_taskmgmt_command(enum task_mgmt_types tasktype,
|
||||
|
||||
/* issue TASK_MGMT_ABORT_TASK */
|
||||
cmdrsp->cmdtype = CMD_SCSITASKMGMT_TYPE;
|
||||
setup_scsitaskmgmt_handles(&devdata->idr, &devdata->privlock, cmdrsp,
|
||||
¬ifyevent, ¬ifyresult);
|
||||
|
||||
ret = setup_scsitaskmgmt_handles(&devdata->xa, cmdrsp,
|
||||
¬ifyevent, ¬ifyresult);
|
||||
if (ret) {
|
||||
dev_dbg(&scsidev->sdev_gendev,
|
||||
"visorhba: setup_scsitaskmgmt_handles returned %d\n", ret);
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
/* save destination */
|
||||
cmdrsp->scsitaskmgmt.tasktype = tasktype;
|
||||
@ -311,14 +294,14 @@ static int forward_taskmgmt_command(enum task_mgmt_types tasktype,
|
||||
dev_dbg(&scsidev->sdev_gendev,
|
||||
"visorhba: taskmgmt type=%d success; result=0x%x\n",
|
||||
tasktype, notifyresult);
|
||||
cleanup_scsitaskmgmt_handles(&devdata->idr, cmdrsp);
|
||||
cleanup_scsitaskmgmt_handles(&devdata->xa, cmdrsp);
|
||||
return SUCCESS;
|
||||
|
||||
err_del_scsipending_ent:
|
||||
dev_dbg(&scsidev->sdev_gendev,
|
||||
"visorhba: taskmgmt type=%d not executed\n", tasktype);
|
||||
del_scsipending_ent(devdata, scsicmd_id);
|
||||
cleanup_scsitaskmgmt_handles(&devdata->idr, cmdrsp);
|
||||
cleanup_scsitaskmgmt_handles(&devdata->xa, cmdrsp);
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
@ -654,13 +637,13 @@ DEFINE_SHOW_ATTRIBUTE(info_debugfs);
|
||||
* Service Partition returned the result of the task management
|
||||
* command. Wake up anyone waiting for it.
|
||||
*/
|
||||
static void complete_taskmgmt_command(struct idr *idrtable,
|
||||
static void complete_taskmgmt_command(struct xarray *xa,
|
||||
struct uiscmdrsp *cmdrsp, int result)
|
||||
{
|
||||
wait_queue_head_t *wq =
|
||||
idr_find(idrtable, cmdrsp->scsitaskmgmt.notify_handle);
|
||||
xa_load(xa, cmdrsp->scsitaskmgmt.notify_handle);
|
||||
int *scsi_result_ptr =
|
||||
idr_find(idrtable, cmdrsp->scsitaskmgmt.notifyresult_handle);
|
||||
xa_load(xa, cmdrsp->scsitaskmgmt.notifyresult_handle);
|
||||
if (unlikely(!(wq && scsi_result_ptr))) {
|
||||
pr_err("visorhba: no completion context; cmd will time out\n");
|
||||
return;
|
||||
@ -708,7 +691,7 @@ static void visorhba_serverdown_complete(struct visorhba_devdata *devdata)
|
||||
break;
|
||||
case CMD_SCSITASKMGMT_TYPE:
|
||||
cmdrsp = pendingdel->sent;
|
||||
complete_taskmgmt_command(&devdata->idr, cmdrsp,
|
||||
complete_taskmgmt_command(&devdata->xa, cmdrsp,
|
||||
TASK_MGMT_FAILED);
|
||||
break;
|
||||
default:
|
||||
@ -905,7 +888,7 @@ static void drain_queue(struct uiscmdrsp *cmdrsp,
|
||||
if (!del_scsipending_ent(devdata,
|
||||
cmdrsp->scsitaskmgmt.handle))
|
||||
break;
|
||||
complete_taskmgmt_command(&devdata->idr, cmdrsp,
|
||||
complete_taskmgmt_command(&devdata->xa, cmdrsp,
|
||||
cmdrsp->scsitaskmgmt.result);
|
||||
} else if (cmdrsp->cmdtype == CMD_NOTIFYGUEST_TYPE)
|
||||
dev_err_once(&devdata->dev->device,
|
||||
@ -1053,7 +1036,7 @@ static int visorhba_probe(struct visor_device *dev)
|
||||
if (err)
|
||||
goto err_debugfs_info;
|
||||
|
||||
idr_init(&devdata->idr);
|
||||
xa_init(&devdata->xa);
|
||||
|
||||
devdata->cmdrsp = kmalloc(sizeof(*devdata->cmdrsp), GFP_ATOMIC);
|
||||
visorbus_enable_channel_interrupts(dev);
|
||||
@ -1096,8 +1079,6 @@ static void visorhba_remove(struct visor_device *dev)
|
||||
scsi_remove_host(scsihost);
|
||||
scsi_host_put(scsihost);
|
||||
|
||||
idr_destroy(&devdata->idr);
|
||||
|
||||
dev_set_drvdata(&dev->device, NULL);
|
||||
debugfs_remove(devdata->debugfs_info);
|
||||
debugfs_remove_recursive(devdata->debugfs_dir);
|
||||
|
Loading…
Reference in New Issue
Block a user