Annotation of qemu/block/cow.c, revision 1.1.1.5

1.1       root        1: /*
                      2:  * Block driver for the COW format
                      3:  *
                      4:  * Copyright (c) 2004 Fabrice Bellard
                      5:  *
                      6:  * Permission is hereby granted, free of charge, to any person obtaining a copy
                      7:  * of this software and associated documentation files (the "Software"), to deal
                      8:  * in the Software without restriction, including without limitation the rights
                      9:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
                     10:  * copies of the Software, and to permit persons to whom the Software is
                     11:  * furnished to do so, subject to the following conditions:
                     12:  *
                     13:  * The above copyright notice and this permission notice shall be included in
                     14:  * all copies or substantial portions of the Software.
                     15:  *
                     16:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
                     17:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
                     19:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
                     20:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
                     21:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
                     22:  * THE SOFTWARE.
                     23:  */
                     24: #include "qemu-common.h"
                     25: #include "block_int.h"
                     26: #include "module.h"
                     27: 
                     28: /**************************************************************/
                     29: /* COW block driver using file system holes */
                     30: 
                     31: /* user mode linux compatible COW file */
                     32: #define COW_MAGIC 0x4f4f4f4d  /* MOOO */
                     33: #define COW_VERSION 2
                     34: 
                     35: struct cow_header_v2 {
                     36:     uint32_t magic;
                     37:     uint32_t version;
                     38:     char backing_file[1024];
                     39:     int32_t mtime;
                     40:     uint64_t size;
                     41:     uint32_t sectorsize;
                     42: };
                     43: 
                     44: typedef struct BDRVCowState {
1.1.1.5 ! root       45:     CoMutex lock;
1.1       root       46:     int64_t cow_sectors_offset;
                     47: } BDRVCowState;
                     48: 
                     49: static int cow_probe(const uint8_t *buf, int buf_size, const char *filename)
                     50: {
                     51:     const struct cow_header_v2 *cow_header = (const void *)buf;
                     52: 
                     53:     if (buf_size >= sizeof(struct cow_header_v2) &&
                     54:         be32_to_cpu(cow_header->magic) == COW_MAGIC &&
                     55:         be32_to_cpu(cow_header->version) == COW_VERSION)
                     56:         return 100;
                     57:     else
                     58:         return 0;
                     59: }
                     60: 
1.1.1.3   root       61: static int cow_open(BlockDriverState *bs, int flags)
1.1       root       62: {
                     63:     BDRVCowState *s = bs->opaque;
                     64:     struct cow_header_v2 cow_header;
1.1.1.3   root       65:     int bitmap_size;
1.1       root       66:     int64_t size;
                     67: 
                     68:     /* see if it is a cow image */
1.1.1.3   root       69:     if (bdrv_pread(bs->file, 0, &cow_header, sizeof(cow_header)) !=
                     70:             sizeof(cow_header)) {
1.1       root       71:         goto fail;
                     72:     }
                     73: 
                     74:     if (be32_to_cpu(cow_header.magic) != COW_MAGIC ||
                     75:         be32_to_cpu(cow_header.version) != COW_VERSION) {
                     76:         goto fail;
                     77:     }
                     78: 
                     79:     /* cow image found */
                     80:     size = be64_to_cpu(cow_header.size);
                     81:     bs->total_sectors = size / 512;
                     82: 
                     83:     pstrcpy(bs->backing_file, sizeof(bs->backing_file),
                     84:             cow_header.backing_file);
                     85: 
1.1.1.3   root       86:     bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
                     87:     s->cow_sectors_offset = (bitmap_size + 511) & ~511;
1.1.1.5 ! root       88:     qemu_co_mutex_init(&s->lock);
1.1       root       89:     return 0;
                     90:  fail:
                     91:     return -1;
                     92: }
                     93: 
1.1.1.3   root       94: /*
                     95:  * XXX(hch): right now these functions are extremly ineffcient.
                     96:  * We should just read the whole bitmap we'll need in one go instead.
                     97:  */
                     98: static inline int cow_set_bit(BlockDriverState *bs, int64_t bitnum)
                     99: {
                    100:     uint64_t offset = sizeof(struct cow_header_v2) + bitnum / 8;
                    101:     uint8_t bitmap;
                    102:     int ret;
                    103: 
                    104:     ret = bdrv_pread(bs->file, offset, &bitmap, sizeof(bitmap));
                    105:     if (ret < 0) {
                    106:        return ret;
                    107:     }
                    108: 
                    109:     bitmap |= (1 << (bitnum % 8));
                    110: 
                    111:     ret = bdrv_pwrite_sync(bs->file, offset, &bitmap, sizeof(bitmap));
                    112:     if (ret < 0) {
                    113:        return ret;
                    114:     }
                    115:     return 0;
1.1       root      116: }
                    117: 
