qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* Re: [Qemu-devel] block composite driver and partition driver
@ 2007-01-31  5:26 jbrown105
  0 siblings, 0 replies; 3+ messages in thread
From: jbrown105 @ 2007-01-31  5:26 UTC (permalink / raw)
  To: qemu-devel

>jma5@umd.edu wrote:
>>I've finally gotten around to working on my multipart driver again.
>
>Why?  I'm new to the list.  Can you elaborate what sorts of things this
>would be used for?  I haven't yet gotten around to writing my per device
>snapshot enablable/specifiable COW tmpfiles patch.  But your code, while
>I have no clue how it might be used, seems like it might interrelate
>with that (or if not, I'm still curious).
>
>-dmc
>

The composite driver lets you split one hard disk image into a bunch of
files.
For example you might wanna split a 100GB hard disk image into 10 images
for
the purpose of having faster backups (you only have to scan 10 GB
instead of
the full 100 GB).

The partition driver lets you use either raw hard disk partitions (such
as
/dev/hda1) or images of partitions directly by generating an MBR for it.

Neither of these is related to the snapshot feature that qcow provides.
I've
never heard of COW tmpfiles but if it is something similar, then my code
will not
be of much use to you.
-- 
  
  jbrown105@speedymail.org

-- 
http://www.fastmail.fm - One of many happy users:
  http://www.fastmail.fm/docs/quotes.html

-- 
  
  jbrown105@speedymail.org

-- 
http://www.fastmail.fm - mmm... Fastmail...

^ permalink raw reply	[flat|nested] 3+ messages in thread
* [Qemu-devel] block composite driver and partition driver
@ 2007-01-30 16:24 jma5
  2007-01-30 22:28 ` Douglas McClendon
  0 siblings, 1 reply; 3+ messages in thread
From: jma5 @ 2007-01-30 16:24 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 683 bytes --]

I've finally gotten around to working on my multipart driver again.

block-composite.c is the basic low level composite image format, which lets you
use a bunch of disk images as a single image.

block-ram.c is a ram block device, with the size of the "image" given in the
number of disk sectors.

block-partition.c is a partition block device that uses the composite driver
to combine partitions together along with a fake mbr that it generates and
stores inside of a ram block device. (It doesn't work yet - for some reason the
number of cylinders being reported to the guest OS is 0.)

--
Infinite complexity begets infinite beauty.
Infinite precision begets infinite perfection.

[-- Attachment #2: block-composite.c --]
[-- Type: text/plain, Size: 6155 bytes --]

/*
 * Block driver to use composite images
 * 
 * Copyright (c) 2007 Jim Brown
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "block_composite.h"

static int composite_probe(const uint8_t *buf, int buf_size, const char *filename)
{
    if (strstart(filename, "composite:", NULL))
        return 100;
    return 0;
}

static int composite_open(BlockDriverState *bs, const char *nfilename, int flags)
{
    BDRVPartState *s = bs->opaque;
    BlockDriverState * slave_bs;
    int previous_start, file_count = 1, i;
    const char * zfilename = &(nfilename[10]), * nptr = zfilename;
    char * filename;

    bs->read_only = 0;
    s->slave_count = 0;
    previous_start = 0;

    while (nptr != NULL)
    {
    	nptr = strchr(nptr, ',')+1;
    	if ((nptr-1) != NULL)
    	{
		file_count++;
	}
	else
	{
		nptr = NULL;
	}
    }
    s->slave_bs = qemu_mallocz(sizeof(SlaveDriverState)*file_count);
    if (s->slave_bs == NULL) return -1;
    nptr = zfilename;

    while (nptr != NULL)
    {
    	nptr = strchr(zfilename, ',')+1;
    	if ((nptr-1) != NULL)
    	{
    		filename = strndup(zfilename, (size_t)((nptr-1)-zfilename));
    		zfilename = nptr;
    	}
    	else
    	{
    		filename = strdup(zfilename);
		nptr = NULL;
    	}

    	slave_bs = qemu_mallocz(sizeof(BlockDriverState));
    	if ((slave_bs == NULL) || (bdrv_open2(slave_bs, filename, 0, NULL) != 0))
    	{
		for (i = 0; i < s->slave_count; i++)
		{
			bdrv_close(s->slave_bs[i].bs);
			qemu_free(s->slave_bs[i].bs);
		}
		qemu_free(s->slave_bs);
    		return -1;
    	}
	free(filename);

    	s->slave_bs[s->slave_count].bs = slave_bs;
    	s->slave_bs[s->slave_count].start_sector = previous_start;
	previous_start = previous_start + s->slave_bs[s->slave_count].bs->total_sectors;
    	s->slave_count++;
    	if (slave_bs->read_only)
	{
    		bs->read_only = 1;
    	}
    }

    bs->total_sectors = previous_start;

    return 0;
}

static int composite_read(BlockDriverState *bs, int64_t sector_num, 
                    uint8_t *buf, int nb_sectors)
{
    BDRVPartState *s = bs->opaque;
    int ret,sstart,send,i;

    sstart = -1;
    for (i = 0; i < s->slave_count; i++)
    {
	    if ((s->slave_bs[i].start_sector +
			    s->slave_bs[i].bs->total_sectors > sector_num)
			    && (s->slave_bs[i].start_sector <= sector_num))
	    {
		    sstart = i;
		    break;
	    }
    }
    if (sstart == -1) return -1;

    send = -1;
    for (i = 0; i < s->slave_count; i++)
    {
	    if((s->slave_bs[i].start_sector + s->slave_bs[i].bs->total_sectors
			    > sector_num+nb_sectors)
			    && (s->slave_bs[i].start_sector
			    <= sector_num+nb_sectors))
	    {
		    send = i;
		    break;
	    }
    }
    if (send == -1) return -1;

    if (sstart > send) return -2; //wtf???

    int a = 0, b = 0, bufpos = 0;
    i = sstart;
    while (i < send)
    {
	    a = s->slave_bs[i].bs->total_sectors;
	    ret = bdrv_read(s->slave_bs[i].bs, sector_num+b, &(buf[bufpos]), a);
	    if (ret != 0) return ret;
	    b = b+a;
	    bufpos = bufpos + (a * 512);
	    i++;
    }
    return bdrv_read(s->slave_bs[send].bs, sector_num+b, &(buf[bufpos]), nb_sectors-b);
}

static int composite_write(BlockDriverState *bs, int64_t sector_num, 
                     const uint8_t *buf, int nb_sectors)
{
    BDRVPartState *s = bs->opaque;
    int ret,sstart,send,i;

    sstart = -1;
    for (i = 0; i < s->slave_count; i++)
    {
	    if ((s->slave_bs[i].start_sector +
			    s->slave_bs[i].bs->total_sectors > sector_num)
			    && (s->slave_bs[i].start_sector <= sector_num))
	    {
		    sstart = i;
		    break;
	    }
    }
    if (sstart == -1) return -1;

    send = -1;
    for (i = 0; i < s->slave_count; i++)
    {
	    if((s->slave_bs[i].start_sector + s->slave_bs[i].bs->total_sectors
			    > sector_num+nb_sectors)
			    && (s->slave_bs[i].start_sector
			    <= sector_num+nb_sectors))
	    {
		    send = i;
		    break;
	    }
    }
    if (send == -1) return -1;

    if (sstart > send) return -2; //wtf???

    int a = 0, b = 0, bufpos = 0;
    i = sstart;
    while (i < send)
    {
	    a = s->slave_bs[i].bs->total_sectors;
	    ret = bdrv_write(s->slave_bs[i].bs, sector_num+b, &(buf[bufpos]), a);
	    if (ret != 0) return ret;
	    b = b+a;
	    bufpos = bufpos + (a * 512);
	    i++;
    }
    i= bdrv_write(s->slave_bs[send].bs, sector_num+b, &(buf[bufpos]), nb_sectors-b);
    return i;
}

static void composite_close(BlockDriverState *bs)
{
    BDRVPartState *s = bs->opaque;
    int i;
    for (i = 0; i < s->slave_count; i++)
    {
        bdrv_close(s->slave_bs[i].bs);
        qemu_free(s->slave_bs[i].bs);
    }
    qemu_free(s->slave_bs);
    s->slave_bs = NULL;
}

static int composite_create(const char *filename, int64_t total_size,
                      const char *backing_file, int flags)
{
    /* what would be the point... just make a raw or qcow */
    return -ENOTSUP;
}

BlockDriver bdrv_composite = {
    "composite",
    sizeof(BDRVPartState),
    composite_probe,
    composite_open,
    composite_read,
    composite_write,
    composite_close,
    composite_create,
    .protocol_name = "composite",
};


[-- Attachment #3: block-ram.c --]
[-- Type: text/plain, Size: 3072 bytes --]

/*
 * Block driver in RAM
 * 
 * Copyright (c) 2007 Jim Boown
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
#include "vl.h"
#include "block_int.h"
#include <assert.h>

#ifndef QEMU_TOOL
#include "exec-all.h"
#endif

typedef struct BDRVRamState {
    char * ram_data;
} BDRVRamState;

static int ram_probe(const uint8_t *buf, int buf_size, const char *filename)
{
    if (strstart(filename, "ram:", NULL))
	    return 100;
    return 0;
}
static int ram_open(BlockDriverState *bs, const char *filename, int flags)
{
    BDRVRamState *s = bs->opaque;

    if (!strstart(filename, "ram:", NULL))
	    return -1;

    int sectnum = atoi(filename+4);
    if (sectnum == 0) return -2;

    s->ram_data = qemu_mallocz(sectnum*512);
    if (s->ram_data == NULL) return -2;
    memset(s->ram_data, ' ', sectnum*512);

    bs->total_sectors = sectnum;
    return 0;
}

static int ram_read(BlockDriverState *bs, int64_t sector_num, 
                     uint8_t *buf, int nb_sectors)
{
    BDRVRamState *s = bs->opaque;
    if (sector_num+nb_sectors >= bs->total_sectors)
	    	return -1;
    memcpy(buf, &(s->ram_data[sector_num*512]), nb_sectors*512);
    return 0;
}

static int ram_write(BlockDriverState *bs, int64_t sector_num, 
                      const uint8_t *buf, int nb_sectors)
{
    BDRVRamState *s = bs->opaque;
    if (sector_num+nb_sectors >= bs->total_sectors)
	    	return -1;
    memcpy(&(s->ram_data[sector_num*512]), buf, nb_sectors*512);
    return 0;
}

static void ram_close(BlockDriverState *bs)
{
    BDRVRamState *s = bs->opaque;
    qemu_free(s->ram_data);
}

static int ram_is_allocated(BlockDriverState *bs,
        int64_t sector_num, int nb_sectors, int* n)
{
    *n = bs->total_sectors - sector_num;
    if (*n > nb_sectors)
        *n = nb_sectors;
    else if (*n < 0)
        return 0;
    return 1;
}

BlockDriver bdrv_ram = {
    "ram",
    sizeof(BDRVRamState),
    ram_probe,
    ram_open,
    ram_read,
    ram_write,
    ram_close,
    NULL,
    NULL,
    ram_is_allocated,
   .protocol_name = "ram",
};

[-- Attachment #4: block_composite.h --]
[-- Type: text/plain, Size: 1508 bytes --]

/*
 * Block driver to use composite images
 * 
 * Copyright (c) 2007 Jim Brown
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
#ifndef BLOCK_COMPOSITE_H
#define BLOCK_COMPOSITE_H

#include "vl.h"
#include "block_int.h"

typedef struct SlaveDriverState {
    BlockDriverState * bs;
    int start_sector;
    int end_sector;
} SlaveDriverState;

typedef struct BDRVPartState {
    SlaveDriverState * slave_bs;
    int slave_count;
} BDRVPartState;

#endif /*BLOCK_COMPOSITE_H*/

[-- Attachment #5: block-partition.c --]
[-- Type: text/plain, Size: 7133 bytes --]

/*
 * Block driver to use partitions as hard disks
 * 
 * Copyright (c) 2007 Jim Brown
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

/* we need this in order to be able to figure out the sizes of the individual partitions */
#include "block_composite.h"

/* in sectors */
#define MBR_SIZE 63

/* ideally this would be dynamically allocated */
#define MAX_PART_STRING 4096

typedef struct CompositeDriverState {
    BlockDriverState * bs;
} CompositeDriverState;

static int partition_probe(const uint8_t *buf, int buf_size, const char *filename)
{
    if (strstart(filename, "partition:", NULL))
        return 100;
    return 0;
}

static int partition_open(BlockDriverState *bs, const char *nfilename, int flags)
{
    CompositeDriverState *s = bs->opaque;
    BlockDriverState * bbs;
    int64_t size, totalsectors;
    int boot_fd, i, partition_count = 0;
    int head, cylinder, sector, oldstart;
    int oldhead, oldcylinder, oldsector;
    int sysid[10]; /* probably only need 4 */
    const char * zfilename = &(nfilename[10]), * nptr = zfilename;
    char * filename, * strerr = (char*)0xF001F001;
    char mbr_data[MBR_SIZE*512], partition_string[MAX_PART_STRING];
    partition_string[0] = '\0';

    strcat(partition_string, "composite:ram:63"); /*63 == MBR_SIZE */
    bs->read_only = 0;

    int n = 0;
    while (nptr != NULL)
    {
    	nptr = strchr(zfilename, ',')+1;
    	if ((nptr-1) != NULL)
    	{
    		filename = strndup(zfilename, (size_t)((nptr-1)-zfilename));
    		zfilename = nptr;
    	}
    	else
    	{
    		filename = strdup(zfilename);
		nptr = NULL;
    	}

	if (strncmp(filename, "sysid=", 6) == 0)
	{
		sysid[partition_count] = (int)strtol(filename+6, (char**)&stderr, 16);

		if (filename+6 == strerr) /* detect error in conversion */
			sysid[partition_count] = 0x0C; /* default to win98 FAT32 */
	}
	else
	{
		/* the string shouldn't start with a ',' */
		if (n)
			strcat(partition_string, ",");
		else
			n = 1;

		strcat(partition_string, filename);
		partition_count ++;
	}
	free(filename);
    }

    s->bs = qemu_mallocz(sizeof(BlockDriverState));
    if (bdrv_open2(s->bs, partition_string, 0, NULL) != 0)
	    return -1;

    bs->total_sectors = s->bs->total_sectors;
    bs->read_only = s->bs->read_only;

    /* get the fake MBR */
    memset(mbr_data, 0, MBR_SIZE*512);
    boot_fd = open("bootmbr.bin", O_RDONLY);
    if (boot_fd == -1)
    {
	    printf("Warning: failed to open bootmbr.bin - MBR will not be bootable\n");
    }
    else
    {
	    if (read(boot_fd, mbr_data, 512) == -1)
	    {
	    	printf("Warning: failed to read bootmbr.bin - MBR will not be bootable\n");
	    }
	    close(boot_fd);
    }

    oldstart = 0x3F; //3F == 63
    oldhead = 0x01;
    oldsector = 0x01;
    oldcylinder = 0x00;
    /* remember that the very first slave in the composite is the ram image **
     * that we're using to store the MBR, so the second slave in the composite
     * is the first partition */
    for (i = 1; i <= partition_count; i++)
    {

    bbs = ((BDRVPartState*)s->bs->opaque)->slave_bs[i+1].bs;
    /* set up c/h/s */
    if (i == partition_count)
    totalsectors = bs->total_sectors;
    else
    totalsectors = bbs->total_sectors;

    size = totalsectors * 512;
    cylinder = size/(63*16);
    head = 16;
    sector = 63;
    /* some bit twiddling here */
    sector = (((cylinder >> 8) & 3) << 6) + sector;

    /* set up fake MBR - each partition entry is 16 bytes long */
    /* start 446 */
    /* first partition is bootable */
    if (i == 0)
    mbr_data[446+(i*16)] = 0x80;
    else
    mbr_data[446+(i*16)] = 0x00;
    /* start head */
    mbr_data[447+(i*16)] = oldhead;
    /* start sector - only first 6 bits */
    mbr_data[448+(i*16)] = oldsector;
    /* start cylinder - this byte plus 2 bits from mbr_data[447] */
    mbr_data[449+(i*16)] = oldcylinder;
    /* system ID */
    mbr_data[450+(i*16)] = 0x0C; /* say we're win98 fat32 */
    /* ending head */
    mbr_data[451+(i*16)] = head;
    /* ending sector */
    mbr_data[452+(i*16)] = sector;
    /* ending cylinder */
    mbr_data[453+(i*16)] = cylinder;
    /* absolute start sector - 4 bytes/DWORD */
    //mbr_data[454+(i*16)] = 0x3F; // 3F = 63
    *((uint32_t*)(mbr_data+454+(i*16))) = cpu_to_le32(oldstart);
    /* absolute total number of sectors - 4 bytes/DWORD */
    *((uint32_t*)(mbr_data+458+(i*16))) = cpu_to_le32(totalsectors);
    /* end 462 */

    oldstart = oldstart + totalsectors;
    oldhead = head;
    oldcylinder = cylinder;
    oldsector = sector;

    oldsector++;
    if (oldsector > 63)
    {
	    oldhead++;
	    oldsector = 0x01;
	    if (oldhead > 16)
	    {
		    oldcylinder++;
		    oldhead = 0x01;
	    }
    }

    }

    /* set the MBR sector signature */
    mbr_data[510] = 0x55;
    mbr_data[511] = 0xAA;

    /* now write it to the ram image */
    bdrv_write(s->bs, 0, mbr_data, MBR_SIZE);

    bs->cyls = cylinder;
    bs->heads = head;
    bs->secs = sector;
    bs->translation = BIOS_ATA_TRANSLATION_NONE;

    return 0;
}

static int partition_read(BlockDriverState *bs, int64_t sector_num, 
                    uint8_t *buf, int nb_sectors)
{
    CompositeDriverState *s = bs->opaque;
    return bdrv_read(s->bs, sector_num, buf, nb_sectors);
}

static int partition_write(BlockDriverState *bs, int64_t sector_num, 
                     const uint8_t *buf, int nb_sectors)
{
    CompositeDriverState *s = bs->opaque;
    return bdrv_write(s->bs, sector_num, buf, nb_sectors);
}

static void partition_close(BlockDriverState *bs)
{
    CompositeDriverState *s = bs->opaque;
    bdrv_close(s->bs);
    qemu_free(s->bs);
    s->bs = NULL;
}

static int partition_create(const char *filename, int64_t total_size,
                      const char *backing_file, int flags)
{
    /* what would be the point... just make a raw or qcow */
    return -ENOTSUP;
}

BlockDriver bdrv_partition = {
    "partition",
    sizeof(CompositeDriverState),
    partition_probe,
    partition_open,
    partition_read,
    partition_write,
    partition_close,
    partition_create,
    .protocol_name = "partition",
};


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2007-01-31  5:26 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-01-31  5:26 [Qemu-devel] block composite driver and partition driver jbrown105
  -- strict thread matches above, loose matches on Subject: below --
2007-01-30 16:24 jma5
2007-01-30 22:28 ` Douglas McClendon

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).