blob: 8bd9204ac1abcaee1be42dc73450b2ee66f99116 [file] [log] [blame]
Jeff Dike6c29256c2006-03-27 01:14:37 -08001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6/* 2001-09-28...2002-04-17
7 * Partition stuff by James_McMechan@hotmail.com
8 * old style ubd by setting UBD_SHIFT to 0
9 * 2002-09-27...2002-10-18 massive tinkering for 2.5
10 * partitions have changed in 2.5
11 * 2003-01-29 more tinkering for 2.5.59-1
12 * This should now address the sysfs problems and has
13 * the symlink for devfs to allow for booting with
14 * the common /dev/ubd/discX/... names rather than
15 * only /dev/ubdN/discN this version also has lots of
16 * clean ups preparing for ubd-many.
17 * James McMechan
18 */
19
20#define MAJOR_NR UBD_MAJOR
21#define UBD_SHIFT 4
22
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include "linux/module.h"
24#include "linux/blkdev.h"
25#include "linux/hdreg.h"
26#include "linux/init.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070027#include "linux/cdrom.h"
28#include "linux/proc_fs.h"
29#include "linux/ctype.h"
30#include "linux/capability.h"
31#include "linux/mm.h"
32#include "linux/vmalloc.h"
33#include "linux/blkpg.h"
34#include "linux/genhd.h"
35#include "linux/spinlock.h"
Russell Kingd052d1b2005-10-29 19:07:23 +010036#include "linux/platform_device.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#include "asm/segment.h"
38#include "asm/uaccess.h"
39#include "asm/irq.h"
40#include "asm/types.h"
41#include "asm/tlbflush.h"
42#include "user_util.h"
43#include "mem_user.h"
44#include "kern_util.h"
45#include "kern.h"
46#include "mconsole_kern.h"
47#include "init.h"
48#include "irq_user.h"
49#include "irq_kern.h"
50#include "ubd_user.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070051#include "os.h"
52#include "mem.h"
53#include "mem_kern.h"
54#include "cow.h"
55
Jeff Dike7b9014c2005-05-20 13:59:11 -070056enum ubd_req { UBD_READ, UBD_WRITE };
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
58struct io_thread_req {
Jeff Dike62f96cb2007-02-10 01:44:16 -080059 struct request *req;
Jeff Dike91acb212005-10-10 23:10:32 -040060 enum ubd_req op;
Linus Torvalds1da177e2005-04-16 15:20:36 -070061 int fds[2];
62 unsigned long offsets[2];
63 unsigned long long offset;
64 unsigned long length;
65 char *buffer;
66 int sectorsize;
Jeff Dike91acb212005-10-10 23:10:32 -040067 unsigned long sector_mask;
68 unsigned long long cow_offset;
69 unsigned long bitmap_words[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 int error;
71};
72
Jeff Dike6c29256c2006-03-27 01:14:37 -080073extern int open_ubd_file(char *file, struct openflags *openflags, int shared,
Linus Torvalds1da177e2005-04-16 15:20:36 -070074 char **backing_file_out, int *bitmap_offset_out,
75 unsigned long *bitmap_len_out, int *data_offset_out,
76 int *create_cow_out);
77extern int create_cow_file(char *cow_file, char *backing_file,
78 struct openflags flags, int sectorsize,
79 int alignment, int *bitmap_offset_out,
80 unsigned long *bitmap_len_out,
81 int *data_offset_out);
82extern int read_cow_bitmap(int fd, void *buf, int offset, int len);
Jeff Dike91acb212005-10-10 23:10:32 -040083extern void do_io(struct io_thread_req *req);
Linus Torvalds1da177e2005-04-16 15:20:36 -070084
Jeff Dike91acb212005-10-10 23:10:32 -040085static inline int ubd_test_bit(__u64 bit, unsigned char *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -070086{
87 __u64 n;
88 int bits, off;
89
Jeff Dike91acb212005-10-10 23:10:32 -040090 bits = sizeof(data[0]) * 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -070091 n = bit / bits;
92 off = bit % bits;
Jeff Dike91acb212005-10-10 23:10:32 -040093 return((data[n] & (1 << off)) != 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070094}
95
Jeff Dike91acb212005-10-10 23:10:32 -040096static inline void ubd_set_bit(__u64 bit, unsigned char *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -070097{
98 __u64 n;
99 int bits, off;
100
Jeff Dike91acb212005-10-10 23:10:32 -0400101 bits = sizeof(data[0]) * 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 n = bit / bits;
103 off = bit % bits;
Jeff Dike91acb212005-10-10 23:10:32 -0400104 data[n] |= (1 << off);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105}
106/*End stuff from ubd_user.h*/
107
108#define DRIVER_NAME "uml-blkdev"
109
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800110static DEFINE_MUTEX(ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112static int ubd_open(struct inode * inode, struct file * filp);
113static int ubd_release(struct inode * inode, struct file * file);
114static int ubd_ioctl(struct inode * inode, struct file * file,
115 unsigned int cmd, unsigned long arg);
Christoph Hellwiga885c8c2006-01-08 01:02:50 -0800116static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117
Paolo 'Blaisorblade' Giarrusso97d88ac2006-10-30 22:07:03 -0800118#define MAX_DEV (16)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120static struct block_device_operations ubd_blops = {
121 .owner = THIS_MODULE,
122 .open = ubd_open,
123 .release = ubd_release,
124 .ioctl = ubd_ioctl,
Christoph Hellwiga885c8c2006-01-08 01:02:50 -0800125 .getgeo = ubd_getgeo,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126};
127
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128/* Protected by ubd_lock */
129static int fake_major = MAJOR_NR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130static struct gendisk *ubd_gendisk[MAX_DEV];
131static struct gendisk *fake_gendisk[MAX_DEV];
Jeff Dike6c29256c2006-03-27 01:14:37 -0800132
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133#ifdef CONFIG_BLK_DEV_UBD_SYNC
134#define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 1, .c = 0, \
135 .cl = 1 })
136#else
137#define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 0, .c = 0, \
138 .cl = 1 })
139#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140static struct openflags global_openflags = OPEN_FLAGS;
141
142struct cow {
Paolo 'Blaisorblade' Giarrusso2a9d32f2006-10-30 22:07:04 -0800143 /* backing file name */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144 char *file;
Paolo 'Blaisorblade' Giarrusso2a9d32f2006-10-30 22:07:04 -0800145 /* backing file fd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 int fd;
147 unsigned long *bitmap;
148 unsigned long bitmap_len;
149 int bitmap_offset;
150 int data_offset;
151};
152
153struct ubd {
Paolo 'Blaisorblade' Giarrusso2a9d32f2006-10-30 22:07:04 -0800154 /* name (and fd, below) of the file opened for writing, either the
155 * backing or the cow file. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 char *file;
157 int count;
158 int fd;
159 __u64 size;
160 struct openflags boot_openflags;
161 struct openflags openflags;
Paolo 'Blaisorblade' Giarrusso84e945e2006-10-30 22:07:10 -0800162 unsigned shared:1;
163 unsigned no_cow:1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 struct cow cow;
165 struct platform_device pdev;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800166 struct request_queue *queue;
167 spinlock_t lock;
Jeff Dike2a9529a2007-03-29 01:20:27 -0700168 int active;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169};
170
171#define DEFAULT_COW { \
172 .file = NULL, \
173 .fd = -1, \
174 .bitmap = NULL, \
175 .bitmap_offset = 0, \
176 .data_offset = 0, \
177}
178
179#define DEFAULT_UBD { \
180 .file = NULL, \
181 .count = 0, \
182 .fd = -1, \
183 .size = -1, \
184 .boot_openflags = OPEN_FLAGS, \
185 .openflags = OPEN_FLAGS, \
186 .no_cow = 0, \
Jeff Dike6c29256c2006-03-27 01:14:37 -0800187 .shared = 0, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 .cow = DEFAULT_COW, \
Jeff Dike62f96cb2007-02-10 01:44:16 -0800189 .lock = SPIN_LOCK_UNLOCKED, \
Jeff Dike2a9529a2007-03-29 01:20:27 -0700190 .active = 0, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191}
192
Jeff Dikeb8831a12007-02-10 01:44:17 -0800193/* Protected by ubd_lock */
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800194struct ubd ubd_devs[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_UBD };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196/* Only changed by fake_ide_setup which is a setup */
197static int fake_ide = 0;
198static struct proc_dir_entry *proc_ide_root = NULL;
199static struct proc_dir_entry *proc_ide = NULL;
200
201static void make_proc_ide(void)
202{
203 proc_ide_root = proc_mkdir("ide", NULL);
204 proc_ide = proc_mkdir("ide0", proc_ide_root);
205}
206
207static int proc_ide_read_media(char *page, char **start, off_t off, int count,
208 int *eof, void *data)
209{
210 int len;
211
212 strcpy(page, "disk\n");
213 len = strlen("disk\n");
214 len -= off;
215 if (len < count){
216 *eof = 1;
217 if (len <= 0) return 0;
218 }
219 else len = count;
220 *start = page + off;
221 return len;
222}
223
224static void make_ide_entries(char *dev_name)
225{
226 struct proc_dir_entry *dir, *ent;
227 char name[64];
228
229 if(proc_ide_root == NULL) make_proc_ide();
230
231 dir = proc_mkdir(dev_name, proc_ide);
232 if(!dir) return;
233
234 ent = create_proc_entry("media", S_IFREG|S_IRUGO, dir);
235 if(!ent) return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 ent->data = NULL;
237 ent->read_proc = proc_ide_read_media;
238 ent->write_proc = NULL;
239 sprintf(name,"ide0/%s", dev_name);
240 proc_symlink(dev_name, proc_ide_root, name);
241}
242
243static int fake_ide_setup(char *str)
244{
245 fake_ide = 1;
246 return(1);
247}
248
249__setup("fake_ide", fake_ide_setup);
250
251__uml_help(fake_ide_setup,
252"fake_ide\n"
253" Create ide0 entries that map onto ubd devices.\n\n"
254);
255
256static int parse_unit(char **ptr)
257{
258 char *str = *ptr, *end;
259 int n = -1;
260
261 if(isdigit(*str)) {
262 n = simple_strtoul(str, &end, 0);
263 if(end == str)
264 return(-1);
265 *ptr = end;
266 }
Paolo 'Blaisorblade' Giarrusso97d88ac2006-10-30 22:07:03 -0800267 else if (('a' <= *str) && (*str <= 'z')) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 n = *str - 'a';
269 str++;
270 *ptr = str;
271 }
272 return(n);
273}
274
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800275/* If *index_out == -1 at exit, the passed option was a general one;
276 * otherwise, the str pointer is used (and owned) inside ubd_devs array, so it
277 * should not be freed on exit.
278 */
Jeff Dikef28169d2007-02-10 01:43:53 -0800279static int ubd_setup_common(char *str, int *index_out, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800281 struct ubd *ubd_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 struct openflags flags = global_openflags;
283 char *backing_file;
Jeff Dikeb8831a12007-02-10 01:44:17 -0800284 int n, err = 0, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285
286 if(index_out) *index_out = -1;
287 n = *str;
288 if(n == '='){
289 char *end;
290 int major;
291
292 str++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 if(!strcmp(str, "sync")){
294 global_openflags = of_sync(global_openflags);
Jeff Dikeb8831a12007-02-10 01:44:17 -0800295 goto out1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 }
297
Jeff Dikef28169d2007-02-10 01:43:53 -0800298 err = -EINVAL;
Jeff Dikeb8831a12007-02-10 01:44:17 -0800299 major = simple_strtoul(str, &end, 0);
300 if((*end != '\0') || (end == str)){
301 *error_out = "Didn't parse major number";
302 goto out1;
303 }
304
Jeff Dikef28169d2007-02-10 01:43:53 -0800305 mutex_lock(&ubd_lock);
306 if(fake_major != MAJOR_NR){
307 *error_out = "Can't assign a fake major twice";
308 goto out1;
309 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800310
Jeff Dikef28169d2007-02-10 01:43:53 -0800311 fake_major = major;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
313 printk(KERN_INFO "Setting extra ubd major number to %d\n",
314 major);
Jeff Dikef28169d2007-02-10 01:43:53 -0800315 err = 0;
316 out1:
317 mutex_unlock(&ubd_lock);
318 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 }
320
321 n = parse_unit(&str);
322 if(n < 0){
Jeff Dikef28169d2007-02-10 01:43:53 -0800323 *error_out = "Couldn't parse device number";
324 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 }
326 if(n >= MAX_DEV){
Jeff Dikef28169d2007-02-10 01:43:53 -0800327 *error_out = "Device number out of range";
328 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 }
330
Jeff Dikef28169d2007-02-10 01:43:53 -0800331 err = -EBUSY;
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800332 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800334 ubd_dev = &ubd_devs[n];
335 if(ubd_dev->file != NULL){
Jeff Dikef28169d2007-02-10 01:43:53 -0800336 *error_out = "Device is already configured";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 goto out;
338 }
339
340 if (index_out)
341 *index_out = n;
342
Jeff Dikef28169d2007-02-10 01:43:53 -0800343 err = -EINVAL;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800344 for (i = 0; i < sizeof("rscd="); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 switch (*str) {
346 case 'r':
347 flags.w = 0;
348 break;
349 case 's':
350 flags.s = 1;
351 break;
352 case 'd':
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800353 ubd_dev->no_cow = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 break;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800355 case 'c':
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800356 ubd_dev->shared = 1;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800357 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 case '=':
359 str++;
360 goto break_loop;
361 default:
Jeff Dikef28169d2007-02-10 01:43:53 -0800362 *error_out = "Expected '=' or flag letter "
363 "(r, s, c, or d)";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 goto out;
365 }
366 str++;
367 }
368
Jeff Dikef28169d2007-02-10 01:43:53 -0800369 if (*str == '=')
370 *error_out = "Too many flags specified";
371 else
372 *error_out = "Missing '='";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 goto out;
374
375break_loop:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 backing_file = strchr(str, ',');
377
Jeff Dikef28169d2007-02-10 01:43:53 -0800378 if (backing_file == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 backing_file = strchr(str, ':');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380
Jeff Dikef28169d2007-02-10 01:43:53 -0800381 if(backing_file != NULL){
382 if(ubd_dev->no_cow){
383 *error_out = "Can't specify both 'd' and a cow file";
384 goto out;
385 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 else {
387 *backing_file = '\0';
388 backing_file++;
389 }
390 }
Jeff Dikef28169d2007-02-10 01:43:53 -0800391 err = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800392 ubd_dev->file = str;
393 ubd_dev->cow.file = backing_file;
394 ubd_dev->boot_openflags = flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800396 mutex_unlock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -0800397 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398}
399
400static int ubd_setup(char *str)
401{
Jeff Dikef28169d2007-02-10 01:43:53 -0800402 char *error;
403 int err;
404
405 err = ubd_setup_common(str, NULL, &error);
406 if(err)
407 printk(KERN_ERR "Failed to initialize device with \"%s\" : "
408 "%s\n", str, error);
409 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410}
411
412__setup("ubd", ubd_setup);
413__uml_help(ubd_setup,
414"ubd<n><flags>=<filename>[(:|,)<filename2>]\n"
415" This is used to associate a device with a file in the underlying\n"
416" filesystem. When specifying two filenames, the first one is the\n"
417" COW name and the second is the backing file name. As separator you can\n"
418" use either a ':' or a ',': the first one allows writing things like;\n"
419" ubd0=~/Uml/root_cow:~/Uml/root_backing_file\n"
420" while with a ',' the shell would not expand the 2nd '~'.\n"
Jeff Dikef28169d2007-02-10 01:43:53 -0800421" When using only one filename, UML will detect whether to treat it like\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422" a COW file or a backing file. To override this detection, add the 'd'\n"
423" flag:\n"
424" ubd0d=BackingFile\n"
425" Usually, there is a filesystem in the file, but \n"
426" that's not required. Swap devices containing swap files can be\n"
427" specified like this. Also, a file which doesn't contain a\n"
428" filesystem can have its contents read in the virtual \n"
429" machine by running 'dd' on the device. <n> must be in the range\n"
430" 0 to 7. Appending an 'r' to the number will cause that device\n"
431" to be mounted read-only. For example ubd1r=./ext_fs. Appending\n"
432" an 's' will cause data to be written to disk on the host immediately.\n\n"
433);
434
435static int udb_setup(char *str)
436{
437 printk("udb%s specified on command line is almost certainly a ubd -> "
438 "udb TYPO\n", str);
439 return(1);
440}
441
442__setup("udb", udb_setup);
443__uml_help(udb_setup,
444"udb\n"
Jeff Dike0894e272005-05-28 15:51:55 -0700445" This option is here solely to catch ubd -> udb typos, which can be\n"
446" to impossible to catch visually unless you specifically look for\n"
447" them. The only result of any option starting with 'udb' is an error\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448" in the boot output.\n\n"
449);
450
451static int fakehd_set = 0;
452static int fakehd(char *str)
453{
454 printk(KERN_INFO "fakehd : Changing ubd name to \"hd\".\n");
455 fakehd_set = 1;
456 return 1;
457}
458
459__setup("fakehd", fakehd);
460__uml_help(fakehd,
461"fakehd\n"
462" Change the ubd device name to \"hd\".\n\n"
463);
464
465static void do_ubd_request(request_queue_t * q);
Jeff Dike91acb212005-10-10 23:10:32 -0400466
467/* Only changed by ubd_init, which is an initcall. */
468int thread_fd = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470/* call ubd_finish if you need to serialize */
Jeff Dike91acb212005-10-10 23:10:32 -0400471static void __ubd_finish(struct request *req, int error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472{
Jeff Dike91acb212005-10-10 23:10:32 -0400473 int nsect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474
Jeff Dike91acb212005-10-10 23:10:32 -0400475 if(error){
476 end_request(req, 0);
477 return;
478 }
479 nsect = req->current_nr_sectors;
480 req->sector += nsect;
481 req->buffer += nsect << 9;
482 req->errors = 0;
483 req->nr_sectors -= nsect;
484 req->current_nr_sectors = 0;
485 end_request(req, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486}
487
Paolo 'Blaisorblade' Giarrusso33f775e2006-10-30 22:07:08 -0800488/* Callable only from interrupt context - otherwise you need to do
489 * spin_lock_irq()/spin_lock_irqsave() */
Jeff Dike91acb212005-10-10 23:10:32 -0400490static inline void ubd_finish(struct request *req, int error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491{
Jeff Dike62f96cb2007-02-10 01:44:16 -0800492 struct ubd *dev = req->rq_disk->private_data;
493
494 spin_lock(&dev->lock);
Jeff Dike91acb212005-10-10 23:10:32 -0400495 __ubd_finish(req, error);
Jeff Dike62f96cb2007-02-10 01:44:16 -0800496 spin_unlock(&dev->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497}
498
Paolo 'Blaisorblade' Giarrusso2fe30a32006-10-30 22:07:09 -0800499/* XXX - move this inside ubd_intr. */
Jeff Dike62f96cb2007-02-10 01:44:16 -0800500/* Called without dev->lock held, and only in interrupt context. */
Jeff Dike91acb212005-10-10 23:10:32 -0400501static void ubd_handler(void)
502{
503 struct io_thread_req req;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800504 struct request *rq;
505 struct ubd *dev;
Jeff Dike91acb212005-10-10 23:10:32 -0400506 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507
Jeff Dike91acb212005-10-10 23:10:32 -0400508 n = os_read_file(thread_fd, &req, sizeof(req));
509 if(n != sizeof(req)){
510 printk(KERN_ERR "Pid %d - spurious interrupt in ubd_handler, "
511 "err = %d\n", os_getpid(), -n);
Jeff Dike91acb212005-10-10 23:10:32 -0400512 return;
513 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800514
Jeff Dike62f96cb2007-02-10 01:44:16 -0800515 rq = req.req;
516 dev = rq->rq_disk->private_data;
Jeff Dike2a9529a2007-03-29 01:20:27 -0700517 dev->active = 0;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800518
Jeff Dike91acb212005-10-10 23:10:32 -0400519 ubd_finish(rq, req.error);
Jeff Dike62f96cb2007-02-10 01:44:16 -0800520 reactivate_fd(thread_fd, UBD_IRQ);
521 spin_lock(&dev->lock);
522 do_ubd_request(dev->queue);
523 spin_unlock(&dev->lock);
Jeff Dike91acb212005-10-10 23:10:32 -0400524}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525
Al Viro7bea96f2006-10-08 22:49:34 +0100526static irqreturn_t ubd_intr(int irq, void *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527{
Jeff Dike91acb212005-10-10 23:10:32 -0400528 ubd_handler();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 return(IRQ_HANDLED);
530}
531
Jeff Dike91acb212005-10-10 23:10:32 -0400532/* Only changed by ubd_init, which is an initcall. */
533static int io_pid = -1;
534
535void kill_io_thread(void)
536{
Jeff Dike6c29256c2006-03-27 01:14:37 -0800537 if(io_pid != -1)
Jeff Dike91acb212005-10-10 23:10:32 -0400538 os_kill_process(io_pid, 1);
539}
540
541__uml_exitcall(kill_io_thread);
542
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800543static inline int ubd_file_size(struct ubd *ubd_dev, __u64 *size_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544{
545 char *file;
546
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800547 file = ubd_dev->cow.file ? ubd_dev->cow.file : ubd_dev->file;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 return(os_file_size(file, size_out));
549}
550
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800551static void ubd_close_dev(struct ubd *ubd_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800553 os_close_file(ubd_dev->fd);
554 if(ubd_dev->cow.file == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 return;
556
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800557 os_close_file(ubd_dev->cow.fd);
558 vfree(ubd_dev->cow.bitmap);
559 ubd_dev->cow.bitmap = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560}
561
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800562static int ubd_open_dev(struct ubd *ubd_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563{
564 struct openflags flags;
565 char **back_ptr;
566 int err, create_cow, *create_ptr;
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800567 int fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800569 ubd_dev->openflags = ubd_dev->boot_openflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 create_cow = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800571 create_ptr = (ubd_dev->cow.file != NULL) ? &create_cow : NULL;
572 back_ptr = ubd_dev->no_cow ? NULL : &ubd_dev->cow.file;
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800573
574 fd = open_ubd_file(ubd_dev->file, &ubd_dev->openflags, ubd_dev->shared,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800575 back_ptr, &ubd_dev->cow.bitmap_offset,
576 &ubd_dev->cow.bitmap_len, &ubd_dev->cow.data_offset,
Jeff Dike6c29256c2006-03-27 01:14:37 -0800577 create_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800579 if((fd == -ENOENT) && create_cow){
580 fd = create_cow_file(ubd_dev->file, ubd_dev->cow.file,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800581 ubd_dev->openflags, 1 << 9, PAGE_SIZE,
582 &ubd_dev->cow.bitmap_offset,
583 &ubd_dev->cow.bitmap_len,
584 &ubd_dev->cow.data_offset);
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800585 if(fd >= 0){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 printk(KERN_INFO "Creating \"%s\" as COW file for "
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800587 "\"%s\"\n", ubd_dev->file, ubd_dev->cow.file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 }
589 }
590
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800591 if(fd < 0){
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800592 printk("Failed to open '%s', errno = %d\n", ubd_dev->file,
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800593 -fd);
594 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 }
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800596 ubd_dev->fd = fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800598 if(ubd_dev->cow.file != NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 err = -ENOMEM;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800600 ubd_dev->cow.bitmap = (void *) vmalloc(ubd_dev->cow.bitmap_len);
601 if(ubd_dev->cow.bitmap == NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 printk(KERN_ERR "Failed to vmalloc COW bitmap\n");
603 goto error;
604 }
605 flush_tlb_kernel_vm();
606
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800607 err = read_cow_bitmap(ubd_dev->fd, ubd_dev->cow.bitmap,
608 ubd_dev->cow.bitmap_offset,
609 ubd_dev->cow.bitmap_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 if(err < 0)
611 goto error;
612
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800613 flags = ubd_dev->openflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 flags.w = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800615 err = open_ubd_file(ubd_dev->cow.file, &flags, ubd_dev->shared, NULL,
Jeff Dike6c29256c2006-03-27 01:14:37 -0800616 NULL, NULL, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 if(err < 0) goto error;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800618 ubd_dev->cow.fd = err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 }
620 return(0);
621 error:
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800622 os_close_file(ubd_dev->fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 return(err);
624}
625
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800626static int ubd_disk_register(int major, u64 size, int unit,
Jeff Dikeb8831a12007-02-10 01:44:17 -0800627 struct gendisk **disk_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628{
629 struct gendisk *disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630
631 disk = alloc_disk(1 << UBD_SHIFT);
632 if(disk == NULL)
633 return(-ENOMEM);
634
635 disk->major = major;
636 disk->first_minor = unit << UBD_SHIFT;
637 disk->fops = &ubd_blops;
638 set_capacity(disk, size / 512);
Greg Kroah-Hartmance7b0f42005-06-20 21:15:16 -0700639 if(major == MAJOR_NR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 sprintf(disk->disk_name, "ubd%c", 'a' + unit);
Greg Kroah-Hartmance7b0f42005-06-20 21:15:16 -0700641 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 sprintf(disk->disk_name, "ubd_fake%d", unit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643
644 /* sysfs register (not for ide fake devices) */
645 if (major == MAJOR_NR) {
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800646 ubd_devs[unit].pdev.id = unit;
647 ubd_devs[unit].pdev.name = DRIVER_NAME;
648 platform_device_register(&ubd_devs[unit].pdev);
649 disk->driverfs_dev = &ubd_devs[unit].pdev.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 }
651
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800652 disk->private_data = &ubd_devs[unit];
Jeff Dike62f96cb2007-02-10 01:44:16 -0800653 disk->queue = ubd_devs[unit].queue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 add_disk(disk);
655
656 *disk_out = disk;
657 return 0;
658}
659
660#define ROUND_BLOCK(n) ((n + ((1 << 9) - 1)) & (-1 << 9))
661
Jeff Dikef28169d2007-02-10 01:43:53 -0800662static int ubd_add(int n, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800664 struct ubd *ubd_dev = &ubd_devs[n];
Jeff Dikef28169d2007-02-10 01:43:53 -0800665 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800667 if(ubd_dev->file == NULL)
Jeff Dikeec7cf782005-09-03 15:57:29 -0700668 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800670 err = ubd_file_size(ubd_dev, &ubd_dev->size);
Jeff Dikef28169d2007-02-10 01:43:53 -0800671 if(err < 0){
672 *error_out = "Couldn't determine size of device's file";
Jeff Dike80c13742006-09-29 01:58:51 -0700673 goto out;
Jeff Dikef28169d2007-02-10 01:43:53 -0800674 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800676 ubd_dev->size = ROUND_BLOCK(ubd_dev->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677
Jeff Dike62f96cb2007-02-10 01:44:16 -0800678 err = -ENOMEM;
679 ubd_dev->queue = blk_init_queue(do_ubd_request, &ubd_dev->lock);
680 if (ubd_dev->queue == NULL) {
681 *error_out = "Failed to initialize device queue";
Jeff Dike80c13742006-09-29 01:58:51 -0700682 goto out;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800683 }
684 ubd_dev->queue->queuedata = ubd_dev;
685
686 err = ubd_disk_register(MAJOR_NR, ubd_dev->size, n, &ubd_gendisk[n]);
687 if(err){
688 *error_out = "Failed to register device";
689 goto out_cleanup;
690 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800691
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 if(fake_major != MAJOR_NR)
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800693 ubd_disk_register(fake_major, ubd_dev->size, n,
Jeff Dike62f96cb2007-02-10 01:44:16 -0800694 &fake_gendisk[n]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695
696 /* perhaps this should also be under the "if (fake_major)" above */
697 /* using the fake_disk->disk_name and also the fakehd_set name */
698 if (fake_ide)
699 make_ide_entries(ubd_gendisk[n]->disk_name);
700
Jeff Dikeec7cf782005-09-03 15:57:29 -0700701 err = 0;
Jeff Dikeec7cf782005-09-03 15:57:29 -0700702out:
703 return err;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800704
705out_cleanup:
706 blk_cleanup_queue(ubd_dev->queue);
707 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708}
709
Jeff Dikef28169d2007-02-10 01:43:53 -0800710static int ubd_config(char *str, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711{
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800712 int n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713
Jeff Dikef28169d2007-02-10 01:43:53 -0800714 /* This string is possibly broken up and stored, so it's only
715 * freed if ubd_setup_common fails, or if only general options
716 * were set.
717 */
Jeff Dike970d6e32006-01-06 00:18:48 -0800718 str = kstrdup(str, GFP_KERNEL);
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800719 if (str == NULL) {
Jeff Dikef28169d2007-02-10 01:43:53 -0800720 *error_out = "Failed to allocate memory";
721 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 }
Jeff Dikef28169d2007-02-10 01:43:53 -0800723
724 ret = ubd_setup_common(str, &n, error_out);
725 if (ret)
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800726 goto err_free;
Jeff Dikef28169d2007-02-10 01:43:53 -0800727
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800728 if (n == -1) {
729 ret = 0;
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800730 goto err_free;
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800731 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800733 mutex_lock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -0800734 ret = ubd_add(n, error_out);
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800735 if (ret)
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800736 ubd_devs[n].file = NULL;
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800737 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800739out:
740 return ret;
741
742err_free:
743 kfree(str);
744 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745}
746
747static int ubd_get_config(char *name, char *str, int size, char **error_out)
748{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800749 struct ubd *ubd_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 int n, len = 0;
751
752 n = parse_unit(&name);
753 if((n >= MAX_DEV) || (n < 0)){
754 *error_out = "ubd_get_config : device number out of range";
755 return(-1);
756 }
757
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800758 ubd_dev = &ubd_devs[n];
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800759 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800761 if(ubd_dev->file == NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 CONFIG_CHUNK(str, size, len, "", 1);
763 goto out;
764 }
765
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800766 CONFIG_CHUNK(str, size, len, ubd_dev->file, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800768 if(ubd_dev->cow.file != NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 CONFIG_CHUNK(str, size, len, ",", 0);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800770 CONFIG_CHUNK(str, size, len, ubd_dev->cow.file, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 }
772 else CONFIG_CHUNK(str, size, len, "", 1);
773
774 out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800775 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 return(len);
777}
778
Jeff Dike29d56cf2005-06-25 14:55:25 -0700779static int ubd_id(char **str, int *start_out, int *end_out)
780{
781 int n;
782
783 n = parse_unit(str);
784 *start_out = 0;
785 *end_out = MAX_DEV - 1;
786 return n;
787}
788
Jeff Dikef28169d2007-02-10 01:43:53 -0800789static int ubd_remove(int n, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800791 struct ubd *ubd_dev;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700792 int err = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800794 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795
796 if(ubd_gendisk[n] == NULL)
797 goto out;
798
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800799 ubd_dev = &ubd_devs[n];
Jeff Dike29d56cf2005-06-25 14:55:25 -0700800
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800801 if(ubd_dev->file == NULL)
Jeff Dike29d56cf2005-06-25 14:55:25 -0700802 goto out;
803
804 /* you cannot remove a open disk */
805 err = -EBUSY;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800806 if(ubd_dev->count > 0)
Jeff Dike29d56cf2005-06-25 14:55:25 -0700807 goto out;
808
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 del_gendisk(ubd_gendisk[n]);
810 put_disk(ubd_gendisk[n]);
811 ubd_gendisk[n] = NULL;
812
813 if(fake_gendisk[n] != NULL){
814 del_gendisk(fake_gendisk[n]);
815 put_disk(fake_gendisk[n]);
816 fake_gendisk[n] = NULL;
817 }
818
Jeff Dike62f96cb2007-02-10 01:44:16 -0800819 blk_cleanup_queue(ubd_dev->queue);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800820 platform_device_unregister(&ubd_dev->pdev);
821 *ubd_dev = ((struct ubd) DEFAULT_UBD);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 err = 0;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700823out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800824 mutex_unlock(&ubd_lock);
Jeff Dike29d56cf2005-06-25 14:55:25 -0700825 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826}
827
Jeff Dikef28169d2007-02-10 01:43:53 -0800828/* All these are called by mconsole in process context and without
Jeff Dikeb8831a12007-02-10 01:44:17 -0800829 * ubd-specific locks. The structure itself is const except for .list.
Jeff Dikef28169d2007-02-10 01:43:53 -0800830 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831static struct mc_device ubd_mc = {
Jeff Dike84f48d42007-02-10 01:44:01 -0800832 .list = LIST_HEAD_INIT(ubd_mc.list),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 .name = "ubd",
834 .config = ubd_config,
835 .get_config = ubd_get_config,
Jeff Dike29d56cf2005-06-25 14:55:25 -0700836 .id = ubd_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 .remove = ubd_remove,
838};
839
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800840static int __init ubd_mc_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841{
842 mconsole_register_dev(&ubd_mc);
843 return 0;
844}
845
846__initcall(ubd_mc_init);
847
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800848static int __init ubd0_init(void)
849{
850 struct ubd *ubd_dev = &ubd_devs[0];
851
Jeff Dikeb8831a12007-02-10 01:44:17 -0800852 mutex_lock(&ubd_lock);
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800853 if(ubd_dev->file == NULL)
854 ubd_dev->file = "root_fs";
Jeff Dikeb8831a12007-02-10 01:44:17 -0800855 mutex_unlock(&ubd_lock);
856
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800857 return(0);
858}
859
860__initcall(ubd0_init);
861
Jeff Dikeb8831a12007-02-10 01:44:17 -0800862/* Used in ubd_init, which is an initcall */
Russell King3ae5eae2005-11-09 22:32:44 +0000863static struct platform_driver ubd_driver = {
864 .driver = {
865 .name = DRIVER_NAME,
866 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867};
868
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800869static int __init ubd_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870{
Jeff Dikef28169d2007-02-10 01:43:53 -0800871 char *error;
872 int i, err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 if (register_blkdev(MAJOR_NR, "ubd"))
875 return -1;
876
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 if (fake_major != MAJOR_NR) {
878 char name[sizeof("ubd_nnn\0")];
879
880 snprintf(name, sizeof(name), "ubd_%d", fake_major);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 if (register_blkdev(fake_major, "ubd"))
882 return -1;
883 }
Russell King3ae5eae2005-11-09 22:32:44 +0000884 platform_driver_register(&ubd_driver);
Jeff Dikeb8831a12007-02-10 01:44:17 -0800885 mutex_lock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -0800886 for (i = 0; i < MAX_DEV; i++){
887 err = ubd_add(i, &error);
888 if(err)
889 printk(KERN_ERR "Failed to initialize ubd device %d :"
890 "%s\n", i, error);
891 }
Jeff Dikeb8831a12007-02-10 01:44:17 -0800892 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 return 0;
894}
895
896late_initcall(ubd_init);
897
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800898static int __init ubd_driver_init(void){
Jeff Dike91acb212005-10-10 23:10:32 -0400899 unsigned long stack;
900 int err;
901
902 /* Set by CONFIG_BLK_DEV_UBD_SYNC or ubd=sync.*/
903 if(global_openflags.s){
904 printk(KERN_INFO "ubd: Synchronous mode\n");
905 /* Letting ubd=sync be like using ubd#s= instead of ubd#= is
906 * enough. So use anyway the io thread. */
907 }
908 stack = alloc_stack(0, 0);
Jeff Dike6c29256c2006-03-27 01:14:37 -0800909 io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *),
Jeff Dike91acb212005-10-10 23:10:32 -0400910 &thread_fd);
911 if(io_pid < 0){
Jeff Dike6c29256c2006-03-27 01:14:37 -0800912 printk(KERN_ERR
Jeff Dike91acb212005-10-10 23:10:32 -0400913 "ubd : Failed to start I/O thread (errno = %d) - "
914 "falling back to synchronous I/O\n", -io_pid);
915 io_pid = -1;
916 return(0);
917 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800918 err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800919 IRQF_DISABLED, "ubd", ubd_devs);
Jeff Dike91acb212005-10-10 23:10:32 -0400920 if(err != 0)
921 printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err);
Jeff Dikef4c57a72006-03-31 02:30:10 -0800922 return 0;
Jeff Dike91acb212005-10-10 23:10:32 -0400923}
924
925device_initcall(ubd_driver_init);
926
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927static int ubd_open(struct inode *inode, struct file *filp)
928{
929 struct gendisk *disk = inode->i_bdev->bd_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800930 struct ubd *ubd_dev = disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 int err = 0;
932
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800933 if(ubd_dev->count == 0){
934 err = ubd_open_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 if(err){
936 printk(KERN_ERR "%s: Can't open \"%s\": errno = %d\n",
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800937 disk->disk_name, ubd_dev->file, -err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 goto out;
939 }
940 }
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800941 ubd_dev->count++;
942 set_disk_ro(disk, !ubd_dev->openflags.w);
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -0700943
944 /* This should no more be needed. And it didn't work anyway to exclude
945 * read-write remounting of filesystems.*/
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800946 /*if((filp->f_mode & FMODE_WRITE) && !ubd_dev->openflags.w){
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800947 if(--ubd_dev->count == 0) ubd_close_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 err = -EROFS;
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -0700949 }*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 out:
951 return(err);
952}
953
954static int ubd_release(struct inode * inode, struct file * file)
955{
956 struct gendisk *disk = inode->i_bdev->bd_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800957 struct ubd *ubd_dev = disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800959 if(--ubd_dev->count == 0)
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800960 ubd_close_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 return(0);
962}
963
Jeff Dike91acb212005-10-10 23:10:32 -0400964static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask,
965 __u64 *cow_offset, unsigned long *bitmap,
966 __u64 bitmap_offset, unsigned long *bitmap_words,
967 __u64 bitmap_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968{
Jeff Dike91acb212005-10-10 23:10:32 -0400969 __u64 sector = io_offset >> 9;
970 int i, update_bitmap = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971
Jeff Dike91acb212005-10-10 23:10:32 -0400972 for(i = 0; i < length >> 9; i++){
973 if(cow_mask != NULL)
974 ubd_set_bit(i, (unsigned char *) cow_mask);
975 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
976 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977
Jeff Dike91acb212005-10-10 23:10:32 -0400978 update_bitmap = 1;
979 ubd_set_bit(sector + i, (unsigned char *) bitmap);
980 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981
Jeff Dike91acb212005-10-10 23:10:32 -0400982 if(!update_bitmap)
983 return;
984
985 *cow_offset = sector / (sizeof(unsigned long) * 8);
986
987 /* This takes care of the case where we're exactly at the end of the
988 * device, and *cow_offset + 1 is off the end. So, just back it up
989 * by one word. Thanks to Lynn Kerby for the fix and James McMechan
990 * for the original diagnosis.
991 */
992 if(*cow_offset == ((bitmap_len + sizeof(unsigned long) - 1) /
993 sizeof(unsigned long) - 1))
994 (*cow_offset)--;
995
996 bitmap_words[0] = bitmap[*cow_offset];
997 bitmap_words[1] = bitmap[*cow_offset + 1];
998
999 *cow_offset *= sizeof(unsigned long);
1000 *cow_offset += bitmap_offset;
1001}
1002
1003static void cowify_req(struct io_thread_req *req, unsigned long *bitmap,
1004 __u64 bitmap_offset, __u64 bitmap_len)
1005{
1006 __u64 sector = req->offset >> 9;
1007 int i;
1008
1009 if(req->length > (sizeof(req->sector_mask) * 8) << 9)
1010 panic("Operation too long");
1011
1012 if(req->op == UBD_READ) {
1013 for(i = 0; i < req->length >> 9; i++){
1014 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
Jeff Dike6c29256c2006-03-27 01:14:37 -08001015 ubd_set_bit(i, (unsigned char *)
Jeff Dike91acb212005-10-10 23:10:32 -04001016 &req->sector_mask);
1017 }
1018 }
1019 else cowify_bitmap(req->offset, req->length, &req->sector_mask,
1020 &req->cow_offset, bitmap, bitmap_offset,
1021 req->bitmap_words, bitmap_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022}
1023
Jeff Dike62f96cb2007-02-10 01:44:16 -08001024/* Called with dev->lock held */
Jeff Dike91acb212005-10-10 23:10:32 -04001025static int prepare_request(struct request *req, struct io_thread_req *io_req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026{
1027 struct gendisk *disk = req->rq_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001028 struct ubd *ubd_dev = disk->private_data;
Jeff Dike91acb212005-10-10 23:10:32 -04001029 __u64 offset;
1030 int len;
1031
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -07001032 /* This should be impossible now */
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001033 if((rq_data_dir(req) == WRITE) && !ubd_dev->openflags.w){
Jeff Dike6c29256c2006-03-27 01:14:37 -08001034 printk("Write attempted on readonly ubd device %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 disk->disk_name);
Jeff Dike91acb212005-10-10 23:10:32 -04001036 end_request(req, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 return(1);
1038 }
1039
Jeff Dike91acb212005-10-10 23:10:32 -04001040 offset = ((__u64) req->sector) << 9;
1041 len = req->current_nr_sectors << 9;
1042
Jeff Dike62f96cb2007-02-10 01:44:16 -08001043 io_req->req = req;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001044 io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd : ubd_dev->fd;
1045 io_req->fds[1] = ubd_dev->fd;
Jeff Dike91acb212005-10-10 23:10:32 -04001046 io_req->cow_offset = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 io_req->offset = offset;
1048 io_req->length = len;
1049 io_req->error = 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001050 io_req->sector_mask = 0;
1051
1052 io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 io_req->offsets[0] = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001054 io_req->offsets[1] = ubd_dev->cow.data_offset;
Jeff Dike91acb212005-10-10 23:10:32 -04001055 io_req->buffer = req->buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 io_req->sectorsize = 1 << 9;
1057
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001058 if(ubd_dev->cow.file != NULL)
1059 cowify_req(io_req, ubd_dev->cow.bitmap, ubd_dev->cow.bitmap_offset,
1060 ubd_dev->cow.bitmap_len);
Jeff Dike91acb212005-10-10 23:10:32 -04001061
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 return(0);
1063}
1064
Jeff Dike62f96cb2007-02-10 01:44:16 -08001065/* Called with dev->lock held */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066static void do_ubd_request(request_queue_t *q)
1067{
1068 struct io_thread_req io_req;
1069 struct request *req;
Jeff Dike91acb212005-10-10 23:10:32 -04001070 int err, n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071
Jeff Dike91acb212005-10-10 23:10:32 -04001072 if(thread_fd == -1){
1073 while((req = elv_next_request(q)) != NULL){
1074 err = prepare_request(req, &io_req);
1075 if(!err){
1076 do_io(&io_req);
1077 __ubd_finish(req, io_req.error);
1078 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 }
1080 }
Jeff Dike91acb212005-10-10 23:10:32 -04001081 else {
Jeff Dike2a9529a2007-03-29 01:20:27 -07001082 struct ubd *dev = q->queuedata;
1083 if(dev->active || (req = elv_next_request(q)) == NULL)
Jeff Dike91acb212005-10-10 23:10:32 -04001084 return;
1085 err = prepare_request(req, &io_req);
1086 if(!err){
Jeff Dike2a9529a2007-03-29 01:20:27 -07001087 dev->active = 1;
Jeff Dike91acb212005-10-10 23:10:32 -04001088 n = os_write_file(thread_fd, (char *) &io_req,
1089 sizeof(io_req));
1090 if(n != sizeof(io_req))
1091 printk("write to io thread failed, "
1092 "errno = %d\n", -n);
1093 }
1094 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095}
1096
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001097static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
1098{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001099 struct ubd *ubd_dev = bdev->bd_disk->private_data;
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001100
1101 geo->heads = 128;
1102 geo->sectors = 32;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001103 geo->cylinders = ubd_dev->size / (128 * 32 * 512);
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001104 return 0;
1105}
1106
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107static int ubd_ioctl(struct inode * inode, struct file * file,
1108 unsigned int cmd, unsigned long arg)
1109{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001110 struct ubd *ubd_dev = inode->i_bdev->bd_disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 struct hd_driveid ubd_id = {
1112 .cyls = 0,
1113 .heads = 128,
1114 .sectors = 32,
1115 };
1116
1117 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 struct cdrom_volctrl volume;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 case HDIO_GET_IDENTITY:
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001120 ubd_id.cyls = ubd_dev->size / (128 * 32 * 512);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 if(copy_to_user((char __user *) arg, (char *) &ubd_id,
1122 sizeof(ubd_id)))
1123 return(-EFAULT);
1124 return(0);
Jeff Dikeb8831a12007-02-10 01:44:17 -08001125
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 case CDROMVOLREAD:
1127 if(copy_from_user(&volume, (char __user *) arg, sizeof(volume)))
1128 return(-EFAULT);
1129 volume.channel0 = 255;
1130 volume.channel1 = 255;
1131 volume.channel2 = 255;
1132 volume.channel3 = 255;
1133 if(copy_to_user((char __user *) arg, &volume, sizeof(volume)))
1134 return(-EFAULT);
1135 return(0);
1136 }
1137 return(-EINVAL);
1138}
1139
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001140static int path_requires_switch(char *from_cmdline, char *from_cow, char *cow)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141{
1142 struct uml_stat buf1, buf2;
1143 int err;
1144
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001145 if(from_cmdline == NULL)
1146 return 0;
1147 if(!strcmp(from_cmdline, from_cow))
1148 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149
1150 err = os_stat_file(from_cmdline, &buf1);
1151 if(err < 0){
1152 printk("Couldn't stat '%s', err = %d\n", from_cmdline, -err);
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001153 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 }
1155 err = os_stat_file(from_cow, &buf2);
1156 if(err < 0){
1157 printk("Couldn't stat '%s', err = %d\n", from_cow, -err);
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001158 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 }
1160 if((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino))
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001161 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162
1163 printk("Backing file mismatch - \"%s\" requested,\n"
1164 "\"%s\" specified in COW header of \"%s\"\n",
1165 from_cmdline, from_cow, cow);
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001166 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167}
1168
1169static int backing_file_mismatch(char *file, __u64 size, time_t mtime)
1170{
1171 unsigned long modtime;
Paolo 'Blaisorblade' Giarrussofe1db502006-02-24 13:03:58 -08001172 unsigned long long actual;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 int err;
1174
1175 err = os_file_modtime(file, &modtime);
1176 if(err < 0){
1177 printk("Failed to get modification time of backing file "
1178 "\"%s\", err = %d\n", file, -err);
1179 return(err);
1180 }
1181
1182 err = os_file_size(file, &actual);
1183 if(err < 0){
1184 printk("Failed to get size of backing file \"%s\", "
1185 "err = %d\n", file, -err);
1186 return(err);
1187 }
1188
1189 if(actual != size){
1190 /*__u64 can be a long on AMD64 and with %lu GCC complains; so
1191 * the typecast.*/
1192 printk("Size mismatch (%llu vs %llu) of COW header vs backing "
1193 "file\n", (unsigned long long) size, actual);
1194 return(-EINVAL);
1195 }
1196 if(modtime != mtime){
1197 printk("mtime mismatch (%ld vs %ld) of COW header vs backing "
1198 "file\n", mtime, modtime);
1199 return(-EINVAL);
1200 }
1201 return(0);
1202}
1203
1204int read_cow_bitmap(int fd, void *buf, int offset, int len)
1205{
1206 int err;
1207
1208 err = os_seek_file(fd, offset);
1209 if(err < 0)
1210 return(err);
1211
1212 err = os_read_file(fd, buf, len);
1213 if(err < 0)
1214 return(err);
1215
1216 return(0);
1217}
1218
Jeff Dike6c29256c2006-03-27 01:14:37 -08001219int open_ubd_file(char *file, struct openflags *openflags, int shared,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 char **backing_file_out, int *bitmap_offset_out,
1221 unsigned long *bitmap_len_out, int *data_offset_out,
1222 int *create_cow_out)
1223{
1224 time_t mtime;
1225 unsigned long long size;
1226 __u32 version, align;
1227 char *backing_file;
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001228 int fd, err, sectorsize, asked_switch, mode = 0644;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229
1230 fd = os_open_file(file, *openflags, mode);
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001231 if (fd < 0) {
1232 if ((fd == -ENOENT) && (create_cow_out != NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233 *create_cow_out = 1;
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001234 if (!openflags->w ||
1235 ((fd != -EROFS) && (fd != -EACCES)))
1236 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 openflags->w = 0;
1238 fd = os_open_file(file, *openflags, mode);
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001239 if (fd < 0)
1240 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 }
1242
Jeff Dike6c29256c2006-03-27 01:14:37 -08001243 if(shared)
1244 printk("Not locking \"%s\" on the host\n", file);
1245 else {
1246 err = os_lock_file(fd, openflags->w);
1247 if(err < 0){
1248 printk("Failed to lock '%s', err = %d\n", file, -err);
1249 goto out_close;
1250 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 }
1252
Andreas Mohrd6e05ed2006-06-26 18:35:02 +02001253 /* Successful return case! */
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001254 if(backing_file_out == NULL)
1255 return(fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256
1257 err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime,
1258 &size, &sectorsize, &align, bitmap_offset_out);
1259 if(err && (*backing_file_out != NULL)){
1260 printk("Failed to read COW header from COW file \"%s\", "
1261 "errno = %d\n", file, -err);
1262 goto out_close;
1263 }
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001264 if(err)
1265 return(fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001267 asked_switch = path_requires_switch(*backing_file_out, backing_file, file);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001269 /* Allow switching only if no mismatch. */
1270 if (asked_switch && !backing_file_mismatch(*backing_file_out, size, mtime)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271 printk("Switching backing file to '%s'\n", *backing_file_out);
1272 err = write_cow_header(file, fd, *backing_file_out,
1273 sectorsize, align, &size);
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001274 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 printk("Switch failed, errno = %d\n", -err);
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001276 goto out_close;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 }
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001278 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279 *backing_file_out = backing_file;
1280 err = backing_file_mismatch(*backing_file_out, size, mtime);
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001281 if (err)
1282 goto out_close;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283 }
1284
1285 cow_sizes(version, size, sectorsize, align, *bitmap_offset_out,
1286 bitmap_len_out, data_offset_out);
1287
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001288 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 out_close:
1290 os_close_file(fd);
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001291 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292}
1293
1294int create_cow_file(char *cow_file, char *backing_file, struct openflags flags,
1295 int sectorsize, int alignment, int *bitmap_offset_out,
1296 unsigned long *bitmap_len_out, int *data_offset_out)
1297{
1298 int err, fd;
1299
1300 flags.c = 1;
Jeff Dike6c29256c2006-03-27 01:14:37 -08001301 fd = open_ubd_file(cow_file, &flags, 0, NULL, NULL, NULL, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 if(fd < 0){
1303 err = fd;
1304 printk("Open of COW file '%s' failed, errno = %d\n", cow_file,
1305 -err);
1306 goto out;
1307 }
1308
1309 err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment,
1310 bitmap_offset_out, bitmap_len_out,
1311 data_offset_out);
1312 if(!err)
1313 return(fd);
1314 os_close_file(fd);
1315 out:
1316 return(err);
1317}
1318
Jeff Dike91acb212005-10-10 23:10:32 -04001319static int update_bitmap(struct io_thread_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320{
Jeff Dike91acb212005-10-10 23:10:32 -04001321 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322
Jeff Dike91acb212005-10-10 23:10:32 -04001323 if(req->cow_offset == -1)
1324 return(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325
Jeff Dike91acb212005-10-10 23:10:32 -04001326 n = os_seek_file(req->fds[1], req->cow_offset);
1327 if(n < 0){
1328 printk("do_io - bitmap lseek failed : err = %d\n", -n);
1329 return(1);
1330 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331
Jeff Dike91acb212005-10-10 23:10:32 -04001332 n = os_write_file(req->fds[1], &req->bitmap_words,
1333 sizeof(req->bitmap_words));
1334 if(n != sizeof(req->bitmap_words)){
1335 printk("do_io - bitmap update failed, err = %d fd = %d\n", -n,
1336 req->fds[1]);
1337 return(1);
1338 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339
Jeff Dike91acb212005-10-10 23:10:32 -04001340 return(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341}
Jeff Dike91acb212005-10-10 23:10:32 -04001342
1343void do_io(struct io_thread_req *req)
1344{
1345 char *buf;
1346 unsigned long len;
1347 int n, nsectors, start, end, bit;
1348 int err;
1349 __u64 off;
1350
1351 nsectors = req->length / req->sectorsize;
1352 start = 0;
1353 do {
1354 bit = ubd_test_bit(start, (unsigned char *) &req->sector_mask);
1355 end = start;
1356 while((end < nsectors) &&
1357 (ubd_test_bit(end, (unsigned char *)
1358 &req->sector_mask) == bit))
1359 end++;
1360
1361 off = req->offset + req->offsets[bit] +
1362 start * req->sectorsize;
1363 len = (end - start) * req->sectorsize;
1364 buf = &req->buffer[start * req->sectorsize];
1365
1366 err = os_seek_file(req->fds[bit], off);
1367 if(err < 0){
1368 printk("do_io - lseek failed : err = %d\n", -err);
1369 req->error = 1;
1370 return;
1371 }
1372 if(req->op == UBD_READ){
1373 n = 0;
1374 do {
1375 buf = &buf[n];
1376 len -= n;
1377 n = os_read_file(req->fds[bit], buf, len);
1378 if (n < 0) {
1379 printk("do_io - read failed, err = %d "
1380 "fd = %d\n", -n, req->fds[bit]);
1381 req->error = 1;
1382 return;
1383 }
1384 } while((n < len) && (n != 0));
1385 if (n < len) memset(&buf[n], 0, len - n);
1386 } else {
1387 n = os_write_file(req->fds[bit], buf, len);
1388 if(n != len){
1389 printk("do_io - write failed err = %d "
1390 "fd = %d\n", -n, req->fds[bit]);
1391 req->error = 1;
1392 return;
1393 }
1394 }
1395
1396 start = end;
1397 } while(start < nsectors);
1398
1399 req->error = update_bitmap(req);
1400}
1401
1402/* Changed in start_io_thread, which is serialized by being called only
1403 * from ubd_init, which is an initcall.
1404 */
1405int kernel_fd = -1;
1406
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001407/* Only changed by the io thread. XXX: currently unused. */
1408static int io_count = 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001409
1410int io_thread(void *arg)
1411{
1412 struct io_thread_req req;
1413 int n;
1414
1415 ignore_sigwinch_sig();
1416 while(1){
1417 n = os_read_file(kernel_fd, &req, sizeof(req));
1418 if(n != sizeof(req)){
1419 if(n < 0)
1420 printk("io_thread - read failed, fd = %d, "
1421 "err = %d\n", kernel_fd, -n);
1422 else {
1423 printk("io_thread - short read, fd = %d, "
1424 "length = %d\n", kernel_fd, n);
1425 }
1426 continue;
1427 }
1428 io_count++;
1429 do_io(&req);
1430 n = os_write_file(kernel_fd, &req, sizeof(req));
1431 if(n != sizeof(req))
1432 printk("io_thread - write failed, fd = %d, err = %d\n",
1433 kernel_fd, -n);
1434 }
Jeff Dike91acb212005-10-10 23:10:32 -04001435
Jeff Dike1b57e9c2006-01-06 00:18:49 -08001436 return 0;
1437}