cregit-Linux how code gets into the kernel

Release 4.14 drivers/vhost/scsi.c

Directory: drivers/vhost
/*******************************************************************************
 * Vhost kernel TCM fabric driver for virtio SCSI initiators
 *
 * (C) Copyright 2010-2013 Datera, Inc.
 * (C) Copyright 2010-2012 IBM Corp.
 *
 * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
 *
 * Authors: Nicholas A. Bellinger <nab@daterainc.com>
 *          Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 ****************************************************************************/

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <generated/utsrelease.h>
#include <linux/utsname.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/kthread.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/configfs.h>
#include <linux/ctype.h>
#include <linux/compat.h>
#include <linux/eventfd.h>
#include <linux/fs.h>
#include <linux/vmalloc.h>
#include <linux/miscdevice.h>
#include <asm/unaligned.h>
#include <scsi/scsi_common.h>
#include <scsi/scsi_proto.h>
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
#include <linux/vhost.h>
#include <linux/virtio_scsi.h>
#include <linux/llist.h>
#include <linux/bitmap.h>
#include <linux/percpu_ida.h>

#include "vhost.h"


#define VHOST_SCSI_VERSION  "v0.1"

#define VHOST_SCSI_NAMELEN 256

#define VHOST_SCSI_MAX_CDB_SIZE 32

#define VHOST_SCSI_DEFAULT_TAGS 256

#define VHOST_SCSI_PREALLOC_SGLS 2048

#define VHOST_SCSI_PREALLOC_UPAGES 2048

#define VHOST_SCSI_PREALLOC_PROT_SGLS 512


struct vhost_scsi_inflight {
	/* Wait for the flush operation to finish */
	
struct completion comp;
	/* Refcount for the inflight reqs */
	
struct kref kref;
};


struct vhost_scsi_cmd {
	/* Descriptor from vhost_get_vq_desc() for virt_queue segment */
	
int tvc_vq_desc;
	/* virtio-scsi initiator task attribute */
	
int tvc_task_attr;
	/* virtio-scsi response incoming iovecs */
	
int tvc_in_iovs;
	/* virtio-scsi initiator data direction */
	
enum dma_data_direction tvc_data_direction;
	/* Expected data transfer length from virtio-scsi header */
	
u32 tvc_exp_data_len;
	/* The Tag from include/linux/virtio_scsi.h:struct virtio_scsi_cmd_req */
	
u64 tvc_tag;
	/* The number of scatterlists associated with this cmd */
	
u32 tvc_sgl_count;
	
u32 tvc_prot_sgl_count;
	/* Saved unpacked SCSI LUN for vhost_scsi_submission_work() */
	
u32 tvc_lun;
	/* Pointer to the SGL formatted memory from virtio-scsi */
	
struct scatterlist *tvc_sgl;
	
struct scatterlist *tvc_prot_sgl;
	
struct page **tvc_upages;
	/* Pointer to response header iovec */
	
struct iovec tvc_resp_iov;
	/* Pointer to vhost_scsi for our device */
	
struct vhost_scsi *tvc_vhost;
	/* Pointer to vhost_virtqueue for the cmd */
	
struct vhost_virtqueue *tvc_vq;
	/* Pointer to vhost nexus memory */
	
struct vhost_scsi_nexus *tvc_nexus;
	/* The TCM I/O descriptor that is accessed via container_of() */
	
struct se_cmd tvc_se_cmd;
	/* work item used for cmwq dispatch to vhost_scsi_submission_work() */
	
struct work_struct work;
	/* Copy of the incoming SCSI command descriptor block (CDB) */
	
unsigned char tvc_cdb[VHOST_SCSI_MAX_CDB_SIZE];
	/* Sense buffer that will be mapped into outgoing status */
	
unsigned char tvc_sense_buf[TRANSPORT_SENSE_BUFFER];
	/* Completed commands list, serviced from vhost worker thread */
	
struct llist_node tvc_completion_list;
	/* Used to track inflight cmd */
	
struct vhost_scsi_inflight *inflight;
};


