mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
bitkeeper revision 1.538 (3f9fec6ak_pRRMuf7OrN5fWEXAx52A)
manual merge
This commit is contained in:
commit
5fefd10f16
24 files changed
+1020
-1424
No files matched your search
@@ -260,8 +260,7 @@
|
||||
3ddb79beNQVrdGyoI4njXhgAjD6a4A xen/drivers/block/genhd.c
|
||||
3ddb79beyWwLRP_BiM2t1JKgr_plEw xen/drivers/block/ll_rw_blk.c
|
||||
3e4a8cb7RhubVgsPwO7cK0pgAN8WCQ xen/drivers/block/xen_block.c
|
||||
3f045882spujO81dMl-fYWGiZ8WcPw xen/drivers/block/xen_physdisk.c
|
||||
3e5d129asHNyZOjBKTkqs-9AFzxemA xen/drivers/block/xen_segment.c
|
||||
3e5d129asHNyZOjBKTkqs-9AFzxemA xen/drivers/block/xen_vbd.c
|
||||
3e9c248afxxsnAzIt2na7Ej24yNFzg xen/drivers/cdrom/Makefile
|
||||
3e9c248ajUkn2W3n4vgm72Hp2ftZ8A xen/drivers/cdrom/cdrom.c
|
||||
3e4a8cb7alzQCDKS7MlioPoHBKYkdQ xen/drivers/char/Makefile
|
||||
@@ -466,7 +465,7 @@
|
||||
3ddb79c25UE59iu4JJcbRalx95mvcg xen/include/hypervisor-ifs/hypervisor-if.h
|
||||
3ead095dE_VF-QA88rl_5cWYRWtRVQ xen/include/hypervisor-ifs/kbd.h
|
||||
3ddb79c2oRPrzClk3zbTkRHlpumzKA xen/include/hypervisor-ifs/network.h
|
||||
3f0d22cbroqp_BkoDPwkfRJhaw1LiQ xen/include/hypervisor-ifs/segment.h
|
||||
3f0d22cbroqp_BkoDPwkfRJhaw1LiQ xen/include/hypervisor-ifs/vbd.h
|
||||
3ddb79c4qbCoOFHrv9sCGshbWzBVlQ xen/include/scsi/scsi.h
|
||||
3ddb79c4R4iVwqIIeychVQYmIH4FUg xen/include/scsi/scsi_ioctl.h
|
||||
3ddb79c4yw_mfd4Uikn3v_IOPRpa1Q xen/include/scsi/scsicam.h
|
||||
@@ -476,7 +475,6 @@
|
||||
3ddb79c0nTsjSpVK4ZVTI9WwN24xtQ xen/include/xeno/blk.h
|
||||
3ddb79c0dVhTHLsv6CPTf4baKix4mA xen/include/xeno/blkdev.h
|
||||
3ddb79c18ePBgitnOs7GiOCFilODVw xen/include/xeno/blkpg.h
|
||||
3ddb79c2SisDOHDyTeK5-MV3m7pNbA xen/include/xeno/block.h
|
||||
3ddb79c1oOjpQbp68MW7yiUpoi-S-w xen/include/xeno/brlock.h
|
||||
3ddb79c1x7Ie3kifu7dQRx8y7HVyvA xen/include/xeno/byteorder/big_endian.h
|
||||
3ddb79c1qFXOEX1eD0yXJ_gsGkUt8w xen/include/xeno/byteorder/generic.h
|
||||
@@ -529,11 +527,9 @@
|
||||
3ddb79c0MOVXq8qZDQRGb6z64_xAwg xen/include/xeno/pci_ids.h
|
||||
3e54c38dlSCVdyVM4PKcrSfzLLxWUQ xen/include/xeno/perfc.h
|
||||
3e54c38de9SUSYSAwxDf_DwkpAnQFA xen/include/xeno/perfc_defn.h
|
||||
3f055a3dwldYR102YcSuBaxIf9t3Jw xen/include/xeno/physdisk.h
|
||||
3ddb79c04nQVR3EYM5L4zxDV_MCo1g xen/include/xeno/prefetch.h
|
||||
3e4540ccU1sgCx8seIMGlahmMfv7yQ xen/include/xeno/reboot.h
|
||||
3ddb79c0LzqqS0LhAQ50ekgj4oGl7Q xen/include/xeno/sched.h
|
||||
3e5d129a2bbGTpVSZFN_mAnbm97ixw xen/include/xeno/segment.h
|
||||
3ddb79c0VDeD-Oft5eNfMneTU3D1dQ xen/include/xeno/skbuff.h
|
||||
3ddb79c14dXIhP7C2ahnoD08K90G_w xen/include/xeno/slab.h
|
||||
3ddb79c09xbS-xxfKxuV3JETIhBzmg xen/include/xeno/smp.h
|
||||
@@ -546,6 +542,7 @@
|
||||
3ddb79c2_m8lT9jDKse_tePj7zcnNQ xen/include/xeno/timex.h
|
||||
3ddb79c2e2C14HkndNEJlYwXaPrF5A xen/include/xeno/tqueue.h
|
||||
3ddb79c1-kVvF8cVa0k3ZHDdBMj01Q xen/include/xeno/types.h
|
||||
3f055a3dwldYR102YcSuBaxIf9t3Jw xen/include/xeno/vbd.h
|
||||
3e8827bdaqPeZAWGVOwswgY9bWSx4g xen/include/xeno/version.h
|
||||
3ddb79c2Ae5KpzhC9LCYG7mP_Vi4Aw xen/include/xeno/vif.h
|
||||
3ddb79c4YQCQ6r0xNLLu0jfbM7pVmA xen/net/Makefile
|
||||
@@ -575,8 +572,7 @@
|
||||
3e67f822FOPwqHiaRKbrskgWgoNL5g xenolinux-2.4.22-sparse/arch/xeno/drivers/block/xl_block.h
|
||||
3e677190SjkzJIvFifRVeYpIZOCtYA xenolinux-2.4.22-sparse/arch/xeno/drivers/block/xl_ide.c
|
||||
3e677193nOKKTLJzcAu4SYdbZaia8g xenolinux-2.4.22-sparse/arch/xeno/drivers/block/xl_scsi.c
|
||||
3e676eb5RXnHzSHgA1BvM0B1aIm4qg xenolinux-2.4.22-sparse/arch/xeno/drivers/block/xl_segment.c
|
||||
3e5d129aDldt6geU2-2SzBae34sQzg xenolinux-2.4.22-sparse/arch/xeno/drivers/block/xl_segment_proc.c
|
||||
3e676eb5RXnHzSHgA1BvM0B1aIm4qg xenolinux-2.4.22-sparse/arch/xeno/drivers/block/xl_vbd.c
|
||||
3e5a4e65G3e2s0ghPMgiJ-gBTUJ0uQ xenolinux-2.4.22-sparse/arch/xeno/drivers/console/Makefile
|
||||
3e5a4e651TH-SXHoufurnWjgl5bfOA xenolinux-2.4.22-sparse/arch/xeno/drivers/console/console.c
|
||||
3e5a4e656nfFISThfbyXQOA6HN6YHw xenolinux-2.4.22-sparse/arch/xeno/drivers/dom0/Makefile
|
||||
|
||||
@@ -27,6 +27,7 @@ typedef signed long long s64;
|
||||
#include <asm-xeno/proc_cmd.h>
|
||||
#include <hypervisor-ifs/hypervisor-if.h>
|
||||
#include <hypervisor-ifs/dom0_ops.h>
|
||||
#include <hypervisor-ifs/vbd.h>
|
||||
|
||||
#define ERROR(_m) \
|
||||
fprintf(stderr, "ERROR: %s\n", (_m))
|
||||
|
||||
+3
-4
@@ -16,8 +16,7 @@
|
||||
#include <asm/msr.h>
|
||||
#include <xeno/blkdev.h>
|
||||
#include <xeno/console.h>
|
||||
#include <hypervisor-ifs/block.h>
|
||||
#include <xeno/physdisk.h>
|
||||
#include <xeno/vbd.h>
|
||||
|
||||
/*
|
||||
* NB. No ring-3 access in initial guestOS pagetables. Note that we allow
|
||||
@@ -144,8 +143,8 @@ void __kill_domain(struct task_struct *p)
|
||||
|
||||
unlink_blkdev_info(p);
|
||||
|
||||
for ( i = 0; i < XEN_MAX_SEGMENTS; i++ )
|
||||
xen_segment_delete(p, i);
|
||||
for ( i = 0; i < XEN_MAX_VBDS; i++ )
|
||||
xen_vbd_delete(p, i);
|
||||
|
||||
for ( i = 0; i < MAX_DOMAIN_VIFS; i++ )
|
||||
unlink_net_vif(p->net_vif_list[i]);
|
||||
|
||||
+70
-117
@@ -13,12 +13,12 @@
|
||||
#include <hypervisor-ifs/block.h>
|
||||
#include <hypervisor-ifs/hypervisor-if.h>
|
||||
#include <asm-i386/io.h>
|
||||
#include <asm/domain_page.h>
|
||||
#include <xeno/spinlock.h>
|
||||
#include <xeno/keyhandler.h>
|
||||
#include <xeno/interrupt.h>
|
||||
#include <xeno/segment.h>
|
||||
#include <xeno/vbd.h>
|
||||
#include <xeno/slab.h>
|
||||
#include <xeno/physdisk.h>
|
||||
|
||||
#if 0
|
||||
#define DPRINTK(_f, _a...) printk( _f , ## _a )
|
||||
@@ -100,12 +100,10 @@ static void unlock_buffer(struct task_struct *p,
|
||||
static void io_schedule(unsigned long unused);
|
||||
static int do_block_io_op_domain(struct task_struct *p, int max_to_do);
|
||||
static void dispatch_rw_block_io(struct task_struct *p, int index);
|
||||
static void dispatch_probe_blk(struct task_struct *p, int index);
|
||||
static void dispatch_probe_seg(struct task_struct *p, int index);
|
||||
static void dispatch_probe_seg_all(struct task_struct *p, int index);
|
||||
static void dispatch_probe(struct task_struct *p, int index);
|
||||
static void dispatch_debug_block_io(struct task_struct *p, int index);
|
||||
static void dispatch_create_segment(struct task_struct *p, int index);
|
||||
static void dispatch_delete_segment(struct task_struct *p, int index);
|
||||
static void dispatch_create_vbd(struct task_struct *p, int index);
|
||||
static void dispatch_delete_vbd(struct task_struct *p, int index);
|
||||
static void dispatch_grant_physdev(struct task_struct *p, int index);
|
||||
static void dispatch_probe_physdev(struct task_struct *p, int index);
|
||||
static void make_response(struct task_struct *p, unsigned long id,
|
||||
@@ -236,29 +234,41 @@ static void end_block_io_op(struct buffer_head *bh, int uptodate)
|
||||
}
|
||||
|
||||
|
||||
long vbd_attach(vbd_attach_t *info)
|
||||
{
|
||||
printk("vbd_attach called!!!\n");
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* GUEST-OS SYSCALL -- Indicates there are requests outstanding.
|
||||
*/
|
||||
/* ----[ Syscall Interface ]------------------------------------------------*/
|
||||
|
||||
long do_block_io_op(unsigned int op)
|
||||
long do_block_io_op(block_io_op_t *u_block_io_op)
|
||||
{
|
||||
long ret = 0;
|
||||
block_io_op_t op;
|
||||
|
||||
switch ( op )
|
||||
{
|
||||
case BLKOP_PUSH_BUFFERS:
|
||||
add_to_blkdev_list_tail(current);
|
||||
maybe_trigger_io_schedule();
|
||||
break;
|
||||
if (copy_from_user(&op, u_block_io_op, sizeof(op)))
|
||||
return -EFAULT;
|
||||
|
||||
case BLKOP_FLUSH_BUFFERS:
|
||||
break;
|
||||
switch (op.cmd) {
|
||||
|
||||
case BLOCK_IO_OP_SIGNAL:
|
||||
/* simply indicates there're reqs outstanding => add current to list */
|
||||
add_to_blkdev_list_tail(current);
|
||||
maybe_trigger_io_schedule();
|
||||
break;
|
||||
|
||||
case BLOCK_IO_OP_ATTACH_VBD:
|
||||
/* attach a VBD to a given domain; caller must be privileged */
|
||||
if(!IS_PRIV(current))
|
||||
return -EPERM;
|
||||
ret = vbd_attach(&op.u.attach_info);
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = -ENOSYS;
|
||||
}
|
||||
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -390,28 +400,20 @@ static int do_block_io_op_domain(struct task_struct *p, int max_to_do)
|
||||
dispatch_rw_block_io(p, i);
|
||||
break;
|
||||
|
||||
case XEN_BLOCK_PROBE_BLK:
|
||||
dispatch_probe_blk(p, i);
|
||||
break;
|
||||
|
||||
case XEN_BLOCK_PROBE_SEG:
|
||||
dispatch_probe_seg(p, i);
|
||||
break;
|
||||
|
||||
case XEN_BLOCK_PROBE_SEG_ALL:
|
||||
dispatch_probe_seg_all(p, i);
|
||||
case XEN_BLOCK_PROBE:
|
||||
dispatch_probe(p, i);
|
||||
break;
|
||||
|
||||
case XEN_BLOCK_DEBUG:
|
||||
dispatch_debug_block_io(p, i);
|
||||
break;
|
||||
|
||||
case XEN_BLOCK_SEG_CREATE:
|
||||
dispatch_create_segment(p, i);
|
||||
case XEN_BLOCK_VBD_CREATE:
|
||||
dispatch_create_vbd(p, i);
|
||||
break;
|
||||
|
||||
case XEN_BLOCK_SEG_DELETE:
|
||||
dispatch_delete_segment(p, i);
|
||||
case XEN_BLOCK_VBD_DELETE:
|
||||
dispatch_delete_vbd(p, i);
|
||||
break;
|
||||
|
||||
case XEN_BLOCK_PHYSDEV_GRANT:
|
||||
@@ -506,7 +508,7 @@ static void dispatch_grant_physdev(struct task_struct *p, int index)
|
||||
XEN_BLOCK_PHYSDEV_GRANT, result);
|
||||
}
|
||||
|
||||
static void dispatch_create_segment(struct task_struct *p, int index)
|
||||
static void dispatch_create_vbd(struct task_struct *p, int index)
|
||||
{
|
||||
blk_ring_t *blk_ring = p->blk_ring_base;
|
||||
unsigned long flags, buffer;
|
||||
@@ -515,7 +517,7 @@ static void dispatch_create_segment(struct task_struct *p, int index)
|
||||
|
||||
if ( p->domain != 0 )
|
||||
{
|
||||
DPRINTK("dispatch_create_segment called by dom%d\n", p->domain);
|
||||
DPRINTK("dispatch_create_vbd called by dom%d\n", p->domain);
|
||||
result = 1;
|
||||
goto out;
|
||||
}
|
||||
@@ -525,7 +527,7 @@ static void dispatch_create_segment(struct task_struct *p, int index)
|
||||
spin_lock_irqsave(&p->page_lock, flags);
|
||||
if ( !__buffer_is_valid(p, buffer, sizeof(xv_disk_t), 1) )
|
||||
{
|
||||
DPRINTK("Bad buffer in dispatch_create_segment\n");
|
||||
DPRINTK("Bad buffer in dispatch_create_vbd\n");
|
||||
spin_unlock_irqrestore(&p->page_lock, flags);
|
||||
result = 1;
|
||||
goto out;
|
||||
@@ -534,24 +536,25 @@ static void dispatch_create_segment(struct task_struct *p, int index)
|
||||
spin_unlock_irqrestore(&p->page_lock, flags);
|
||||
|
||||
xvd = phys_to_virt(buffer);
|
||||
result = xen_segment_create(xvd);
|
||||
result = xen_vbd_create(xvd);
|
||||
|
||||
unlock_buffer(p, buffer, sizeof(xv_disk_t), 1);
|
||||
|
||||
out:
|
||||
make_response(p, blk_ring->ring[index].req.id,
|
||||
XEN_BLOCK_SEG_CREATE, result);
|
||||
XEN_BLOCK_VBD_CREATE, result);
|
||||
}
|
||||
|
||||
static void dispatch_delete_segment(struct task_struct *p, int index)
|
||||
static void dispatch_delete_vbd(struct task_struct *p, int index)
|
||||
{
|
||||
DPRINTK("dispatch_delete_segment: unimplemented\n");
|
||||
DPRINTK("dispatch_delete_vbd: unimplemented\n");
|
||||
}
|
||||
|
||||
static void dispatch_probe_blk(struct task_struct *p, int index)
|
||||
static void dispatch_probe(struct task_struct *p, int index)
|
||||
{
|
||||
extern void ide_probe_devices(xen_disk_info_t *xdi);
|
||||
extern void scsi_probe_devices(xen_disk_info_t *xdi);
|
||||
extern void vbd_probe_devices(xen_disk_info_t *xdi, struct task_struct *p);
|
||||
|
||||
blk_ring_t *blk_ring = p->blk_ring_base;
|
||||
xen_disk_info_t *xdi;
|
||||
@@ -568,80 +571,30 @@ static void dispatch_probe_blk(struct task_struct *p, int index)
|
||||
rc = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
__lock_buffer(buffer, sizeof(xen_disk_info_t), 1);
|
||||
spin_unlock_irqrestore(&p->page_lock, flags);
|
||||
|
||||
xdi = phys_to_virt(buffer);
|
||||
ide_probe_devices(xdi);
|
||||
scsi_probe_devices(xdi);
|
||||
/*
|
||||
** XXX SMH: all three of the below probe functions /append/ their
|
||||
** info to the xdi array; i.e. they assume that all earlier slots
|
||||
** are correctly filled, and that xdi->count points to the first
|
||||
** free entry in the array. All kinda gross but it'll do for now.
|
||||
*/
|
||||
xdi = map_domain_mem(buffer);
|
||||
xdi->count = 0;
|
||||
if(IS_PRIV(p)) {
|
||||
/* privilege domains always gets access to the 'real' devices */
|
||||
ide_probe_devices(xdi);
|
||||
scsi_probe_devices(xdi);
|
||||
}
|
||||
vbd_probe_devices(xdi, p);
|
||||
unmap_domain_mem(xdi);
|
||||
|
||||
unlock_buffer(p, buffer, sizeof(xen_disk_info_t), 1);
|
||||
|
||||
out:
|
||||
make_response(p, blk_ring->ring[index].req.id, XEN_BLOCK_PROBE_BLK, rc);
|
||||
}
|
||||
|
||||
static void dispatch_probe_seg(struct task_struct *p,
|
||||
int index)
|
||||
{
|
||||
extern void xen_segment_probe(struct task_struct *, xen_disk_info_t *);
|
||||
|
||||
blk_ring_t *blk_ring = p->blk_ring_base;
|
||||
xen_disk_info_t *xdi;
|
||||
unsigned long flags, buffer;
|
||||
int rc = 0;
|
||||
|
||||
buffer = blk_ring->ring[index].req.buffer_and_sects[0] & ~0x1FF;
|
||||
|
||||
spin_lock_irqsave(&p->page_lock, flags);
|
||||
if ( !__buffer_is_valid(p, buffer, sizeof(xen_disk_info_t), 1) )
|
||||
{
|
||||
DPRINTK("Bad buffer in dispatch_probe_seg\n");
|
||||
spin_unlock_irqrestore(&p->page_lock, flags);
|
||||
rc = 1;
|
||||
goto out;
|
||||
}
|
||||
__lock_buffer(buffer, sizeof(xen_disk_info_t), 1);
|
||||
spin_unlock_irqrestore(&p->page_lock, flags);
|
||||
|
||||
xdi = phys_to_virt(buffer);
|
||||
xen_segment_probe(p, xdi);
|
||||
|
||||
unlock_buffer(p, buffer, sizeof(xen_disk_info_t), 1);
|
||||
|
||||
out:
|
||||
make_response(p, blk_ring->ring[index].req.id, XEN_BLOCK_PROBE_SEG, rc);
|
||||
}
|
||||
|
||||
static void dispatch_probe_seg_all(struct task_struct *p, int index)
|
||||
{
|
||||
extern void xen_segment_probe_all(xen_segment_info_t *);
|
||||
|
||||
blk_ring_t *blk_ring = p->blk_ring_base;
|
||||
xen_segment_info_t *xsi;
|
||||
unsigned long flags, buffer;
|
||||
int rc = 0;
|
||||
|
||||
buffer = blk_ring->ring[index].req.buffer_and_sects[0] & ~0x1FF;
|
||||
|
||||
spin_lock_irqsave(&p->page_lock, flags);
|
||||
if ( !__buffer_is_valid(p, buffer, sizeof(xen_segment_info_t), 1) )
|
||||
{
|
||||
DPRINTK("Bad buffer in dispatch_probe_seg_all\n");
|
||||
spin_unlock_irqrestore(&p->page_lock, flags);
|
||||
rc = 1;
|
||||
goto out;
|
||||
}
|
||||
__lock_buffer(buffer, sizeof(xen_segment_info_t), 1);
|
||||
spin_unlock_irqrestore(&p->page_lock, flags);
|
||||
|
||||
xsi = phys_to_virt(buffer);
|
||||
xen_segment_probe_all(xsi);
|
||||
|
||||
unlock_buffer(p, buffer, sizeof(xen_segment_info_t), 1);
|
||||
|
||||
out:
|
||||
make_response(p, blk_ring->ring[index].req.id, XEN_BLOCK_PROBE_SEG_ALL, rc);
|
||||
make_response(p, blk_ring->ring[index].req.id, XEN_BLOCK_PROBE, rc);
|
||||
}
|
||||
|
||||
static void dispatch_rw_block_io(struct task_struct *p, int index)
|
||||
@@ -695,14 +648,14 @@ static void dispatch_rw_block_io(struct task_struct *p, int index)
|
||||
/* Get the physical device and block index. */
|
||||
if ( (req->device & XENDEV_TYPE_MASK) == XENDEV_VIRTUAL )
|
||||
{
|
||||
new_segs = xen_segment_map_request(
|
||||
new_segs = xen_vbd_map_request(
|
||||
&phys_seg[nr_psegs], p, operation,
|
||||
req->device,
|
||||
req->sector_number + tot_sects,
|
||||
buffer, nr_sects);
|
||||
if ( new_segs <= 0 )
|
||||
{
|
||||
DPRINTK("bogus xen_segment_map_request\n");
|
||||
DPRINTK("bogus xen_vbd_map_request\n");
|
||||
goto bad_descriptor;
|
||||
}
|
||||
}
|
||||
@@ -876,10 +829,10 @@ void init_blkdev_info(struct task_struct *p)
|
||||
SHARE_PFN_WITH_DOMAIN(virt_to_page(p->blk_ring_base), p->domain);
|
||||
p->blkdev_list.next = NULL;
|
||||
|
||||
memset(p->segment_list, 0, sizeof(p->segment_list));
|
||||
memset(p->vbd_list, 0, sizeof(p->vbd_list));
|
||||
|
||||
/* Get any previously created segments. */
|
||||
xen_refresh_segment_list(p);
|
||||
xen_refresh_vbd_list(p);
|
||||
}
|
||||
|
||||
/* End-of-day teardown for a domain. */
|
||||
@@ -920,7 +873,7 @@ void initialize_block_io ()
|
||||
"buffer_head_cache", sizeof(struct buffer_head),
|
||||
0, SLAB_HWCACHE_ALIGN, NULL, NULL);
|
||||
|
||||
xen_segment_initialize();
|
||||
xen_vbd_initialize();
|
||||
|
||||
add_key_handler('b', dump_blockq, "dump xen ide blkdev statistics");
|
||||
}
|
||||
@@ -1,277 +0,0 @@
|
||||
#include <xeno/sched.h>
|
||||
#include <xeno/list.h>
|
||||
#include <xeno/blkdev.h>
|
||||
#include <xeno/sched.h>
|
||||
#include <xeno/slab.h>
|
||||
#include <asm/domain_page.h>
|
||||
#include <asm/io.h>
|
||||
#include <xeno/segment.h>
|
||||
#include <xeno/physdisk.h>
|
||||
|
||||
#define MAX(a,b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
#if 0
|
||||
#define DPRINTK printk
|
||||
#else
|
||||
#define DPRINTK(...)
|
||||
#endif
|
||||
|
||||
/* The idea is that, for each sector of each disk, each domain has two
|
||||
bits, saying whether they can read the sector or write it. That
|
||||
would take too much memory, so instead each process has a list of
|
||||
(device, start, end, mode) quads which say what it has access to,
|
||||
and we fake the logical view on top of that. */
|
||||
struct physdisk_ace {
|
||||
struct list_head list;
|
||||
unsigned short device;
|
||||
unsigned short partition;
|
||||
unsigned long start_sect;
|
||||
unsigned long n_sectors;
|
||||
int mode;
|
||||
};
|
||||
|
||||
/* Operation is a blkdev constant i.e. READ, WRITE, ... */
|
||||
/* Must be called with p->physdev_lock held. */
|
||||
static struct physdisk_ace *find_ace(const struct task_struct *p,
|
||||
unsigned short dev,
|
||||
unsigned long sect, int operation)
|
||||
{
|
||||
struct list_head *cur_ace_head;
|
||||
struct physdisk_ace *cur_ace;
|
||||
|
||||
list_for_each(cur_ace_head, &p->physdisk_aces)
|
||||
{
|
||||
cur_ace = list_entry(cur_ace_head, struct physdisk_ace, list);
|
||||
DPRINTK("Is [%lx, %lx) good for %lx?\n",
|
||||
cur_ace->start_sect,
|
||||
cur_ace->start_sect + cur_ace->n_sectors, sect);
|
||||
if ( (sect >= cur_ace->start_sect) &&
|
||||
(sect < (cur_ace->start_sect + cur_ace->n_sectors)) &&
|
||||
(dev == cur_ace->device) &&
|
||||
(((operation == READ) && (cur_ace->mode & PHYSDISK_MODE_R)) ||
|
||||
((operation == WRITE) && (cur_ace->mode & PHYSDISK_MODE_W))) )
|
||||
return cur_ace;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Hold the lock on entry, it remains held on exit. */
|
||||
static void xen_physdisk_revoke_access(unsigned short dev,
|
||||
unsigned long start_sect,
|
||||
unsigned long n_sectors,
|
||||
struct task_struct *p)
|
||||
{
|
||||
/* Find every ace which intersects [start_sect, start_sect +
|
||||
n_sectors] and either remove it completely or truncate it
|
||||
down. */
|
||||
struct list_head *cur_ace_head;
|
||||
struct physdisk_ace *cur_ace, *new_ace;
|
||||
unsigned long kill_zone_end, ace_end;
|
||||
|
||||
kill_zone_end = start_sect + n_sectors;
|
||||
list_for_each(cur_ace_head, &p->physdisk_aces)
|
||||
{
|
||||
cur_ace = list_entry(cur_ace_head, struct physdisk_ace, list);
|
||||
ace_end = cur_ace->start_sect + cur_ace->n_sectors;
|
||||
if ( (cur_ace->start_sect >= kill_zone_end) ||
|
||||
(ace_end <= start_sect) ||
|
||||
(cur_ace->device != dev) )
|
||||
continue;
|
||||
|
||||
DPRINTK("Killing ace [%lx, %lx) against kill zone [%lx, %lx)\n",
|
||||
cur_ace->start_sect, ace_end, start_sect, kill_zone_end);
|
||||
|
||||
if ( (cur_ace->start_sect >= start_sect) &&
|
||||
(ace_end <= kill_zone_end) )
|
||||
{
|
||||
/* ace entirely within kill zone -> kill it */
|
||||
list_del(cur_ace_head);
|
||||
cur_ace_head = cur_ace_head->prev;
|
||||
kfree(cur_ace);
|
||||
}
|
||||
else if ( ace_end <= kill_zone_end )
|
||||
{
|
||||
/* ace start before kill start, ace end in kill zone,
|
||||
move ace end. */
|
||||
cur_ace->n_sectors = start_sect - cur_ace->start_sect;
|
||||
}
|
||||
else if ( cur_ace->start_sect >= start_sect )
|
||||
{
|
||||
/* ace start after kill start, ace end outside kill zone,
|
||||
move ace start. */
|
||||
cur_ace->start_sect = kill_zone_end;
|
||||
cur_ace->n_sectors = ace_end - cur_ace->start_sect;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The fun one: the ace entirely includes the kill zone. */
|
||||
/* Cut the current ace down to just the bit before the kzone,
|
||||
create a new ace for the bit just after it. */
|
||||
new_ace = kmalloc(sizeof(*cur_ace), GFP_KERNEL);
|
||||
new_ace->device = dev;
|
||||
new_ace->start_sect = kill_zone_end;
|
||||
new_ace->n_sectors = ace_end - kill_zone_end;
|
||||
new_ace->mode = cur_ace->mode;
|
||||
|
||||
cur_ace->n_sectors = start_sect - cur_ace->start_sect;
|
||||
|
||||
list_add(&new_ace->list, cur_ace_head);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Hold the lock on entry, it remains held on exit. */
|
||||
static int xen_physdisk_grant_access(unsigned short dev,
|
||||
unsigned short partition,
|
||||
unsigned long start_sect,
|
||||
unsigned long n_sectors,
|
||||
int mode, struct task_struct *p)
|
||||
{
|
||||
struct physdisk_ace *cur_ace;
|
||||
|
||||
/* Make sure it won't overlap with any existing ACEs. */
|
||||
/* XXX this isn't quite right if the domain already has read access
|
||||
and we try to grant write access, or vice versa. */
|
||||
xen_physdisk_revoke_access(dev, start_sect, n_sectors, p);
|
||||
|
||||
if ( mode )
|
||||
{
|
||||
cur_ace = kmalloc(sizeof(*cur_ace), GFP_KERNEL);
|
||||
cur_ace->device = dev;
|
||||
cur_ace->start_sect = start_sect;
|
||||
cur_ace->n_sectors = n_sectors;
|
||||
cur_ace->mode = mode;
|
||||
cur_ace->partition = partition;
|
||||
|
||||
list_add_tail(&cur_ace->list, &p->physdisk_aces);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xen_physdisk_probe_access(physdisk_probebuf_t * buf,
|
||||
struct task_struct *p)
|
||||
{
|
||||
int n_aces;
|
||||
struct list_head *cur_ace_head;
|
||||
struct physdisk_ace *cur_ace;
|
||||
int x = 0;
|
||||
|
||||
n_aces = 0;
|
||||
list_for_each(cur_ace_head, &p->physdisk_aces)
|
||||
{
|
||||
x++;
|
||||
if ( x >= buf->start_ind )
|
||||
{
|
||||
cur_ace = list_entry(cur_ace_head, struct physdisk_ace, list);
|
||||
buf->entries[n_aces].device = cur_ace->device;
|
||||
buf->entries[n_aces].partition = cur_ace->partition;
|
||||
buf->entries[n_aces].start_sect = cur_ace->start_sect;
|
||||
buf->entries[n_aces].n_sectors = cur_ace->n_sectors;
|
||||
buf->entries[n_aces].mode = cur_ace->mode;
|
||||
n_aces++;
|
||||
}
|
||||
}
|
||||
buf->n_aces = n_aces;
|
||||
}
|
||||
|
||||
int xen_physdisk_grant(xp_disk_t * xpd_in)
|
||||
{
|
||||
struct task_struct *p = current;
|
||||
xp_disk_t *xpd = map_domain_mem(virt_to_phys(xpd_in));
|
||||
int res;
|
||||
|
||||
p = find_domain_by_id(xpd->domain);
|
||||
if ( p == NULL )
|
||||
{
|
||||
DPRINTK("Bad domain!\n");
|
||||
res = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
spin_lock(&p->physdev_lock);
|
||||
res = xen_physdisk_grant_access(xpd->device,
|
||||
xpd->partition,
|
||||
xpd->start_sect,
|
||||
xpd->n_sectors, xpd->mode, p);
|
||||
spin_unlock(&p->physdev_lock);
|
||||
put_task_struct(p);
|
||||
|
||||
out:
|
||||
unmap_domain_mem(xpd);
|
||||
return res;
|
||||
}
|
||||
|
||||
int xen_physdisk_probe(struct task_struct *requesting_domain,
|
||||
physdisk_probebuf_t * buf_in)
|
||||
{
|
||||
struct task_struct *p;
|
||||
physdisk_probebuf_t *buf = map_domain_mem(virt_to_phys(buf_in));
|
||||
int res;
|
||||
|
||||
if ( (requesting_domain->domain != 0) &&
|
||||
(requesting_domain->domain != buf->domain) )
|
||||
{
|
||||
res = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
p = find_domain_by_id(buf->domain);
|
||||
if ( p == NULL )
|
||||
{
|
||||
res = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
spin_lock(&p->physdev_lock);
|
||||
xen_physdisk_probe_access(buf, p);
|
||||
spin_unlock(&p->physdev_lock);
|
||||
put_task_struct(p);
|
||||
|
||||
res = 0;
|
||||
out:
|
||||
unmap_domain_mem(buf);
|
||||
return res;
|
||||
}
|
||||
|
||||
int xen_physdisk_access_okay(phys_seg_t * pseg, struct task_struct *p,
|
||||
int operation)
|
||||
{
|
||||
struct physdisk_ace *cur_ace;
|
||||
unsigned long sect;
|
||||
|
||||
DPRINTK
|
||||
("Checking access for domain %d, start sect 0x%lx, length 0x%x.\n",
|
||||
p->domain, pseg->sector_number, pseg->nr_sects);
|
||||
|
||||
for ( sect = pseg->sector_number;
|
||||
sect < pseg->sector_number + pseg->nr_sects; )
|
||||
{
|
||||
/* XXX this would be a lot faster if the aces were sorted on start
|
||||
address. Also in revoke_access. */
|
||||
spin_lock(&p->physdev_lock);
|
||||
cur_ace = find_ace(p, pseg->dev, sect, operation);
|
||||
spin_unlock(&p->physdev_lock);
|
||||
if ( cur_ace == NULL )
|
||||
return 0;
|
||||
sect +=
|
||||
MAX(cur_ace->n_sectors,
|
||||
pseg->nr_sects + pseg->sector_number - sect);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void destroy_physdisk_aces(struct task_struct *p)
|
||||
{
|
||||
struct list_head *cur_ace_head, *next_head;
|
||||
struct physdisk_ace *cur_ace;
|
||||
|
||||
for ( cur_ace_head = p->physdisk_aces.next;
|
||||
cur_ace_head != &p->physdisk_aces;
|
||||
cur_ace_head = next_head )
|
||||
{
|
||||
cur_ace = list_entry(cur_ace_head, struct physdisk_ace, list);
|
||||
next_head = cur_ace_head->next;
|
||||
kfree(cur_ace);
|
||||
}
|
||||
}
|
||||
@@ -1,429 +0,0 @@
|
||||
/*
|
||||
* xen_segment.c
|
||||
*/
|
||||
|
||||
#include <xeno/config.h>
|
||||
#include <xeno/types.h>
|
||||
#include <xeno/lib.h>
|
||||
#include <asm/io.h>
|
||||
#include <xeno/slab.h>
|
||||
#include <xeno/segment.h>
|
||||
#include <xeno/sched.h>
|
||||
#include <xeno/blkdev.h>
|
||||
#include <xeno/keyhandler.h>
|
||||
#include <asm/current.h>
|
||||
#include <asm/domain_page.h>
|
||||
#include <hypervisor-ifs/block.h>
|
||||
|
||||
/* Global list of all possible segments. This can be changed in
|
||||
the following way:
|
||||
|
||||
1) UNUSED segment -> RO or RW segment. This requires the spinlock.
|
||||
|
||||
2) RO or RW -> UNUSED. This requires the lock and can only happen
|
||||
during process teardown.
|
||||
|
||||
This means that processes can access entries in the list safely
|
||||
without having to hold any lock at all: they already have an entry
|
||||
allocated, and we know that entry can't become unused, as segments
|
||||
are only torn down when the domain is dieing, by which point it
|
||||
can't be accessing them anymore. */
|
||||
static segment_t xsegments[XEN_MAX_SEGMENTS];
|
||||
static spinlock_t xsegment_lock = SPIN_LOCK_UNLOCKED;
|
||||
|
||||
#if 0
|
||||
#define DPRINTK(_f, _a...) printk( _f , ## _a )
|
||||
#else
|
||||
#define DPRINTK(_f, _a...) ((void)0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* xen_segment_map_request
|
||||
*
|
||||
* xen_device must be a valid device.
|
||||
*
|
||||
* NB. All offsets and sizes here are in sector units.
|
||||
* eg. 'size == 1' means an actual size of 512 bytes.
|
||||
*
|
||||
* Note that no locking is performed here whatsoever --
|
||||
* we rely on the fact that once segment information is
|
||||
* established, it is only modified by domain shutdown,
|
||||
* and so if this is being called, noone is trying
|
||||
* to modify the segment list.
|
||||
*/
|
||||
int xen_segment_map_request(
|
||||
phys_seg_t *pseg, struct task_struct *p, int operation,
|
||||
unsigned short segment_number,
|
||||
unsigned long sect_nr, unsigned long buffer, unsigned short nr_sects)
|
||||
{
|
||||
segment_t *seg;
|
||||
extent_t *ext;
|
||||
int sum, i;
|
||||
|
||||
segment_number &= XENDEV_IDX_MASK;
|
||||
if ( segment_number >= XEN_MAX_SEGMENTS )
|
||||
{
|
||||
DPRINTK("invalid segment number. %d %d\n",
|
||||
segment_number, XEN_MAX_SEGMENTS);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
seg = p->segment_list[segment_number];
|
||||
if ( seg == NULL )
|
||||
{
|
||||
DPRINTK("segment is null. %d\n", segment_number);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* check domain permissions */
|
||||
if ( seg->domain != p->domain )
|
||||
{
|
||||
DPRINTK("seg is for another domain. %d %d\n", seg->domain, p->domain);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* check rw access */
|
||||
if ( ((operation == WRITE) && (seg->mode != XEN_SEGMENT_RW)) ||
|
||||
((operation == READ) && (seg->mode == XEN_SEGMENT_UNUSED)) )
|
||||
{
|
||||
DPRINTK("illegal operation: %d %d\n", operation, seg->mode);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ( (nr_sects + sect_nr) <= sect_nr )
|
||||
{
|
||||
DPRINTK("sector + size wrap! %08lx %04x\n", sect_nr, nr_sects);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* find extent, check size */
|
||||
sum = 0;
|
||||
i = 0;
|
||||
ext = seg->extents;
|
||||
while ( (i < seg->num_extents) && ((sum + ext->size) <= sect_nr) )
|
||||
{
|
||||
sum += ext->size;
|
||||
ext++; i++;
|
||||
}
|
||||
|
||||
if ( (sum + ext->size) <= sect_nr )
|
||||
{
|
||||
DPRINTK("extent size mismatch: %d %d : %d %ld %ld\n",
|
||||
i, seg->num_extents, sum, ext->size, sect_nr);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pseg->sector_number = (sect_nr - sum) + ext->offset;
|
||||
pseg->buffer = buffer;
|
||||
pseg->nr_sects = nr_sects;
|
||||
pseg->dev = xendev_to_physdev(ext->disk);
|
||||
if ( pseg->dev == 0 )
|
||||
{
|
||||
DPRINTK ("invalid device 0x%x 0x%lx 0x%lx\n",
|
||||
ext->disk, ext->offset, ext->size);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* We're finished if the virtual extent didn't overrun the phys extent. */
|
||||
if ( (sum + ext->size) >= (sect_nr + nr_sects) )
|
||||
return 1; /* entire read fits in this extent */
|
||||
|
||||
/* Hmmm... make sure there's another extent to overrun onto! */
|
||||
if ( (i+1) == seg->num_extents )
|
||||
{
|
||||
DPRINTK ("not enough extents %d %d\n",
|
||||
i, seg->num_extents);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pseg[1].nr_sects = (sect_nr + nr_sects) - (sum + ext->size);
|
||||
pseg[0].nr_sects = sum + ext->size - sect_nr;
|
||||
pseg[1].buffer = buffer + (pseg->nr_sects << 9);
|
||||
pseg[1].sector_number = ext[1].offset;
|
||||
pseg[1].dev = xendev_to_physdev(ext[1].disk);
|
||||
if ( pseg[1].dev == 0 )
|
||||
{
|
||||
DPRINTK ("bogus device for pseg[1] \n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* We don't allow overrun onto a third physical extent. */
|
||||
if ( pseg[1].nr_sects > ext[1].size )
|
||||
{
|
||||
DPRINTK ("third extent\n");
|
||||
DPRINTK (" sum:%d, e0:%ld, e1:%ld p1.sect:%ld p1.nr:%d\n",
|
||||
sum, ext[0].size, ext[1].size,
|
||||
pseg[1].sector_number, pseg[1].nr_sects);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 2; /* We overran onto a second physical extent. */
|
||||
|
||||
fail:
|
||||
DPRINTK ("xen_segment_map_request failure\n");
|
||||
DPRINTK ("operation: %d\n", operation);
|
||||
DPRINTK ("segment number: %d\n", segment_number);
|
||||
DPRINTK ("sect_nr: %ld 0x%lx\n", sect_nr, sect_nr);
|
||||
DPRINTK ("nr_sects: %d 0x%x\n", nr_sects, nr_sects);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* xen_segment_probe
|
||||
*
|
||||
* return a list of segments to the guestos
|
||||
*/
|
||||
void xen_segment_probe(struct task_struct *p, xen_disk_info_t *raw_xdi)
|
||||
{
|
||||
int loop, i;
|
||||
xen_disk_info_t *xdi = map_domain_mem(virt_to_phys(raw_xdi));
|
||||
unsigned long capacity = 0, device;
|
||||
|
||||
spin_lock(&xsegment_lock);
|
||||
xdi->count = 0;
|
||||
for ( loop = 0; loop < XEN_MAX_SEGMENTS; loop++ )
|
||||
{
|
||||
if ( (xsegments[loop].mode == XEN_SEGMENT_UNUSED) ||
|
||||
(xsegments[loop].domain != p->domain) )
|
||||
continue;
|
||||
|
||||
device = MK_VIRTUAL_XENDEV(xsegments[loop].segment_number);
|
||||
for ( i = 0; i < xsegments[loop].num_extents; i++ )
|
||||
capacity += xsegments[loop].extents[i].size;
|
||||
|
||||
xdi->disks[xdi->count].device = device;
|
||||
xdi->disks[xdi->count].capacity = capacity;
|
||||
xdi->count++;
|
||||
}
|
||||
spin_unlock(&xsegment_lock);
|
||||
|
||||
unmap_domain_mem(xdi);
|
||||
}
|
||||
|
||||
/*
|
||||
* xen_segment_probe_all
|
||||
*
|
||||
* return a list of all segments to domain 0
|
||||
*/
|
||||
void xen_segment_probe_all(xen_segment_info_t *raw_xsi)
|
||||
{
|
||||
int loop;
|
||||
xen_segment_info_t *xsi = map_domain_mem(virt_to_phys(raw_xsi));
|
||||
|
||||
spin_lock(&xsegment_lock);
|
||||
xsi->count = 0;
|
||||
for ( loop = 0; loop < XEN_MAX_SEGMENTS; loop++ )
|
||||
{
|
||||
if ( xsegments[loop].mode == XEN_SEGMENT_UNUSED )
|
||||
continue;
|
||||
|
||||
xsi->segments[xsi->count].mode = xsegments[loop].mode;
|
||||
xsi->segments[xsi->count].domain = xsegments[loop].domain;
|
||||
memcpy(xsi->segments[xsi->count].key,
|
||||
xsegments[loop].key,
|
||||
XEN_SEGMENT_KEYSIZE);
|
||||
xsi->segments[xsi->count].seg_nr = xsegments[loop].segment_number;
|
||||
xsi->count++;
|
||||
}
|
||||
spin_unlock(&xsegment_lock);
|
||||
|
||||
unmap_domain_mem(xsi);
|
||||
}
|
||||
|
||||
/*
|
||||
* xen_refresh_segment_list
|
||||
*
|
||||
* find all segments associated with a domain and assign
|
||||
* them to the domain
|
||||
*
|
||||
*/
|
||||
void xen_refresh_segment_list (struct task_struct *p)
|
||||
{
|
||||
int loop;
|
||||
|
||||
spin_lock(&xsegment_lock);
|
||||
for (loop = 0; loop < XEN_MAX_SEGMENTS; loop++)
|
||||
{
|
||||
if ( (xsegments[loop].mode == XEN_SEGMENT_UNUSED) ||
|
||||
(xsegments[loop].domain != p->domain) )
|
||||
continue;
|
||||
|
||||
p->segment_list[xsegments[loop].segment_number] = &xsegments[loop];
|
||||
}
|
||||
spin_unlock(&xsegment_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* create a new segment for a domain
|
||||
*
|
||||
* return 0 on success, 1 on failure
|
||||
*
|
||||
* if we see the same DOM#/SEG# combination, we reuse the slot in
|
||||
* the segment table (overwriting what was there before).
|
||||
* an alternative would be to raise an error if the slot is reused.
|
||||
*/
|
||||
int xen_segment_create(xv_disk_t *xvd_in)
|
||||
{
|
||||
int idx;
|
||||
int loop;
|
||||
xv_disk_t *xvd = map_domain_mem(virt_to_phys(xvd_in));
|
||||
struct task_struct *p;
|
||||
|
||||
spin_lock(&xsegment_lock);
|
||||
for (idx = 0; idx < XEN_MAX_SEGMENTS; idx++)
|
||||
{
|
||||
if (xsegments[idx].mode == XEN_SEGMENT_UNUSED ||
|
||||
(xsegments[idx].domain == xvd->domain &&
|
||||
xsegments[idx].segment_number == xvd->segment)) break;
|
||||
}
|
||||
if (idx == XEN_MAX_SEGMENTS)
|
||||
{
|
||||
printk (KERN_ALERT "xen_segment_create: unable to find free slot\n");
|
||||
unmap_domain_mem(xvd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
xsegments[idx].mode = xvd->mode;
|
||||
xsegments[idx].domain = xvd->domain;
|
||||
xsegments[idx].segment_number = xvd->segment;
|
||||
memcpy(xsegments[idx].key, xvd->key, XEN_SEGMENT_KEYSIZE);
|
||||
xsegments[idx].num_extents = xvd->ext_count;
|
||||
|
||||
|
||||
if (xsegments[idx].extents)
|
||||
kfree(xsegments[idx].extents);
|
||||
xsegments[idx].extents = (extent_t *)kmalloc(
|
||||
sizeof(extent_t)*xvd->ext_count,
|
||||
GFP_KERNEL);
|
||||
|
||||
/* could memcpy, but this is safer */
|
||||
for (loop = 0; loop < xvd->ext_count; loop++)
|
||||
{
|
||||
xsegments[idx].extents[loop].disk = xvd->extents[loop].disk;
|
||||
xsegments[idx].extents[loop].offset = xvd->extents[loop].offset;
|
||||
xsegments[idx].extents[loop].size = xvd->extents[loop].size;
|
||||
if (xsegments[idx].extents[loop].size == 0)
|
||||
{
|
||||
printk("xen_segment_create: extent %d is zero length\n", loop);
|
||||
unmap_domain_mem(xvd);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* if the domain exists, assign the segment to the domain */
|
||||
p = find_domain_by_id(xvd->domain);
|
||||
if (p != NULL)
|
||||
{
|
||||
p->segment_list[xvd->segment] = &xsegments[idx];
|
||||
put_task_struct(p);
|
||||
}
|
||||
|
||||
spin_unlock(&xsegment_lock);
|
||||
|
||||
unmap_domain_mem(xvd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* delete a segment from a domain
|
||||
*
|
||||
* return 0 on success, 1 on failure
|
||||
*
|
||||
* This should *only* be called from domain shutdown, or else we
|
||||
* race with access checking.
|
||||
*/
|
||||
int xen_segment_delete(struct task_struct *p, int segnr)
|
||||
{
|
||||
segment_t *seg;
|
||||
|
||||
if (!p) {
|
||||
printk("xen_segment delete called with NULL domain?\n");
|
||||
BUG();
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (segnr < 0 || segnr > XEN_MAX_SEGMENTS) {
|
||||
printk("xen_segment_delete called with bad segnr?\n");
|
||||
BUG();
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!p->segment_list[segnr])
|
||||
return 1;
|
||||
|
||||
seg = p->segment_list[segnr];
|
||||
|
||||
/* sanity checking */
|
||||
if (seg->domain != p->domain || seg->segment_number != segnr ||
|
||||
(seg->mode != XEN_SEGMENT_RO && seg->mode != XEN_SEGMENT_RW) ||
|
||||
seg->num_extents <= 0 || seg->extents == NULL) {
|
||||
printk("segment is insane!\n");
|
||||
BUG();
|
||||
return 1;
|
||||
}
|
||||
|
||||
spin_lock(&xsegment_lock);
|
||||
|
||||
p->segment_list[segnr] = NULL;
|
||||
seg->domain = -1;
|
||||
seg->segment_number = -1;
|
||||
kfree(seg->extents);
|
||||
seg->mode = XEN_SEGMENT_UNUSED;
|
||||
|
||||
spin_unlock(&xsegment_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dump_segments(u_char key, void *dev_id, struct pt_regs *regs)
|
||||
{
|
||||
int loop, i;
|
||||
struct task_struct *p;
|
||||
|
||||
printk("segment list\n");
|
||||
for (loop = 0; loop < XEN_MAX_SEGMENTS; loop++)
|
||||
{
|
||||
if (xsegments[loop].mode != XEN_SEGMENT_UNUSED)
|
||||
{
|
||||
printk(" %2d: %s dom%d, seg# %d, num_exts: %d\n",
|
||||
loop,
|
||||
xsegments[loop].mode == XEN_SEGMENT_RO ? "RO" : "RW",
|
||||
xsegments[loop].domain, xsegments[loop].segment_number,
|
||||
xsegments[loop].num_extents);
|
||||
for (i = 0; i < xsegments[loop].num_extents; i++)
|
||||
{
|
||||
printk(" extent %d: disk 0x%x, offset 0x%lx, size 0x%lx\n",
|
||||
i, xsegments[loop].extents[i].disk,
|
||||
xsegments[loop].extents[i].offset,
|
||||
xsegments[loop].extents[i].size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printk("segments by domain (index into segments list)\n");
|
||||
p = current;
|
||||
do
|
||||
{
|
||||
printk(" domain %d: ", p->domain);
|
||||
for (loop = 0; loop < XEN_MAX_SEGMENTS; loop++)
|
||||
{
|
||||
if (p->segment_list[loop])
|
||||
{
|
||||
printk (" %d", p->segment_list[loop] - xsegments);
|
||||
}
|
||||
}
|
||||
printk("\n");
|
||||
p = p->next_task;
|
||||
} while (p != current);
|
||||
}
|
||||
|
||||
/*
|
||||
* initialize segments
|
||||
*/
|
||||
|
||||
void xen_segment_initialize(void)
|
||||
{
|
||||
memset (xsegments, 0, sizeof(xsegments));
|
||||
|
||||
add_key_handler('S', dump_segments, "dump segments");
|
||||
}
|
||||
@@ -0,0 +1,666 @@
|
||||
/*
|
||||
* xen_vbd.c : routines for managing virtual block devices
|
||||
*/
|
||||
|
||||
#include <xeno/config.h>
|
||||
#include <xeno/types.h>
|
||||
#include <xeno/lib.h>
|
||||
#include <asm/io.h>
|
||||
#include <xeno/slab.h>
|
||||
#include <xeno/sched.h>
|
||||
#include <xeno/vbd.h>
|
||||
#include <xeno/blkdev.h>
|
||||
#include <xeno/keyhandler.h>
|
||||
#include <asm/current.h>
|
||||
#include <asm/domain_page.h>
|
||||
|
||||
/* Global list of all possible vbds. This can be changed in
|
||||
the following way:
|
||||
|
||||
1) UNUSED vbd -> RO or RW vbd. This requires the spinlock.
|
||||
|
||||
2) RO or RW -> UNUSED. This requires the lock and can only happen
|
||||
during process teardown.
|
||||
|
||||
This means that processes can access entries in the list safely
|
||||
without having to hold any lock at all: they already have an entry
|
||||
allocated, and we know that entry can't become unused, as vbds
|
||||
are only torn down when the domain is dieing, by which point it
|
||||
can't be accessing them anymore. */
|
||||
static vbd_t xvbds[XEN_MAX_VBDS];
|
||||
static spinlock_t xvbd_lock = SPIN_LOCK_UNLOCKED;
|
||||
|
||||
#if 0
|
||||
#define DPRINTK(_f, _a...) printk( _f , ## _a )
|
||||
#else
|
||||
#define DPRINTK(_f, _a...) ((void)0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* xen_vbd_map_request
|
||||
*
|
||||
* xen_device must be a valid device.
|
||||
*
|
||||
* NB. All offsets and sizes here are in sector units.
|
||||
* eg. 'size == 1' means an actual size of 512 bytes.
|
||||
*
|
||||
* Note that no locking is performed here whatsoever --
|
||||
* we rely on the fact that once vbd information is
|
||||
* established, it is only modified by domain shutdown,
|
||||
* and so if this is being called, noone is trying
|
||||
* to modify the vbd list.
|
||||
*/
|
||||
int xen_vbd_map_request(
|
||||
phys_seg_t *pseg, struct task_struct *p, int operation,
|
||||
unsigned short vbd_number,
|
||||
unsigned long sect_nr, unsigned long buffer, unsigned short nr_sects)
|
||||
{
|
||||
vbd_t *seg;
|
||||
extent_t *ext;
|
||||
int sum, i;
|
||||
|
||||
vbd_number &= XENDEV_IDX_MASK;
|
||||
if ( vbd_number >= XEN_MAX_VBDS )
|
||||
{
|
||||
DPRINTK("invalid vbd number. %d %d\n",
|
||||
vbd_number, XEN_MAX_VBDS);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
seg = p->vbd_list[vbd_number];
|
||||
if ( seg == NULL )
|
||||
{
|
||||
DPRINTK("vbd is null. %d\n", vbd_number);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* check domain permissions */
|
||||
if ( seg->domain != p->domain )
|
||||
{
|
||||
DPRINTK("seg is for another domain. %d %d\n", seg->domain, p->domain);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* check rw access */
|
||||
if ( ((operation == WRITE) && (seg->mode != XEN_VBD_RW)) ||
|
||||
((operation == READ) && (seg->mode == XEN_VBD_UNUSED)) )
|
||||
{
|
||||
DPRINTK("illegal operation: %d %d\n", operation, seg->mode);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ( (nr_sects + sect_nr) <= sect_nr )
|
||||
{
|
||||
DPRINTK("sector + size wrap! %08lx %04x\n", sect_nr, nr_sects);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* find extent, check size */
|
||||
sum = 0;
|
||||
i = 0;
|
||||
ext = seg->extents;
|
||||
while ( (i < seg->num_extents) && ((sum + ext->nr_sectors) <= sect_nr) )
|
||||
{
|
||||
sum += ext->nr_sectors;
|
||||
ext++; i++;
|
||||
}
|
||||
|
||||
if ( (sum + ext->nr_sectors) <= sect_nr )
|
||||
{
|
||||
DPRINTK("extent size mismatch: %d %d : %d %ld %ld\n",
|
||||
i, seg->num_extents, sum, ext->nr_sectors, sect_nr);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pseg->sector_number = (sect_nr - sum) + ext->start_sector;
|
||||
pseg->buffer = buffer;
|
||||
pseg->nr_sects = nr_sects;
|
||||
pseg->dev = xendev_to_physdev(ext->raw_device);
|
||||
if ( pseg->dev == 0 )
|
||||
{
|
||||
DPRINTK ("invalid device 0x%x 0x%lx 0x%lx\n",
|
||||
ext->raw_device, ext->start_sector, ext->nr_sectors);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* We're finished if the virtual extent didn't overrun the phys extent. */
|
||||
if ( (sum + ext->nr_sectors) >= (sect_nr + nr_sects) )
|
||||
return 1; /* entire read fits in this extent */
|
||||
|
||||
/* Hmmm... make sure there's another extent to overrun onto! */
|
||||
if ( (i+1) == seg->num_extents )
|
||||
{
|
||||
DPRINTK ("not enough extents %d %d\n",
|
||||
i, seg->num_extents);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pseg[1].nr_sects = (sect_nr + nr_sects) - (sum + ext->nr_sectors);
|
||||
pseg[0].nr_sects = sum + ext->nr_sectors - sect_nr;
|
||||
pseg[1].buffer = buffer + (pseg->nr_sects << 9);
|
||||
pseg[1].sector_number = ext[1].start_sector;
|
||||
pseg[1].dev = xendev_to_physdev(ext[1].raw_device);
|
||||
if ( pseg[1].dev == 0 )
|
||||
{
|
||||
DPRINTK ("bogus device for pseg[1] \n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* We don't allow overrun onto a third physical extent. */
|
||||
if ( pseg[1].nr_sects > ext[1].nr_sectors )
|
||||
{
|
||||
DPRINTK ("third extent\n");
|
||||
DPRINTK (" sum:%d, e0:%ld, e1:%ld p1.sect:%ld p1.nr:%d\n",
|
||||
sum, ext[0].nr_sectors, ext[1].nr_sectors,
|
||||
pseg[1].sector_number, pseg[1].nr_sects);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 2; /* We overran onto a second physical extent. */
|
||||
|
||||
fail:
|
||||
DPRINTK ("xen_vbd_map_request failure\n");
|
||||
DPRINTK ("operation: %d\n", operation);
|
||||
DPRINTK ("vbd number: %d\n", vbd_number);
|
||||
DPRINTK ("sect_nr: %ld 0x%lx\n", sect_nr, sect_nr);
|
||||
DPRINTK ("nr_sects: %d 0x%x\n", nr_sects, nr_sects);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* vbd_probe_devices:
|
||||
*
|
||||
* add the virtual block devices for this domain to a xen_disk_info_t;
|
||||
* we assume xdi->count points to the first unused place in the array.
|
||||
*/
|
||||
void vbd_probe_devices(xen_disk_info_t *xdi, struct task_struct *p)
|
||||
{
|
||||
int loop, i;
|
||||
unsigned long capacity = 0, device;
|
||||
|
||||
spin_lock(&xvbd_lock);
|
||||
for (loop = 0; loop < XEN_MAX_VBDS; loop++ )
|
||||
{
|
||||
if ( (xvbds[loop].mode == XEN_VBD_UNUSED) ||
|
||||
(xvbds[loop].domain != p->domain) )
|
||||
continue;
|
||||
|
||||
device = MK_VIRTUAL_XENDEV(xvbds[loop].vbd_number);
|
||||
for ( i = 0; i < xvbds[loop].num_extents; i++ )
|
||||
capacity += xvbds[loop].extents[i].nr_sectors;
|
||||
|
||||
xdi->disks[xdi->count].device = device;
|
||||
xdi->disks[xdi->count].capacity = capacity;
|
||||
xdi->count++;
|
||||
}
|
||||
spin_unlock(&xvbd_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* xen_refresh_vbd_list
|
||||
*
|
||||
* find all vbds associated with a domain and assign
|
||||
* them to the domain
|
||||
*
|
||||
*/
|
||||
void xen_refresh_vbd_list (struct task_struct *p)
|
||||
{
|
||||
int loop;
|
||||
|
||||
spin_lock(&xvbd_lock);
|
||||
for (loop = 0; loop < XEN_MAX_VBDS; loop++)
|
||||
{
|
||||
if ( (xvbds[loop].mode == XEN_VBD_UNUSED) ||
|
||||
(xvbds[loop].domain != p->domain) )
|
||||
continue;
|
||||
|
||||
p->vbd_list[xvbds[loop].vbd_number] = &xvbds[loop];
|
||||
}
|
||||
spin_unlock(&xvbd_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* create a new vbd for a domain
|
||||
*
|
||||
* return 0 on success, 1 on failure
|
||||
*
|
||||
* if we see the same DOM#/SEG# combination, we reuse the slot in
|
||||
* the vbd table (overwriting what was there before).
|
||||
* an alternative would be to raise an error if the slot is reused.
|
||||
*/
|
||||
int xen_vbd_create(xv_disk_t *xvd_in)
|
||||
{
|
||||
int idx;
|
||||
int loop;
|
||||
xv_disk_t *xvd = map_domain_mem(virt_to_phys(xvd_in));
|
||||
struct task_struct *p;
|
||||
|
||||
spin_lock(&xvbd_lock);
|
||||
for (idx = 0; idx < XEN_MAX_VBDS; idx++)
|
||||
{
|
||||
if (xvbds[idx].mode == XEN_VBD_UNUSED ||
|
||||
(xvbds[idx].domain == xvd->domain &&
|
||||
xvbds[idx].vbd_number == xvd->vbd)) break;
|
||||
}
|
||||
if (idx == XEN_MAX_VBDS)
|
||||
{
|
||||
printk (KERN_ALERT "xen_vbd_create: unable to find free slot\n");
|
||||
unmap_domain_mem(xvd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
xvbds[idx].mode = xvd->mode;
|
||||
xvbds[idx].domain = xvd->domain;
|
||||
xvbds[idx].vbd_number = xvd->vbd;
|
||||
memcpy(xvbds[idx].key, xvd->key, XEN_VBD_KEYSIZE);
|
||||
xvbds[idx].num_extents = xvd->ext_count;
|
||||
|
||||
|
||||
if (xvbds[idx].extents)
|
||||
kfree(xvbds[idx].extents);
|
||||
xvbds[idx].extents = (extent_t *)kmalloc(
|
||||
sizeof(extent_t)*xvd->ext_count,
|
||||
GFP_KERNEL);
|
||||
|
||||
/* could memcpy, but this is safer */
|
||||
for (loop = 0; loop < xvd->ext_count; loop++)
|
||||
{
|
||||
xvbds[idx].extents[loop].raw_device = xvd->extents[loop].disk;
|
||||
xvbds[idx].extents[loop].start_sector =
|
||||
xvd->extents[loop].offset;
|
||||
xvbds[idx].extents[loop].nr_sectors = xvd->extents[loop].size;
|
||||
if (xvbds[idx].extents[loop].nr_sectors == 0)
|
||||
{
|
||||
printk("xen_vbd_create: extent %d is zero length\n", loop);
|
||||
unmap_domain_mem(xvd);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* if the domain exists, assign the vbd to the domain */
|
||||
p = find_domain_by_id(xvd->domain);
|
||||
if (p != NULL)
|
||||
{
|
||||
p->vbd_list[xvd->vbd] = &xvbds[idx];
|
||||
put_task_struct(p);
|
||||
}
|
||||
|
||||
spin_unlock(&xvbd_lock);
|
||||
|
||||
unmap_domain_mem(xvd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* delete a vbd from a domain
|
||||
*
|
||||
* return 0 on success, 1 on failure
|
||||
*
|
||||
* This should *only* be called from domain shutdown, or else we
|
||||
* race with access checking.
|
||||
*/
|
||||
int xen_vbd_delete(struct task_struct *p, int segnr)
|
||||
{
|
||||
vbd_t *seg;
|
||||
|
||||
if (!p) {
|
||||
printk("xen_vbd delete called with NULL domain?\n");
|
||||
BUG();
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (segnr < 0 || segnr > XEN_MAX_VBDS) {
|
||||
printk("xen_vbd_delete called with bad segnr?\n");
|
||||
BUG();
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!p->vbd_list[segnr])
|
||||
return 1;
|
||||
|
||||
seg = p->vbd_list[segnr];
|
||||
|
||||
/* sanity checking */
|
||||
if (seg->domain != p->domain || seg->vbd_number != segnr ||
|
||||
(seg->mode != XEN_VBD_RO && seg->mode != XEN_VBD_RW) ||
|
||||
seg->num_extents <= 0 || seg->extents == NULL) {
|
||||
printk("vbd is insane!\n");
|
||||
BUG();
|
||||
return 1;
|
||||
}
|
||||
|
||||
spin_lock(&xvbd_lock);
|
||||
|
||||
p->vbd_list[segnr] = NULL;
|
||||
seg->domain = -1;
|
||||
seg->vbd_number = -1;
|
||||
kfree(seg->extents);
|
||||
seg->mode = XEN_VBD_UNUSED;
|
||||
|
||||
spin_unlock(&xvbd_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dump_vbds(u_char key, void *dev_id, struct pt_regs *regs)
|
||||
{
|
||||
int loop, i;
|
||||
struct task_struct *p;
|
||||
|
||||
printk("vbd list\n");
|
||||
for (loop = 0; loop < XEN_MAX_VBDS; loop++)
|
||||
{
|
||||
if (xvbds[loop].mode != XEN_VBD_UNUSED)
|
||||
{
|
||||
printk(" %2d: %s dom%d, seg# %d, num_exts: %d\n",
|
||||
loop,
|
||||
xvbds[loop].mode == XEN_VBD_RO ? "RO" : "RW",
|
||||
xvbds[loop].domain, xvbds[loop].vbd_number,
|
||||
xvbds[loop].num_extents);
|
||||
for (i = 0; i < xvbds[loop].num_extents; i++)
|
||||
{
|
||||
printk(" extent %d: raw device 0x%x, start_sector 0x%lx"
|
||||
" nr_sectors 0x%lx\n",
|
||||
i, xvbds[loop].extents[i].raw_device,
|
||||
xvbds[loop].extents[i].start_sector,
|
||||
xvbds[loop].extents[i].nr_sectors);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printk("vbds by domain (index into vbds list)\n");
|
||||
p = current;
|
||||
do
|
||||
{
|
||||
if(is_idle_task(p))
|
||||
continue;
|
||||
|
||||
printk(" domain %d: ", p->domain);
|
||||
for (loop = 0; loop < XEN_MAX_VBDS; loop++)
|
||||
{
|
||||
if (p->vbd_list[loop])
|
||||
{
|
||||
printk (" %d", p->vbd_list[loop] - xvbds);
|
||||
}
|
||||
}
|
||||
printk("\n");
|
||||
p = p->next_task;
|
||||
} while (p != current);
|
||||
}
|
||||
|
||||
/*
|
||||
* initialize vbds
|
||||
*/
|
||||
|
||||
void xen_vbd_initialize(void)
|
||||
{
|
||||
memset (xvbds, 0, sizeof(xvbds));
|
||||
|
||||
add_key_handler('S', dump_vbds, "dump vbds");
|
||||
}
|
||||
|
||||
|
||||
/* The idea is that, for each sector of each disk, each domain has two
|
||||
bits, saying whether they can read the sector or write it. That
|
||||
would take too much memory, so instead each process has a list of
|
||||
(device, start, end, mode) quads which say what it has access to,
|
||||
and we fake the logical view on top of that. */
|
||||
struct physdisk_ace {
|
||||
struct list_head list;
|
||||
unsigned short device;
|
||||
unsigned short partition;
|
||||
unsigned long start_sect;
|
||||
unsigned long n_sectors;
|
||||
int mode;
|
||||
};
|
||||
|
||||
|
||||
/* Operation is a blkdev constant i.e. READ, WRITE, ... */
|
||||
/* Must be called with p->physdev_lock held. */
|
||||
static struct physdisk_ace *find_ace(const struct task_struct *p,
|
||||
unsigned short dev,
|
||||
unsigned long sect, int operation)
|
||||
{
|
||||
struct list_head *cur_ace_head;
|
||||
struct physdisk_ace *cur_ace;
|
||||
|
||||
list_for_each(cur_ace_head, &p->physdisk_aces)
|
||||
{
|
||||
cur_ace = list_entry(cur_ace_head, struct physdisk_ace, list);
|
||||
DPRINTK("Is [%lx, %lx) good for %lx?\n",
|
||||
cur_ace->start_sect,
|
||||
cur_ace->start_sect + cur_ace->n_sectors, sect);
|
||||
if ( (sect >= cur_ace->start_sect) &&
|
||||
(sect < (cur_ace->start_sect + cur_ace->n_sectors)) &&
|
||||
(dev == cur_ace->device) &&
|
||||
(((operation == READ) && (cur_ace->mode & PHYSDISK_MODE_R)) ||
|
||||
((operation == WRITE) && (cur_ace->mode & PHYSDISK_MODE_W))) )
|
||||
return cur_ace;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Hold the lock on entry, it remains held on exit. */
|
||||
static void xen_physdisk_revoke_access(unsigned short dev,
|
||||
unsigned long start_sect,
|
||||
unsigned long n_sectors,
|
||||
struct task_struct *p)
|
||||
{
|
||||
/* Find every ace which intersects [start_sect, start_sect +
|
||||
n_sectors] and either remove it completely or truncate it
|
||||
down. */
|
||||
struct list_head *cur_ace_head;
|
||||
struct physdisk_ace *cur_ace, *new_ace;
|
||||
unsigned long kill_zone_end, ace_end;
|
||||
|
||||
kill_zone_end = start_sect + n_sectors;
|
||||
list_for_each(cur_ace_head, &p->physdisk_aces)
|
||||
{
|
||||
cur_ace = list_entry(cur_ace_head, struct physdisk_ace, list);
|
||||
ace_end = cur_ace->start_sect + cur_ace->n_sectors;
|
||||
if ( (cur_ace->start_sect >= kill_zone_end) ||
|
||||
(ace_end <= start_sect) ||
|
||||
(cur_ace->device != dev) )
|
||||
continue;
|
||||
|
||||
DPRINTK("Killing ace [%lx, %lx) against kill zone [%lx, %lx)\n",
|
||||
cur_ace->start_sect, ace_end, start_sect, kill_zone_end);
|
||||
|
||||
if ( (cur_ace->start_sect >= start_sect) &&
|
||||
(ace_end <= kill_zone_end) )
|
||||
{
|
||||
/* ace entirely within kill zone -> kill it */
|
||||
list_del(cur_ace_head);
|
||||
cur_ace_head = cur_ace_head->prev;
|
||||
kfree(cur_ace);
|
||||
}
|
||||
else if ( ace_end <= kill_zone_end )
|
||||
{
|
||||
/* ace start before kill start, ace end in kill zone,
|
||||
move ace end. */
|
||||
cur_ace->n_sectors = start_sect - cur_ace->start_sect;
|
||||
}
|
||||
else if ( cur_ace->start_sect >= start_sect )
|
||||
{
|
||||
/* ace start after kill start, ace end outside kill zone,
|
||||
move ace start. */
|
||||
cur_ace->start_sect = kill_zone_end;
|
||||
cur_ace->n_sectors = ace_end - cur_ace->start_sect;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The fun one: the ace entirely includes the kill zone. */
|
||||
/* Cut the current ace down to just the bit before the kzone,
|
||||
create a new ace for the bit just after it. */
|
||||
new_ace = kmalloc(sizeof(*cur_ace), GFP_KERNEL);
|
||||
new_ace->device = dev;
|
||||
new_ace->start_sect = kill_zone_end;
|
||||
new_ace->n_sectors = ace_end - kill_zone_end;
|
||||
new_ace->mode = cur_ace->mode;
|
||||
|
||||
cur_ace->n_sectors = start_sect - cur_ace->start_sect;
|
||||
|
||||
list_add(&new_ace->list, cur_ace_head);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Hold the lock on entry, it remains held on exit. */
|
||||
static int xen_physdisk_grant_access(unsigned short dev,
|
||||
unsigned short partition,
|
||||
unsigned long start_sect,
|
||||
unsigned long n_sectors,
|
||||
int mode, struct task_struct *p)
|
||||
{
|
||||
struct physdisk_ace *cur_ace;
|
||||
|
||||
/* Make sure it won't overlap with any existing ACEs. */
|
||||
/* XXX this isn't quite right if the domain already has read access
|
||||
and we try to grant write access, or vice versa. */
|
||||
xen_physdisk_revoke_access(dev, start_sect, n_sectors, p);
|
||||
|
||||
if ( mode )
|
||||
{
|
||||
cur_ace = kmalloc(sizeof(*cur_ace), GFP_KERNEL);
|
||||
cur_ace->device = dev;
|
||||
cur_ace->start_sect = start_sect;
|
||||
cur_ace->n_sectors = n_sectors;
|
||||
cur_ace->mode = mode;
|
||||
cur_ace->partition = partition;
|
||||
|
||||
list_add_tail(&cur_ace->list, &p->physdisk_aces);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xen_physdisk_probe_access(physdisk_probebuf_t * buf,
|
||||
struct task_struct *p)
|
||||
{
|
||||
int n_aces;
|
||||
struct list_head *cur_ace_head;
|
||||
struct physdisk_ace *cur_ace;
|
||||
int x = 0;
|
||||
|
||||
n_aces = 0;
|
||||
list_for_each(cur_ace_head, &p->physdisk_aces)
|
||||
{
|
||||
x++;
|
||||
if ( x >= buf->start_ind )
|
||||
{
|
||||
cur_ace = list_entry(cur_ace_head, struct physdisk_ace, list);
|
||||
buf->entries[n_aces].device = cur_ace->device;
|
||||
buf->entries[n_aces].partition = cur_ace->partition;
|
||||
buf->entries[n_aces].start_sect = cur_ace->start_sect;
|
||||
buf->entries[n_aces].n_sectors = cur_ace->n_sectors;
|
||||
buf->entries[n_aces].mode = cur_ace->mode;
|
||||
n_aces++;
|
||||
}
|
||||
}
|
||||
buf->n_aces = n_aces;
|
||||
}
|
||||
|
||||
int xen_physdisk_grant(xp_disk_t * xpd_in)
|
||||
{
|
||||
struct task_struct *p = current;
|
||||
xp_disk_t *xpd = map_domain_mem(virt_to_phys(xpd_in));
|
||||
int res;
|
||||
|
||||
p = find_domain_by_id(xpd->domain);
|
||||
if ( p == NULL )
|
||||
{
|
||||
DPRINTK("Bad domain!\n");
|
||||
res = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
spin_lock(&p->physdev_lock);
|
||||
res = xen_physdisk_grant_access(xpd->device,
|
||||
xpd->partition,
|
||||
xpd->start_sect,
|
||||
xpd->n_sectors, xpd->mode, p);
|
||||
spin_unlock(&p->physdev_lock);
|
||||
put_task_struct(p);
|
||||
|
||||
out:
|
||||
unmap_domain_mem(xpd);
|
||||
return res;
|
||||
}
|
||||
|
||||
int xen_physdisk_probe(struct task_struct *requesting_domain,
|
||||
physdisk_probebuf_t * buf_in)
|
||||
{
|
||||
struct task_struct *p;
|
||||
physdisk_probebuf_t *buf = map_domain_mem(virt_to_phys(buf_in));
|
||||
int res;
|
||||
|
||||
if ( (requesting_domain->domain != 0) &&
|
||||
(requesting_domain->domain != buf->domain) )
|
||||
{
|
||||
res = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
p = find_domain_by_id(buf->domain);
|
||||
if ( p == NULL )
|
||||
{
|
||||
res = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
spin_lock(&p->physdev_lock);
|
||||
xen_physdisk_probe_access(buf, p);
|
||||
spin_unlock(&p->physdev_lock);
|
||||
put_task_struct(p);
|
||||
|
||||
res = 0;
|
||||
out:
|
||||
unmap_domain_mem(buf);
|
||||
return res;
|
||||
}
|
||||
|
||||
#define MAX(a,b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
int xen_physdisk_access_okay(phys_seg_t * pseg, struct task_struct *p,
|
||||
int operation)
|
||||
{
|
||||
struct physdisk_ace *cur_ace;
|
||||
unsigned long sect;
|
||||
|
||||
DPRINTK
|
||||
("Checking access for domain %d, start sect 0x%lx, length 0x%x.\n",
|
||||
p->domain, pseg->sector_number, pseg->nr_sects);
|
||||
|
||||
for ( sect = pseg->sector_number;
|
||||
sect < pseg->sector_number + pseg->nr_sects; )
|
||||
{
|
||||
/* XXX this would be a lot faster if the aces were sorted on start
|
||||
address. Also in revoke_access. */
|
||||
spin_lock(&p->physdev_lock);
|
||||
cur_ace = find_ace(p, pseg->dev, sect, operation);
|
||||
spin_unlock(&p->physdev_lock);
|
||||
if ( cur_ace == NULL )
|
||||
return 0;
|
||||
sect +=
|
||||
MAX(cur_ace->n_sectors,
|
||||
pseg->nr_sects + pseg->sector_number - sect);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void destroy_physdisk_aces(struct task_struct *p)
|
||||
{
|
||||
struct list_head *cur_ace_head, *next_head;
|
||||
struct physdisk_ace *cur_ace;
|
||||
|
||||
for ( cur_ace_head = p->physdisk_aces.next;
|
||||
cur_ace_head != &p->physdisk_aces;
|
||||
cur_ace_head = next_head )
|
||||
{
|
||||
cur_ace = list_entry(cur_ace_head, struct physdisk_ace, list);
|
||||
next_head = cur_ace_head->next;
|
||||
kfree(cur_ace);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
#include <xeno/types.h>
|
||||
#include <xeno/lib.h>
|
||||
#include <xeno/ide.h>
|
||||
#include <xeno/segment.h>
|
||||
#include <hypervisor-ifs/block.h>
|
||||
#include <xeno/vbd.h>
|
||||
#include <asm/domain_page.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
@@ -11,7 +10,6 @@ void ide_probe_devices(xen_disk_info_t* xdi)
|
||||
{
|
||||
int loop;
|
||||
unsigned int unit;
|
||||
xen_disk_info_t *xen_xdi = map_domain_mem(virt_to_phys(xdi));
|
||||
unsigned long capacity;
|
||||
unsigned short device, type;
|
||||
ide_drive_t *drive;
|
||||
@@ -36,17 +34,17 @@ void ide_probe_devices(xen_disk_info_t* xdi)
|
||||
device = MK_IDE_XENDEV((loop * MAX_DRIVES) + unit);
|
||||
capacity = current_capacity(drive);
|
||||
|
||||
xen_xdi->disks[xen_xdi->count].device = device;
|
||||
xen_xdi->disks[xen_xdi->count].type = type;
|
||||
xen_xdi->disks[xen_xdi->count].capacity = capacity;
|
||||
xen_xdi->count++;
|
||||
xdi->disks[xdi->count].device = device;
|
||||
xdi->disks[xdi->count].type = type;
|
||||
xdi->disks[xdi->count].capacity = capacity;
|
||||
xdi->count++;
|
||||
|
||||
printk("Device %d: IDE-XENO (%s) capacity %ldkB (%ldMB)\n",
|
||||
xen_xdi->count, (type == XD_TYPE_DISK) ? "disk" :
|
||||
xdi->count, (type == XD_TYPE_DISK) ? "disk" :
|
||||
((type == XD_TYPE_CDROM) ? "cdrom" : "unknown"),
|
||||
capacity>>1, capacity>>11);
|
||||
}
|
||||
}
|
||||
|
||||
unmap_domain_mem(xen_xdi);
|
||||
|
||||
return;
|
||||
}
|
||||
+16
-11
@@ -1310,16 +1310,21 @@ static void sd_finish()
|
||||
|
||||
|
||||
/*
|
||||
** XXX SMH: gross 'probe' function to allow xeno world to grope us;
|
||||
** this should really not be in the disk-specific code as it should
|
||||
** report tapes, CDs, etc. But for now this looks like the easiest
|
||||
** place to hook it in :-(
|
||||
** scsi_probe_devices:
|
||||
**
|
||||
** add the scsi block devices for this domain to a xen_disk_info_t;
|
||||
** we assume xdi->count points to the first unused place in the array.
|
||||
**
|
||||
** XXX SMH: this is a rather gross 'probe' function to allow xeno world
|
||||
** to grope us; this should really not be in the disk-specific code as
|
||||
** it should report tapes, CDs, etc. But for now this looks like the
|
||||
** easiest place to hook it in :-(
|
||||
**
|
||||
*/
|
||||
void scsi_probe_devices(xen_disk_info_t *xdi)
|
||||
{
|
||||
Scsi_Disk *sd;
|
||||
int i;
|
||||
xen_disk_info_t *xen_xdi = map_domain_mem(virt_to_phys(xdi));
|
||||
unsigned long capacity, device;
|
||||
|
||||
for ( sd = rscsi_disks, i = 0; i < sd_template.dev_max; i++, sd++ )
|
||||
@@ -1330,16 +1335,16 @@ void scsi_probe_devices(xen_disk_info_t *xdi)
|
||||
capacity = sd->capacity;
|
||||
|
||||
/* XXX SMH: if make generic, need to properly determine 'type' */
|
||||
xen_xdi->disks[xen_xdi->count].device = device;
|
||||
xen_xdi->disks[xen_xdi->count].type = XD_TYPE_DISK;
|
||||
xen_xdi->disks[xen_xdi->count].capacity = capacity;
|
||||
xen_xdi->count++;
|
||||
xdi->disks[xdi->count].device = device;
|
||||
xdi->disks[xdi->count].type = XD_TYPE_DISK;
|
||||
xdi->disks[xdi->count].capacity = capacity;
|
||||
xdi->count++;
|
||||
|
||||
printk("Device %d: SCSI-XENO (disk) capacity %ldkB (%ldMB)\n",
|
||||
xen_xdi->count, capacity>>1, capacity>>11);
|
||||
xdi->count, capacity>>1, capacity>>11);
|
||||
}
|
||||
|
||||
unmap_domain_mem(xen_xdi);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -50,16 +50,14 @@
|
||||
#define XEN_BLOCK_WRITE 1
|
||||
#define XEN_BLOCK_READA 2
|
||||
#define XEN_BLOCK_SPECIAL 4
|
||||
#define XEN_BLOCK_PROBE_BLK 5 /* get xhd config from hypervisor */
|
||||
#define XEN_BLOCK_DEBUG 6 /* debug */
|
||||
#define XEN_BLOCK_SEG_CREATE 7 /* create segment (vhd) */
|
||||
#define XEN_BLOCK_SEG_DELETE 8 /* delete segment (vhd) */
|
||||
#define XEN_BLOCK_PROBE_SEG 9 /* get vhd config from hypervisor */
|
||||
#define XEN_BLOCK_PROBE 5 /* get config from hypervisor */
|
||||
#define XEN_BLOCK_DEBUG 6 /* debug */
|
||||
#define XEN_BLOCK_VBD_CREATE 7 /* create vbd */
|
||||
#define XEN_BLOCK_VBD_DELETE 8 /* delete vbd */
|
||||
/* XXX SMH: was 'probe vbd' */
|
||||
#define XEN_BLOCK_PHYSDEV_GRANT 10 /* grant access to range of disk blocks */
|
||||
#define XEN_BLOCK_PHYSDEV_PROBE 11 /* probe for a domain's physdev
|
||||
accesses */
|
||||
#define XEN_BLOCK_PROBE_SEG_ALL 12 /* prove for every domain's segments,
|
||||
not just ours. */
|
||||
#define XEN_BLOCK_PHYSDEV_PROBE 11 /* probe for a domain's physdev accesses */
|
||||
/* XXX SMH: was 'probe vbd all' */
|
||||
|
||||
/* NB. Ring size must be small enough for sizeof(blk_ring_t) <= PAGE_SIZE. */
|
||||
#define BLK_RING_SIZE 64
|
||||
@@ -127,59 +125,4 @@ typedef struct xen_disk_info
|
||||
xen_disk_t disks[XEN_MAX_DISK_COUNT];
|
||||
} xen_disk_info_t;
|
||||
|
||||
/*
|
||||
*
|
||||
* virtual disk (vhd) structures, used by XEN_BLOCK_SEG_{CREATE, DELETE}
|
||||
*
|
||||
*/
|
||||
|
||||
#define XEN_DISK_READ_WRITE 1
|
||||
#define XEN_DISK_READ_ONLY 2
|
||||
|
||||
typedef struct xv_extent
|
||||
{
|
||||
int disk; /* physical disk number */
|
||||
unsigned long offset; /* offset in blocks into physical disk */
|
||||
unsigned long size; /* size in blocks */
|
||||
} xv_extent_t;
|
||||
|
||||
#define XEN_SEGMENT_KEYSIZE 10
|
||||
|
||||
typedef struct xv_disk
|
||||
{
|
||||
int mode; /* XEN_DISK_READ_WRITE or XEN_DISK_READ_ONLY */
|
||||
int domain; /* domain */
|
||||
int segment; /* segment number */
|
||||
char key[XEN_SEGMENT_KEYSIZE]; /* key for benefit of dom0 userspace */
|
||||
int ext_count; /* number of xv_extent_t to follow */
|
||||
xv_extent_t extents[XEN_MAX_DISK_COUNT]; /* arbitrary reuse of constant */
|
||||
} xv_disk_t;
|
||||
|
||||
#define PHYSDISK_MODE_R 1
|
||||
#define PHYSDISK_MODE_W 2
|
||||
typedef struct xp_disk
|
||||
{
|
||||
int mode; /* 0 -> revoke existing access, otherwise bitmask of
|
||||
PHYSDISK_MODE_? constants */
|
||||
int domain;
|
||||
unsigned short device; /* XENDEV_??? + idx */
|
||||
unsigned short partition; /* partition number */
|
||||
unsigned long start_sect;
|
||||
unsigned long n_sectors;
|
||||
} xp_disk_t;
|
||||
|
||||
#define PHYSDISK_MAX_ACES_PER_REQUEST 254 /* Make it fit in one page */
|
||||
typedef struct {
|
||||
int n_aces;
|
||||
int domain;
|
||||
int start_ind;
|
||||
struct {
|
||||
unsigned short device; /* XENDEV_??? + idx */
|
||||
unsigned short partition; /* partition number */
|
||||
unsigned long start_sect;
|
||||
unsigned long n_sectors;
|
||||
unsigned mode;
|
||||
} entries[PHYSDISK_MAX_ACES_PER_REQUEST];
|
||||
} physdisk_probebuf_t;
|
||||
|
||||
#endif
|
||||
@@ -1,21 +0,0 @@
|
||||
#ifndef __HYP_IFS_SEGMENT_H__
|
||||
#define __HYP_IFS_SEGMENT_H__
|
||||
|
||||
#define XEN_MAX_SEGMENTS 100 /* total number of segments across all doms */
|
||||
|
||||
#define XEN_SEGMENT_UNUSED 0 /* bzero default */
|
||||
#define XEN_SEGMENT_RO XEN_DISK_READ_ONLY
|
||||
#define XEN_SEGMENT_RW XEN_DISK_READ_WRITE
|
||||
|
||||
typedef struct xen_segment_info
|
||||
{
|
||||
int count;
|
||||
struct {
|
||||
unsigned domain;
|
||||
unsigned seg_nr;
|
||||
char key[XEN_SEGMENT_KEYSIZE];
|
||||
unsigned short mode; /* UNUSED, RO, or RW. */
|
||||
} segments[XEN_MAX_SEGMENTS];
|
||||
} xen_segment_info_t;
|
||||
|
||||
#endif /* __HYP_IFS_SEGMENT_H__ */
|
||||
@@ -0,0 +1,115 @@
|
||||
#ifndef __HYP_IFS_VBD_H__
|
||||
#define __HYP_IFS_VBD_H__
|
||||
|
||||
#define XEN_MAX_VBDS 100 /* total number of vbds across all doms */
|
||||
|
||||
#define XEN_VBD_UNUSED 0 /* bzero default */
|
||||
#define XEN_DISK_READ_WRITE 1
|
||||
#define XEN_DISK_READ_ONLY 2
|
||||
#define XEN_VBD_RO XEN_DISK_READ_ONLY
|
||||
#define XEN_VBD_RW XEN_DISK_READ_WRITE
|
||||
|
||||
/*
|
||||
*
|
||||
* virtual disk (vhd) structures, used by XEN_BLOCK_VBD_{CREATE, DELETE}
|
||||
*
|
||||
*/
|
||||
|
||||
typedef struct xv_extent
|
||||
{
|
||||
int disk; /* physical disk number */
|
||||
unsigned long offset; /* offset in blocks into physical disk */
|
||||
unsigned long size; /* size in blocks */
|
||||
} xv_extent_t;
|
||||
|
||||
#define XEN_VBD_KEYSIZE 10
|
||||
|
||||
typedef struct xv_disk
|
||||
{
|
||||
int mode; /* XEN_DISK_READ_WRITE or XEN_DISK_READ_ONLY */
|
||||
int domain; /* domain */
|
||||
int vbd; /* segment number */
|
||||
char key[XEN_VBD_KEYSIZE]; /* key for benefit of dom0 userspace */
|
||||
int ext_count; /* number of xv_extent_t to follow */
|
||||
xv_extent_t extents[XEN_MAX_DISK_COUNT]; /* arbitrary reuse of constant */
|
||||
} xv_disk_t;
|
||||
|
||||
#define PHYSDISK_MODE_R 1
|
||||
#define PHYSDISK_MODE_W 2
|
||||
typedef struct xp_disk
|
||||
{
|
||||
int mode; /* 0 -> revoke existing access, otherwise bitmask of
|
||||
PHYSDISK_MODE_? constants */
|
||||
int domain;
|
||||
unsigned short device; /* XENDEV_??? + idx */
|
||||
unsigned short partition; /* partition number */
|
||||
unsigned long start_sect;
|
||||
unsigned long n_sectors;
|
||||
} xp_disk_t;
|
||||
|
||||
#define PHYSDISK_MAX_ACES_PER_REQUEST 254 /* Make it fit in one page */
|
||||
typedef struct {
|
||||
int n_aces;
|
||||
int domain;
|
||||
int start_ind;
|
||||
struct {
|
||||
unsigned short device; /* XENDEV_??? + idx */
|
||||
unsigned short partition; /* partition number */
|
||||
unsigned long start_sect;
|
||||
unsigned long n_sectors;
|
||||
unsigned mode;
|
||||
} entries[PHYSDISK_MAX_ACES_PER_REQUEST];
|
||||
} physdisk_probebuf_t;
|
||||
|
||||
|
||||
typedef struct xen_vbd_info
|
||||
{
|
||||
int count;
|
||||
struct {
|
||||
unsigned domain;
|
||||
unsigned seg_nr;
|
||||
char key[XEN_VBD_KEYSIZE];
|
||||
unsigned short mode; /* UNUSED, RO, or RW. */
|
||||
} vbds[XEN_MAX_VBDS];
|
||||
} xen_vbd_info_t;
|
||||
|
||||
|
||||
|
||||
/* Block I/O trap operations and associated structures.
|
||||
*/
|
||||
|
||||
#define BLOCK_IO_OP_SIGNAL 0 // let xen know we have work to do
|
||||
#define BLOCK_IO_OP_ATTACH_VBD 1 // attach a VBD to a given domain
|
||||
|
||||
|
||||
typedef struct _extent {
|
||||
u16 raw_device;
|
||||
ulong start_sector;
|
||||
ulong nr_sectors;
|
||||
} extent_t;
|
||||
|
||||
|
||||
typedef struct _vbd_attach {
|
||||
int domain;
|
||||
u16 mode; // read-only or read-write
|
||||
u16 device; // how this domain refers to this VBD
|
||||
int nr_extents; // number of extents in the VBD
|
||||
extent_t *extents; // pointer to /array/ of extents
|
||||
} vbd_attach_t;
|
||||
|
||||
|
||||
typedef struct block_io_op_st
|
||||
{
|
||||
unsigned long cmd;
|
||||
union
|
||||
{
|
||||
long signal_val_unused;
|
||||
vbd_attach_t attach_info;
|
||||
}
|
||||
u;
|
||||
} block_io_op_t;
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* __HYP_IFS_VBD_H__ */
|
||||
@@ -1,11 +0,0 @@
|
||||
/* block.h
|
||||
*
|
||||
* this is the hypervisor end of the block io code.
|
||||
*/
|
||||
|
||||
#include <hypervisor-ifs/block.h>
|
||||
|
||||
/* vif prototypes */
|
||||
blk_ring_t *create_block_ring(int domain);
|
||||
void destroy_block_ring(struct task_struct *p);
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
#ifndef PHYSDISK_ACES__
|
||||
#define PHYSDISK_ACES__
|
||||
|
||||
struct task_struct;
|
||||
|
||||
void destroy_physdisk_aces(struct task_struct *p);
|
||||
|
||||
int xen_physdisk_grant(xp_disk_t *);
|
||||
int xen_physdisk_probe(struct task_struct *requesting_task,
|
||||
physdisk_probebuf_t *);
|
||||
int xen_physdisk_access_okay(phys_seg_t *pseg, struct task_struct *p,
|
||||
int operation);
|
||||
|
||||
#endif /* PHYSDISK_ACES__ */
|
||||
@@ -1,49 +0,0 @@
|
||||
#ifndef __SEGMENT_H__
|
||||
#define __SEGMENT_H__
|
||||
|
||||
#include <hypervisor-ifs/block.h>
|
||||
#include <hypervisor-ifs/segment.h>
|
||||
|
||||
/* Describes a physical disk extent. */
|
||||
typedef struct {
|
||||
unsigned short dev;
|
||||
unsigned short nr_sects;
|
||||
unsigned long sector_number;
|
||||
unsigned long buffer;
|
||||
} phys_seg_t;
|
||||
|
||||
struct task_struct;
|
||||
|
||||
void xen_segment_initialize(void);
|
||||
void xen_refresh_segment_list (struct task_struct *p);
|
||||
int xen_segment_create(xv_disk_t *xvd);
|
||||
int xen_segment_delete(struct task_struct *p, int segnr);
|
||||
int xen_segment_map_request(
|
||||
phys_seg_t *pseg, struct task_struct *p, int operation,
|
||||
unsigned short segment_number,
|
||||
unsigned long sect_nr, unsigned long buffer, unsigned short nr_sects);
|
||||
|
||||
/*
|
||||
* virtual hard disks
|
||||
*
|
||||
* each segment is composed of a number of extents
|
||||
*/
|
||||
|
||||
typedef struct extent
|
||||
{
|
||||
int disk; /* A XEN_IDE_DEV or a XEN_SCSI_DEV */
|
||||
unsigned long offset; /* offset into disk */
|
||||
unsigned long size; /* size of this extent */
|
||||
} extent_t;
|
||||
|
||||
typedef struct segment
|
||||
{
|
||||
int mode; /* UNUSED, RO, or RW */
|
||||
int domain;
|
||||
int segment_number; /* segment number for domain */
|
||||
char key[XEN_SEGMENT_KEYSIZE]; /* for the userspace tools in dom0 */
|
||||
int num_extents; /* number of extents */
|
||||
extent_t *extents;
|
||||
} segment_t;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
** include/xeno/vbd.h:
|
||||
** -- xen internal declarations + prototypes for virtual block devices
|
||||
**
|
||||
*/
|
||||
#ifndef __VBD_H__
|
||||
#define __VBD_H__
|
||||
|
||||
#include <hypervisor-ifs/block.h>
|
||||
#include <hypervisor-ifs/vbd.h>
|
||||
|
||||
/* Describes a physical disk extent. */
|
||||
typedef struct {
|
||||
unsigned short dev;
|
||||
unsigned short nr_sects;
|
||||
unsigned long sector_number;
|
||||
unsigned long buffer;
|
||||
} phys_seg_t;
|
||||
|
||||
struct task_struct;
|
||||
|
||||
void xen_vbd_initialize(void);
|
||||
void xen_refresh_vbd_list (struct task_struct *p);
|
||||
int xen_vbd_create(xv_disk_t *xvd);
|
||||
int xen_vbd_delete(struct task_struct *p, int segnr);
|
||||
int xen_vbd_map_request(
|
||||
phys_seg_t *pseg, struct task_struct *p, int operation,
|
||||
unsigned short vbd_number,
|
||||
unsigned long sect_nr, unsigned long buffer, unsigned short nr_sects);
|
||||
|
||||
typedef struct vbd
|
||||
{
|
||||
int mode; /* UNUSED, RO, or RW */
|
||||
int domain;
|
||||
int vbd_number; /* vbd number for domain */
|
||||
char key[XEN_VBD_KEYSIZE]; /* for the userspace tools in dom0 */
|
||||
int num_extents; /* number of extents */
|
||||
extent_t *extents;
|
||||
} vbd_t;
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef PHYSDISK_ACES__
|
||||
#define PHYSDISK_ACES__
|
||||
|
||||
struct task_struct;
|
||||
|
||||
void destroy_physdisk_aces(struct task_struct *p);
|
||||
|
||||
int xen_physdisk_grant(xp_disk_t *);
|
||||
int xen_physdisk_probe(struct task_struct *requesting_task,
|
||||
physdisk_probebuf_t *);
|
||||
int xen_physdisk_access_okay(phys_seg_t *pseg, struct task_struct *p,
|
||||
int operation);
|
||||
|
||||
#endif /* PHYSDISK_ACES__ */
|
||||
@@ -1,3 +1,3 @@
|
||||
O_TARGET := blk.o
|
||||
obj-y := xl_block.o xl_ide.o xl_scsi.o xl_segment.o xl_segment_proc.o info.o
|
||||
obj-y := xl_block.o xl_ide.o xl_scsi.o xl_vbd.o info.o
|
||||
include $(TOPDIR)/Rules.make
|
||||
@@ -38,9 +38,14 @@ static unsigned long sg_next_sect;
|
||||
|
||||
static inline void signal_requests_to_xen(void)
|
||||
{
|
||||
block_io_op_t op;
|
||||
|
||||
DISABLE_SCATTERGATHER();
|
||||
blk_ring->req_prod = req_prod;
|
||||
HYPERVISOR_block_io_op(BLKOP_PUSH_BUFFERS);
|
||||
|
||||
op.cmd = BLOCK_IO_OP_SIGNAL;
|
||||
HYPERVISOR_block_io_op(&op);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -117,7 +122,7 @@ static inline struct gendisk *xldev_to_gendisk(kdev_t xldev)
|
||||
break;
|
||||
|
||||
case XLVIRT_MAJOR:
|
||||
gd = xlsegment_gendisk;
|
||||
gd = xlvbd_gendisk;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -194,8 +199,8 @@ int xenolinux_block_ioctl(struct inode *inode, struct file *filep,
|
||||
|
||||
case XLVIRT_MAJOR:
|
||||
DPRINTK_IOCTL(" BLKSSZGET: %x 0x%x\n", BLKSSZGET,
|
||||
xlsegment_hwsect(MINOR(dev)));
|
||||
return xlsegment_hwsect(MINOR(dev));
|
||||
xlsbd_hwsect(MINOR(dev)));
|
||||
return xlvbd_hwsect(MINOR(dev));
|
||||
|
||||
default:
|
||||
printk(KERN_ALERT "BLKSSZGET ioctl() on bogus disk!\n");
|
||||
@@ -289,7 +294,7 @@ int xenolinux_block_revalidate(kdev_t dev)
|
||||
if ( xdi != NULL )
|
||||
{
|
||||
memset(xdi, 0, sizeof(*xdi));
|
||||
xenolinux_control_msg(XEN_BLOCK_PROBE_SEG,
|
||||
xenolinux_control_msg(XEN_BLOCK_PROBE,
|
||||
(char *)xdi, sizeof(*xdi));
|
||||
for ( i = 0; i < xdi->count; i++ )
|
||||
if ( IS_VIRTUAL_XENDEV(xdi->disks[i].device) &&
|
||||
@@ -313,7 +318,7 @@ int xenolinux_block_revalidate(kdev_t dev)
|
||||
* request block io
|
||||
*
|
||||
* id: for guest use only.
|
||||
* operation: XEN_BLOCK_{READ,WRITE,PROBE*,SEG*}
|
||||
* operation: XEN_BLOCK_{READ,WRITE,PROBE,VBD*}
|
||||
* buffer: buffer to read/write into. this should be a
|
||||
* virtual address in the guest os.
|
||||
*/
|
||||
@@ -335,13 +340,11 @@ static int hypervisor_request(unsigned long id,
|
||||
|
||||
switch ( operation )
|
||||
{
|
||||
case XEN_BLOCK_SEG_CREATE:
|
||||
case XEN_BLOCK_SEG_DELETE:
|
||||
case XEN_BLOCK_VBD_CREATE:
|
||||
case XEN_BLOCK_VBD_DELETE:
|
||||
case XEN_BLOCK_PHYSDEV_GRANT:
|
||||
case XEN_BLOCK_PHYSDEV_PROBE:
|
||||
case XEN_BLOCK_PROBE_BLK:
|
||||
case XEN_BLOCK_PROBE_SEG:
|
||||
case XEN_BLOCK_PROBE_SEG_ALL:
|
||||
case XEN_BLOCK_PROBE:
|
||||
if ( RING_FULL ) return 1;
|
||||
phys_device = (kdev_t) 0;
|
||||
sector_number = 0;
|
||||
@@ -495,8 +498,8 @@ static void xlblk_response_int(int irq, void *dev_id, struct pt_regs *ptregs)
|
||||
case XEN_BLOCK_READ:
|
||||
case XEN_BLOCK_WRITE:
|
||||
if ( bret->status )
|
||||
printk("Bad return from blkdev data request: %lx\n",
|
||||
bret->status);
|
||||
DPRINTK("Bad return from blkdev data request: %lx\n",
|
||||
bret->status);
|
||||
for ( bh = (struct buffer_head *)bret->id;
|
||||
bh != NULL;
|
||||
bh = next_bh )
|
||||
@@ -507,11 +510,9 @@ static void xlblk_response_int(int irq, void *dev_id, struct pt_regs *ptregs)
|
||||
}
|
||||
break;
|
||||
|
||||
case XEN_BLOCK_SEG_CREATE:
|
||||
case XEN_BLOCK_SEG_DELETE:
|
||||
case XEN_BLOCK_PROBE_SEG:
|
||||
case XEN_BLOCK_PROBE_SEG_ALL:
|
||||
case XEN_BLOCK_PROBE_BLK:
|
||||
case XEN_BLOCK_VBD_CREATE:
|
||||
case XEN_BLOCK_VBD_DELETE:
|
||||
case XEN_BLOCK_PROBE:
|
||||
case XEN_BLOCK_PHYSDEV_GRANT:
|
||||
case XEN_BLOCK_PHYSDEV_PROBE:
|
||||
xlblk_control_msg_pending = bret->status;
|
||||
@@ -570,7 +571,7 @@ int xenolinux_control_msg(int operation, char *buffer, int size)
|
||||
|
||||
int __init xlblk_init(void)
|
||||
{
|
||||
int error;
|
||||
int error;
|
||||
|
||||
xlblk_control_msg_pending = 0;
|
||||
nr_pending = 0;
|
||||
@@ -589,7 +590,7 @@ int __init xlblk_init(void)
|
||||
|
||||
/* Probe for disk information. */
|
||||
memset(&xlblk_disk_info, 0, sizeof(xlblk_disk_info));
|
||||
error = xenolinux_control_msg(XEN_BLOCK_PROBE_BLK,
|
||||
error = xenolinux_control_msg(XEN_BLOCK_PROBE,
|
||||
(char *)&xlblk_disk_info,
|
||||
sizeof(xen_disk_info_t));
|
||||
if ( error )
|
||||
@@ -599,10 +600,26 @@ int __init xlblk_init(void)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
{
|
||||
int i;
|
||||
printk(KERN_ALERT "xlblk_init: xen returned info for %d disks\n",
|
||||
xlblk_disk_info.count);
|
||||
for(i=0; i < xlblk_disk_info.count; i++) {
|
||||
printk("%d -- device no=%x, type=%d, capacity=%ldMB\n",
|
||||
i, xlblk_disk_info.disks[i].device,
|
||||
xlblk_disk_info.disks[i].type,
|
||||
xlblk_disk_info.disks[i].capacity >> 11);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
/* Pass the information to our fake IDE and SCSI susbystems. */
|
||||
xlide_init(&xlblk_disk_info);
|
||||
xlscsi_init(&xlblk_disk_info);
|
||||
|
||||
/* And do the same for the 'virtual block device' world */
|
||||
xlvbd_init(&xlblk_disk_info);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
@@ -611,8 +628,9 @@ int __init xlblk_init(void)
|
||||
|
||||
static void __exit xlblk_cleanup(void)
|
||||
{
|
||||
xlide_cleanup();
|
||||
xlvbd_cleanup();
|
||||
xlscsi_cleanup();
|
||||
xlide_cleanup();
|
||||
free_irq(XLBLK_RESPONSE_IRQ, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/major.h>
|
||||
|
||||
#include <asm/hypervisor-ifs/block.h>
|
||||
#include <asm/hypervisor-ifs/hypervisor-if.h>
|
||||
#include <asm/hypervisor-ifs/vbd.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/atomic.h>
|
||||
#include <asm/uaccess.h>
|
||||
@@ -101,8 +101,10 @@ extern void xlscsi_cleanup(void);
|
||||
extern struct gendisk *xlscsi_gendisk;
|
||||
|
||||
/* Virtual block-device subsystem. */
|
||||
extern int xlsegment_hwsect(int minor);
|
||||
extern struct gendisk *xlsegment_gendisk;
|
||||
extern int xlvbd_init(xen_disk_info_t *xdi);
|
||||
extern int xlvbd_hwsect(int minor);
|
||||
extern void xlvbd_cleanup(void);
|
||||
extern struct gendisk *xlvbd_gendisk;
|
||||
|
||||
extern unsigned short xldev_to_physdev(kdev_t xldev);
|
||||
extern kdev_t physdev_to_xldev(unsigned short physdev);
|
||||
|
||||
@@ -1,337 +0,0 @@
|
||||
/*
|
||||
* xl_segment_proc.c
|
||||
*
|
||||
* XenoLinux virtual disk proc interface .
|
||||
*/
|
||||
|
||||
#include "xl_block.h"
|
||||
#include <asm/xeno_proc.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <asm/hypervisor-ifs/segment.h>
|
||||
|
||||
static struct proc_dir_entry *vhd;
|
||||
|
||||
static void *proc_vhd_next(struct seq_file *s, void *v, loff_t *pos)
|
||||
{
|
||||
xen_segment_info_t *data;
|
||||
|
||||
if ( pos != NULL )
|
||||
++(*pos);
|
||||
|
||||
data = v;
|
||||
return data->count-- ? NULL : v;
|
||||
}
|
||||
|
||||
static void *proc_vhd_start(struct seq_file *s, loff_t *ppos)
|
||||
{
|
||||
loff_t pos = *ppos;
|
||||
xen_segment_info_t *data;
|
||||
|
||||
data = kmalloc(sizeof(*data), GFP_KERNEL);
|
||||
xenolinux_control_msg(XEN_BLOCK_PROBE_SEG_ALL, (char *)data, sizeof(*data));
|
||||
data->count -= pos;
|
||||
|
||||
if (data->count > 0)
|
||||
return data;
|
||||
|
||||
kfree(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int proc_vhd_show(struct seq_file *s, void *v)
|
||||
{
|
||||
xen_segment_info_t *data = v;
|
||||
|
||||
seq_printf (s,
|
||||
"%x %x %10.10s %x\n",
|
||||
data->segments[data->count - 1].domain,
|
||||
data->segments[data->count - 1].seg_nr,
|
||||
data->segments[data->count - 1].key,
|
||||
data->segments[data->count - 1].mode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void proc_vhd_stop(struct seq_file *s, void *v)
|
||||
{
|
||||
kfree(v);
|
||||
}
|
||||
|
||||
static struct seq_operations proc_vhd_op = {
|
||||
.start = proc_vhd_start,
|
||||
.next = proc_vhd_next,
|
||||
.show = proc_vhd_show,
|
||||
.stop = proc_vhd_stop
|
||||
};
|
||||
|
||||
static int proc_open_vhd(struct inode *inode, struct file *file)
|
||||
{
|
||||
return seq_open(file, &proc_vhd_op);
|
||||
}
|
||||
|
||||
|
||||
#define isdelim(c) \
|
||||
(c==' '||c==','||c=='\n'||c=='\r'||c=='\t'||c==':'||c=='('||c==')' ? 1 : 0)
|
||||
|
||||
char *get_string(char *string) /* a bit like strtok */
|
||||
{
|
||||
static char *temp;
|
||||
int loop = 0;
|
||||
|
||||
if (string != NULL)
|
||||
temp = string;
|
||||
else
|
||||
string = temp;
|
||||
|
||||
try_again:
|
||||
|
||||
while (!isdelim(string[loop]))
|
||||
{
|
||||
if (string[loop] == '\0')
|
||||
return NULL;
|
||||
loop++;
|
||||
}
|
||||
|
||||
string[loop] = '\0';
|
||||
temp = (string + loop + 1);
|
||||
|
||||
if (loop == 0)
|
||||
{
|
||||
string = temp;
|
||||
goto try_again;
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
|
||||
#define isdigit(c) (c >= '0' && c <= '9' ? 1 : 0)
|
||||
unsigned long to_number(char *string) /* atoi */
|
||||
{
|
||||
unsigned long value = 0;
|
||||
|
||||
if (string == NULL) return 0;
|
||||
|
||||
while (!isdigit(*string) && *string != '\0') string++;
|
||||
|
||||
while (isdigit(*string))
|
||||
{
|
||||
value = value * 10 + (*string - '0');
|
||||
string++;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static int proc_write_vhd(struct file *file, const char *buffer,
|
||||
size_t count, loff_t *offp)
|
||||
{
|
||||
char *local = kmalloc((count + 1) * sizeof(char), GFP_KERNEL);
|
||||
char *string;
|
||||
int loop;
|
||||
xv_disk_t xvd;
|
||||
int res;
|
||||
|
||||
if( !(start_info.flags & SIF_PRIVILEGED) )
|
||||
return -EPERM;
|
||||
|
||||
if (!local)
|
||||
return -ENOMEM;
|
||||
|
||||
memset (&xvd, 0, sizeof(xvd));
|
||||
|
||||
if (copy_from_user(local, buffer, count))
|
||||
{
|
||||
res = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
local[count] = '\0';
|
||||
|
||||
res = count;
|
||||
string = get_string(local); /* domain specifier */
|
||||
if (string == NULL)
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
if (*string != 'd' && *string != 'D')
|
||||
{
|
||||
printk (KERN_ALERT
|
||||
"error: domain specifier missing [%s]. should be \"domain\".\n",
|
||||
string);
|
||||
goto out;
|
||||
}
|
||||
|
||||
string = get_string(NULL); /* domain number */
|
||||
if (string == NULL)
|
||||
{
|
||||
printk (KERN_ALERT "error: domain number missing\n");
|
||||
goto out;
|
||||
}
|
||||
xvd.domain = (int) to_number(string);
|
||||
|
||||
string = get_string(NULL);
|
||||
if (string && (strcmp(string, "RO") == 0 || strcmp(string, "ro") == 0))
|
||||
{
|
||||
xvd.mode = XEN_DISK_READ_ONLY;
|
||||
}
|
||||
else if (string && (strcmp(string, "RW") == 0 || strcmp(string, "rw") == 0))
|
||||
{
|
||||
xvd.mode = XEN_DISK_READ_WRITE;
|
||||
}
|
||||
else
|
||||
{
|
||||
printk (KERN_ALERT
|
||||
"error: bad mode [%s]. should be \"rw\" or \"ro\".\n",
|
||||
string);
|
||||
goto out;
|
||||
}
|
||||
|
||||
string = get_string(NULL); /* look for Segment */
|
||||
if (string == NULL || (*string != 's' && *string != 'S'))
|
||||
{
|
||||
printk (KERN_ALERT
|
||||
"error: segment specifier missing [%s]. should be \"segment\".\n",
|
||||
string);
|
||||
goto out;
|
||||
}
|
||||
|
||||
string = get_string(NULL); /* segment number */
|
||||
if (string == NULL)
|
||||
{
|
||||
printk (KERN_ALERT "error: segment number missing\n");
|
||||
goto out;
|
||||
}
|
||||
xvd.segment = (int) to_number(string);
|
||||
|
||||
string = get_string(NULL); /* look for key */
|
||||
if (string == NULL || (*string != 'k' && *string != 'K'))
|
||||
{
|
||||
printk (KERN_ALERT
|
||||
"error: key specifier missing [%s]. should be \"key\".\n",
|
||||
string);
|
||||
goto out;
|
||||
}
|
||||
string = get_string(NULL);
|
||||
if (string == NULL || strlen(string) != XEN_SEGMENT_KEYSIZE)
|
||||
{
|
||||
printk (KERN_ALERT "error: key missing\n");
|
||||
goto out;
|
||||
}
|
||||
memcpy(xvd.key, string, XEN_SEGMENT_KEYSIZE);
|
||||
|
||||
string = get_string(NULL); /* look for Extents */
|
||||
if (string == NULL || (*string != 'e' && *string != 'E'))
|
||||
{
|
||||
printk (KERN_ALERT
|
||||
"error: extents specifier missing [%s]. should be \"extents\".\n",
|
||||
string);
|
||||
goto out;
|
||||
}
|
||||
|
||||
string = get_string(NULL); /* number of extents */
|
||||
if (string == NULL)
|
||||
{
|
||||
printk (KERN_ALERT "error: number of extents missing\n");
|
||||
goto out;
|
||||
}
|
||||
xvd.ext_count = (int) to_number(string);
|
||||
|
||||
/* ignore parenthesis */
|
||||
|
||||
for (loop = 0; loop < xvd.ext_count; loop++)
|
||||
{
|
||||
string = get_string(NULL); /* look for Disk */
|
||||
if (string == NULL || (*string != 'd' && *string != 'D'))
|
||||
{
|
||||
printk (KERN_ALERT
|
||||
"hmm, extent disk specifier missing [%s]. should be \"disk\".\n",
|
||||
string);
|
||||
goto out;
|
||||
}
|
||||
string = get_string(NULL); /* disk number */
|
||||
if (string == NULL)
|
||||
{
|
||||
printk (KERN_ALERT "error: disk number missing\n");
|
||||
goto out;
|
||||
}
|
||||
xvd.extents[loop].disk = xldev_to_physdev((int) to_number(string));
|
||||
|
||||
string = get_string(NULL); /* look for Offset */
|
||||
if (string == NULL || (*string != 'o' && *string != 'O'))
|
||||
{
|
||||
printk (KERN_ALERT
|
||||
"error: disk offset missing [%s]. should be \"offset\".\n",
|
||||
string);
|
||||
goto out;
|
||||
}
|
||||
string = get_string(NULL); /* offset */
|
||||
if (string == NULL)
|
||||
{
|
||||
printk (KERN_ALERT "error: offset missing\n");
|
||||
goto out;
|
||||
}
|
||||
xvd.extents[loop].offset = to_number(string);
|
||||
|
||||
string = get_string(NULL); /* look for Size */
|
||||
if (string == NULL || (*string != 's' && *string != 'S'))
|
||||
{
|
||||
printk (KERN_ALERT
|
||||
"error: extent size missing [%s]. should be \"size\".\n",
|
||||
string);
|
||||
goto out;
|
||||
}
|
||||
string = get_string(NULL); /* size */
|
||||
if (string == NULL)
|
||||
{
|
||||
printk (KERN_ALERT "error: extent size missing\n");
|
||||
goto out;
|
||||
}
|
||||
xvd.extents[loop].size = to_number(string);
|
||||
}
|
||||
|
||||
xenolinux_control_msg(XEN_BLOCK_SEG_CREATE, (char *)&xvd, sizeof(xvd));
|
||||
|
||||
out:
|
||||
kfree(local);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static struct file_operations proc_vhd_operations = {
|
||||
open: proc_open_vhd,
|
||||
read: seq_read,
|
||||
llseek: seq_lseek,
|
||||
release: seq_release,
|
||||
write: proc_write_vhd
|
||||
};
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
int __init xlseg_proc_init(void)
|
||||
{
|
||||
if ( !(start_info.flags & SIF_PRIVILEGED) )
|
||||
return 0;
|
||||
|
||||
vhd = create_xeno_proc_entry("vhd", 0600);
|
||||
if ( vhd == NULL )
|
||||
panic ("xlseg_init: unable to create vhd proc entry\n");
|
||||
|
||||
vhd->data = NULL;
|
||||
vhd->proc_fops = &proc_vhd_operations;
|
||||
vhd->owner = THIS_MODULE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit xlseg_proc_cleanup(void)
|
||||
{
|
||||
if ( vhd == NULL ) return;
|
||||
remove_xeno_proc_entry("vhd");
|
||||
vhd = NULL;
|
||||
}
|
||||
|
||||
#ifdef MODULE
|
||||
module_init(xlseg_proc_init);
|
||||
module_exit(xlseg_proc_cleanup);
|
||||
#endif
|
||||
+28
-42
@@ -1,5 +1,5 @@
|
||||
/******************************************************************************
|
||||
* xl_segment.c
|
||||
* xl_vbd.c
|
||||
*
|
||||
* Xenolinux virtual block-device driver (xvd).
|
||||
*
|
||||
@@ -15,15 +15,13 @@ typedef unsigned char byte;
|
||||
|
||||
#define XLVIRT_MAX 256
|
||||
#define XLVIRT_MAJOR_NAME "xvd"
|
||||
static int xlseg_blksize_size[XLVIRT_MAX];
|
||||
static int xlseg_hardsect_size[XLVIRT_MAX];
|
||||
static int xlseg_max_sectors[XLVIRT_MAX];
|
||||
static int xlvbd_blksize_size[XLVIRT_MAX];
|
||||
static int xlvbd_hardsect_size[XLVIRT_MAX];
|
||||
static int xlvbd_max_sectors[XLVIRT_MAX];
|
||||
|
||||
struct gendisk *xlsegment_gendisk = NULL;
|
||||
struct gendisk *xlvbd_gendisk = NULL;
|
||||
|
||||
static xen_disk_info_t xlseg_disk_info;
|
||||
|
||||
static struct block_device_operations xlsegment_block_fops =
|
||||
static struct block_device_operations xlvbd_block_fops =
|
||||
{
|
||||
open: xenolinux_block_open,
|
||||
release: xenolinux_block_release,
|
||||
@@ -33,51 +31,39 @@ static struct block_device_operations xlsegment_block_fops =
|
||||
};
|
||||
|
||||
|
||||
int xlsegment_hwsect(int minor)
|
||||
int xlvbd_hwsect(int minor)
|
||||
{
|
||||
return xlseg_hardsect_size[minor];
|
||||
return xlvbd_hardsect_size[minor];
|
||||
}
|
||||
|
||||
|
||||
int __init xlseg_init(void)
|
||||
int __init xlvbd_init(xen_disk_info_t *xdi)
|
||||
{
|
||||
int i, result, units, minors, disk;
|
||||
xen_disk_info_t *xdi = &xlseg_disk_info;
|
||||
struct gendisk *gd;
|
||||
|
||||
SET_MODULE_OWNER(&xlsegment_block_fops);
|
||||
|
||||
/* Probe for disk information. */
|
||||
memset(xdi, 0, sizeof(*xdi));
|
||||
xenolinux_control_msg(XEN_BLOCK_PROBE_SEG, (char *)xdi, sizeof(*xdi));
|
||||
|
||||
DPRINTK("xvd block device probe:\n");
|
||||
for ( i = 0; i < xdi->count; i++ )
|
||||
{
|
||||
DPRINTK(" %2d: device: %d, capacity: %ld\n",
|
||||
i, xdi->disks[i].device, xdi->disks[i].capacity);
|
||||
}
|
||||
SET_MODULE_OWNER(&xlvbd_block_fops);
|
||||
|
||||
result = register_blkdev(XLVIRT_MAJOR, XLVIRT_MAJOR_NAME,
|
||||
&xlsegment_block_fops);
|
||||
&xlvbd_block_fops);
|
||||
if ( result < 0 )
|
||||
{
|
||||
printk(KERN_ALERT "XL Segment: can't get major %d\n", XLVIRT_MAJOR);
|
||||
printk(KERN_ALERT "XL VBD: can't get major %d\n", XLVIRT_MAJOR);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Initialize global arrays. */
|
||||
for (i = 0; i < XLVIRT_MAX; i++)
|
||||
{
|
||||
xlseg_blksize_size[i] = 512;
|
||||
xlseg_hardsect_size[i] = 512;
|
||||
xlseg_max_sectors[i] = 128;
|
||||
xlvbd_blksize_size[i] = 512;
|
||||
xlvbd_hardsect_size[i] = 512;
|
||||
xlvbd_max_sectors[i] = 128;
|
||||
}
|
||||
|
||||
blk_size[XLVIRT_MAJOR] = NULL;
|
||||
blksize_size[XLVIRT_MAJOR] = xlseg_blksize_size;
|
||||
hardsect_size[XLVIRT_MAJOR] = xlseg_hardsect_size;
|
||||
max_sectors[XLVIRT_MAJOR] = xlseg_max_sectors;
|
||||
blksize_size[XLVIRT_MAJOR] = xlvbd_blksize_size;
|
||||
hardsect_size[XLVIRT_MAJOR] = xlvbd_hardsect_size;
|
||||
max_sectors[XLVIRT_MAJOR] = xlvbd_max_sectors;
|
||||
read_ahead[XLVIRT_MAJOR] = 8;
|
||||
|
||||
blk_init_queue(BLK_DEFAULT_QUEUE(XLVIRT_MAJOR), do_xlblk_request);
|
||||
@@ -102,7 +88,7 @@ int __init xlseg_init(void)
|
||||
gd->nr_real = units;
|
||||
gd->real_devices = kmalloc(units * sizeof(xl_disk_t), GFP_KERNEL);
|
||||
gd->next = NULL;
|
||||
gd->fops = &xlsegment_block_fops;
|
||||
gd->fops = &xlvbd_block_fops;
|
||||
gd->de_arr = kmalloc(sizeof(*gd->de_arr) * units, GFP_KERNEL);
|
||||
gd->flags = kmalloc(sizeof(*gd->flags) * units, GFP_KERNEL);
|
||||
memset(gd->sizes, 0, minors * sizeof(int));
|
||||
@@ -110,7 +96,7 @@ int __init xlseg_init(void)
|
||||
memset(gd->de_arr, 0, sizeof(*gd->de_arr) * units);
|
||||
memset(gd->flags, 0, sizeof(*gd->flags) * units);
|
||||
memset(gd->real_devices, 0, sizeof(xl_disk_t) * units);
|
||||
xlsegment_gendisk = gd;
|
||||
xlvbd_gendisk = gd;
|
||||
add_gendisk(gd);
|
||||
|
||||
/* Now register each disk in turn. */
|
||||
@@ -127,25 +113,25 @@ int __init xlseg_init(void)
|
||||
register_disk(gd,
|
||||
MKDEV(XLVIRT_MAJOR, disk<<XLVIRT_PARTN_SHIFT),
|
||||
1<<XLVIRT_PARTN_SHIFT,
|
||||
&xlsegment_block_fops,
|
||||
&xlvbd_block_fops,
|
||||
xdi->disks[i].capacity);
|
||||
}
|
||||
|
||||
printk(KERN_ALERT
|
||||
"XenoLinux Virtual Segment Device Driver installed [device: %d]\n",
|
||||
"XenoLinux Virtual Block Device Driver installed [device: %d]\n",
|
||||
XLVIRT_MAJOR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void __exit xlseg_cleanup(void)
|
||||
void xlvbd_cleanup(void)
|
||||
{
|
||||
if ( xlsegment_gendisk == NULL ) return;
|
||||
if ( xlvbd_gendisk == NULL ) return;
|
||||
|
||||
blk_cleanup_queue(BLK_DEFAULT_QUEUE(XLVIRT_MAJOR));
|
||||
|
||||
xlsegment_gendisk = NULL;
|
||||
xlvbd_gendisk = NULL;
|
||||
|
||||
read_ahead[XLVIRT_MAJOR] = 0;
|
||||
|
||||
@@ -170,13 +156,13 @@ static void __exit xlseg_cleanup(void)
|
||||
if ( unregister_blkdev(XLVIRT_MAJOR, XLVIRT_MAJOR_NAME) != 0 )
|
||||
{
|
||||
printk(KERN_ALERT
|
||||
"XenoLinux Virtual Segment Device Driver"
|
||||
"XenoLinux Virtual Block Device Driver"
|
||||
" uninstalled w/ errs\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef MODULE
|
||||
module_init(xlseg_init);
|
||||
module_exit(xlseg_cleanup);
|
||||
module_init(xlvbd_init);
|
||||
module_exit(xlvbd_cleanup);
|
||||
#endif
|
||||
@@ -1598,8 +1598,6 @@ int __init blk_dev_init(void)
|
||||
|
||||
#ifdef CONFIG_XENOLINUX_BLOCK
|
||||
xlblk_init();
|
||||
xlseg_init();
|
||||
xlseg_proc_init();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <linux/blk.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/genhd.h>
|
||||
#include <asm/hypervisor-ifs/block.h>
|
||||
#include <asm/hypervisor-ifs/vbd.h>
|
||||
#include <linux/pagemap.h>
|
||||
|
||||
#include "check.h"
|
||||
|
||||
@@ -57,8 +57,6 @@ extern int tapeblock_init(void);
|
||||
|
||||
#if defined(CONFIG_XENOLINUX_BLOCK)
|
||||
extern int xlblk_init(void);
|
||||
extern int xlseg_init(void);
|
||||
extern int xlseg_proc_init(void);
|
||||
#endif /* CONFIG_ARCH_XENO */
|
||||
|
||||
extern void set_device_ro(kdev_t dev,int flag);
|
||||
|
||||