Statistics
| Branch: | Revision:

root / drivers / block-ram.c @ abdb293f

History | View | Annotate | Download (7.2 kB)

1
/* 
2
 * Copyright (c) 2007, XenSource Inc.
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions are met:
7
 *     * Redistributions of source code must retain the above copyright
8
 *       notice, this list of conditions and the following disclaimer.
9
 *     * Redistributions in binary form must reproduce the above copyright
10
 *       notice, this list of conditions and the following disclaimer in the
11
 *       documentation and/or other materials provided with the distribution.
12
 *     * Neither the name of XenSource Inc. nor the names of its contributors
13
 *       may be used to endorse or promote products derived from this software
14
 *       without specific prior written permission.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
20
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 */
28

    
29
#ifdef HAVE_CONFIG_H
30
#include "config.h"
31
#endif
32

    
33
#include <errno.h>
34
#include <fcntl.h>
35
#include <stdio.h>
36
#include <stdlib.h>
37
#include <unistd.h>
38
#include <sys/statvfs.h>
39
#include <sys/stat.h>
40
#include <sys/ioctl.h>
41
#include <linux/fs.h>
42
#include <string.h>
43

    
44
#include "tapdisk.h"
45
#include "tapdisk-driver.h"
46
#include "tapdisk-interface.h"
47

    
48
void *img;
49
long int   disksector_size;
50
long int   disksize;
51
long int   diskinfo;
52
static int connections = 0;
53

    
54
struct tdram_state {
55
        int fd;
56
};
57

    
58
/*Get Image size, secsize*/
59
static int get_image_info(int fd, td_disk_info_t *info)
60
{
61
        int ret;
62
        struct stat stat;
63

    
64
        ret = fstat(fd, &stat);
65
        if (ret != 0) {
66
                DPRINTF("ERROR: fstat failed, Couldn't stat image");
67
                return -EINVAL;
68
        }
69

    
70
        if (S_ISBLK(stat.st_mode)) {
71
                /*Accessing block device directly*/
72
                info->size = 0;
73
                if (ioctl(fd,BLKGETSIZE,&info->size)!=0) {
74
                        DPRINTF("ERR: BLKGETSIZE failed, couldn't stat image");
75
                        return -EINVAL;
76
                }
77

    
78
                DPRINTF("Image size: \n\tpre sector_shift  [%llu]\n\tpost "
79
                        "sector_shift [%llu]\n",
80
                        (long long unsigned)(info->size << SECTOR_SHIFT),
81
                        (long long unsigned)info->size);
82

    
83
                /*Get the sector size*/
84
#if defined(BLKSSZGET)
85
                {
86
                        info->sector_size = DEFAULT_SECTOR_SIZE;
87
                        ioctl(fd, BLKSSZGET, &info->sector_size);
88
                        
89
                        if (info->sector_size != DEFAULT_SECTOR_SIZE)
90
                                DPRINTF("Note: sector size is %ld (not %d)\n",
91
                                        info->sector_size, DEFAULT_SECTOR_SIZE);
92
                }
93
#else
94
                info->sector_size = DEFAULT_SECTOR_SIZE;
95
#endif
96

    
97
        } else {
98
                /*Local file? try fstat instead*/
99
                info->size = (stat.st_size >> SECTOR_SHIFT);
100
                info->sector_size = DEFAULT_SECTOR_SIZE;
101
                DPRINTF("Image size: \n\tpre sector_shift  [%llu]\n\tpost "
102
                        "sector_shift [%llu]\n",
103
                        (long long unsigned)(info->size << SECTOR_SHIFT),
104
                        (long long unsigned)info->size);
105
        }
106

    
107
        if (info->size == 0) {                
108
                info->size =((uint64_t) MAX_RAMDISK_SIZE);
109
                info->sector_size = DEFAULT_SECTOR_SIZE;
110
        }
111
        info->info = 0;
112

    
113
        /*Store variables locally*/
114
        disksector_size = info->sector_size;
115
        disksize        = info->size;
116
        diskinfo        = info->info;
117
        DPRINTF("Image sector_size: \n\t[%lu]\n",
118
                info->sector_size);
119

    
120
        return 0;
121
}
122

    
123
/* Open the disk file and initialize ram state. */
124
int tdram_open (td_driver_t *driver, const char *name, td_flag_t flags)
125
{
126
        char *p;
127
        uint64_t size;
128
        int i, fd, ret = 0, count = 0, o_flags;
129
        struct tdram_state *prv = (struct tdram_state *)driver->data;
130

    
131
        connections++;
132

    
133
        if (connections > 1) {
134
                driver->info.sector_size = disksector_size;
135
                driver->info.size        = disksize;
136
                driver->info.info        = diskinfo; 
137
                DPRINTF("Image already open, returning parameters:\n");
138
                DPRINTF("Image size: \n\tpre sector_shift  [%llu]\n\tpost "
139
                        "sector_shift [%llu]\n",
140
                        (long long unsigned)(driver->info.size << SECTOR_SHIFT),
141
                        (long long unsigned)driver->info.size);
142
                DPRINTF("Image sector_size: \n\t[%lu]\n",
143
                        driver->info.sector_size);
144

    
145
                prv->fd = -1;
146
                goto done;
147
        }
148

    
149
        /* Open the file */
150
        o_flags = O_DIRECT | O_LARGEFILE | 
151
                ((flags == TD_OPEN_RDONLY) ? O_RDONLY : O_RDWR);
152
        fd = open(name, o_flags);
153

    
154
        if ((fd == -1) && (errno == EINVAL)) {
155

    
156
                /* Maybe O_DIRECT isn't supported. */
157
                o_flags &= ~O_DIRECT;
158
                fd = open(name, o_flags);
159
                if (fd != -1) DPRINTF("WARNING: Accessing image without"
160
                                     "O_DIRECT! (%s)\n", name);
161

    
162
        } else if (fd != -1) DPRINTF("open(%s) with O_DIRECT\n", name);
163
        
164
        if (fd == -1) {
165
                DPRINTF("Unable to open [%s]!\n",name);
166
                ret = 0 - errno;
167
                goto done;
168
        }
169

    
170
        prv->fd = fd;
171

    
172
        ret = get_image_info(fd, &driver->info);
173
        size = MAX_RAMDISK_SIZE;
174

    
175
        if (driver->info.size > size) {
176
                DPRINTF("Disk exceeds limit, must be less than [%d]MB",
177
                        (MAX_RAMDISK_SIZE<<SECTOR_SHIFT)>>20);
178
                return -ENOMEM;
179
        }
180

    
181
        /*Read the image into memory*/
182
        if (posix_memalign(&img, DEFAULT_SECTOR_SIZE,
183
                           driver->info.size << SECTOR_SHIFT)) {
184
                DPRINTF("Mem malloc failed\n");
185
                return -errno;
186
        }
187
        p = img;
188
        DPRINTF("Reading %llu bytes.......",
189
                (long long unsigned)driver->info.size << SECTOR_SHIFT);
190

    
191
        for (i = 0; i < driver->info.size; i++) {
192
                ret = read(prv->fd, p, driver->info.sector_size);
193
                if (ret != driver->info.sector_size) {
194
                        DPRINTF("ret = %d, errno = %d\n", ret, errno);
195
                        ret = 0 - errno;
196
                        break;
197
                } else {
198
                        count += ret;
199
                        p = img + count;
200
                }
201
        }
202
        DPRINTF("[%d]\n",count);
203
        if (count != driver->info.size << SECTOR_SHIFT) {
204
                ret = -1;
205
        } else {
206
                ret = 0;
207
        }
208

    
209
done:
210
        return ret;
211
}
212

    
213
void tdram_queue_read(td_driver_t *driver, td_request_t treq)
214
{
215
        int      size    = treq.secs * driver->info.sector_size;
216
        uint64_t offset  = treq.sec * (uint64_t)driver->info.sector_size;
217

    
218
        memcpy(treq.buf, img + offset, size);
219

    
220
        td_complete_request(treq, 0);
221
}
222

    
223
void tdram_queue_write(td_driver_t *driver, td_request_t treq)
224
{
225
        int      size    = treq.secs * driver->info.sector_size;
226
        uint64_t offset  = treq.sec * (uint64_t)driver->info.sector_size;
227
        
228
        /* We assume that write access is controlled
229
         * at a higher level for multiple disks */
230
        memcpy(img + offset, treq.buf, size);
231

    
232
        td_complete_request(treq, 0);
233
}
234

    
235
int tdram_close(td_driver_t *driver)
236
{
237
        connections--;
238
        
239
        return 0;
240
}
241

    
242
int tdram_get_parent_id(td_driver_t *driver, td_disk_id_t *id)
243
{
244
        return TD_NO_PARENT;
245
}
246

    
247
int tdram_validate_parent(td_driver_t *driver,
248
                          td_driver_t *pdriver, td_flag_t flags)
249
{
250
        return -EINVAL;
251
}
252

    
253
struct tap_disk tapdisk_ram = {
254
        .disk_type          = "tapdisk_ram",
255
        .flags              = 0,
256
        .private_data_size  = sizeof(struct tdram_state),
257
        .td_open            = tdram_open,
258
        .td_close           = tdram_close,
259
        .td_queue_read      = tdram_queue_read,
260
        .td_queue_write     = tdram_queue_write,
261
        .td_get_parent_id   = tdram_get_parent_id,
262
        .td_validate_parent = tdram_validate_parent,
263
        .td_debug           = NULL,
264
};