struct vhost_scsi_nexus {
	/* Pointer to TCM session for I_T Nexus */
	
struct se_session *tvn_se_sess;
};


struct vhost_scsi_tpg {
	/* Vhost port target portal group tag for TCM */
	
u16 tport_tpgt;
	/* Used to track number of TPG Port/Lun Links wrt to explict I_T Nexus shutdown */
	
int tv_tpg_port_count;
	/* Used for vhost_scsi device reference to tpg_nexus, protected by tv_tpg_mutex */
	
int tv_tpg_vhost_count;
	/* Used for enabling T10-PI with legacy devices */
	
int tv_fabric_prot_type;
	/* list for vhost_scsi_list */
	
struct list_head tv_tpg_list;
	/* Used to protect access for tpg_nexus */
	
struct mutex tv_tpg_mutex;
	/* Pointer to the TCM VHost I_T Nexus for this TPG endpoint */
	
struct vhost_scsi_nexus *tpg_nexus;
	/* Pointer back to vhost_scsi_tport */
	
struct vhost_scsi_tport *tport;
	/* Returned by vhost_scsi_make_tpg() */
	
struct se_portal_group se_tpg;
	/* Pointer back to vhost_scsi, protected by tv_tpg_mutex */
	
struct vhost_scsi *vhost_scsi;
};


struct vhost_scsi_tport {
	/* SCSI protocol the tport is providing */
	
u8 tport_proto_id;
	/* Binary World Wide unique Port Name for Vhost Target port */
	
u64 tport_wwpn;
	/* ASCII formatted WWPN for Vhost Target port */
	
char tport_name[VHOST_SCSI_NAMELEN];
	/* Returned by vhost_scsi_make_tport() */
	
struct se_wwn tport_wwn;
};


struct vhost_scsi_evt {
	/* event to be sent to guest */
	
struct virtio_scsi_event event;
	/* event list, serviced from vhost worker thread */
	
struct llist_node list;
};

enum {
	
VHOST_SCSI_VQ_CTL = 0,
	
VHOST_SCSI_VQ_EVT = 1,
	
VHOST_SCSI_VQ_IO = 2,
};

/* Note: can't set VIRTIO_F_VERSION_1 yet, since that implies ANY_LAYOUT. */
enum {
	
VHOST_SCSI_FEATURES = VHOST_FEATURES | (1ULL << VIRTIO_SCSI_F_HOTPLUG) |
					       (1ULL << VIRTIO_SCSI_F_T10_PI)
};


#define VHOST_SCSI_MAX_TARGET	256

#define VHOST_SCSI_MAX_VQ	128

#define VHOST_SCSI_MAX_EVENT	128


struct vhost_scsi_virtqueue {
	
struct vhost_virtqueue vq;
	/*
         * Reference counting for inflight reqs, used for flush operation. At
         * each time, one reference tracks new commands submitted, while we
         * wait for another one to reach 0.
         */
	
struct vhost_scsi_inflight inflights[2];
	/*
         * Indicate current inflight in use, protected by vq->mutex.
         * Writers must also take dev mutex and flush under it.
         */
	
int inflight_idx;
};


struct vhost_scsi {
	/* Protected by vhost_scsi->dev.mutex */
	
struct vhost_scsi_tpg **vs_tpg;
	
char vs_vhost_wwpn[TRANSPORT_IQN_LEN];

	
struct vhost_dev dev;
	
struct vhost_scsi_virtqueue vqs[VHOST_SCSI_MAX_VQ];

	
struct vhost_work vs_completion_work; /* cmd completion work item */
	
struct llist_head vs_completion_list; /* cmd completion queue */

	
struct vhost_work vs_event_work; /* evt injection work item */
	
struct llist_head vs_event_list; /* evt injection queue */

	
bool vs_events_missed; /* any missed events, protected by vq->mutex */
	
int vs_events_nr; /* num of pending events, protected by vq->mutex */
};


