bitkeeper revision 1.1159.185.1 (41a2270734COZXi8QOV4quF847fEWg)

Merge labyrinth.cl.cam.ac.uk:/auto/groups/xeno/BK/xeno.bk
into labyrinth.cl.cam.ac.uk:/auto/anfs/nos1/akw27/xeno-clone/xeno.bk
This commit is contained in:
akw27@labyrinth.cl.cam.ac.uk committed 2004-11-22 17:51:03 +00:00
commit 955bfd2d85
13 files changed
+1536 -5

No files matched your search

+6
View File
@@ -192,6 +192,12 @@
40f56239-JNIaTzlviVJohVdoYOUpw linux-2.6.9-xen-sparse/drivers/xen/blkfront/blkfront.c
40f56239y9naBTXe40Pi2J_z3p-d1g linux-2.6.9-xen-sparse/drivers/xen/blkfront/block.h
40f56239BVfPsXBiWQitXgDRtOsiqg linux-2.6.9-xen-sparse/drivers/xen/blkfront/vbd.c
41a226e0vjAcDXHOnXE5ummcdUD2mg linux-2.6.9-xen-sparse/drivers/xen/blktap/Makefile
41a226e0VeZA1N8tbU6nvJ3OxUcJmw linux-2.6.9-xen-sparse/drivers/xen/blktap/blktap.c
41a226e1k4J5VMLnrYXDWRqElS49YQ linux-2.6.9-xen-sparse/drivers/xen/blktap/blktap.h
41a226e1-A_Hy7utS8vJKaXnH_tzfA linux-2.6.9-xen-sparse/drivers/xen/blktap/blktap_controlmsg.c
41a226e19NoUUTOvs7jumDMRYDIO4Q linux-2.6.9-xen-sparse/drivers/xen/blktap/blktap_datapath.c
41a226e1MNSyWWK5dEVgvSQ5OW0fDA linux-2.6.9-xen-sparse/drivers/xen/blktap/blktap_userdev.c
40f56239fsLjvtD8YBRAWphps4FDjg linux-2.6.9-xen-sparse/drivers/xen/console/Makefile
3e5a4e651TH-SXHoufurnWjgl5bfOA linux-2.6.9-xen-sparse/drivers/xen/console/console.c
40f56239KYxO0YabhPzCTeUuln-lnA linux-2.6.9-xen-sparse/drivers/xen/evtchn/Makefile
+24
View File
@@ -49,6 +49,20 @@ config XEN_BLKDEV_BACKEND
block devices to other guests via a high-performance shared-memory
interface.
if XEN_BLKDEV_BACKEND
config XEN_BLKDEV_TAP_BE
bool "Block Tap support for backend driver (DANGEROUS)"
default n
help
If you intend to use the block tap driver, the backend domain will
not know the domain id of the real frontend, and so will not be able
to map its data pages. This modifies the backend to attempt to map
from both the tap domain and the real frontend. This presents a
security risk, and so should ONLY be used for development
with the blktap. This option will be removed as the block drivers are
modified to use grant tables.
endif
config XEN_NETDEV_BACKEND
bool "Network-device backend driver"
default y if XEN_PHYSDEV_ACCESS
@@ -94,6 +108,16 @@ config XEN_NETDEV_FRONTEND_PIPELINED_TRANSMITTER
enabled; then you must say N here.
endif
config XEN_BLKDEV_TAP
bool "Block device tap driver"
default n
help
This driver allows a VM to interact on block device channels
to other VMs. Block messages may be passed through or redirected
to a character device, allowing device prototyping in application
space. Odds are that you want to say N here.
config XEN_WRITABLE_PAGETABLES
bool
default y
@@ -13,9 +13,11 @@ CONFIG_NO_IDLE_HZ=y
CONFIG_XEN_PRIVILEGED_GUEST=y
CONFIG_XEN_PHYSDEV_ACCESS=y
CONFIG_XEN_BLKDEV_BACKEND=y
# CONFIG_XEN_BLKDEV_TAP_BE is not set
CONFIG_XEN_NETDEV_BACKEND=y
CONFIG_XEN_BLKDEV_FRONTEND=y
CONFIG_XEN_NETDEV_FRONTEND=y
# CONFIG_XEN_BLKDEV_TAP is not set
# CONFIG_XEN_NETDEV_FRONTEND_PIPELINED_TRANSMITTER is not set
CONFIG_XEN_WRITABLE_PAGETABLES=y
CONFIG_XEN_SCRUB_PAGES=y
@@ -13,9 +13,11 @@ CONFIG_NO_IDLE_HZ=y
# CONFIG_XEN_PRIVILEGED_GUEST is not set
# CONFIG_XEN_PHYSDEV_ACCESS is not set
# CONFIG_XEN_BLKDEV_BACKEND is not set
# CONFIG_XEN_BLKDEV_TAP_BE is not set
# CONFIG_XEN_NETDEV_BACKEND is not set
CONFIG_XEN_BLKDEV_FRONTEND=y
CONFIG_XEN_NETDEV_FRONTEND=y
# CONFIG_XEN_BLKDEV_TAP is not set
# CONFIG_XEN_NETDEV_FRONTEND_PIPELINED_TRANSMITTER is not set
CONFIG_XEN_WRITABLE_PAGETABLES=y
CONFIG_XEN_SCRUB_PAGES=y
@@ -9,4 +9,5 @@ obj-$(CONFIG_XEN_BLKDEV_BACKEND) += blkback/
obj-$(CONFIG_XEN_NETDEV_BACKEND) += netback/
obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += blkfront/
obj-$(CONFIG_XEN_NETDEV_FRONTEND) += netfront/
obj-$(CONFIG_XEN_BLKDEV_TAP) += blktap/
@@ -68,6 +68,19 @@ static PEND_RING_IDX pending_prod, pending_cons;
static kmem_cache_t *buffer_head_cachep;
#endif
#ifdef CONFIG_XEN_BLKDEV_TAP_BE
/*
* If the tap driver is used, we may get pages belonging to either the tap
* or (more likely) the real frontend. The backend must specify which domain
* a given page belongs to in update_va_mapping though. For the moment,
* we pass in the domid of the real frontend in PROBE messages and store
* this value in alt_dom. Then on mapping, we try both. This is a Guiness
* book of records-calibre grim hack, and represents a bit of a security risk.
* Grant tables will soon solve the problem though!
*/
static domid_t alt_dom = 0;
#endif
static int do_block_io_op(blkif_t *blkif, int max_to_do);
static void dispatch_probe(blkif_t *blkif, blkif_request_t *req);
static void dispatch_rw_block_io(blkif_t *blkif, blkif_request_t *req);
@@ -323,12 +336,27 @@ static void dispatch_probe(blkif_t *blkif, blkif_request_t *req)
(blkif_last_sect(req->frame_and_sects[0]) != 7) )
goto out;
#ifdef CONFIG_XEN_BLKDEV_TAP_BE
/* Grab the real frontend out of the probe message. */
alt_dom = (domid_t)req->frame_and_sects[1];
#endif
if ( HYPERVISOR_update_va_mapping_otherdomain(
MMAP_VADDR(pending_idx, 0) >> PAGE_SHIFT,
(pte_t) { (req->frame_and_sects[0] & PAGE_MASK) | __PAGE_KERNEL },
0, blkif->domid) )
0, blkif->domid) ) {
#ifdef CONFIG_XEN_BLKDEV_TAP_BE
/* That didn't work. Try alt_dom. */
if ( HYPERVISOR_update_va_mapping_otherdomain(
MMAP_VADDR(pending_idx, 0) >> PAGE_SHIFT,
(pte_t) { (req->frame_and_sects[0] & PAGE_MASK) | __PAGE_KERNEL },
0, alt_dom) )
goto out;
#else
goto out;
#endif
}
rsp = vbd_probe(blkif, (vdisk_t *)MMAP_VADDR(pending_idx, 0),
PAGE_SIZE / sizeof(vdisk_t));
@@ -411,8 +439,11 @@ static void dispatch_rw_block_io(blkif_t *blkif, blkif_request_t *req)
mcl[i].args[0] = MMAP_VADDR(pending_idx, i) >> PAGE_SHIFT;
mcl[i].args[1] = (phys_seg[i].buffer & PAGE_MASK) | remap_prot;
mcl[i].args[2] = 0;
#ifdef CONFIG_XEN_BLKDEV_TAP_BE
mcl[i].args[3] = (alt_dom != 0) ? alt_dom : blkif->domid;
#else
mcl[i].args[3] = blkif->domid;
#endif
phys_to_machine_mapping[__pa(MMAP_VADDR(pending_idx, i))>>PAGE_SHIFT] =
FOREIGN_FRAME(phys_seg[i].buffer >> PAGE_SHIFT);
}
@@ -579,7 +610,10 @@ static int __init blkif_init(void)
#endif
blkif_ctrlif_init();
#ifdef CONFIG_XEN_BLKDEV_TAP_BE
printk(KERN_ALERT "NOTE: Blkif backend is running with tap support on!\n");
#endif
return 0;
}
@@ -1262,7 +1262,8 @@ static void blkif_status(blkif_fe_interface_status_t *status)
{
if ( status->handle != blkif_handle )
{
WPRINTK(" Invalid blkif: handle=%u", status->handle);
WPRINTK(" Invalid blkif: handle=%u\n", status->handle);
unexpected(status);
return;
}
@@ -0,0 +1,3 @@
obj-y := blktap_userdev.o blktap_datapath.o blktap_controlmsg.o blktap.o
@@ -0,0 +1,86 @@
/******************************************************************************
* blktap.c
*
* XenLinux virtual block-device tap.
*
* Copyright (c) 2004, Andrew Warfield
*
* Based on the original split block driver:
* Copyright (c) 2003-2004, Keir Fraser & Steve Hand
* Modifications by Mark A. Williamson are (c) Intel Research Cambridge
* Copyright (c) 2004, Christian Limpach
*
* Note that unlike the split block driver code, this driver has been developed
* strictly for Linux 2.6
*/
#include "blktap.h"
int __init xlblk_init(void)
{
ctrl_msg_t cmsg;
blkif_fe_driver_status_t fe_st;
blkif_be_driver_status_t be_st;
printk(KERN_INFO "Initialising Xen block tap device\n");
DPRINTK(" tap - Backend connection init:\n");
(void)ctrl_if_register_receiver(CMSG_BLKIF_FE, blkif_ctrlif_rx,
CALLBACK_IN_BLOCKING_CONTEXT);
/* Send a driver-UP notification to the domain controller. */
cmsg.type = CMSG_BLKIF_FE;
cmsg.subtype = CMSG_BLKIF_FE_DRIVER_STATUS;
cmsg.length = sizeof(blkif_fe_driver_status_t);
fe_st.status = BLKIF_DRIVER_STATUS_UP;
memcpy(cmsg.msg, &fe_st, sizeof(fe_st));
ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
DPRINTK(" tap - Frontend connection init:\n");
active_reqs_init();
ptfe_blkif.status = DISCONNECTED;
(void)ctrl_if_register_receiver(CMSG_BLKIF_BE, blkif_ctrlif_rx,
CALLBACK_IN_BLOCKING_CONTEXT);
/* Send a driver-UP notification to the domain controller. */
cmsg.type = CMSG_BLKIF_BE;
cmsg.subtype = CMSG_BLKIF_BE_DRIVER_STATUS;
cmsg.length = sizeof(blkif_be_driver_status_t);
be_st.status = BLKIF_DRIVER_STATUS_UP;
memcpy(cmsg.msg, &be_st, sizeof(be_st));
ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
DPRINTK(" tap - Userland channel init:\n");
blktap_init();
DPRINTK("Blkif tap device initialized.\n");
return 0;
}
void blkdev_suspend(void)
{
}
void blkdev_resume(void)
{
ctrl_msg_t cmsg;
blkif_fe_driver_status_t st;
/* Send a driver-UP notification to the domain controller. */
cmsg.type = CMSG_BLKIF_FE;
cmsg.subtype = CMSG_BLKIF_FE_DRIVER_STATUS;
cmsg.length = sizeof(blkif_fe_driver_status_t);
st.status = BLKIF_DRIVER_STATUS_UP;
memcpy(cmsg.msg, &st, sizeof(st));
ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
}
__initcall(xlblk_init);
@@ -0,0 +1,254 @@
/*
* blktap.h
*
* Interfaces for the Xen block tap driver.
*
* (c) 2004, Andrew Warfield, University of Cambridge
*
*/
#ifndef __BLKTAP_H__
#define __BLKTAP_H__
#include <linux/version.h>
#include <linux/blkdev.h>
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <asm-xen/ctrl_if.h>
#include <linux/slab.h>
#include <linux/blkdev.h>
#include <asm/io.h>
#include <asm/setup.h>
#include <asm/pgalloc.h>
#include <asm-xen/hypervisor.h>
#include <asm-xen/xen-public/io/blkif.h>
/* -------[ debug / pretty printing ]--------------------------------- */
#if 0
#define ASSERT(_p) \
if ( !(_p) ) { printk("Assertion '%s' failed, line %d, file %s", #_p , \
__LINE__, __FILE__); *(int*)0=0; }
#define DPRINTK(_f, _a...) printk(KERN_ALERT "(file=%s, line=%d) " _f, \
__FILE__ , __LINE__ , ## _a )
#else
#define ASSERT(_p) ((void)0)
#define DPRINTK(_f, _a...) ((void)0)
#endif
#define WPRINTK(fmt, args...) printk(KERN_WARNING "blk_tap: " fmt, ##args)
/* -------[ connection / request tracking ]--------------------------- */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
#define VMALLOC_VMADDR(x) ((unsigned long)(x))
#endif
extern spinlock_t blkif_io_lock;
typedef struct blkif_st {
/* Unique identifier for this interface. */
domid_t domid;
unsigned int handle;
/* Physical parameters of the comms window. */
unsigned long shmem_frame;
unsigned int evtchn;
int irq;
/* Comms information. */
blkif_ring_t *blk_ring_base; /* ioremap()'ed ptr to shmem_frame. */
BLKIF_RING_IDX blk_req_cons; /* Request consumer. */
BLKIF_RING_IDX blk_resp_prod; /* Private version of resp. producer. */
enum { DISCONNECTED, DISCONNECTING, CONNECTED } status;
/*
* DISCONNECT response is deferred until pending requests are ack'ed.
* We therefore need to store the id from the original request.
*/ u8 disconnect_rspid;
struct blkif_st *hash_next;
struct list_head blkdev_list;
spinlock_t blk_ring_lock;
atomic_t refcnt;
struct work_struct work;
} blkif_t;
typedef struct {
blkif_t *blkif;
unsigned long id;
int nr_pages;
unsigned long mach_fas[BLKIF_MAX_SEGMENTS_PER_REQUEST];
unsigned long virt_fas[BLKIF_MAX_SEGMENTS_PER_REQUEST];
int next_free;
} active_req_t;
/* -------[ block ring structs ]-------------------------------------- */
/* Types of ring. */
#define BLKIF_REQ_RING_TYPE 1
#define BLKIF_RSP_RING_TYPE 2
/* generic ring struct. */
typedef struct blkif_generic_ring_struct {
int type;
} blkif_generic_ring_t;
/* A requestor's view of a ring. */
typedef struct blkif_req_ring_struct {
int type; /* Will be BLKIF_REQ_RING_TYPE */
BLKIF_RING_IDX req_prod; /* PRIVATE req_prod index */
BLKIF_RING_IDX rsp_cons; /* Response consumer index */
blkif_ring_t *ring; /* Pointer to shared ring struct */
} blkif_req_ring_t;
#define BLKIF_REQ_RING_INIT { BLKIF_REQ_RING_TYPE, 0, 0, 0 }
/* A responder's view of a ring. */
typedef struct blkif_rsp_ring_struct {
int type;
BLKIF_RING_IDX rsp_prod; /* PRIVATE rsp_prod index */
BLKIF_RING_IDX req_cons; /* Request consumer index */
blkif_ring_t *ring; /* Pointer to shared ring struct */
} blkif_rsp_ring_t;
#define BLKIF_RSP_RING_INIT = { BLKIF_RSP_RING_TYPE, 0, 0, 0 }
#define RING(a) (blkif_generic_ring_t *)(a)
inline int BLKTAP_RING_FULL(blkif_generic_ring_t *ring);
/* -------[ interposition -> character device interface ]------------- */
/* /dev/xen/blktap resides at device number major=10, minor=200 */
#define BLKTAP_MINOR 202
/* size of the extra VMA area to map in attached pages. */
#define BLKTAP_VMA_PAGES BLKIF_RING_SIZE
/* blktap IOCTLs: */
#define BLKTAP_IOCTL_KICK_FE 1
#define BLKTAP_IOCTL_KICK_BE 2
#define BLKTAP_IOCTL_SETMODE 3
/* blktap switching modes: (Set with BLKTAP_IOCTL_SETMODE) */
#define BLKTAP_MODE_PASSTHROUGH 0x00000000 /* default */
#define BLKTAP_MODE_INTERCEPT_FE 0x00000001
#define BLKTAP_MODE_INTERCEPT_BE 0x00000002
#define BLKTAP_MODE_COPY_FE 0x00000004
#define BLKTAP_MODE_COPY_BE 0x00000008
#define BLKTAP_MODE_COPY_FE_PAGES 0x00000010
#define BLKTAP_MODE_COPY_BE_PAGES 0x00000020
#define BLKTAP_MODE_INTERPOSE \
(BLKTAP_MODE_INTERCEPT_FE | BLKTAP_MODE_INTERCEPT_BE)
#define BLKTAP_MODE_COPY_BOTH \
(BLKTAP_MODE_COPY_FE | BLKTAP_MODE_COPY_BE)
#define BLKTAP_MODE_COPY_BOTH_PAGES \
(BLKTAP_MODE_COPY_FE_PAGES | BLKTAP_MODE_COPY_BE_PAGES)
static inline int BLKTAP_MODE_VALID(unsigned long arg)
{
return (
( arg == BLKTAP_MODE_PASSTHROUGH ) ||
( arg == BLKTAP_MODE_INTERCEPT_FE ) ||
( arg == BLKTAP_MODE_INTERCEPT_BE ) ||
( arg == BLKTAP_MODE_INTERPOSE ) ||
( (arg & ~BLKTAP_MODE_COPY_FE_PAGES) == BLKTAP_MODE_COPY_FE ) ||
( (arg & ~BLKTAP_MODE_COPY_BE_PAGES) == BLKTAP_MODE_COPY_BE ) ||
( (arg & ~BLKTAP_MODE_COPY_BOTH_PAGES) == BLKTAP_MODE_COPY_BOTH )
);
}
/* -------[ Mappings to User VMA ]------------------------------------ */
#define MAX_PENDING_REQS 64
#define BATCH_PER_DOMAIN 16
extern struct vm_area_struct *blktap_vma;
/* The following are from blkback.c and should probably be put in a
* header and included from there.
* The mmap area described here is where attached data pages eill be mapped.
*/
extern unsigned long mmap_vstart;
#define MMAP_PAGES_PER_REQUEST \
(BLKIF_MAX_SEGMENTS_PER_REQUEST + 1)
#define MMAP_PAGES \
(MAX_PENDING_REQS * MMAP_PAGES_PER_REQUEST)
#define MMAP_VADDR(_req,_seg) \
(mmap_vstart + \
((_req) * MMAP_PAGES_PER_REQUEST * PAGE_SIZE) + \
((_seg) * PAGE_SIZE))
/* immediately before the mmap area, we have a bunch of pages reserved
* for shared memory rings.
*/
#define RING_PAGES 128
extern unsigned long rings_vstart;
/* -------[ Here be globals ]----------------------------------------- */
extern unsigned long blktap_mode;
/* blkif struct, containing ring to FE domain */
extern blkif_t ptfe_blkif;
/* Connection to a single backend domain. */
extern blkif_ring_t *blk_ptbe_ring; /* Ring from the PT to the BE dom */
extern BLKIF_RING_IDX ptbe_resp_cons; /* Response consumer for comms ring. */
extern BLKIF_RING_IDX ptbe_req_prod; /* Private request producer. */
/* Rings up to user space. */
extern blkif_req_ring_t fe_ring;// = BLKIF_REQ_RING_INIT;
extern blkif_rsp_ring_t be_ring;// = BLKIF_RSP_RING_INIT;
/* Event channel to backend domain. */
extern unsigned int blkif_ptbe_evtchn;
/* User ring status... this will soon vanish into a ring struct. */
extern unsigned long blktap_ring_ok;
/* -------[ ...and function prototypes. ]----------------------------- */
/* init function for character device interface. */
int blktap_init(void);
/* interfaces to the char driver, passing messages to and from apps. */
void blktap_kick_user(void);
int blktap_write_to_ring(blkif_request_t *req);
/* 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);
/* and the helpers they call: */
inline int write_resp_to_fe_ring(blkif_response_t *rsp);
inline void kick_fe_domain(void);
inline int write_req_to_be_ring(blkif_request_t *req);
inline void kick_be_domain(void);
/* Interrupt handlers. */
irqreturn_t blkif_ptbe_int(int irq, void *dev_id,
struct pt_regs *ptregs);
irqreturn_t blkif_ptfe_int(int irq, void *dev_id, struct pt_regs *regs);
/* Control message receiver. */
extern void blkif_ctrlif_rx(ctrl_msg_t *msg, unsigned long id);
#define __BLKINT_H__
#endif
@@ -0,0 +1,358 @@
/******************************************************************************
* blktap_controlmsg.c
*
* XenLinux virtual block-device tap.
* Control interfaces to the frontend and backend drivers.
*
* Copyright (c) 2004, Andrew Warfield
*
*/
#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",
[BLKIF_STATE_CONNECTED] = "connected",
};
static char * blkif_status_name[] = {
[BLKIF_INTERFACE_STATUS_CLOSED] = "closed",
[BLKIF_INTERFACE_STATUS_DISCONNECTED] = "disconnected",
[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;
/*-----[ Control Messages to/from Frontend VMs ]--------------------------*/
void blkif_ptfe_create(blkif_be_create_t *create)
{
blkif_t *blkif;
domid_t domid = create->domid;
unsigned int handle = create->blkif_handle;
/* May want to store info on the connecting domain here. */
DPRINTK("PT got BE_CREATE\n");
blkif = &ptfe_blkif; /* for convenience if the hash is readded later. */
/* blkif struct init code from blkback.c */
memset(blkif, 0, sizeof(*blkif));
blkif->domid = domid;
blkif->handle = handle;
blkif->status = DISCONNECTED;
spin_lock_init(&blkif->blk_ring_lock);
atomic_set(&blkif->refcnt, 0);
create->status = BLKIF_BE_STATUS_OKAY;
}
void blkif_ptfe_destroy(blkif_be_destroy_t *destroy)
{
/* Clear anything that we initialized above. */
DPRINTK("PT got BE_DESTROY\n");
destroy->status = BLKIF_BE_STATUS_OKAY;
}
void blkif_ptfe_connect(blkif_be_connect_t *connect)
{
domid_t domid = connect->domid;
/*unsigned int handle = connect->blkif_handle;*/
unsigned int evtchn = connect->evtchn;
unsigned long shmem_frame = connect->shmem_frame;
struct vm_struct *vma;
pgprot_t prot;
int error;
blkif_t *blkif;
DPRINTK("PT got BE_CONNECT\n");
blkif = &ptfe_blkif; /* for convenience if the hash is readded later. */
if ( (vma = get_vm_area(PAGE_SIZE, VM_IOREMAP)) == NULL )
{
connect->status = BLKIF_BE_STATUS_OUT_OF_MEMORY;
return;
}
prot = __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED);
error = direct_remap_area_pages(&init_mm, VMALLOC_VMADDR(vma->addr),
shmem_frame<<PAGE_SHIFT, PAGE_SIZE,
prot, domid);
if ( error != 0 )
{
WPRINTK("BE_CONNECT: error! (%d)\n", error);
if ( error == -ENOMEM )
connect->status = BLKIF_BE_STATUS_OUT_OF_MEMORY;
else if ( error == -EFAULT ) {
connect->status = BLKIF_BE_STATUS_MAPPING_ERROR;
WPRINTK("BE_CONNECT: MAPPING error!\n");
}
else
connect->status = BLKIF_BE_STATUS_ERROR;
vfree(vma->addr);
return;
}
if ( blkif->status != DISCONNECTED )
{
connect->status = BLKIF_BE_STATUS_INTERFACE_CONNECTED;
vfree(vma->addr);
return;
}
blkif->evtchn = evtchn;
blkif->irq = bind_evtchn_to_irq(evtchn);
blkif->shmem_frame = shmem_frame;
blkif->blk_ring_base = (blkif_ring_t *)vma->addr;
blkif->status = CONNECTED;
/*blkif_get(blkif);*/
request_irq(blkif->irq, blkif_ptfe_int, 0, "blkif-pt-backend", blkif);
connect->status = BLKIF_BE_STATUS_OKAY;
}
void blkif_ptfe_disconnect(blkif_be_disconnect_t *disconnect)
{
/*
* don't actually set the passthrough to disconnected.
* We just act as a pipe, and defer to the real ends to handle things like
* recovery.
*/
DPRINTK("PT got BE_DISCONNECT\n");
disconnect->status = BLKIF_BE_STATUS_OKAY;
return;
}
/*-----[ Control Messages to/from Backend VM ]----------------------------*/
/* Tell the controller to bring up the interface. */
static void blkif_ptbe_send_interface_connect(void)
{
ctrl_msg_t cmsg = {
.type = CMSG_BLKIF_FE,
.subtype = CMSG_BLKIF_FE_INTERFACE_CONNECT,
.length = sizeof(blkif_fe_interface_connect_t),
};
blkif_fe_interface_connect_t *msg = (void*)cmsg.msg;
msg->handle = 0;
msg->shmem_frame = virt_to_machine(blk_ptbe_ring) >> PAGE_SHIFT;
ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
}
static void blkif_ptbe_close(void)
{
}
/* Move from CLOSED to DISCONNECTED state. */
static void blkif_ptbe_disconnect(void)
{
blk_ptbe_ring = (blkif_ring_t *)__get_free_page(GFP_KERNEL);
blk_ptbe_ring->req_prod = blk_ptbe_ring->resp_prod
= ptbe_resp_cons = ptbe_req_prod = 0;
blkif_pt_state = BLKIF_STATE_DISCONNECTED;
DPRINTK("Blkif-Passthrough-BE is now DISCONNECTED.\n");
blkif_ptbe_send_interface_connect();
}
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);
err = request_irq(blkif_ptbe_irq, blkif_ptbe_int,
SA_SAMPLE_RANDOM, "blkif", NULL);
if ( err ) {
WPRINTK("blkfront request_irq failed (%d)\n", err);
return;
} else {
/* transtion to connected in case we need to do a
a partion probe on a whole disk */
blkif_pt_state = BLKIF_STATE_CONNECTED;
}
}
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]);
}
static void blkif_ptbe_status(
blkif_fe_interface_status_t *status)
{
if ( status->handle != 0 )
{
DPRINTK("Status change on unsupported blkif %d\n",
status->handle);
return;
}
DPRINTK("ptbe_status: got %s\n", blkif_status_name[status->status]);
switch ( status->status )
{
case BLKIF_INTERFACE_STATUS_CLOSED:
switch ( blkif_pt_state )
{
case BLKIF_STATE_CLOSED:
unexpected(status);
break;
case BLKIF_STATE_DISCONNECTED:
case BLKIF_STATE_CONNECTED:
unexpected(status);
blkif_ptbe_close();
break;
}
break;
case BLKIF_INTERFACE_STATUS_DISCONNECTED:
switch ( blkif_pt_state )
{
case BLKIF_STATE_CLOSED:
blkif_ptbe_disconnect();
break;
case BLKIF_STATE_DISCONNECTED:
case BLKIF_STATE_CONNECTED:
printk(KERN_ALERT "*** add recovery code to the tap driver. ***\n");
unexpected(status);
break;
}
break;
case BLKIF_INTERFACE_STATUS_CONNECTED:
switch ( blkif_pt_state )
{
case BLKIF_STATE_CLOSED:
unexpected(status);
blkif_ptbe_disconnect();
blkif_ptbe_connect(status);
break;
case BLKIF_STATE_DISCONNECTED:
blkif_ptbe_connect(status);
break;
case BLKIF_STATE_CONNECTED:
unexpected(status);
blkif_ptbe_connect(status);
break;
}
break;
case BLKIF_INTERFACE_STATUS_CHANGED:
switch ( blkif_pt_state )
{
case BLKIF_STATE_CLOSED:
case BLKIF_STATE_DISCONNECTED:
unexpected(status);
break;
case BLKIF_STATE_CONNECTED:
/* vbd_update(); */
/* tap doesn't really get state changes... */
unexpected(status);
break;
}
break;
default:
DPRINTK("Status change to unknown value %d\n", status->status);
break;
}
}
/*-----[ All control messages enter here: ]-------------------------------*/
void blkif_ctrlif_rx(ctrl_msg_t *msg, unsigned long id)
{
switch ( msg->type )
{
case CMSG_BLKIF_FE:
switch ( msg->subtype )
{
case CMSG_BLKIF_FE_INTERFACE_STATUS:
if ( msg->length != sizeof(blkif_fe_interface_status_t) )
goto parse_error;
blkif_ptbe_status((blkif_fe_interface_status_t *) &msg->msg[0]);
break;
default:
goto parse_error;
}
case CMSG_BLKIF_BE:
switch ( msg->subtype )
{
case CMSG_BLKIF_BE_CREATE:
if ( msg->length != sizeof(blkif_be_create_t) )
goto parse_error;
blkif_ptfe_create((blkif_be_create_t *)&msg->msg[0]);
break;
case CMSG_BLKIF_BE_DESTROY:
if ( msg->length != sizeof(blkif_be_destroy_t) )
goto parse_error;
blkif_ptfe_destroy((blkif_be_destroy_t *)&msg->msg[0]);
break;
case CMSG_BLKIF_BE_CONNECT:
if ( msg->length != sizeof(blkif_be_connect_t) )
goto parse_error;
blkif_ptfe_connect((blkif_be_connect_t *)&msg->msg[0]);
break;
case CMSG_BLKIF_BE_DISCONNECT:
if ( msg->length != sizeof(blkif_be_disconnect_t) )
goto parse_error;
blkif_ptfe_disconnect((blkif_be_disconnect_t *)&msg->msg[0]);
break;
/* We just ignore anything to do with vbds for now. */
case CMSG_BLKIF_BE_VBD_CREATE:
DPRINTK("PT got VBD_CREATE\n");
((blkif_be_vbd_create_t *)&msg->msg[0])->status
= BLKIF_BE_STATUS_OKAY;
break;
case CMSG_BLKIF_BE_VBD_DESTROY:
DPRINTK("PT got VBD_DESTROY\n");
((blkif_be_vbd_destroy_t *)&msg->msg[0])->status
= BLKIF_BE_STATUS_OKAY;
break;
case CMSG_BLKIF_BE_VBD_GROW:
DPRINTK("PT got VBD_GROW\n");
((blkif_be_vbd_grow_t *)&msg->msg[0])->status
= BLKIF_BE_STATUS_OKAY;
break;
case CMSG_BLKIF_BE_VBD_SHRINK:
DPRINTK("PT got VBD_SHRINK\n");
((blkif_be_vbd_shrink_t *)&msg->msg[0])->status
= BLKIF_BE_STATUS_OKAY;
break;
default:
goto parse_error;
}
}
ctrl_if_send_response(msg);
return;
parse_error:
msg->length = 0;
ctrl_if_send_response(msg);
}
@@ -0,0 +1,517 @@
/******************************************************************************
* blktap_datapath.c
*
* XenLinux virtual block-device tap.
* Block request routing data path.
*
* Copyright (c) 2004, Andrew Warfield
*
*/
#include "blktap.h"
/*-----[ The data paths ]-------------------------------------------------*/
/* Connections to the frontend domains.*/
blkif_t ptfe_blkif;
/* Connection to a single backend domain. */
blkif_ring_t *blk_ptbe_ring; /* Ring from the PT to the BE dom */
BLKIF_RING_IDX ptbe_resp_cons; /* Response consumer for comms ring. */
BLKIF_RING_IDX ptbe_req_prod; /* Private request producer. */
/* Rings up to user space. */
blkif_req_ring_t fe_ring;// = BLKIF_REQ_RING_INIT;
blkif_rsp_ring_t be_ring;// = BLKIF_RSP_RING_INIT;
/*-----[ Ring helpers ]---------------------------------------------------*/
inline int BLKTAP_RING_FULL(blkif_generic_ring_t *ring)
{
if (ring->type == BLKIF_REQ_RING_TYPE) {
blkif_req_ring_t *r = (blkif_req_ring_t *)ring;
return ( ( r->req_prod - r->rsp_cons ) == BLKIF_RING_SIZE );
}
/* for now assume that there is always room in the response path. */
return 0;
}
/*-----[ Tracking active requests ]---------------------------------------*/
/* this must be the same as MAX_PENDING_REQS in blkback.c */
#define MAX_ACTIVE_REQS 64
active_req_t active_reqs[MAX_ACTIVE_REQS];
unsigned char active_req_ring[MAX_ACTIVE_REQS];
spinlock_t active_req_lock = SPIN_LOCK_UNLOCKED;
typedef unsigned int ACTIVE_RING_IDX;
ACTIVE_RING_IDX active_prod, active_cons;
#define MASK_ACTIVE_IDX(_i) ((_i)&(MAX_ACTIVE_REQS-1))
#define ACTIVE_IDX(_ar) (_ar - active_reqs)
inline active_req_t *get_active_req(void)
{
ASSERT(active_cons != active_prod);
return &active_reqs[MASK_ACTIVE_IDX(active_cons++)];
}
inline void free_active_req(active_req_t *ar)
{
unsigned long flags;
spin_lock_irqsave(&active_req_lock, flags);
active_req_ring[MASK_ACTIVE_IDX(active_prod++)] = ACTIVE_IDX(ar);
spin_unlock_irqrestore(&active_req_lock, flags);
}
inline void active_reqs_init(void)
{
ACTIVE_RING_IDX i;
active_cons = 0;
active_prod = MAX_ACTIVE_REQS;
memset(active_reqs, 0, sizeof(active_reqs));
for ( i = 0; i < MAX_ACTIVE_REQS; i++ )
active_req_ring[i] = i;
}
/*-----[ Data to/from Frontend (client) VMs ]-----------------------------*/
irqreturn_t blkif_ptfe_int(int irq, void *dev_id, struct pt_regs *regs)
{
/* we have pending messages from the real frontend. */
blkif_request_t *req_s, *req_d;
BLKIF_RING_IDX fe_rp;
unsigned long flags;
int notify;
unsigned long i;
active_req_t *ar;
DPRINTK("PT got FE interrupt.\n");
/* lock both rings */
spin_lock_irqsave(&blkif_io_lock, flags);
/* While there are REQUESTS on FERing: */
fe_rp = ptfe_blkif.blk_ring_base->req_prod;
rmb();
notify = (ptfe_blkif.blk_req_cons != fe_rp);
for (i = ptfe_blkif.blk_req_cons; i != fe_rp; i++) {
/* Get the next request */
req_s = &ptfe_blkif.blk_ring_base->ring[MASK_BLKIF_IDX(i)].req;
/* This is a new request:
* Assign an active request record, and remap the id.
*/
ar = get_active_req();
ar->id = req_s->id;
req_s->id = ACTIVE_IDX(ar);
DPRINTK("%3lu < %3lu\n", req_s->id, ar->id);
/* FE -> BE interposition point is here. */
/* ------------------------------------------------------------- */
/* BLKIF_OP_PROBE_HACK: */
/* Until we have grant tables, we need to allow the backent to */
/* map pages that are either from this domain, or more commonly */
/* from the real front end. We achieve this in a terrible way, */
/* by passing the front end's domid allong with PROBE messages */
/* Once grant tables appear, this should all go away. */
if (req_s->operation == BLKIF_OP_PROBE) {
DPRINTK("Adding FE domid to PROBE request.\n");
(domid_t)(req_s->frame_and_sects[1]) = ptfe_blkif.domid;
}
/* ------------------------------------------------------------- */
/* If we are in MODE_INTERCEPT_FE or MODE_COPY_FE: */
if ( (blktap_mode & BLKTAP_MODE_INTERCEPT_FE) ||
(blktap_mode & BLKTAP_MODE_COPY_FE) ) {
/* Copy the response message to UFERing */
/* In MODE_INTERCEPT_FE, map attached pages into the app vma */
/* In MODE_COPY_FE_PAGES, copy attached pages into the app vma */
/* XXX: mapping/copying of attached pages is still not done! */
DPRINTK("req->UFERing\n");
blktap_write_fe_ring(req_s);
}
/* If we are not in MODE_INTERCEPT_FE or MODE_INTERCEPT_BE: */
if ( !((blktap_mode & BLKTAP_MODE_INTERCEPT_FE) ||
(blktap_mode & BLKTAP_MODE_INTERCEPT_BE)) ) {
/* be included to prevent noise from the fe when its off */
/* copy the request message to the BERing */
DPRINTK("blktap: FERing[%u] -> BERing[%u]\n",
(unsigned)MASK_BLKIF_IDX(i),
(unsigned)MASK_BLKIF_IDX(ptbe_req_prod));
req_d = &blk_ptbe_ring->ring[MASK_BLKIF_IDX(ptbe_req_prod)].req;
memcpy(req_d, req_s, sizeof(blkif_request_t));
ptbe_req_prod++;
}
}
ptfe_blkif.blk_req_cons = i;
/* If we have forwarded any responses, notify the appropriate ends. */
if (notify) {
/* we have sent stuff to the be, notify it. */
if ( !((blktap_mode & BLKTAP_MODE_INTERCEPT_FE) ||
(blktap_mode & BLKTAP_MODE_INTERCEPT_BE)) ) {
wmb();
blk_ptbe_ring->req_prod = ptbe_req_prod;
notify_via_evtchn(blkif_ptbe_evtchn);
DPRINTK(" -- and notified.\n");
}
/* we sent stuff to the app, notify it. */
if ( (blktap_mode & BLKTAP_MODE_INTERCEPT_FE) ||
(blktap_mode & BLKTAP_MODE_COPY_FE) ) {
blktap_kick_user();
}
}
/* unlock rings */
spin_unlock_irqrestore(&blkif_io_lock, flags);
return IRQ_HANDLED;
}
inline int write_req_to_be_ring(blkif_request_t *req)
{
blkif_request_t *req_d;
req_d = &blk_ptbe_ring->ring[MASK_BLKIF_IDX(ptbe_req_prod)].req;
memcpy(req_d, req, sizeof(blkif_request_t));
ptbe_req_prod++;
return 0;
}
inline void kick_be_domain(void) {
wmb();
blk_ptbe_ring->req_prod = ptbe_req_prod;
notify_via_evtchn(blkif_ptbe_evtchn);
}
/*-----[ Data to/from Backend (server) VM ]------------------------------*/
irqreturn_t blkif_ptbe_int(int irq, void *dev_id,
struct pt_regs *ptregs)
{
blkif_response_t *resp_s, *resp_d;
BLKIF_RING_IDX be_rp;
unsigned long flags;
int notify;
unsigned long i;
active_req_t *ar;
DPRINTK("PT got BE interrupt.\n");
/* lock both rings */
spin_lock_irqsave(&blkif_io_lock, flags);
/* While there are RESPONSES on BERing: */
be_rp = blk_ptbe_ring->resp_prod;
rmb();
notify = (ptbe_resp_cons != be_rp);
for ( i = ptbe_resp_cons; i != be_rp; i++ )
{
/* BE -> FE interposition point is here. */
/* Get the next response */
resp_s = &blk_ptbe_ring->ring[MASK_BLKIF_IDX(i)].resp;
/* If we are in MODE_INTERCEPT_BE or MODE_COPY_BE: */
if ( (blktap_mode & BLKTAP_MODE_INTERCEPT_BE) ||
(blktap_mode & BLKTAP_MODE_COPY_BE) ) {
/* Copy the response message to UBERing */
/* In MODE_INTERCEPT_BE, map attached pages into the app vma */
/* In MODE_COPY_BE_PAGES, copy attached pages into the app vma */
/* XXX: copy/map the attached page! */
DPRINTK("rsp->UBERing\n");
blktap_write_be_ring(resp_s);
}
/* If we are NOT in MODE_INTERCEPT_BE or MODE_INTERCEPT_FE: */
if ( !((blktap_mode & BLKTAP_MODE_INTERCEPT_BE) ||
(blktap_mode & BLKTAP_MODE_INTERCEPT_FE)) ) {
/* (fe included to prevent random interference from the BE) */
/* Copy the response message to FERing */
DPRINTK("blktap: BERing[%u] -> FERing[%u]\n",
(unsigned) MASK_BLKIF_IDX(i),
(unsigned) MASK_BLKIF_IDX(ptfe_blkif.blk_resp_prod));
/* remap id, and free the active req. blkif lookup goes here too.*/
ar = &active_reqs[resp_s->id];
DPRINTK("%3lu > %3lu\n", resp_s->id, ar->id);
resp_s->id = ar->id;
free_active_req(ar);
resp_d = &ptfe_blkif.blk_ring_base->ring[
MASK_BLKIF_IDX(ptfe_blkif.blk_resp_prod)].resp;
memcpy(resp_d, resp_s, sizeof(blkif_response_t));
ptfe_blkif.blk_resp_prod++;
}
}
ptbe_resp_cons = i;
/* If we have forwarded any responses, notify the apropriate domains. */
if (notify) {
/* we have sent stuff to the fe. notify it. */
if ( !((blktap_mode & BLKTAP_MODE_INTERCEPT_BE) ||
(blktap_mode & BLKTAP_MODE_INTERCEPT_FE)) ) {
wmb();
ptfe_blkif.blk_ring_base->resp_prod = ptfe_blkif.blk_resp_prod;
notify_via_evtchn(ptfe_blkif.evtchn);
DPRINTK(" -- and notified.\n");
}
/* we sent stuff to the app, notify it. */
if ( (blktap_mode & BLKTAP_MODE_INTERCEPT_BE) ||
(blktap_mode & BLKTAP_MODE_COPY_BE) ) {
blktap_kick_user();
}
}
spin_unlock_irqrestore(&blkif_io_lock, flags);
return IRQ_HANDLED;
}
inline int write_resp_to_fe_ring(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[rsp->id];
DPRINTK("%3lu > %3lu\n", rsp->id, ar->id);
rsp->id = ar->id;
free_active_req(ar);
resp_d = &ptfe_blkif.blk_ring_base->ring[
MASK_BLKIF_IDX(ptfe_blkif.blk_resp_prod)].resp;
memcpy(resp_d, rsp, sizeof(blkif_response_t));
ptfe_blkif.blk_resp_prod++;
return 0;
}
inline void kick_fe_domain(void) {
wmb();
ptfe_blkif.blk_ring_base->resp_prod = ptfe_blkif.blk_resp_prod;
notify_via_evtchn(ptfe_blkif.evtchn);
}
static inline void flush_requests(void)
{
wmb(); /* Ensure that the frontend can see the requests. */
blk_ptbe_ring->req_prod = ptbe_req_prod;
notify_via_evtchn(blkif_ptbe_evtchn);
}
/*-----[ Data to/from user space ]----------------------------------------*/
int blktap_write_fe_ring(blkif_request_t *req)
{
blkif_request_t *target;
int error, i;
/*
* This is called to pass a request from the real frontend domain's
* blkif ring to the character device.
*/
if ( ! blktap_ring_ok ) {
DPRINTK("blktap: fe_ring not ready for a request!\n");
return 0;
}
if ( BLKTAP_RING_FULL(RING(&fe_ring)) ) {
DPRINTK("blktap: fe_ring is full, can't add.\n");
return 0;
}
target = &fe_ring.ring->ring[MASK_BLKIF_IDX(fe_ring.req_prod)].req;
memcpy(target, req, sizeof(*req));
/* maybe move this stuff out into a seperate func ------------------- */
/*
* For now, map attached page into a fixed position into the vma.
* XXX: make this map to a free page.
*/
/* Attempt to map the foreign pages directly in to the application */
for (i=0; i<target->nr_segments; i++) {
/* get an unused virtual address from the char device */
/* store the old page address */
/* replace the address with the virtual address */
/* blktap_vma->vm_start+((2+i)*PAGE_SIZE) */
error = direct_remap_area_pages(blktap_vma->vm_mm,
MMAP_VADDR(req->id, i),
target->frame_and_sects[0] & PAGE_MASK,
PAGE_SIZE,
blktap_vma->vm_page_prot,
ptfe_blkif.domid);
if ( error != 0 ) {
printk(KERN_INFO "remapping attached page failed! (%d)\n", error);
return 0;
}
}
/* fix the address of the attached page in the message. */
/* TODO: preserve the segment number stuff here... */
/* target->frame_and_sects[0] = blktap_vma->vm_start + PAGE_SIZE;*/
/* ------------------------------------------------------------------ */
fe_ring.req_prod++;
return 0;
}
int blktap_write_be_ring(blkif_response_t *rsp)
{
blkif_response_t *target;
/*
* This is called to pass a request from the real backend domain's
* blkif ring to the character device.
*/
if ( ! blktap_ring_ok ) {
DPRINTK("blktap: be_ring not ready for a request!\n");
return 0;
}
if ( BLKTAP_RING_FULL(RING(&be_ring)) ) {
DPRINTK("blktap: be_ring is full, can't add.\n");
return 0;
}
target = &be_ring.ring->ring[MASK_BLKIF_IDX(be_ring.rsp_prod)].resp;
memcpy(target, rsp, sizeof(*rsp));
/* XXX: map attached pages and fix-up addresses in the copied address. */
be_ring.rsp_prod++;
return 0;
}
int blktap_read_fe_ring(void)
{
/* This is called to read responses from the UFE ring. */
BLKIF_RING_IDX fe_rp;
unsigned long i;
int notify;
DPRINTK("blktap_read_fe_ring()\n");
fe_rp = fe_ring.ring->resp_prod;
rmb();
notify = (fe_rp != fe_ring.rsp_cons);
/* if we are forwarding from UFERring to FERing */
if (blktap_mode & BLKTAP_MODE_INTERCEPT_FE) {
/* for each outstanding message on the UFEring */
for ( i = fe_ring.rsp_cons; i != fe_rp; i++ ) {
/* XXX: remap pages on that message as necessary */
/* copy the message to the UBEring */
DPRINTK("resp->fe_ring\n");
write_resp_to_fe_ring(&fe_ring.ring->ring[MASK_BLKIF_IDX(i)].resp);
}
fe_ring.rsp_cons = fe_rp;
/* notify the fe if necessary */
if ( notify ) {
DPRINTK("kick_fe_domain()\n");
kick_fe_domain();
}
}
return 0;
}
int blktap_read_be_ring(void)
{
/* This is called to read responses from the UBE ring. */
BLKIF_RING_IDX be_rp;
unsigned long i;
int notify;
DPRINTK("blktap_read_be_ring()\n");
be_rp = be_ring.ring->req_prod;
rmb();
notify = (be_rp != be_ring.req_cons);
/* if we are forwarding from UFERring to FERing */
if (blktap_mode & BLKTAP_MODE_INTERCEPT_BE) {
/* for each outstanding message on the UFEring */
for ( i = be_ring.req_cons; i != be_rp; i++ ) {
/* XXX: remap pages on that message as necessary */
/* copy the message to the UBEring */
DPRINTK("req->be_ring\n");
write_req_to_be_ring(&be_ring.ring->ring[MASK_BLKIF_IDX(i)].req);
}
be_ring.req_cons = be_rp;
/* notify the fe if necessary */
if ( notify ) {
DPRINTK("kick_be_domain()\n");
kick_be_domain();
}
}
return 0;
}
@@ -0,0 +1,243 @@
/******************************************************************************
* blktap_userdev.c
*
* XenLinux virtual block-device tap.
* Control interface between the driver and a character device.
*
* Copyright (c) 2004, Andrew Warfield
*
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/miscdevice.h>
#include <linux/errno.h>
#include <linux/major.h>
#include <linux/gfp.h>
#include <linux/poll.h>
#include <asm/pgalloc.h>
#include "blktap.h"
unsigned long blktap_mode = BLKTAP_MODE_PASSTHROUGH;
/* Only one process may open /dev/xen/blktap at any time. */
static unsigned long blktap_dev_inuse;
unsigned long blktap_ring_ok; /* make this ring->state */
/* for poll: */
static wait_queue_head_t blktap_wait;
/* Where things are inside the device mapping. */
struct vm_area_struct *blktap_vma;
unsigned long mmap_vstart;
unsigned long rings_vstart;
/* -------[ blktap vm ops ]------------------------------------------- */
static struct page *blktap_nopage(struct vm_area_struct *vma,
unsigned long address,
int *type)
{
/*
* if the page has not been mapped in by the driver then generate
* a SIGBUS to the domain.
*/
force_sig(SIGBUS, current);
return 0;
}
struct vm_operations_struct blktap_vm_ops = {
nopage: blktap_nopage,
};
/* -------[ blktap file ops ]----------------------------------------- */
static int blktap_open(struct inode *inode, struct file *filp)
{
if ( test_and_set_bit(0, &blktap_dev_inuse) )
return -EBUSY;
printk(KERN_ALERT "blktap open.\n");
/* Allocate the fe ring. */
fe_ring.ring = (blkif_ring_t *)get_zeroed_page(GFP_KERNEL);
if (fe_ring.ring == NULL)
goto fail_nomem;
SetPageReserved(virt_to_page(fe_ring.ring));
fe_ring.ring->req_prod = fe_ring.ring->resp_prod
= fe_ring.req_prod
= fe_ring.rsp_cons
= 0;
/* Allocate the be ring. */
be_ring.ring = (blkif_ring_t *)get_zeroed_page(GFP_KERNEL);
if (be_ring.ring == NULL)
goto fail_free_fe;
SetPageReserved(virt_to_page(be_ring.ring));
be_ring.ring->req_prod = be_ring.ring->resp_prod
= be_ring.rsp_prod
= be_ring.req_cons
= 0;
DPRINTK(KERN_ALERT "blktap open.\n");
return 0;
fail_free_fe:
free_page( (unsigned long) fe_ring.ring);
fail_nomem:
return -ENOMEM;
}
static int blktap_release(struct inode *inode, struct file *filp)
{
blktap_dev_inuse = 0;
blktap_ring_ok = 0;
printk(KERN_ALERT "blktap closed.\n");
/* Free the ring page. */
ClearPageReserved(virt_to_page(fe_ring.ring));
free_page((unsigned long) fe_ring.ring);
ClearPageReserved(virt_to_page(be_ring.ring));
free_page((unsigned long) be_ring.ring);
return 0;
}
static int blktap_mmap(struct file *filp, struct vm_area_struct *vma)
{
int size;
printk(KERN_ALERT "blktap mmap (%lx, %lx)\n",
vma->vm_start, vma->vm_end);
vma->vm_ops = &blktap_vm_ops;
size = vma->vm_end - vma->vm_start;
if ( size != ( (MMAP_PAGES + RING_PAGES) << PAGE_SHIFT ) ) {
printk(KERN_INFO
"blktap: you _must_ map exactly %d pages!\n",
MMAP_PAGES + RING_PAGES);
return -EAGAIN;
}
size >>= PAGE_SHIFT;
printk(KERN_INFO "blktap: 2 rings + %d pages.\n", size-1);
rings_vstart = vma->vm_start;
mmap_vstart = rings_vstart + (RING_PAGES << PAGE_SHIFT);
/* Map the ring pages to the start of the region and reserve it. */
/* 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(be_ring.ring));
if (remap_page_range(vma, vma->vm_start, __pa(be_ring.ring), PAGE_SIZE,
vma->vm_page_prot)) {
printk(KERN_ERR "be_ring: remap_page_range failure!\n");
}
DPRINTK("Mapping fe_ring page %lx.\n", __pa(fe_ring.ring));
if (remap_page_range(vma, vma->vm_start + PAGE_SIZE, __pa(fe_ring.ring),
PAGE_SIZE, vma->vm_page_prot)) {
printk(KERN_ERR "fe_ring: remap_page_range failure!\n");
}
blktap_vma = vma;
blktap_ring_ok = 1;
return 0;
}
static int blktap_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
switch(cmd) {
case BLKTAP_IOCTL_KICK_FE: /* There are fe messages to process. */
return blktap_read_fe_ring();
case BLKTAP_IOCTL_KICK_BE: /* There are be messages to process. */
return blktap_read_be_ring();
case BLKTAP_IOCTL_SETMODE:
if (BLKTAP_MODE_VALID(arg)) {
blktap_mode = arg;
/* XXX: may need to flush rings here. */
printk(KERN_INFO "blktap: set mode to %lx\n", arg);
return 0;
}
/* XXX: return a more meaningful error case here. */
}
return -ENOIOCTLCMD;
}
static unsigned int blktap_poll(struct file *file, poll_table *wait)
{
poll_wait(file, &blktap_wait, wait);
if ( (fe_ring.req_prod != fe_ring.ring->req_prod) ||
(be_ring.rsp_prod != be_ring.ring->resp_prod) ) {
fe_ring.ring->req_prod = fe_ring.req_prod;
be_ring.ring->resp_prod = be_ring.rsp_prod;
return POLLIN | POLLRDNORM;
}
return 0;
}
void blktap_kick_user(void)
{
/* blktap_ring->req_prod = blktap_req_prod; */
wake_up_interruptible(&blktap_wait);
}
static struct file_operations blktap_fops = {
owner: THIS_MODULE,
poll: blktap_poll,
ioctl: blktap_ioctl,
open: blktap_open,
release: blktap_release,
mmap: blktap_mmap,
};
/* -------[ blktap module setup ]------------------------------------- */
static struct miscdevice blktap_miscdev = {
.minor = BLKTAP_MINOR,
.name = "blktap",
.fops = &blktap_fops,
.devfs_name = "misc/blktap",
};
int blktap_init(void)
{
int err;
err = misc_register(&blktap_miscdev);
if ( err != 0 )
{
printk(KERN_ALERT "Couldn't register /dev/misc/blktap (%d)\n", err);
return err;
}
init_waitqueue_head(&blktap_wait);
return 0;
}
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.