bitkeeper revision 1.1159.249.1 (4208d0edi9hSgBaQl0hrDcYiEH0yxg)

blktap driver fixes:  
Allow the tap to terminate a block device (not need a backend). 
Allow it to run in dom0.
Forward control messages to user space as well.

Signed-off-by: akw27@cl.cam.ac.uk
This commit is contained in:
akw27@labyrinth.cl.cam.ac.uk committed 2005-02-08 14:47:09 +00:00
1 parent 196c87d157
commit 4a33b9f396
5 files changed
+142 -59

No files matched your search

@@ -16,7 +16,7 @@
#include "blktap.h"
int __init xlblk_init(void)
int __init xlblktap_init(void)
{
ctrl_msg_t cmsg;
blkif_fe_driver_status_t fe_st;
@@ -64,6 +64,7 @@ int __init xlblk_init(void)
return 0;
}
#if 0 /* tap doesn't handle suspend/resume */
void blkdev_suspend(void)
{
}
@@ -81,6 +82,6 @@ void blkdev_resume(void)
memcpy(cmsg.msg, &st, sizeof(st));
ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
}
#endif
__initcall(xlblk_init);
__initcall(xlblktap_init);
@@ -48,6 +48,12 @@
#define WPRINTK(fmt, args...) printk(KERN_WARNING "blk_tap: " fmt, ##args)
/* -------[ state descriptors ]--------------------------------------- */
#define BLKIF_STATE_CLOSED 0
#define BLKIF_STATE_DISCONNECTED 1
#define BLKIF_STATE_CONNECTED 2
/* -------[ connection tracking ]------------------------------------- */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
@@ -99,7 +105,6 @@ typedef struct {
unsigned long mach_fas[BLKIF_MAX_SEGMENTS_PER_REQUEST];
unsigned long virt_fas[BLKIF_MAX_SEGMENTS_PER_REQUEST];
int next_free;
int inuse; /* debugging */
} active_req_t;
typedef unsigned int ACTIVE_RING_IDX;
@@ -181,7 +186,7 @@ extern unsigned long mmap_vstart;
* for shared memory rings.
*/
#define RING_PAGES 128
#define RING_PAGES 3 /* Ctrl, Front, and Back */
extern unsigned long rings_vstart;
@@ -190,11 +195,10 @@ extern unsigned long blktap_mode;
/* Connection to a single backend domain. */
extern blkif_front_ring_t blktap_be_ring;
extern unsigned int blktap_be_evtchn;
extern unsigned int blktap_be_state;
/* Event channel to backend domain. */
extern unsigned int blkif_ptbe_evtchn;
/* User ring status... this will soon vanish into a ring struct. */
/* User ring status. */
extern unsigned long blktap_ring_ok;
/* -------[ ...and function prototypes. ]----------------------------- */
@@ -213,8 +217,7 @@ void blktap_kick_user(void);
/* user ring access functions: */
int blktap_write_fe_ring(blkif_request_t *req);
int blktap_write_be_ring(blkif_response_t *rsp);
int blktap_read_fe_ring(void);
int blktap_read_be_ring(void);
int blktap_write_ctrl_ring(ctrl_msg_t *msg);
/* fe/be ring access functions: */
int write_resp_to_fe_ring(blkif_t *blkif, blkif_response_t *rsp);
@@ -10,10 +10,6 @@
#include "blktap.h"
#define BLKIF_STATE_CLOSED 0
#define BLKIF_STATE_DISCONNECTED 1
#define BLKIF_STATE_CONNECTED 2
static char *blkif_state_name[] = {
[BLKIF_STATE_CLOSED] = "closed",
[BLKIF_STATE_DISCONNECTED] = "disconnected",
@@ -26,9 +22,10 @@ static char * blkif_status_name[] = {
[BLKIF_INTERFACE_STATUS_CONNECTED] = "connected",
[BLKIF_INTERFACE_STATUS_CHANGED] = "changed",
};
static unsigned int blkif_pt_state = BLKIF_STATE_CLOSED;
static unsigned blkif_ptbe_irq;
unsigned int blkif_ptbe_evtchn;
static unsigned blktap_be_irq;
unsigned int blktap_be_state = BLKIF_STATE_CLOSED;
unsigned int blktap_be_evtchn;
/*-----[ Control Messages to/from Frontend VMs ]--------------------------*/
@@ -306,7 +303,7 @@ static void blkif_ptbe_disconnect(void)
sring = (blkif_sring_t *)__get_free_page(GFP_KERNEL);
SHARED_RING_INIT(BLKIF_RING, sring);
FRONT_RING_INIT(BLKIF_RING, &blktap_be_ring, sring);
blkif_pt_state = BLKIF_STATE_DISCONNECTED;
blktap_be_state = BLKIF_STATE_DISCONNECTED;
DPRINTK("Blkif-Passthrough-BE is now DISCONNECTED.\n");
blkif_ptbe_send_interface_connect();
}
@@ -315,10 +312,10 @@ static void blkif_ptbe_connect(blkif_fe_interface_status_t *status)
{
int err = 0;
blkif_ptbe_evtchn = status->evtchn;
blkif_ptbe_irq = bind_evtchn_to_irq(blkif_ptbe_evtchn);
blktap_be_evtchn = status->evtchn;
blktap_be_irq = bind_evtchn_to_irq(blktap_be_evtchn);
err = request_irq(blkif_ptbe_irq, blkif_ptbe_int,
err = request_irq(blktap_be_irq, blkif_ptbe_int,
SA_SAMPLE_RANDOM, "blkif", NULL);
if ( err ) {
WPRINTK("blkfront request_irq failed (%d)\n", err);
@@ -326,7 +323,7 @@ static void blkif_ptbe_connect(blkif_fe_interface_status_t *status)
} else {
/* transtion to connected in case we need to do a
a partion probe on a whole disk */
blkif_pt_state = BLKIF_STATE_CONNECTED;
blktap_be_state = BLKIF_STATE_CONNECTED;
}
}
@@ -334,7 +331,7 @@ static void unexpected(blkif_fe_interface_status_t *status)
{
WPRINTK(" TAP: Unexpected blkif status %s in state %s\n",
blkif_status_name[status->status],
blkif_state_name[blkif_pt_state]);
blkif_state_name[blktap_be_state]);
}
static void blkif_ptbe_status(
@@ -352,7 +349,7 @@ static void blkif_ptbe_status(
switch ( status->status )
{
case BLKIF_INTERFACE_STATUS_CLOSED:
switch ( blkif_pt_state )
switch ( blktap_be_state )
{
case BLKIF_STATE_CLOSED:
unexpected(status);
@@ -366,7 +363,7 @@ static void blkif_ptbe_status(
break;
case BLKIF_INTERFACE_STATUS_DISCONNECTED:
switch ( blkif_pt_state )
switch ( blktap_be_state )
{
case BLKIF_STATE_CLOSED:
blkif_ptbe_disconnect();
@@ -380,7 +377,7 @@ static void blkif_ptbe_status(
break;
case BLKIF_INTERFACE_STATUS_CONNECTED:
switch ( blkif_pt_state )
switch ( blktap_be_state )
{
case BLKIF_STATE_CLOSED:
unexpected(status);
@@ -398,7 +395,7 @@ static void blkif_ptbe_status(
break;
case BLKIF_INTERFACE_STATUS_CHANGED:
switch ( blkif_pt_state )
switch ( blktap_be_state )
{
case BLKIF_STATE_CLOSED:
case BLKIF_STATE_DISCONNECTED:
@@ -440,6 +437,14 @@ void blkif_ctrlif_rx(ctrl_msg_t *msg, unsigned long id)
case CMSG_BLKIF_BE:
/* send a copy of the message to user if wanted */
if ( (blktap_mode & BLKTAP_MODE_INTERCEPT_FE) ||
(blktap_mode & BLKTAP_MODE_COPY_FE) ) {
blktap_write_ctrl_ring(msg);
}
switch ( msg->subtype )
{
case CMSG_BLKIF_BE_CREATE:
@@ -500,11 +505,13 @@ void blkif_ctrlif_rx(ctrl_msg_t *msg, unsigned long id)
ctrl_if_send_response(msg);
}
/*-----[ All control messages enter here: ]-------------------------------*/
/*-----[ Initialization ]-------------------------------------------------*/
void __init blkif_interface_init(void)
{
blkif_cachep = kmem_cache_create("blkif_cache", sizeof(blkif_t),
0, 0, NULL, NULL);
memset(blkif_hash, 0, sizeof(blkif_hash));
blktap_be_ring.sring = NULL;
}
@@ -40,8 +40,6 @@ inline active_req_t *get_active_req(void)
spin_lock_irqsave(&active_req_lock, flags);
idx = active_req_ring[MASK_ACTIVE_IDX(active_cons++)];
ar = &active_reqs[idx];
if (ar->inuse) WPRINTK("AR INUSE! (%lu)\n", ar->id);
ar->inuse = 1;
spin_unlock_irqrestore(&active_req_lock, flags);
return ar;
@@ -52,7 +50,6 @@ inline void free_active_req(active_req_t *ar)
unsigned long flags;
spin_lock_irqsave(&active_req_lock, flags);
ar->inuse = 0;
active_req_ring[MASK_ACTIVE_IDX(active_prod++)] = ACTIVE_IDX(ar);
spin_unlock_irqrestore(&active_req_lock, flags);
}
@@ -97,11 +94,8 @@ inline int write_resp_to_fe_ring(blkif_t *blkif, blkif_response_t *rsp)
blkif_response_t *resp_d;
active_req_t *ar;
/* remap id, and free the active req. blkif lookup goes here too.*/
ar = &active_reqs[ID_TO_IDX(rsp->id)];
/* WPRINTK("%3u > %3lu\n", ID_TO_IDX(rsp->id), ar->id); */
rsp->id = ar->id;
free_active_req(ar);
resp_d = RING_GET_RESPONSE(BLKIF_RING, &blkif->blk_ring,
blkif->blk_ring.rsp_prod_pvt);
@@ -109,6 +103,9 @@ inline int write_resp_to_fe_ring(blkif_t *blkif, blkif_response_t *rsp)
wmb();
blkif->blk_ring.rsp_prod_pvt++;
blkif_put(ar->blkif);
free_active_req(ar);
return 0;
}
@@ -116,6 +113,11 @@ inline int write_req_to_be_ring(blkif_request_t *req)
{
blkif_request_t *req_d;
if ( blktap_be_state != BLKIF_STATE_CONNECTED ) {
WPRINTK("Tap trying to access an unconnected backend!\n");
return 0;
}
req_d = RING_GET_REQUEST(BLKIF_RING, &blktap_be_ring,
blktap_be_ring.req_prod_pvt);
memcpy(req_d, req, sizeof(blkif_request_t));
@@ -135,6 +137,9 @@ inline void kick_fe_domain(blkif_t *blkif)
inline void kick_be_domain(void)
{
if ( blktap_be_state != BLKIF_STATE_CONNECTED )
return;
wmb(); /* Ensure that the frontend can see the requests. */
RING_PUSH_REQUESTS(BLKIF_RING, &blktap_be_ring);
notify_via_evtchn(blkif_ptbe_evtchn);
@@ -310,6 +315,7 @@ static int do_block_io_op(blkif_t *blkif, int max_to_do)
*/
ar = get_active_req();
ar->id = req_s->id;
blkif_get(blkif);
ar->blkif = blkif;
req_s->id = MAKE_ID(blkif->domid, ACTIVE_IDX(ar));
/* WPRINTK("%3u < %3lu\n", ID_TO_IDX(req_s->id), ar->id); */
@@ -458,11 +464,13 @@ void print_vm_ring_idxs(void)
blkif->blk_ring.sring->req_prod,
blkif->blk_ring.sring->rsp_prod);
}
WPRINTK("BE Ring: \n--------\n");
WPRINTK("BE: rsp_cons: %2d, req_prod_prv: %2d "
"| req_prod: %2d, rsp_prod: %2d\n",
blktap_be_ring.rsp_cons,
blktap_be_ring.req_prod_pvt,
blktap_be_ring.sring->req_prod,
blktap_be_ring.sring->rsp_prod);
if (blktap_be_ring.sring != NULL) {
WPRINTK("BE Ring: \n--------\n");
WPRINTK("BE: rsp_cons: %2d, req_prod_prv: %2d "
"| req_prod: %2d, rsp_prod: %2d\n",
blktap_be_ring.rsp_cons,
blktap_be_ring.req_prod_pvt,
blktap_be_ring.sring->req_prod,
blktap_be_ring.sring->rsp_prod);
}
}
@@ -19,6 +19,7 @@
#include <linux/gfp.h>
#include <linux/poll.h>
#include <asm/pgalloc.h>
#include <asm-xen/xen-public/io/blkif.h> /* for control ring. */
#include "blktap.h"
@@ -40,6 +41,11 @@ unsigned long rings_vstart;
/* Rings up to user space. */
static blkif_front_ring_t blktap_ufe_ring;
static blkif_back_ring_t blktap_ube_ring;
static ctrl_front_ring_t blktap_uctrl_ring;
/* local prototypes */
static int blktap_read_fe_ring(void);
static int blktap_read_be_ring(void);
/* -------[ blktap vm ops ]------------------------------------------- */
@@ -66,16 +72,28 @@ struct vm_operations_struct blktap_vm_ops = {
static int blktap_open(struct inode *inode, struct file *filp)
{
blkif_sring_t *sring;
ctrl_sring_t *csring;
if ( test_and_set_bit(0, &blktap_dev_inuse) )
return -EBUSY;
printk(KERN_ALERT "blktap open.\n");
/* Allocate the ctrl ring. */
csring = (ctrl_sring_t *)get_zeroed_page(GFP_KERNEL);
if (csring == NULL)
goto fail_nomem;
SetPageReserved(virt_to_page(csring));
SHARED_RING_INIT(CTRL_RING, csring);
FRONT_RING_INIT(CTRL_RING, &blktap_uctrl_ring, csring);
/* Allocate the fe ring. */
sring = (blkif_sring_t *)get_zeroed_page(GFP_KERNEL);
if (sring == NULL)
goto fail_nomem;
goto fail_free_ctrl;
SetPageReserved(virt_to_page(sring));
@@ -95,6 +113,9 @@ static int blktap_open(struct inode *inode, struct file *filp)
DPRINTK(KERN_ALERT "blktap open.\n");
return 0;
fail_free_ctrl:
free_page( (unsigned long) blktap_uctrl_ring.sring);
fail_free_fe:
free_page( (unsigned long) blktap_ufe_ring.sring);
@@ -111,6 +132,9 @@ static int blktap_release(struct inode *inode, struct file *filp)
printk(KERN_ALERT "blktap closed.\n");
/* Free the ring page. */
ClearPageReserved(virt_to_page(blktap_uctrl_ring.sring));
free_page((unsigned long) blktap_uctrl_ring.sring);
ClearPageReserved(virt_to_page(blktap_ufe_ring.sring));
free_page((unsigned long) blktap_ufe_ring.sring);
@@ -120,6 +144,15 @@ static int blktap_release(struct inode *inode, struct file *filp)
return 0;
}
/* Note on mmap:
* remap_pfn_range sets VM_IO on vma->vm_flags. In trying to make libaio
* work to do direct page access from userspace, this ended up being a
* problem. The bigger issue seems to be that there is no way to map
* a foreign page in to user space and have the virtual address of that
* page map sanely down to a mfn.
* Removing the VM_IO flag results in a loop in get_user_pages, as
* pfn_valid() always fails on a foreign page.
*/
static int blktap_mmap(struct file *filp, struct vm_area_struct *vma)
{
int size;
@@ -148,20 +181,28 @@ static int blktap_mmap(struct file *filp, struct vm_area_struct *vma)
/* not sure if I really need to do this... */
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
DPRINTK("Mapping be_ring page %lx.\n", __pa(blktap_ube_ring.sring));
if (remap_page_range(vma, vma->vm_start,
__pa(blktap_ube_ring.sring),
DPRINTK("Mapping ctrl_ring page %lx.\n", __pa(blktap_uctrl_ring.sring));
if (remap_pfn_range(vma, vma->vm_start,
__pa(blktap_uctrl_ring.sring) >> PAGE_SHIFT,
PAGE_SIZE, vma->vm_page_prot)) {
WPRINTK("be_ring: remap_page_range failure!\n");
WPRINTK("ctrl_ring: remap_pfn_range failure!\n");
}
DPRINTK("Mapping be_ring page %lx.\n", __pa(blktap_ube_ring.sring));
if (remap_pfn_range(vma, vma->vm_start + PAGE_SIZE,
__pa(blktap_ube_ring.sring) >> PAGE_SHIFT,
PAGE_SIZE, vma->vm_page_prot)) {
WPRINTK("be_ring: remap_pfn_range failure!\n");
}
DPRINTK("Mapping fe_ring page %lx.\n", __pa(blktap_ufe_ring.sring));
if (remap_page_range(vma, vma->vm_start + PAGE_SIZE,
__pa(blktap_ufe_ring.sring),
if (remap_pfn_range(vma, vma->vm_start + ( 2 * PAGE_SIZE ),
__pa(blktap_ufe_ring.sring) >> PAGE_SHIFT,
PAGE_SIZE, vma->vm_page_prot)) {
WPRINTK("fe_ring: remap_page_range failure!\n");
WPRINTK("fe_ring: remap_pfn_range failure!\n");
}
blktap_vma = vma;
blktap_ring_ok = 1;
@@ -211,9 +252,11 @@ static unsigned int blktap_poll(struct file *file, poll_table *wait)
{
poll_wait(file, &blktap_wait, wait);
if ( RING_HAS_UNPUSHED_REQUESTS(BLKIF_RING, &blktap_ufe_ring) ||
if ( RING_HAS_UNPUSHED_REQUESTS(BLKIF_RING, &blktap_uctrl_ring) ||
RING_HAS_UNPUSHED_REQUESTS(BLKIF_RING, &blktap_ufe_ring) ||
RING_HAS_UNPUSHED_RESPONSES(BLKIF_RING, &blktap_ube_ring) ) {
RING_PUSH_REQUESTS(BLKIF_RING, &blktap_uctrl_ring);
RING_PUSH_REQUESTS(BLKIF_RING, &blktap_ufe_ring);
RING_PUSH_RESPONSES(BLKIF_RING, &blktap_ube_ring);
return POLLIN | POLLRDNORM;
@@ -260,7 +303,6 @@ int blktap_write_fe_ring(blkif_request_t *req)
return 0;
}
//target = RING_NEXT_EMPTY_REQUEST(BLKIF_RING, &blktap_ufe_ring);
target = RING_GET_REQUEST(BLKIF_RING, &blktap_ufe_ring,
blktap_ufe_ring.req_prod_pvt);
memcpy(target, req, sizeof(*req));
@@ -270,7 +312,7 @@ int blktap_write_fe_ring(blkif_request_t *req)
error = direct_remap_area_pages(blktap_vma->vm_mm,
MMAP_VADDR(ID_TO_IDX(req->id), i),
target->frame_and_sects[0] & PAGE_MASK,
target->frame_and_sects[i] & PAGE_MASK,
PAGE_SIZE,
blktap_vma->vm_page_prot,
ID_TO_DOM(req->id));
@@ -302,7 +344,6 @@ int blktap_write_be_ring(blkif_response_t *rsp)
/* No test for fullness in the response direction. */
//target = RING_NEXT_EMPTY_RESPONSE(BLKIF_RING, &blktap_ube_ring);
target = RING_GET_RESPONSE(BLKIF_RING, &blktap_ube_ring,
blktap_ube_ring.rsp_prod_pvt);
memcpy(target, rsp, sizeof(*rsp));
@@ -314,7 +355,7 @@ int blktap_write_be_ring(blkif_response_t *rsp)
return 0;
}
int blktap_read_fe_ring(void)
static int blktap_read_fe_ring(void)
{
/* This is called to read responses from the UFE ring. */
@@ -329,7 +370,6 @@ int blktap_read_fe_ring(void)
if (blktap_mode & BLKTAP_MODE_INTERCEPT_FE) {
/* for each outstanding message on the UFEring */
//RING_FOREACH_RESPONSE(BLKIF_RING, &blktap_ufe_ring, prod, resp_s) {
rp = blktap_ufe_ring.sring->rsp_prod;
rmb();
@@ -349,7 +389,7 @@ int blktap_read_fe_ring(void)
return 0;
}
int blktap_read_be_ring(void)
static int blktap_read_be_ring(void)
{
/* This is called to read requests from the UBE ring. */
@@ -362,7 +402,6 @@ int blktap_read_be_ring(void)
if (blktap_mode & BLKTAP_MODE_INTERCEPT_BE) {
/* for each outstanding message on the UFEring */
//RING_FOREACH_REQUEST(BLKIF_RING, &blktap_ube_ring, prod, req_s) {
rp = blktap_ube_ring.sring->req_prod;
rmb();
for ( i = blktap_ube_ring.req_cons; i != rp; i++ )
@@ -379,6 +418,31 @@ int blktap_read_be_ring(void)
return 0;
}
int blktap_write_ctrl_ring(ctrl_msg_t *msg)
{
ctrl_msg_t *target;
if ( ! blktap_ring_ok ) {
DPRINTK("blktap: be_ring not ready for a request!\n");
return 0;
}
/* No test for fullness in the response direction. */
target = RING_GET_REQUEST(CTRL_RING, &blktap_uctrl_ring,
blktap_uctrl_ring.req_prod_pvt);
memcpy(target, msg, sizeof(*msg));
blktap_uctrl_ring.req_prod_pvt++;
/* currently treat the ring as unidirectional. */
blktap_uctrl_ring.rsp_cons = blktap_uctrl_ring.sring->rsp_prod;
return 0;
}
/* -------[ blktap module setup ]------------------------------------- */
static struct miscdevice blktap_miscdev = {
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.