1.1.1.3   root      118: static inline int is_bit_set(BlockDriverState *bs, int64_t bitnum)
1.1       root      119: {
1.1.1.3   root      120:     uint64_t offset = sizeof(struct cow_header_v2) + bitnum / 8;
                    121:     uint8_t bitmap;
                    122:     int ret;
                    123: 
                    124:     ret = bdrv_pread(bs->file, offset, &bitmap, sizeof(bitmap));
                    125:     if (ret < 0) {
                    126:        return ret;
                    127:     }
1.1       root      128: 
1.1.1.3   root      129:     return !!(bitmap & (1 << (bitnum % 8)));
                    130: }
1.1       root      131: 
                    132: /* Return true if first block has been changed (ie. current version is
                    133:  * in COW file).  Set the number of continuous blocks for which that
                    134:  * is true. */
1.1.1.3   root      135: static int cow_is_allocated(BlockDriverState *bs, int64_t sector_num,
                    136:         int nb_sectors, int *num_same)
1.1       root      137: {
                    138:     int changed;
                    139: 
1.1.1.3   root      140:     if (nb_sectors == 0) {
1.1       root      141:        *num_same = nb_sectors;
                    142:        return 0;
                    143:     }
                    144: 
1.1.1.3   root      145:     changed = is_bit_set(bs, sector_num);
                    146:     if (changed < 0) {
                    147:         return 0; /* XXX: how to return I/O errors? */
                    148:     }
                    149: 
1.1       root      150:     for (*num_same = 1; *num_same < nb_sectors; (*num_same)++) {
1.1.1.3   root      151:        if (is_bit_set(bs, sector_num + *num_same) != changed)
1.1       root      152:            break;
                    153:     }
                    154: 
                    155:     return changed;
                    156: }
                    157: 
1.1.1.3   root      158: static int cow_update_bitmap(BlockDriverState *bs, int64_t sector_num,
                    159:         int nb_sectors)
1.1       root      160: {
1.1.1.3   root      161:     int error = 0;
                    162:     int i;
                    163: 
                    164:     for (i = 0; i < nb_sectors; i++) {
                    165:         error = cow_set_bit(bs, sector_num + i);
                    166:         if (error) {
                    167:             break;
                    168:         }
                    169:     }
                    170: 
                    171:     return error;
1.1       root      172: }
                    173: 
                    174: static int cow_read(BlockDriverState *bs, int64_t sector_num,
                    175:                     uint8_t *buf, int nb_sectors)
                    176: {
                    177:     BDRVCowState *s = bs->opaque;
                    178:     int ret, n;
                    179: 
                    180:     while (nb_sectors > 0) {
1.1.1.3   root      181:         if (cow_is_allocated(bs, sector_num, nb_sectors, &n)) {
                    182:             ret = bdrv_pread(bs->file,
                    183:                         s->cow_sectors_offset + sector_num * 512,
                    184:                         buf, n * 512);
1.1       root      185:             if (ret != n * 512)
                    186:                 return -1;
                    187:         } else {
                    188:             if (bs->backing_hd) {
                    189:                 /* read from the base image */
                    190:                 ret = bdrv_read(bs->backing_hd, sector_num, buf, n);
                    191:                 if (ret < 0)
                    192:                     return -1;
                    193:             } else {
                    194:             memset(buf, 0, n * 512);
                    195:         }
                    196:         }
                    197:         nb_sectors -= n;
                    198:         sector_num += n;
                    199:         buf += n * 512;
                    200:     }
                    201:     return 0;
                    202: }
                    203: 
1.1.1.5 ! root      204: static coroutine_fn int cow_co_read(BlockDriverState *bs, int64_t sector_num,
        !           205:                                     uint8_t *buf, int nb_sectors)
        !           206: {
        !           207:     int ret;
        !           208:     BDRVCowState *s = bs->opaque;
        !           209:     qemu_co_mutex_lock(&s->lock);
        !           210:     ret = cow_read(bs, sector_num, buf, nb_sectors);
        !           211:     qemu_co_mutex_unlock(&s->lock);
        !           212:     return ret;
        !           213: }
        !           214: 
1.1       root      215: static int cow_write(BlockDriverState *bs, int64_t sector_num,
                    216:                      const uint8_t *buf, int nb_sectors)
                    217: {
                    218:     BDRVCowState *s = bs->opaque;
1.1.1.3   root      219:     int ret;
1.1       root      220: 
1.1.1.3   root      221:     ret = bdrv_pwrite(bs->file, s->cow_sectors_offset + sector_num * 512,
                    222:                       buf, nb_sectors * 512);
1.1       root      223:     if (ret != nb_sectors * 512)
                    224:         return -1;
1.1.1.3   root      225: 
                    226:     return cow_update_bitmap(bs, sector_num, nb_sectors);
1.1       root      227: }
                    228: 