static struct workqueue_struct *vhost_scsi_workqueue;

/* Global spinlock to protect vhost_scsi TPG list for vhost IOCTL access */
static DEFINE_MUTEX(vhost_scsi_mutex);
static LIST_HEAD(vhost_scsi_list);


static int iov_num_pages(void __user *iov_base, size_t iov_len) { return (PAGE_ALIGN((unsigned long)iov_base + iov_len) - ((unsigned long)iov_base & PAGE_MASK)) >> PAGE_SHIFT; }

Contributors

PersonTokensPropCommitsCommitProp
Asias He3485.00%150.00%
Nicholas Bellinger615.00%150.00%
Total40100.00%2100.00%


static void vhost_scsi_done_inflight(struct kref *kref) { struct vhost_scsi_inflight *inflight; inflight = container_of(kref, struct vhost_scsi_inflight, kref); complete(&inflight->comp); }

Contributors

PersonTokensPropCommitsCommitProp
Asias He3597.22%266.67%
Nicholas Bellinger12.78%133.33%
Total36100.00%3100.00%


static void vhost_scsi_init_inflight(struct vhost_scsi *vs, struct vhost_scsi_inflight *old_inflight[]) { struct vhost_scsi_inflight *new_inflight; struct vhost_virtqueue *vq; int idx, i; for (i = 0; i < VHOST_SCSI_MAX_VQ; i++) { vq = &vs->vqs[i].vq; mutex_lock(&vq->mutex); /* store old infight */ idx = vs->vqs[i].inflight_idx; if (old_inflight) old_inflight[i] = &vs->vqs[i].inflights[idx]; /* setup new infight */ vs->vqs[i].inflight_idx = idx ^ 1; new_inflight = &vs->vqs[i].inflights[idx ^ 1]; kref_init(&new_inflight->kref); init_completion(&new_inflight->comp); mutex_unlock(&vq->mutex); } }

Contributors

PersonTokensPropCommitsCommitProp
Asias He15599.36%150.00%
Nicholas Bellinger10.64%150.00%
Total156100.00%2100.00%


static struct vhost_scsi_inflight * vhost_scsi_get_inflight(struct vhost_virtqueue *vq) { struct vhost_scsi_inflight *inflight; struct vhost_scsi_virtqueue *svq; svq = container_of(vq, struct vhost_scsi_virtqueue, vq); inflight = &svq->inflights[svq->inflight_idx]; kref_get(&inflight->kref); return inflight; }

Contributors

PersonTokensPropCommitsCommitProp
Asias He5798.28%150.00%
Nicholas Bellinger11.72%150.00%
Total58100.00%2100.00%


static void vhost_scsi_put_inflight(struct vhost_scsi_inflight *inflight) { kref_put(&inflight->kref, vhost_scsi_done_inflight); }

Contributors

PersonTokensPropCommitsCommitProp
Asias He1990.48%150.00%
Nicholas Bellinger29.52%150.00%
Total21100.00%2100.00%


