]> git.proxmox.com Git - qemu.git/blobdiff - block/vpc.c
block: take lock around bdrv_write implementations
[qemu.git] / block / vpc.c
index 214e9d121f2e7f0df904eaf8539618ed42851087..74ca64260510d0856c46f238ab44a5edbb9378a6 100644 (file)
@@ -110,8 +110,7 @@ struct vhd_dyndisk_header {
 };
 
 typedef struct BDRVVPCState {
-    BlockDriverState *hd;
-
+    CoMutex lock;
     uint8_t footer_buf[HEADER_SIZE];
     uint64_t free_data_block_offset;
     int max_table_entries;
@@ -158,6 +157,7 @@ static int vpc_open(BlockDriverState *bs, int flags)
     struct vhd_dyndisk_header* dyndisk_header;
     uint8_t buf[HEADER_SIZE];
     uint32_t checksum;
+    int err = -1;
 
     if (bdrv_pread(bs->file, 0, s->footer_buf, HEADER_SIZE) != HEADER_SIZE)
         goto fail;
@@ -178,6 +178,11 @@ static int vpc_open(BlockDriverState *bs, int flags)
     bs->total_sectors = (int64_t)
         be16_to_cpu(footer->cyls) * footer->heads * footer->secs_per_cyl;
 
+    if (bs->total_sectors >= 65535 * 16 * 255) {
+        err = -EFBIG;
+        goto fail;
+    }
+
     if (bdrv_pread(bs->file, be64_to_cpu(footer->data_offset), buf, HEADER_SIZE)
             != HEADER_SIZE)
         goto fail;
@@ -192,7 +197,7 @@ static int vpc_open(BlockDriverState *bs, int flags)
     s->bitmap_size = ((s->block_size / (8 * 512)) + 511) & ~511;
 
     s->max_table_entries = be32_to_cpu(dyndisk_header->max_table_entries);
-    s->pagetable = qemu_malloc(s->max_table_entries * 4);
+    s->pagetable = g_malloc(s->max_table_entries * 4);
 
     s->bat_offset = be64_to_cpu(dyndisk_header->table_offset);
     if (bdrv_pread(bs->file, s->bat_offset, s->pagetable,
@@ -216,15 +221,16 @@ static int vpc_open(BlockDriverState *bs, int flags)
     s->last_bitmap_offset = (int64_t) -1;
 
 #ifdef CACHE
-    s->pageentry_u8 = qemu_malloc(512);
+    s->pageentry_u8 = g_malloc(512);
     s->pageentry_u32 = s->pageentry_u8;
     s->pageentry_u16 = s->pageentry_u8;
     s->last_pagetable = -1;
 #endif
 
+    qemu_co_mutex_init(&s->lock);
     return 0;
  fail:
-    return -1;
+    return err;
 }
 
 /*
@@ -261,7 +267,7 @@ static inline int64_t get_sector_offset(BlockDriverState *bs,
 
         s->last_bitmap_offset = bitmap_offset;
         memset(bitmap, 0xff, s->bitmap_size);
-        bdrv_pwrite(bs->file, bitmap_offset, bitmap, s->bitmap_size);
+        bdrv_pwrite_sync(bs->file, bitmap_offset, bitmap, s->bitmap_size);
     }
 
 //    printf("sector: %" PRIx64 ", index: %x, offset: %x, bioff: %" PRIx64 ", bloff: %" PRIx64 "\n",
@@ -311,7 +317,7 @@ static int rewrite_footer(BlockDriverState* bs)
     BDRVVPCState *s = bs->opaque;
     int64_t offset = s->free_data_block_offset;
 
-    ret = bdrv_pwrite(bs->file, offset, s->footer_buf, HEADER_SIZE);
+    ret = bdrv_pwrite_sync(bs->file, offset, s->footer_buf, HEADER_SIZE);
     if (ret < 0)
         return ret;
 
@@ -346,7 +352,8 @@ static int64_t alloc_block(BlockDriverState* bs, int64_t sector_num)
 
     // Initialize the block's bitmap
     memset(bitmap, 0xff, s->bitmap_size);
-    bdrv_pwrite(bs->file, s->free_data_block_offset, bitmap, s->bitmap_size);
+    bdrv_pwrite_sync(bs->file, s->free_data_block_offset, bitmap,
+        s->bitmap_size);
 
     // Write new footer (the old one will be overwritten)
     s->free_data_block_offset += s->block_size + s->bitmap_size;
@@ -357,7 +364,7 @@ static int64_t alloc_block(BlockDriverState* bs, int64_t sector_num)
     // Write BAT entry to disk
     bat_offset = s->bat_offset + (4 * index);
     bat_value = be32_to_cpu(s->pagetable[index]);
-    ret = bdrv_pwrite(bs->file, bat_offset, &bat_value, 4);
+    ret = bdrv_pwrite_sync(bs->file, bat_offset, &bat_value, 4);
     if (ret < 0)
         goto fail;
 
@@ -371,54 +378,99 @@ fail:
 static int vpc_read(BlockDriverState *bs, int64_t sector_num,
                     uint8_t *buf, int nb_sectors)
 {
+    BDRVVPCState *s = bs->opaque;
     int ret;
     int64_t offset;
+    int64_t sectors, sectors_per_block;
 
     while (nb_sectors > 0) {
         offset = get_sector_offset(bs, sector_num, 0);
 
+        sectors_per_block = s->block_size >> BDRV_SECTOR_BITS;
+        sectors = sectors_per_block - (sector_num % sectors_per_block);
+        if (sectors > nb_sectors) {
+            sectors = nb_sectors;
+        }
+
         if (offset == -1) {
-            memset(buf, 0, 512);
+            memset(buf, 0, sectors * BDRV_SECTOR_SIZE);
         } else {
-            ret = bdrv_pread(bs->file, offset, buf, 512);
-            if (ret != 512)
+            ret = bdrv_pread(bs->file, offset, buf,
+                sectors * BDRV_SECTOR_SIZE);
+            if (ret != sectors * BDRV_SECTOR_SIZE) {
                 return -1;
+            }
         }
 
-        nb_sectors--;
-        sector_num++;
-        buf += 512;
+        nb_sectors -= sectors;
+        sector_num += sectors;
+        buf += sectors * BDRV_SECTOR_SIZE;
     }
     return 0;
 }
 
+static coroutine_fn int vpc_co_read(BlockDriverState *bs, int64_t sector_num,
+                                    uint8_t *buf, int nb_sectors)
+{
+    int ret;
+    BDRVVPCState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = vpc_read(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
+
 static int vpc_write(BlockDriverState *bs, int64_t sector_num,
     const uint8_t *buf, int nb_sectors)
 {
+    BDRVVPCState *s = bs->opaque;
     int64_t offset;
+    int64_t sectors, sectors_per_block;
     int ret;
 
     while (nb_sectors > 0) {
         offset = get_sector_offset(bs, sector_num, 1);
 
+        sectors_per_block = s->block_size >> BDRV_SECTOR_BITS;
+        sectors = sectors_per_block - (sector_num % sectors_per_block);
+        if (sectors > nb_sectors) {
+            sectors = nb_sectors;
+        }
+
         if (offset == -1) {
             offset = alloc_block(bs, sector_num);
             if (offset < 0)
                 return -1;
         }
 
-        ret = bdrv_pwrite(bs->file, offset, buf, 512);
-        if (ret != 512)
+        ret = bdrv_pwrite(bs->file, offset, buf, sectors * BDRV_SECTOR_SIZE);
+        if (ret != sectors * BDRV_SECTOR_SIZE) {
             return -1;
+        }
 
-        nb_sectors--;
-        sector_num++;
-        buf += 512;
+        nb_sectors -= sectors;
+        sector_num += sectors;
+        buf += sectors * BDRV_SECTOR_SIZE;
     }
 
     return 0;
 }
 
+static coroutine_fn int vpc_co_write(BlockDriverState *bs, int64_t sector_num,
+                                     const uint8_t *buf, int nb_sectors)
+{
+    int ret;
+    BDRVVPCState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = vpc_write(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
+
+static int vpc_flush(BlockDriverState *bs)
+{
+    return bdrv_flush(bs->file);
+}
 
 /*
  * Calculates the number of cylinders, heads and sectors per cylinder
@@ -480,14 +532,11 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options)
     uint8_t secs_per_cyl = 0;
     size_t block_size, num_bat_entries;
     int64_t total_sectors = 0;
+    int ret = -EIO;
 
     // Read out options
-    while (options && options->name) {
-        if (!strcmp(options->name, "size")) {
-            total_sectors = options->value.n / 512;
-        }
-        options++;
-    }
+    total_sectors = get_option_parameter(options, BLOCK_OPT_SIZE)->value.n /
+                    BDRV_SECTOR_SIZE;
 
     // Create the file
     fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
@@ -499,7 +548,8 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options)
     for (i = 0; total_sectors > (int64_t)cyls * heads * secs_per_cyl; i++) {
         if (calculate_geometry(total_sectors + i,
                                &cyls, &heads, &secs_per_cyl)) {
-            return -EFBIG;
+            ret = -EFBIG;
+            goto fail;
         }
     }
     total_sectors = (int64_t) cyls * heads * secs_per_cyl;
@@ -538,22 +588,28 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options)
     block_size = 0x200000;
     num_bat_entries = (total_sectors + block_size / 512) / (block_size / 512);
 
-    if (write(fd, buf, HEADER_SIZE) != HEADER_SIZE)
-        return -EIO;
+    if (write(fd, buf, HEADER_SIZE) != HEADER_SIZE) {
+        goto fail;
+    }
 
-    if (lseek(fd, 1536 + ((num_bat_entries * 4 + 511) & ~511), SEEK_SET) < 0)
-        return -EIO;
-    if (write(fd, buf, HEADER_SIZE) != HEADER_SIZE)
-        return -EIO;
+    if (lseek(fd, 1536 + ((num_bat_entries * 4 + 511) & ~511), SEEK_SET) < 0) {
+        goto fail;
+    }
+    if (write(fd, buf, HEADER_SIZE) != HEADER_SIZE) {
+        goto fail;
+    }
 
     // Write the initial BAT
-    if (lseek(fd, 3 * 512, SEEK_SET) < 0)
-        return -EIO;
+    if (lseek(fd, 3 * 512, SEEK_SET) < 0) {
+        goto fail;
+    }
 
     memset(buf, 0xFF, 512);
-    for (i = 0; i < (num_bat_entries * 4 + 511) / 512; i++)
-        if (write(fd, buf, 512) != 512)
-            return -EIO;
+    for (i = 0; i < (num_bat_entries * 4 + 511) / 512; i++) {
+        if (write(fd, buf, 512) != 512) {
+            goto fail;
+        }
+    }
 
 
     // Prepare the Dynamic Disk Header
@@ -570,21 +626,26 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options)
     dyndisk_header->checksum = be32_to_cpu(vpc_checksum(buf, 1024));
 
     // Write the header
-    if (lseek(fd, 512, SEEK_SET) < 0)
-        return -EIO;
-    if (write(fd, buf, 1024) != 1024)
-        return -EIO;
+    if (lseek(fd, 512, SEEK_SET) < 0) {
+        goto fail;
+    }
+
+    if (write(fd, buf, 1024) != 1024) {
+        goto fail;
+    }
+    ret = 0;
 
+ fail:
     close(fd);
-    return 0;
+    return ret;
 }
 
 static void vpc_close(BlockDriverState *bs)
 {
     BDRVVPCState *s = bs->opaque;
-    qemu_free(s->pagetable);
+    g_free(s->pagetable);
 #ifdef CACHE
-    qemu_free(s->pageentry_u8);
+    g_free(s->pageentry_u8);
 #endif
 }
 
@@ -598,14 +659,15 @@ static QEMUOptionParameter vpc_create_options[] = {
 };
 
 static BlockDriver bdrv_vpc = {
-    .format_name       = "vpc",
-    .instance_size     = sizeof(BDRVVPCState),
-    .bdrv_probe                = vpc_probe,
-    .bdrv_open         = vpc_open,
-    .bdrv_read         = vpc_read,
-    .bdrv_write                = vpc_write,
-    .bdrv_close                = vpc_close,
-    .bdrv_create       = vpc_create,
+    .format_name    = "vpc",
+    .instance_size  = sizeof(BDRVVPCState),
+    .bdrv_probe     = vpc_probe,
+    .bdrv_open      = vpc_open,
+    .bdrv_read      = vpc_co_read,
+    .bdrv_write     = vpc_co_write,
+    .bdrv_flush     = vpc_flush,
+    .bdrv_close     = vpc_close,
+    .bdrv_create    = vpc_create,
 
     .create_options = vpc_create_options,
 };