~ubuntu-branches/ubuntu/utopic/xen/utopic

« back to all changes in this revision

Viewing changes to tools/blktap/drivers/block-ram.c

  • Committer: Bazaar Package Importer
  • Author(s): Bastian Blank
  • Date: 2010-05-06 15:47:38 UTC
  • mto: (1.3.1) (15.1.1 sid) (4.1.1 experimental)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20100506154738-agoz0rlafrh1fnq7
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* block-ram.c
 
2
 *
 
3
 * Fast Ramdisk implementation.
 
4
 *
 
5
 * (c) 2006 Andrew Warfield and Julian Chesterfield
 
6
 *
 
7
 * This program is free software; you can redistribute it and/or
 
8
 * modify it under the terms of the GNU General Public License version 2
 
9
 * as published by the Free Software Foundation; or, when distributed
 
10
 * separately from the Linux kernel or incorporated into other
 
11
 * software packages, subject to the following license:
 
12
 *
 
13
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 
14
 * of this source file (the "Software"), to deal in the Software without
 
15
 * restriction, including without limitation the rights to use, copy, modify,
 
16
 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
 
17
 * and to permit persons to whom the Software is furnished to do so, subject to
 
18
 * the following conditions:
 
19
 *
 
20
 * The above copyright notice and this permission notice shall be included in
 
21
 * all copies or substantial portions of the Software.
 
22
 *
 
23
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
24
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
25
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 
26
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 
27
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 
28
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 
29
 * IN THE SOFTWARE.
 
30
 */
 
31
 
 
32
#include <errno.h>
 
33
#include <fcntl.h>
 
34
#include <stdio.h>
 
35
#include <stdlib.h>
 
36
#include <inttypes.h>
 
37
#include <unistd.h>
 
38
#include <sys/statvfs.h>
 
39
#include <sys/stat.h>
 
40
#include <sys/ioctl.h>
 
41
#include <string.h>
 
42
#include "tapdisk.h"
 
43
#include "blk.h"
 
44
 
 
45
#define MAX_DISK_SIZE 1024000 /*500MB disk limit*/
 
46
 
 
47
/* *BSD has no O_LARGEFILE */
 
48
#ifndef O_LARGEFILE
 
49
#define O_LARGEFILE     0
 
50
#endif
 
51
 
 
52
char *img;
 
53
long int   disksector_size;
 
54
long int   disksize;
 
55
long int   diskinfo;
 
56
static int connections = 0;
 
57
 
 
58
struct tdram_state {
 
59
        int fd;
 
60
        int poll_pipe[2]; /* dummy fd for polling on */
 
61
};
 
62
 
 
63
/*Get Image size, secsize*/
 
64
static int get_image_info(struct td_state *s, int fd)
 
65
{
 
66
        int ret;
 
67
        long size;
 
68
        unsigned long total_size;
 
69
        struct statvfs statBuf;
 
70
        struct stat stat;
 
71
 
 
72
        ret = fstat(fd, &stat);
 
73
        if (ret != 0) {
 
74
                DPRINTF("ERROR: fstat failed, Couldn't stat image");
 
75
                return -EINVAL;
 
76
        }
 
77
 
 
78
        if (S_ISBLK(stat.st_mode)) {
 
79
                /*Accessing block device directly*/
 
80
                if (blk_getimagesize(fd, &s->size) != 0)
 
81
                        return -EINVAL;
 
82
 
 
83
                DPRINTF("Image size: \n\tpre sector_shift  [%llu]\n\tpost "
 
84
                        "sector_shift [%llu]\n",
 
85
                        (long long unsigned)(s->size << SECTOR_SHIFT),
 
86
                        (long long unsigned)s->size);
 
87
 
 
88
                /*Get the sector size*/
 
89
                if (blk_getsectorsize(fd, &s->sector_size) != 0)
 
90
                        s->sector_size = DEFAULT_SECTOR_SIZE;
 
91
 
 
92
        } else {
 
93
                /*Local file? try fstat instead*/
 
94
                s->size = (stat.st_size >> SECTOR_SHIFT);
 
95
                s->sector_size = DEFAULT_SECTOR_SIZE;
 
96
                DPRINTF("Image size: \n\tpre sector_shift  [%llu]\n\tpost "
 
97
                        "sector_shift [%llu]\n",
 
98
                        (long long unsigned)(s->size << SECTOR_SHIFT),
 
99
                        (long long unsigned)s->size);
 
100
        }
 
101
 
 
102
        if (s->size == 0) {             
 
103
                s->size =((uint64_t) MAX_DISK_SIZE);
 
104
                s->sector_size = DEFAULT_SECTOR_SIZE;
 
105
        }
 
106
        s->info = 0;
 
107
 
 
108
        /*Store variables locally*/
 
109
        disksector_size = s->sector_size;
 
110
        disksize        = s->size;
 
111
        diskinfo        = s->info;
 
112
        DPRINTF("Image sector_size: \n\t[%"PRIu64"]\n",
 
113
                s->sector_size);
 
114
 
 
115
        return 0;
 
116
}
 