static int vhost_scsi_check_true(struct se_portal_group *se_tpg) { return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Bellinger14100.00%2100.00%
Total14100.00%2100.00%


static int vhost_scsi_check_false(struct se_portal_group *se_tpg) { return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Bellinger14100.00%2100.00%
Total14100.00%2100.00%


static char *vhost_scsi_get_fabric_name(void) { return "vhost"; }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Bellinger12100.00%2100.00%
Total12100.00%2100.00%


static char *vhost_scsi_get_fabric_wwn(struct se_portal_group *se_tpg) { struct vhost_scsi_tpg *tpg = container_of(se_tpg, struct vhost_scsi_tpg, se_tpg); struct vhost_scsi_tport *tport = tpg->tport; return &tport->tport_name[0]; }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Bellinger45100.00%2100.00%
Total45100.00%2100.00%


static u16 vhost_scsi_get_tpgt(struct se_portal_group *se_tpg) { struct vhost_scsi_tpg *tpg = container_of(se_tpg, struct vhost_scsi_tpg, se_tpg); return tpg->tport_tpgt; }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Bellinger31100.00%2100.00%
Total31100.00%2100.00%


static int vhost_scsi_check_prot_fabric_only(struct se_portal_group *se_tpg) { struct vhost_scsi_tpg *tpg = container_of(se_tpg, struct vhost_scsi_tpg, se_tpg); return tpg->tv_fabric_prot_type; }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Bellinger31100.00%2100.00%
Total31100.00%2100.00%


static u32 vhost_scsi_tpg_get_inst_index(struct se_portal_group *se_tpg) { return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Bellinger14100.00%2100.00%
Total14100.00%2100.00%


static void vhost_scsi_release_cmd(struct se_cmd *se_cmd) { struct vhost_scsi_cmd *tv_cmd = container_of(se_cmd, struct vhost_scsi_cmd, tvc_se_cmd); struct se_session *se_sess = tv_cmd->tvc_nexus->tvn_se_sess; int i; if (tv_cmd->tvc_sgl_count) { for (i = 0; i < tv_cmd->tvc_sgl_count; i++) put_page(sg_page(&tv_cmd->tvc_sgl[i])); } if (tv_cmd->tvc_prot_sgl_count) { for (i = 0; i < tv_cmd->tvc_prot_sgl_count; i++) put_page(sg_page(&tv_cmd->tvc_prot_sgl[i])); } vhost_scsi_put_inflight(tv_cmd->inflight); percpu_ida_free(&se_sess->sess_tag_pool, se_cmd->map_tag); }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Bellinger133100.00%6100.00%
Total133100.00%6100.00%


static u32 vhost_scsi_sess_get_index(struct se_session *se_sess) { return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Bellinger14100.00%2100.00%
Total14100.00%2100.00%


static int vhost_scsi_write_pending(struct se_cmd *se_cmd) { /* Go ahead and process the write immediately */ target_execute_cmd(se_cmd); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Bellinger20100.00%2100.00%
Total20100.00%2100.00%


static int vhost_scsi_write_pending_status(struct se_cmd *se_cmd) { return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Bellinger14100.00%2100.00%
Total14100.00%2100.00%


static void vhost_scsi_set_default_node_attrs(struct se_node_acl *nacl) { return; }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Bellinger12100.00%2100.00%
Total12100.00%2100.00%


static int vhost_scsi_get_cmd_state(struct se_cmd *se_cmd) { return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Bellinger14100.00%2100.00%
Total14100.00%2100.00%


static void vhost_scsi_complete_cmd(struct vhost_scsi_cmd *cmd) { struct vhost_scsi *vs = cmd->tvc_vhost; llist_add(&cmd->tvc_completion_list, &vs->vs_completion_list); vhost_work_queue(&vs->dev, &vs->vs_completion_work); }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Bellinger4291.30%360.00%
Asias He48.70%240.00%
Total46100.00%5100.00%


static int vhost_scsi_queue_data_in(struct se_cmd *se_cmd) { struct vhost_scsi_cmd *cmd = container_of(se_cmd, struct vhost_scsi_cmd, tvc_se_cmd); vhost_scsi_complete_cmd(cmd); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Bellinger3294.12%266.67%
Asias He25.88%133.33%
Total34100.00%3100.00%


static int vhost_scsi_queue_status(struct se_cmd *se_cmd) { struct vhost_scsi_cmd *cmd = container_of(se_cmd, struct vhost_scsi_cmd, tvc_se_cmd); vhost_scsi_complete_cmd(cmd); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Bellinger3294.12%266.67%
Asias He25.88%133.33%
Total34100.00%3100.00%


static void vhost_scsi_queue_tm_rsp(struct se_cmd *se_cmd) { return; }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Bellinger1083.33%266.67%
Jörn Engel216.67%133.33%
Total12100.00%3100.00%


static void vhost_scsi_aborted_task(struct se_cmd *se_cmd) { return; }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Bellinger12100.00%2100.00%
Total12100.00%2100.00%


static void vhost_scsi_free_evt(struct vhost_scsi *vs, struct vhost_scsi_evt *evt) { vs->vs_events_nr--; kfree(evt); }

Contributors

PersonTokensPropCommitsCommitProp
Asias He2492.31%150.00%
Nicholas Bellinger27.69%150.00%
Total26100.00%2100.00%


static struct vhost_scsi_evt * vhost_scsi_allocate_evt(struct vhost_scsi *vs, u32 event, u32 reason) { struct vhost_virtqueue *vq = &vs->vqs[VHOST_SCSI_VQ_EVT].vq; struct vhost_scsi_evt *evt; if (vs->vs_events_nr > VHOST_SCSI_MAX_EVENT) { vs->vs_events_missed = true; return NULL; } evt = kzalloc(sizeof(*evt), GFP_KERNEL); if (!evt) { vq_err(vq, "Failed to allocate vhost_scsi_evt\n"); vs->vs_events_missed = true; return NULL; } evt->event.event = cpu_to_vhost32(vq, event); evt->event.reason = cpu_to_vhost32(vq, reason); vs->vs_events_nr++; return evt; }

Contributors

PersonTokensPropCommitsCommitProp
Asias He11489.06%250.00%
Michael S. Tsirkin107.81%125.00%
Nicholas Bellinger43.12%125.00%
Total128100.00%4100.00%


static void vhost_scsi_free_cmd(struct vhost_scsi_cmd *cmd) { struct se_cmd *se_cmd = &cmd->tvc_se_cmd; /* TODO locking against target/backend threads? */ transport_generic_free_cmd(se_cmd, 0); }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Bellinger2482.76%250.00%
Asias He517.24%250.00%
Total29100.00%4100.00%


static int vhost_scsi_check_stop_free(struct se_cmd *se_cmd) { return target_put_sess_cmd(se_cmd); }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Bellinger1482.35%133.33%
Asias He317.65%266.67%
Total17100.00%3100.00%


static void vhost_scsi_do_evt_work(struct vhost_scsi *vs, struct vhost_scsi_evt *evt) { struct vhost_virtqueue *vq = &vs->vqs[VHOST_SCSI_VQ_EVT].vq; struct virtio_scsi_event *event = &evt->event; struct virtio_scsi_event __user *eventp; unsigned out, in; int head, ret; if (!vq->private_data) { vs->vs_events_missed = true; return; } again: vhost_disable_notify(&vs->dev, vq); head = vhost_get_vq_desc(vq, vq->iov, ARRAY_SIZE(vq->iov), &out, &in, NULL, NULL); if (head < 0) { vs->vs_events_missed = true; return; } if (head == vq->num) { if (vhost_enable_notify(&vs->dev, vq)) goto again; vs->vs_events_missed = true; return; } if ((vq->iov[out].iov_len != sizeof(struct virtio_scsi_event))) { vq_err(vq, "Expecting virtio_scsi_event, got %zu bytes\n", vq->iov[out].iov_len); vs->vs_events_missed = true; return; } if (vs->vs_events_missed) { event->event |= cpu_to_vhost32(vq, VIRTIO_SCSI_T_EVENTS_MISSED); vs->vs_events_missed = false; } eventp = vq->iov[out].iov_base; ret = __copy_to_user(eventp, event, sizeof(*event)); if (!ret) vhost_add_used_and_signal(&vs->dev, vq, head, 0); else vq_err(vq, "Faulted on vhost_scsi_send_event\n"); }

Contributors

PersonTokensPropCommitsCommitProp
Asias He27497.16%250.00%
Michael S. Tsirkin51.77%125.00%
Nicholas Bellinger31.06%125.00%
Total282100.00%4100.00%


static void vhost_scsi_evt_work(struct vhost_work *work) { struct vhost_scsi *vs = container_of(work, struct vhost_scsi, vs_event_work); struct vhost_virtqueue *vq = &vs->vqs[VHOST_SCSI_VQ_EVT].vq; struct vhost_scsi_evt *evt, *t; struct llist_node *llnode; mutex_lock(&vq->mutex); llnode = llist_del_all(&vs->vs_event_list); llist_for_each_entry_safe(evt, t, llnode, list) { vhost_scsi_do_evt_work(vs, evt); vhost_scsi_free_evt(vs, evt); } mutex_unlock(&vq->mutex); }

Contributors

PersonTokensPropCommitsCommitProp
Asias He8176.42%240.00%
Nicholas Bellinger1514.15%240.00%
Byungchul Park109.43%120.00%
Total106100.00%5100.00%

/* Fill in status and signal that we are done processing this command * * This is scheduled in the vhost work queue so we are called with the owner * process mm and can access the vring. */
static void vhost_scsi_complete_cmd_work(struct vhost_work *work) { struct vhost_scsi *vs = container_of(work, struct vhost_scsi, vs_completion_work); DECLARE_BITMAP(signal, VHOST_SCSI_MAX_VQ); struct virtio_scsi_cmd_resp v_rsp; struct vhost_scsi_cmd *cmd; struct llist_node *llnode; struct se_cmd *se_cmd; struct iov_iter iov_iter; int ret, vq; bitmap_zero(signal, VHOST_SCSI_MAX_VQ); llnode = llist_del_all(&vs->vs_completion_list); llist_for_each_entry(cmd, llnode, tvc_completion_list) { se_cmd = &cmd->tvc_se_cmd; pr_debug("%s tv_cmd %p resid %u status %#02x\n", __func__, cmd, se_cmd->residual_count, se_cmd->scsi_status); memset(&v_rsp, 0, sizeof(v_rsp)); v_rsp.resid = cpu_to_vhost32(cmd->tvc_vq, se_cmd->residual_count); /* TODO is status_qualifier field needed? */ v_rsp.status = se_cmd->scsi_status; v_rsp.sense_len = cpu_to_vhost32(cmd->tvc_vq, se_cmd->scsi_sense_length); memcpy(v_rsp.sense, cmd->tvc_sense_buf, se_cmd->scsi_sense_length); iov_iter_init(&iov_iter, READ, &cmd->tvc_resp_iov, cmd->tvc_in_iovs, sizeof(v_rsp)); ret = copy_to_iter(&v_rsp, sizeof(v_rsp), &iov_iter); if (likely(ret == sizeof(v_rsp))) { struct vhost_scsi_virtqueue *q; vhost_add_used(cmd->tvc_vq, cmd->tvc_vq_desc, 0); q = container_of(cmd->tvc_vq, struct vhost_scsi_virtqueue, vq); vq = q - vs->vqs; __set_bit(vq, signal); } else pr_err("Faulted on virtio_scsi_cmd_resp\n"); vhost_scsi_free_cmd(cmd); } vq = -1; while ((vq = find_next_bit(signal, VHOST_SCSI_MAX_VQ, vq + 1)) < VHOST_SCSI_MAX_VQ) vhost_signal(&vs->dev, &vs->vqs[vq].vq); }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Bellinger19157.70%330.00%
Asias He11735.35%440.00%
Michael S. Tsirkin175.14%110.00%
Byungchul Park51.51%110.00%
Benjamin Coddington10.30%110.00%
Total331100.00%10100.00%


static struct vhost_scsi_cmd * vhost_scsi_get_tag(struct vhost_virtqueue *vq, struct vhost_scsi_tpg *tpg, unsigned char *cdb, u64 scsi_tag, u16 lun, u8 task_attr, u32 exp_data_len, int data_direction) { struct vhost_scsi_cmd *cmd; struct vhost_scsi_nexus *tv_nexus; struct se_session *se_sess; struct scatterlist *sg, *prot_sg; struct page **pages; int tag; tv_nexus = tpg->tpg_nexus; if (!tv_nexus) { pr_err("Unable to locate active struct vhost_scsi_nexus\n"); return ERR_PTR(-EIO); } se_sess = tv_nexus->tvn_se_sess; tag = percpu_ida_alloc(&se_sess->sess_tag_pool, TASK_RUNNING); if (tag < 0) { pr_err("Unable to obtain tag for vhost_scsi_cmd\n"); return ERR_PTR(-ENOMEM); } cmd = &((struct vhost_scsi_cmd *)se_sess->sess_cmd_map)[tag]; sg = cmd->tvc_sgl; prot_sg = cmd->tvc_prot_sgl; pages = cmd->tvc_upages; memset(cmd, 0, sizeof(struct vhost_scsi_cmd)); cmd->tvc_sgl = sg; cmd->tvc_prot_sgl = prot_sg; cmd->tvc_upages = pages; cmd->tvc_se_cmd.map_tag = tag; cmd->tvc_tag = scsi_tag; cmd->tvc_lun = lun; cmd->tvc_task_attr = task_attr; cmd->tvc_exp_data_len = exp_data_len; cmd->tvc_data_direction = data_direction; cmd->tvc_nexus = tv_nexus; cmd->inflight = vhost_scsi_get_inflight(vq); memcpy(cmd->tvc_cdb, cdb, VHOST_SCSI_MAX_CDB_SIZE); return cmd; }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Bellinger24190.60%866.67%
Asias He249.02%325.00%
Kent Overstreet10.38%18.33%
Total266100.00%12100.00%

/* * Map a user memory range into a scatterlist * * Returns the number of scatterlist entries used or -errno on error. */
static int vhost_scsi_map_to_sgl(struct vhost_scsi_cmd *cmd, void __user *ptr, size_t len, struct scatterlist *sgl, bool write) { unsigned int npages = 0, offset, nbytes; unsigned int pages_nr = iov_num_pages(ptr, len); struct scatterlist *sg = sgl; struct page **pages = cmd->tvc_upages; int ret, i; if (pages_nr > VHOST_SCSI_PREALLOC_UPAGES) { pr_err("vhost_scsi_map_to_sgl() pages_nr: %u greater than" " preallocated VHOST_SCSI_PREALLOC_UPAGES: %u\n", pages_nr, VHOST_SCSI_PREALLOC_UPAGES); return -ENOBUFS; } ret = get_user_pages_fast((unsigned long)ptr, pages_nr, write, pages); /* No pages were pinned */ if (ret < 0) goto out; /* Less pages pinned than wanted */ if (ret != pages_nr) { for (i = 0; i < ret; i++) put_page(pages[i]); ret = -EFAULT; goto out; } while (len > 0) { offset = (uintptr_t)ptr & ~PAGE_MASK; nbytes = min_t(unsigned int, PAGE_SIZE - offset, len); sg_set_page(sg, pages[npages], nbytes, offset); ptr += nbytes; len -= nbytes; sg++; npages++; } out: return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Bellinger12054.79%583.33%
Asias He9945.21%116.67%
Total219100.00%6100.00%


static int vhost_scsi_calc_sgls(struct iov_iter *iter, size_t bytes, int max_sgls) { int sgl_count = 0; if (!iter || !iter->iov) { pr_err("%s: iter->iov is NULL, but expected bytes: %zu" " present\n", __func__, bytes); return -EINVAL; } sgl_count = iov_iter_npages(iter, 0xffff); if (sgl_count > max_sgls) { pr_err("%s: requested sgl_count: %d exceeds pre-allocated" " max_sgls: %d\n", __func__, sgl_count, max_sgls); return -EINVAL; } return sgl_count; }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Bellinger84100.00%3100.00%
Total84100.00%3100.00%


static int vhost_scsi_iov_to_sgl(struct vhost_scsi_cmd *cmd, bool write, struct iov_iter *iter, struct scatterlist *sg, int sg_count) { size_t off = iter->iov_offset; int i, ret; for (i = 0; i < iter->nr_segs; i++) { void __user *base = iter->iov[i].iov_base + off; size_t len = iter->iov[i]