93c270f23ad4b90b0f752d29e4378ec0220915db
[qemu] / block-vmstate.c
1 /*
2  * Block driver for vmstate format
3  *
4  * Copyright (c) 2009 Nokia Corporation
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
27 #define VMSTATE_MAGIC 0x564D53544154451ALL
28 #define VMSTATE_VERSION 1
29
30 typedef struct VMStateHeader {
31     uint64_t magic;
32     uint32_t version;
33     uint64_t state_offset;
34     uint64_t state_size;
35 } VMStateHeader;
36
37 typedef struct BDRVVmState {
38     int fd;
39     uint64_t state_offset;
40     uint64_t state_size;
41     uint64_t write_offset;
42 } BDRVVMState;
43
44 static int vmstate_probe(const uint8_t *buf, int buf_size, const char *filename)
45 {
46     const VMStateHeader *header = (const VMStateHeader *)buf;
47     if (buf_size >= sizeof(VMStateHeader) &&
48         be64_to_cpu(header->magic) == VMSTATE_MAGIC &&
49         be32_to_cpu(header->version) == VMSTATE_VERSION)
50         return 100;
51     return 0;
52 }
53
54 static int vmstate_open(BlockDriverState *bs, const char *filename, int flags)
55 {
56     BDRVVMState *s = bs->opaque;
57     VMStateHeader header;
58     
59     s->fd = open(filename, O_RDWR | O_BINARY);
60     if (s->fd < 0)
61         return -errno;
62     if (read(s->fd, &header, sizeof(header)) == sizeof(header) &&
63         be64_to_cpu(header.magic) == VMSTATE_MAGIC &&
64         be32_to_cpu(header.version) == VMSTATE_VERSION) {
65         s->state_offset = be64_to_cpu(header.state_offset);
66         s->state_size = be64_to_cpu(header.state_size);
67         
68         s->write_offset = s->state_offset;
69         return 0;
70     }
71     close(s->fd);
72     return -EIO;
73 }
74
75 static void vmstate_flush(BlockDriverState *bs)
76 {
77 }
78
79 static void vmstate_close(BlockDriverState *bs)
80 {
81     BDRVVMState *s = bs->opaque;
82     
83     vmstate_flush(bs);
84     close(s->fd);
85 }
86
87 static int vmstate_create(const char *filename, int64_t total_size,
88                           const char *backing_file, int flags)
89 {
90     VMStateHeader header;
91     int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
92     if (fd < 0)
93         return -EIO;
94     memset(&header, 0, sizeof(header));
95     header.magic = cpu_to_be64(VMSTATE_MAGIC);
96     header.version = cpu_to_be32(VMSTATE_VERSION);
97     header.state_offset = cpu_to_be64(sizeof(header));
98     write(fd, &header, sizeof(header));
99     close(fd);
100     return 0;
101 }
102
103 static int vmstate_refresh_header(BDRVVMState *s)
104 {
105     VMStateHeader header;
106     
107     if (!lseek(s->fd, 0, SEEK_SET) &&
108         read(s->fd, &header, sizeof(header)) == sizeof(header)) {
109         header.state_size = cpu_to_be64(s->state_size);
110         if (!lseek(s->fd, 0, SEEK_SET) &&
111             write(s->fd, &header, sizeof(header)) == sizeof(header))
112             return 0;
113     }
114     return -EIO;
115 }
116
117 static int vmstate_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
118 {
119     BDRVVMState *s = bs->opaque;
120     
121     bdi->cluster_size = 0;//VMSTATE_BLOCK_SIZE;
122     bdi->vm_state_offset = s->state_offset;
123     bdi->highest_alloc = s->state_offset;
124     bdi->num_free_bytes = 0;
125     return 0;
126 }
127
128 static int vmstate_read(BlockDriverState *bs, int64_t sector_num,
129                         uint8_t *buf, int nb_sectors)
130 {
131     BDRVVMState *s = bs->opaque;
132     
133     if (lseek(s->fd, sector_num * 512, SEEK_SET) != sector_num * 512)
134         return -EIO;
135     return read(s->fd, buf, nb_sectors * 512);
136 }
137
138 static int vmstate_write(BlockDriverState *bs, int64_t sector_num,
139                          const uint8_t *buf, int nb_sectors)
140 {
141     BDRVVMState *s = bs->opaque;
142     
143     if (lseek(s->fd, sector_num * 512, SEEK_SET) != sector_num * 512)
144         return -EIO;
145     return write(s->fd, buf, nb_sectors * 512);
146 }
147
148 static int vmstate_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
149 {
150     BDRVVMState *s = bs->opaque;
151
152     return s->state_size ? 0 : -ENOENT;
153 }
154
155 static int vmstate_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
156 {
157     BDRVVMState *s = bs->opaque;
158     
159     if (s->state_size) {
160         s->state_size = 0;
161         vmstate_refresh_header(s);
162         if (!lseek(s->fd, 0, SEEK_SET))
163             return ftruncate(s->fd, sizeof(VMStateHeader));
164     }
165     return -ENOENT;
166 }
167
168 static int vmstate_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
169 {
170     BDRVVMState *s = bs->opaque;
171     
172     if (s->state_size)
173         vmstate_snapshot_delete(bs, NULL);
174     s->state_size = sn_info->vm_state_size;
175     s->write_offset = s->state_offset;
176     return vmstate_refresh_header(s);
177 }
178
179 static int vmstate_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
180 {
181     BDRVVMState *s = bs->opaque;
182     QEMUSnapshotInfo *sn_info;
183     
184     sn_info = qemu_mallocz(sizeof(QEMUSnapshotInfo));
185     if (s->state_size) {
186         pstrcpy(sn_info->id_str, sizeof(sn_info->id_str), "vmstate");
187         pstrcpy(sn_info->name, sizeof(sn_info->name), "vmstate");
188         sn_info->vm_state_size = s->state_size;
189     }
190     *psn_tab = sn_info;
191     return s->state_size ? 1 : 0;
192 }
193
194 static int64_t vmstate_getlength(BlockDriverState *bs)
195 {
196     return 1LL << 63; /* big enough? */
197 }
198
199 BlockDriver bdrv_vmstate = {
200     .format_name = "vmstate",
201     .instance_size = sizeof(BDRVVMState),
202     .bdrv_probe = vmstate_probe,
203     .bdrv_open = vmstate_open,
204     .bdrv_read = vmstate_read,
205     .bdrv_write = vmstate_write,
206     .bdrv_close = vmstate_close,
207     .bdrv_create = vmstate_create,
208     .bdrv_flush = vmstate_flush,
209     .bdrv_getlength = vmstate_getlength,
210     .bdrv_snapshot_create = vmstate_snapshot_create,
211     .bdrv_snapshot_goto = vmstate_snapshot_goto,
212     .bdrv_snapshot_delete = vmstate_snapshot_delete,
213     .bdrv_snapshot_list = vmstate_snapshot_list,
214     .bdrv_get_info = vmstate_get_info
215 };