File:  [Qemu by Fabrice Bellard] / qemu / block-cow.c
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 16:47:01 2018 UTC (3 years, 1 month ago) by root
Branches: qemu, MAIN
CVS tags: qemu0105, qemu0104, qemu0103, qemu0102, qemu0101, qemu0100, qemu0091, HEAD
qemu 0.9.1

    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: #ifndef _WIN32
   25: #include "qemu-common.h"
   26: #include "block_int.h"
   27: #include <sys/mman.h>
   28: 
   29: /**************************************************************/
   30: /* COW block driver using file system holes */
   31: 
   32: /* user mode linux compatible COW file */
   33: #define COW_MAGIC 0x4f4f4f4d  /* MOOO */
   34: #define COW_VERSION 2
   35: 
   36: struct cow_header_v2 {
   37:     uint32_t magic;
   38:     uint32_t version;
   39:     char backing_file[1024];
   40:     int32_t mtime;
   41:     uint64_t size;
   42:     uint32_t sectorsize;
   43: };
   44: 
   45: typedef struct BDRVCowState {
   46:     int fd;
   47:     uint8_t *cow_bitmap; /* if non NULL, COW mappings are used first */
   48:     uint8_t *cow_bitmap_addr; /* mmap address of cow_bitmap */
   49:     int cow_bitmap_size;
   50:     int64_t cow_sectors_offset;
   51: } BDRVCowState;
   52: 
   53: static int cow_probe(const uint8_t *buf, int buf_size, const char *filename)
   54: {
   55:     const struct cow_header_v2 *cow_header = (const void *)buf;
   56: 
   57:     if (buf_size >= sizeof(struct cow_header_v2) &&
   58:         be32_to_cpu(cow_header->magic) == COW_MAGIC &&
   59:         be32_to_cpu(cow_header->version) == COW_VERSION)
   60:         return 100;
   61:     else
   62:         return 0;
   63: }
   64: 
   65: static int cow_open(BlockDriverState *bs, const char *filename, int flags)
   66: {
   67:     BDRVCowState *s = bs->opaque;
   68:     int fd;
   69:     struct cow_header_v2 cow_header;
   70:     int64_t size;
   71: 
   72:     fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
   73:     if (fd < 0) {
   74:         fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
   75:         if (fd < 0)
   76:             return -1;
   77:     }
   78:     s->fd = fd;
   79:     /* see if it is a cow image */
   80:     if (read(fd, &cow_header, sizeof(cow_header)) != sizeof(cow_header)) {
   81:         goto fail;
   82:     }
   83: 
   84:     if (be32_to_cpu(cow_header.magic) != COW_MAGIC ||
   85:         be32_to_cpu(cow_header.version) != COW_VERSION) {
   86:         goto fail;
   87:     }
   88: 
   89:     /* cow image found */
   90:     size = be64_to_cpu(cow_header.size);
   91:     bs->total_sectors = size / 512;
   92: 
   93:     pstrcpy(bs->backing_file, sizeof(bs->backing_file),
   94:             cow_header.backing_file);
   95: 
   96:     /* mmap the bitmap */
   97:     s->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
   98:     s->cow_bitmap_addr = mmap(get_mmap_addr(s->cow_bitmap_size),
   99:                               s->cow_bitmap_size,
  100:                               PROT_READ | PROT_WRITE,
  101:                               MAP_SHARED, s->fd, 0);
  102:     if (s->cow_bitmap_addr == MAP_FAILED)
  103:         goto fail;
  104:     s->cow_bitmap = s->cow_bitmap_addr + sizeof(cow_header);
  105:     s->cow_sectors_offset = (s->cow_bitmap_size + 511) & ~511;
  106:     return 0;
  107:  fail:
  108:     close(fd);
  109:     return -1;
  110: }
  111: 
  112: static inline void cow_set_bit(uint8_t *bitmap, int64_t bitnum)
  113: {
  114:     bitmap[bitnum / 8] |= (1 << (bitnum%8));
  115: }
  116: 
  117: static inline int is_bit_set(const uint8_t *bitmap, int64_t bitnum)
  118: {
  119:     return !!(bitmap[bitnum / 8] & (1 << (bitnum%8)));
  120: }
  121: 
  122: 
  123: /* Return true if first block has been changed (ie. current version is
  124:  * in COW file).  Set the number of continuous blocks for which that
  125:  * is true. */
  126: static inline int is_changed(uint8_t *bitmap,
  127:                              int64_t sector_num, int nb_sectors,
  128:                              int *num_same)
  129: {
  130:     int changed;
  131: 
  132:     if (!bitmap || nb_sectors == 0) {
  133: 	*num_same = nb_sectors;
  134: 	return 0;
  135:     }
  136: 
  137:     changed = is_bit_set(bitmap, sector_num);
  138:     for (*num_same = 1; *num_same < nb_sectors; (*num_same)++) {
  139: 	if (is_bit_set(bitmap, sector_num + *num_same) != changed)
  140: 	    break;
  141:     }
  142: 
  143:     return changed;
  144: }
  145: 
  146: static int cow_is_allocated(BlockDriverState *bs, int64_t sector_num,
  147:                             int nb_sectors, int *pnum)
  148: {
  149:     BDRVCowState *s = bs->opaque;
  150:     return is_changed(s->cow_bitmap, sector_num, nb_sectors, pnum);
  151: }
  152: 
  153: static int cow_read(BlockDriverState *bs, int64_t sector_num,
  154:                     uint8_t *buf, int nb_sectors)
  155: {
  156:     BDRVCowState *s = bs->opaque;
  157:     int ret, n;
  158: 
  159:     while (nb_sectors > 0) {
  160:         if (is_changed(s->cow_bitmap, sector_num, nb_sectors, &n)) {
  161:             lseek(s->fd, s->cow_sectors_offset + sector_num * 512, SEEK_SET);
  162:             ret = read(s->fd, buf, n * 512);
  163:             if (ret != n * 512)
  164:                 return -1;
  165:         } else {
  166:             if (bs->backing_hd) {
  167:                 /* read from the base image */
  168:                 ret = bdrv_read(bs->backing_hd, sector_num, buf, n);
  169:                 if (ret < 0)
  170:                     return -1;
  171:             } else {
  172:             memset(buf, 0, n * 512);
  173:         }
  174:         }
  175:         nb_sectors -= n;
  176:         sector_num += n;
  177:         buf += n * 512;
  178:     }
  179:     return 0;
  180: }
  181: 
  182: static int cow_write(BlockDriverState *bs, int64_t sector_num,
  183:                      const uint8_t *buf, int nb_sectors)
  184: {
  185:     BDRVCowState *s = bs->opaque;
  186:     int ret, i;
  187: 
  188:     lseek(s->fd, s->cow_sectors_offset + sector_num * 512, SEEK_SET);
  189:     ret = write(s->fd, buf, nb_sectors * 512);
  190:     if (ret != nb_sectors * 512)
  191:         return -1;
  192:     for (i = 0; i < nb_sectors; i++)
  193:         cow_set_bit(s->cow_bitmap, sector_num + i);
  194:     return 0;
  195: }
  196: 
  197: static void cow_close(BlockDriverState *bs)
  198: {
  199:     BDRVCowState *s = bs->opaque;
  200:     munmap(s->cow_bitmap_addr, s->cow_bitmap_size);
  201:     close(s->fd);
  202: }
  203: 
  204: static int cow_create(const char *filename, int64_t image_sectors,
  205:                       const char *image_filename, int flags)
  206: {
  207:     int fd, cow_fd;
  208:     struct cow_header_v2 cow_header;
  209:     struct stat st;
  210: 
  211:     if (flags)
  212:         return -ENOTSUP;
  213: 
  214:     cow_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
  215:               0644);
  216:     if (cow_fd < 0)
  217:         return -1;
  218:     memset(&cow_header, 0, sizeof(cow_header));
  219:     cow_header.magic = cpu_to_be32(COW_MAGIC);
  220:     cow_header.version = cpu_to_be32(COW_VERSION);
  221:     if (image_filename) {
  222:         /* Note: if no file, we put a dummy mtime */
  223:         cow_header.mtime = cpu_to_be32(0);
  224: 
  225:         fd = open(image_filename, O_RDONLY | O_BINARY);
  226:         if (fd < 0) {
  227:             close(cow_fd);
  228:             goto mtime_fail;
  229:         }
  230:         if (fstat(fd, &st) != 0) {
  231:             close(fd);
  232:             goto mtime_fail;
  233:         }
  234:         close(fd);
  235:         cow_header.mtime = cpu_to_be32(st.st_mtime);
  236:     mtime_fail:
  237:         pstrcpy(cow_header.backing_file, sizeof(cow_header.backing_file),
  238:                 image_filename);
  239:     }
  240:     cow_header.sectorsize = cpu_to_be32(512);
  241:     cow_header.size = cpu_to_be64(image_sectors * 512);
  242:     write(cow_fd, &cow_header, sizeof(cow_header));
  243:     /* resize to include at least all the bitmap */
  244:     ftruncate(cow_fd, sizeof(cow_header) + ((image_sectors + 7) >> 3));
  245:     close(cow_fd);
  246:     return 0;
  247: }
  248: 
  249: static void cow_flush(BlockDriverState *bs)
  250: {
  251:     BDRVCowState *s = bs->opaque;
  252:     fsync(s->fd);
  253: }
  254: 
  255: BlockDriver bdrv_cow = {
  256:     "cow",
  257:     sizeof(BDRVCowState),
  258:     cow_probe,
  259:     cow_open,
  260:     cow_read,
  261:     cow_write,
  262:     cow_close,
  263:     cow_create,
  264:     cow_flush,
  265:     cow_is_allocated,
  266: };
  267: #endif

unix.superglobalmegacorp.com