117
 
 
118
static inline void init_fds(struct disk_driver *dd)
 
119
{
 
120
        int i;
 
121
        struct tdram_state *prv = (struct tdram_state *)dd->private;
 
122
 
 
123
        for(i =0 ; i < MAX_IOFD; i++)
 
124
                dd->io_fd[i] = 0;
 
125
 
 
126
        dd->io_fd[0] = prv->poll_pipe[0];
 
127
}
 
128
 
 
129
/* Open the disk file and initialize ram state. */
 
130
static int tdram_open (struct disk_driver *dd, const char *name, td_flag_t flags)
 
131
{
 
132
        char *p;
 
133
        uint64_t size;
 
134
        int i, fd, ret = 0, count = 0, o_flags;
 
135
        struct td_state    *s     = dd->td_state;
 
136
        struct tdram_state *prv   = (struct tdram_state *)dd->private;
 
137
 
 
138
        connections++;
 
139
        
 
140
        /* set up a pipe so that we can hand back a poll fd that won't fire.*/
 
141
        ret = pipe(prv->poll_pipe);
 
142
        if (ret != 0)
 
143
                return (0 - errno);
 
144
 
 
145
        if (connections > 1) {
 
146
                s->sector_size = disksector_size;
 
147
                s->size        = disksize;
 
148
                s->info        = diskinfo; 
 
149
                DPRINTF("Image already open, returning parameters:\n");
 
150
                DPRINTF("Image size: \n\tpre sector_shift  [%llu]\n\tpost "
 
151
                        "sector_shift [%llu]\n",
 
152
                        (long long unsigned)(s->size << SECTOR_SHIFT),
 
153
                        (long long unsigned)s->size);
 
154
                DPRINTF("Image sector_size: \n\t[%"PRIu64"]\n",
 
155
                        s->sector_size);
 
156
 
 
157
                prv->fd = -1;
 
158
                goto done;
 
159
        }
 
160
 
 
161
        /* Open the file */
 
162
        o_flags = O_DIRECT | O_LARGEFILE | 
 
163
                ((flags == TD_RDONLY) ? O_RDONLY : O_RDWR);
 
164
        fd = open(name, o_flags);
 
165
 
 
166
        if ((fd == -1) && (errno == EINVAL)) {
 
167
 
 
168
                /* Maybe O_DIRECT isn't supported. */
 
169
                o_flags &= ~O_DIRECT;
 
170
                fd = open(name, o_flags);
 
171
                if (fd != -1) DPRINTF("WARNING: Accessing image without"
 
172
                                     "O_DIRECT! (%s)\n", name);
 
173
 
 
174
        } else if (fd != -1) DPRINTF("open(%s) with O_DIRECT\n", name);
 
175
        
 
176
        if (fd == -1) {
 
177
                DPRINTF("Unable to open [%s]!\n",name);
 
178
                ret = 0 - errno;
 
179
                goto done;
 
180
        }
 
181
 
 
182
        prv->fd = fd;
 
183
 
 
184
        ret = get_image_info(s, fd);
 
185
        size = MAX_DISK_SIZE;
 
186
 
 
187
        if (s->size > size) {
 
188
                DPRINTF("Disk exceeds limit, must be less than [%d]MB",
 
189
                        (MAX_DISK_SIZE<<SECTOR_SHIFT)>>20);
 
190
                return -ENOMEM;
 
191
        }
 
192
 
 
193
        /*Read the image into memory*/
 
194
        p = img = malloc(s->size << SECTOR_SHIFT);
 
195
        if (img == NULL) {
 
196
                DPRINTF("Mem malloc failed\n");
 
197
                return -1;
 
198
        }
 
199
        DPRINTF("Reading %llu bytes.......",(long long unsigned)s->size << SECTOR_SHIFT);
 
200
 
 
201
        for (i = 0; i < s->size; i++) {
 
202
                ret = read(prv->fd, p, s->sector_size);
 
203
                if (ret != s->sector_size) {
 
204
                        ret = 0 - errno;
 
205
                        break;
 
206
                } else {
 
207
                        count += ret;
 
208
                        p = img + count;
 
209
                }
 
210
        }
 
211
        DPRINTF("[%d]\n",count);
 
212
        if (count != s->size << SECTOR_SHIFT) {
 
213
                ret = -1;
 
214
        } else {
 
215
                ret = 0;
 
216
        } 
 
217
 
 
218
        init_fds(dd);
 
219
done:
 
220
        return ret;
 
221
}
 