1.1.1.5 ! root      229: static coroutine_fn int cow_co_write(BlockDriverState *bs, int64_t sector_num,
        !           230:                                      const uint8_t *buf, int nb_sectors)
        !           231: {
        !           232:     int ret;
        !           233:     BDRVCowState *s = bs->opaque;
        !           234:     qemu_co_mutex_lock(&s->lock);
        !           235:     ret = cow_write(bs, sector_num, buf, nb_sectors);
        !           236:     qemu_co_mutex_unlock(&s->lock);
        !           237:     return ret;
        !           238: }
        !           239: 
1.1       root      240: static void cow_close(BlockDriverState *bs)
                    241: {
                    242: }
                    243: 
                    244: static int cow_create(const char *filename, QEMUOptionParameter *options)
                    245: {
                    246:     int fd, cow_fd;
                    247:     struct cow_header_v2 cow_header;
                    248:     struct stat st;
                    249:     int64_t image_sectors = 0;
                    250:     const char *image_filename = NULL;
1.1.1.3   root      251:     int ret;
1.1       root      252: 
                    253:     /* Read out options */
                    254:     while (options && options->name) {
                    255:         if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
                    256:             image_sectors = options->value.n / 512;
                    257:         } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
                    258:             image_filename = options->value.s;
                    259:         }
                    260:         options++;
                    261:     }
                    262: 
                    263:     cow_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
                    264:               0644);
                    265:     if (cow_fd < 0)
1.1.1.3   root      266:         return -errno;
1.1       root      267:     memset(&cow_header, 0, sizeof(cow_header));
                    268:     cow_header.magic = cpu_to_be32(COW_MAGIC);
                    269:     cow_header.version = cpu_to_be32(COW_VERSION);
                    270:     if (image_filename) {
                    271:         /* Note: if no file, we put a dummy mtime */
                    272:         cow_header.mtime = cpu_to_be32(0);
                    273: 
                    274:         fd = open(image_filename, O_RDONLY | O_BINARY);
                    275:         if (fd < 0) {
                    276:             close(cow_fd);
                    277:             goto mtime_fail;
                    278:         }
                    279:         if (fstat(fd, &st) != 0) {
                    280:             close(fd);
                    281:             goto mtime_fail;
                    282:         }
                    283:         close(fd);
                    284:         cow_header.mtime = cpu_to_be32(st.st_mtime);
                    285:     mtime_fail:
                    286:         pstrcpy(cow_header.backing_file, sizeof(cow_header.backing_file),
                    287:                 image_filename);
                    288:     }
                    289:     cow_header.sectorsize = cpu_to_be32(512);
                    290:     cow_header.size = cpu_to_be64(image_sectors * 512);
1.1.1.3   root      291:     ret = qemu_write_full(cow_fd, &cow_header, sizeof(cow_header));
                    292:     if (ret != sizeof(cow_header)) {
                    293:         ret = -errno;
                    294:         goto exit;
                    295:     }
                    296: 
1.1       root      297:     /* resize to include at least all the bitmap */
1.1.1.3   root      298:     ret = ftruncate(cow_fd, sizeof(cow_header) + ((image_sectors + 7) >> 3));
                    299:     if (ret) {
                    300:         ret = -errno;
                    301:         goto exit;
                    302:     }
                    303: 
                    304: exit:
1.1       root      305:     close(cow_fd);
1.1.1.3   root      306:     return ret;
1.1       root      307: }
                    308: 
1.1.1.5 ! root      309: static coroutine_fn int cow_co_flush(BlockDriverState *bs)
1.1       root      310: {
1.1.1.5 ! root      311:     return bdrv_co_flush(bs->file);
1.1       root      312: }
                    313: 
                    314: static QEMUOptionParameter cow_create_options[] = {
                    315:     {
                    316:         .name = BLOCK_OPT_SIZE,
                    317:         .type = OPT_SIZE,
                    318:         .help = "Virtual disk size"
                    319:     },
                    320:     {
                    321:         .name = BLOCK_OPT_BACKING_FILE,
                    322:         .type = OPT_STRING,
                    323:         .help = "File name of a base image"
                    324:     },
                    325:     { NULL }
                    326: };
                    327: 
                    328: static BlockDriver bdrv_cow = {
1.1.1.5 ! root      329:     .format_name    = "cow",
        !           330:     .instance_size  = sizeof(BDRVCowState),
        !           331: 
        !           332:     .bdrv_probe     = cow_probe,
        !           333:     .bdrv_open      = cow_open,
        !           334:     .bdrv_close     = cow_close,
        !           335:     .bdrv_create    = cow_create,
        !           336: 
        !           337:     .bdrv_read              = cow_co_read,
        !           338:     .bdrv_write             = cow_co_write,
        !           339:     .bdrv_co_flush_to_disk  = cow_co_flush,
        !           340:     .bdrv_is_allocated      = cow_is_allocated,
1.1       root      341: 
                    342:     .create_options = cow_create_options,
                    343: };
                    344: 
                    345: static void bdrv_cow_init(void)
                    346: {
                    347:     bdrv_register(&bdrv_cow);
                    348: }
                    349: 
                    350: block_init(bdrv_cow_init);

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.