222
 
 
223
static int tdram_queue_read(struct disk_driver *dd, uint64_t sector,
 
224
                      int nb_sectors, char *buf, td_callback_t cb,
 
225
                      int id, void *private)
 
226
{
 
227
        struct td_state    *s   = dd->td_state;
 
228
        struct tdram_state *prv = (struct tdram_state *)dd->private;
 
229
        int      size    = nb_sectors * s->sector_size;
 
230
        uint64_t offset  = sector * (uint64_t)s->sector_size;
 
231
 
 
232
        memcpy(buf, img + offset, size);
 
233
 
 
234
        return cb(dd, 0, sector, nb_sectors, id, private);
 
235
}
 
236
 
 
237
static int tdram_queue_write(struct disk_driver *dd, uint64_t sector,
 
238
                      int nb_sectors, char *buf, td_callback_t cb,
 
239
                      int id, void *private)
 
240
{
 
241
        struct td_state    *s   = dd->td_state;
 
242
        struct tdram_state *prv = (struct tdram_state *)dd->private;
 
243
        int      size    = nb_sectors * s->sector_size;
 
244
        uint64_t offset  = sector * (uint64_t)s->sector_size;
 
245
        
 
246
        /* We assume that write access is controlled
 
247
         * at a higher level for multiple disks */
 
248
        memcpy(img + offset, buf, size);
 
249
 
 
250
        return cb(dd, 0, sector, nb_sectors, id, private);
 
251
}
 
252
                
 
253
static int tdram_submit(struct disk_driver *dd)
 
254
{
 
255
        return 0;       
 
256
}
 
257
 
 
258
static int tdram_close(struct disk_driver *dd)
 
259
{
 
260
        struct tdram_state *prv = (struct tdram_state *)dd->private;
 
261
        
 
262
        connections--;
 
263
        
 
264
        return 0;
 
265
}
 
266
 
 
267
static int tdram_do_callbacks(struct disk_driver *dd, int sid)
 
268
{
 
269
        /* always ask for a kick */
 
270
        return 1;
 
271
}
 
272
 
 
273
static int tdram_get_parent_id(struct disk_driver *dd, struct disk_id *id)
 
274
{
 
275
        return TD_NO_PARENT;
 
276
}
 
277
 
 
278
static int tdram_validate_parent(struct disk_driver *dd, 
 
279
                          struct disk_driver *parent, td_flag_t flags)
 
280
{
 
281
        return -EINVAL;
 
282
}
 
283
 
 
284
struct tap_disk tapdisk_ram = {
 
285
        .disk_type          = "tapdisk_ram",
 
286
        .private_data_size  = sizeof(struct tdram_state),
 
287
        .td_open            = tdram_open,
 
288
        .td_queue_read      = tdram_queue_read,
 
289
        .td_queue_write     = tdram_queue_write,
 
290
        .td_submit          = tdram_submit,
 
291
        .td_close           = tdram_close,
 
292
        .td_do_callbacks    = tdram_do_callbacks,
 
293
        .td_get_parent_id   = tdram_get_parent_id,
 
294
        .td_validate_parent = tdram_validate_parent
 
295
};