blob: 53c36d1770c5df94167433c29726dee9cafca105 [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{
Jeff Dikeb47d2de2007-05-06 14:51:01 -0700791 struct gendisk *disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800792 struct ubd *ubd_dev;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700793 int err = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800795 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800797 ubd_dev = &ubd_devs[n];
Jeff Dike29d56cf2005-06-25 14:55:25 -0700798
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800799 if(ubd_dev->file == NULL)
Jeff Dike29d56cf2005-06-25 14:55:25 -0700800 goto out;
801
802 /* you cannot remove a open disk */
803 err = -EBUSY;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800804 if(ubd_dev->count > 0)
Jeff Dike29d56cf2005-06-25 14:55:25 -0700805 goto out;
806
Jeff Dikeb47d2de2007-05-06 14:51:01 -0700807 disk = ubd_gendisk[n];
808 ubd_gendisk[n] = NULL;
809 if(disk != NULL){
810 del_gendisk(disk);
811 put_disk(disk);
812 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813
814 if(fake_gendisk[n] != NULL){
815 del_gendisk(fake_gendisk[n]);
816 put_disk(fake_gendisk[n]);
817 fake_gendisk[n] = NULL;
818 }
819
Jeff Dike62f96cb2007-02-10 01:44:16 -0800820 blk_cleanup_queue(ubd_dev->queue);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800821 platform_device_unregister(&ubd_dev->pdev);
822 *ubd_dev = ((struct ubd) DEFAULT_UBD);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 err = 0;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700824out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800825 mutex_unlock(&ubd_lock);
Jeff Dike29d56cf2005-06-25 14:55:25 -0700826 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827}
828
Jeff Dikef28169d2007-02-10 01:43:53 -0800829/* All these are called by mconsole in process context and without
Jeff Dikeb8831a12007-02-10 01:44:17 -0800830 * ubd-specific locks. The structure itself is const except for .list.
Jeff Dikef28169d2007-02-10 01:43:53 -0800831 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832static struct mc_device ubd_mc = {
Jeff Dike84f48d42007-02-10 01:44:01 -0800833 .list = LIST_HEAD_INIT(ubd_mc.list),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 .name = "ubd",
835 .config = ubd_config,
836 .get_config = ubd_get_config,
Jeff Dike29d56cf2005-06-25 14:55:25 -0700837 .id = ubd_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 .remove = ubd_remove,
839};
840
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800841static int __init ubd_mc_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842{
843 mconsole_register_dev(&ubd_mc);
844 return 0;
845}
846
847__initcall(ubd_mc_init);
848
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800849static int __init ubd0_init(void)
850{
851 struct ubd *ubd_dev = &ubd_devs[0];
852
Jeff Dikeb8831a12007-02-10 01:44:17 -0800853 mutex_lock(&ubd_lock);
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800854 if(ubd_dev->file == NULL)
855 ubd_dev->file = "root_fs";
Jeff Dikeb8831a12007-02-10 01:44:17 -0800856 mutex_unlock(&ubd_lock);
857
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800858 return(0);
859}
860
861__initcall(ubd0_init);
862
Jeff Dikeb8831a12007-02-10 01:44:17 -0800863/* Used in ubd_init, which is an initcall */
Russell King3ae5eae2005-11-09 22:32:44 +0000864static struct platform_driver ubd_driver = {
865 .driver = {
866 .name = DRIVER_NAME,
867 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868};
869
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800870static int __init ubd_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871{
Jeff Dikef28169d2007-02-10 01:43:53 -0800872 char *error;
873 int i, err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 if (register_blkdev(MAJOR_NR, "ubd"))
876 return -1;
877
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 if (fake_major != MAJOR_NR) {
879 char name[sizeof("ubd_nnn\0")];
880
881 snprintf(name, sizeof(name), "ubd_%d", fake_major);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 if (register_blkdev(fake_major, "ubd"))
883 return -1;
884 }
Russell King3ae5eae2005-11-09 22:32:44 +0000885 platform_driver_register(&ubd_driver);
Jeff Dikeb8831a12007-02-10 01:44:17 -0800886 mutex_lock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -0800887 for (i = 0; i < MAX_DEV; i++){
888 err = ubd_add(i, &error);
889 if(err)
890 printk(KERN_ERR "Failed to initialize ubd device %d :"
891 "%s\n", i, error);
892 }
Jeff Dikeb8831a12007-02-10 01:44:17 -0800893 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 return 0;
895}
896
897late_initcall(ubd_init);
898
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800899static int __init ubd_driver_init(void){
Jeff Dike91acb212005-10-10 23:10:32 -0400900 unsigned long stack;
901 int err;
902
903 /* Set by CONFIG_BLK_DEV_UBD_SYNC or ubd=sync.*/
904 if(global_openflags.s){
905 printk(KERN_INFO "ubd: Synchronous mode\n");
906 /* Letting ubd=sync be like using ubd#s= instead of ubd#= is
907 * enough. So use anyway the io thread. */
908 }
909 stack = alloc_stack(0, 0);
Jeff Dike6c29256c2006-03-27 01:14:37 -0800910 io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *),
Jeff Dike91acb212005-10-10 23:10:32 -0400911 &thread_fd);
912 if(io_pid < 0){
Jeff Dike6c29256c2006-03-27 01:14:37 -0800913 printk(KERN_ERR
Jeff Dike91acb212005-10-10 23:10:32 -0400914 "ubd : Failed to start I/O thread (errno = %d) - "
915 "falling back to synchronous I/O\n", -io_pid);
916 io_pid = -1;
917 return(0);
918 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800919 err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800920 IRQF_DISABLED, "ubd", ubd_devs);
Jeff Dike91acb212005-10-10 23:10:32 -0400921 if(err != 0)
922 printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err);
Jeff Dikef4c57a72006-03-31 02:30:10 -0800923 return 0;
Jeff Dike91acb212005-10-10 23:10:32 -0400924}
925
926device_initcall(ubd_driver_init);
927
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928static int ubd_open(struct inode *inode, struct file *filp)
929{
930 struct gendisk *disk = inode->i_bdev->bd_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800931 struct ubd *ubd_dev = disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 int err = 0;
933
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800934 if(ubd_dev->count == 0){
935 err = ubd_open_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 if(err){
937 printk(KERN_ERR "%s: Can't open \"%s\": errno = %d\n",
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800938 disk->disk_name, ubd_dev->file, -err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 goto out;
940 }
941 }
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800942 ubd_dev->count++;
943 set_disk_ro(disk, !ubd_dev->openflags.w);
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -0700944
945 /* This should no more be needed. And it didn't work anyway to exclude
946 * read-write remounting of filesystems.*/
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800947 /*if((filp->f_mode & FMODE_WRITE) && !ubd_dev->openflags.w){
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800948 if(--ubd_dev->count == 0) ubd_close_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 err = -EROFS;
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -0700950 }*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 out:
952 return(err);
953}
954
955static int ubd_release(struct inode * inode, struct file * file)
956{
957 struct gendisk *disk = inode->i_bdev->bd_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800958 struct ubd *ubd_dev = disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800960 if(--ubd_dev->count == 0)
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800961 ubd_close_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 return(0);
963}
964
Jeff Dike91acb212005-10-10 23:10:32 -0400965static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask,
966 __u64 *cow_offset, unsigned long *bitmap,
967 __u64 bitmap_offset, unsigned long *bitmap_words,
968 __u64 bitmap_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969{
Jeff Dike91acb212005-10-10 23:10:32 -0400970 __u64 sector = io_offset >> 9;
971 int i, update_bitmap = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972
Jeff Dike91acb212005-10-10 23:10:32 -0400973 for(i = 0; i < length >> 9; i++){
974 if(cow_mask != NULL)
975 ubd_set_bit(i, (unsigned char *) cow_mask);
976 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
977 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978
Jeff Dike91acb212005-10-10 23:10:32 -0400979 update_bitmap = 1;
980 ubd_set_bit(sector + i, (unsigned char *) bitmap);
981 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982
Jeff Dike91acb212005-10-10 23:10:32 -0400983 if(!update_bitmap)
984 return;
985
986 *cow_offset = sector / (sizeof(unsigned long) * 8);
987
988 /* This takes care of the case where we're exactly at the end of the
989 * device, and *cow_offset + 1 is off the end. So, just back it up
990 * by one word. Thanks to Lynn Kerby for the fix and James McMechan
991 * for the original diagnosis.
992 */
993 if(*cow_offset == ((bitmap_len + sizeof(unsigned long) - 1) /
994 sizeof(unsigned long) - 1))
995 (*cow_offset)--;
996
997 bitmap_words[0] = bitmap[*cow_offset];
998 bitmap_words[1] = bitmap[*cow_offset + 1];
999
1000 *cow_offset *= sizeof(unsigned long);
1001 *cow_offset += bitmap_offset;
1002}
1003
1004static void cowify_req(struct io_thread_req *req, unsigned long *bitmap,
1005 __u64 bitmap_offset, __u64 bitmap_len)
1006{
1007 __u64 sector = req->offset >> 9;
1008 int i;
1009
1010 if(req->length > (sizeof(req->sector_mask) * 8) << 9)
1011 panic("Operation too long");
1012
1013 if(req->op == UBD_READ) {
1014 for(i = 0; i < req->length >> 9; i++){
1015 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
Jeff Dike6c29256c2006-03-27 01:14:37 -08001016 ubd_set_bit(i, (unsigned char *)
Jeff Dike91acb212005-10-10 23:10:32 -04001017 &req->sector_mask);
1018 }
1019 }
1020 else cowify_bitmap(req->offset, req->length, &req->sector_mask,
1021 &req->cow_offset, bitmap, bitmap_offset,
1022 req->bitmap_words, bitmap_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023}
1024
Jeff Dike62f96cb2007-02-10 01:44:16 -08001025/* Called with dev->lock held */
Jeff Dike91acb212005-10-10 23:10:32 -04001026static int prepare_request(struct request *req, struct io_thread_req *io_req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027{
1028 struct gendisk *disk = req->rq_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001029 struct ubd *ubd_dev = disk->private_data;
Jeff Dike91acb212005-10-10 23:10:32 -04001030 __u64 offset;
1031 int len;
1032
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -07001033 /* This should be impossible now */
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001034 if((rq_data_dir(req) == WRITE) && !ubd_dev->openflags.w){
Jeff Dike6c29256c2006-03-27 01:14:37 -08001035 printk("Write attempted on readonly ubd device %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 disk->disk_name);
Jeff Dike91acb212005-10-10 23:10:32 -04001037 end_request(req, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 return(1);
1039 }
1040
Jeff Dike91acb212005-10-10 23:10:32 -04001041 offset = ((__u64) req->sector) << 9;
1042 len = req->current_nr_sectors << 9;
1043
Jeff Dike62f96cb2007-02-10 01:44:16 -08001044 io_req->req = req;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001045 io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd : ubd_dev->fd;
1046 io_req->fds[1] = ubd_dev->fd;
Jeff Dike91acb212005-10-10 23:10:32 -04001047 io_req->cow_offset = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 io_req->offset = offset;
1049 io_req->length = len;
1050 io_req->error = 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001051 io_req->sector_mask = 0;
1052
1053 io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 io_req->offsets[0] = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001055 io_req->offsets[1] = ubd_dev->cow.data_offset;
Jeff Dike91acb212005-10-10 23:10:32 -04001056 io_req->buffer = req->buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 io_req->sectorsize = 1 << 9;
1058
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001059 if(ubd_dev->cow.file != NULL)
1060 cowify_req(io_req, ubd_dev->cow.bitmap, ubd_dev->cow.bitmap_offset,
1061 ubd_dev->cow.bitmap_len);
Jeff Dike91acb212005-10-10 23:10:32 -04001062
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 return(0);
1064}
1065
Jeff Dike62f96cb2007-02-10 01:44:16 -08001066/* Called with dev->lock held */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067static void do_ubd_request(request_queue_t *q)
1068{
1069 struct io_thread_req io_req;
1070 struct request *req;
Jeff Dike91acb212005-10-10 23:10:32 -04001071 int err, n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072
Jeff Dike91acb212005-10-10 23:10:32 -04001073 if(thread_fd == -1){
1074 while((req = elv_next_request(q)) != NULL){
1075 err = prepare_request(req, &io_req);
1076 if(!err){
1077 do_io(&io_req);
1078 __ubd_finish(req, io_req.error);
1079 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 }
1081 }
Jeff Dike91acb212005-10-10 23:10:32 -04001082 else {
Jeff Dike2a9529a2007-03-29 01:20:27 -07001083 struct ubd *dev = q->queuedata;
1084 if(dev->active || (req = elv_next_request(q)) == NULL)
Jeff Dike91acb212005-10-10 23:10:32 -04001085 return;
1086 err = prepare_request(req, &io_req);
1087 if(!err){
Jeff Dike2a9529a2007-03-29 01:20:27 -07001088 dev->active = 1;
Jeff Dike91acb212005-10-10 23:10:32 -04001089 n = os_write_file(thread_fd, (char *) &io_req,
1090 sizeof(io_req));
1091 if(n != sizeof(io_req))
1092 printk("write to io thread failed, "
1093 "errno = %d\n", -n);
1094 }
1095 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096}
1097
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001098static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
1099{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001100 struct ubd *ubd_dev = bdev->bd_disk->private_data;
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001101
1102 geo->heads = 128;
1103 geo->sectors = 32;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001104 geo->cylinders = ubd_dev->size / (128 * 32 * 512);
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001105 return 0;
1106}
1107
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108static int ubd_ioctl(struct inode * inode, struct file * file,
1109 unsigned int cmd, unsigned long arg)
1110{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001111 struct ubd *ubd_dev = inode->i_bdev->bd_disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 struct hd_driveid ubd_id = {
1113 .cyls = 0,
1114 .heads = 128,
1115 .sectors = 32,
1116 };
1117
1118 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 struct cdrom_volctrl volume;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 case HDIO_GET_IDENTITY:
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001121 ubd_id.cyls = ubd_dev->size / (128 * 32 * 512);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 if(copy_to_user((char __user *) arg, (char *) &ubd_id,
1123 sizeof(ubd_id)))
1124 return(-EFAULT);
1125 return(0);
Jeff Dikeb8831a12007-02-10 01:44:17 -08001126
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 case CDROMVOLREAD:
1128 if(copy_from_user(&volume, (char __user *) arg, sizeof(volume)))
1129 return(-EFAULT);
1130 volume.channel0 = 255;
1131 volume.channel1 = 255;
1132 volume.channel2 = 255;
1133 volume.channel3 = 255;
1134 if(copy_to_user((char __user *) arg, &volume, sizeof(volume)))
1135 return(-EFAULT);
1136 return(0);
1137 }
1138 return(-EINVAL);
1139}
1140
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001141static int path_requires_switch(char *from_cmdline, char *from_cow, char *cow)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142{
1143 struct uml_stat buf1, buf2;
1144 int err;
1145
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001146 if(from_cmdline == NULL)
1147 return 0;
1148 if(!strcmp(from_cmdline, from_cow))
1149 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150
1151 err = os_stat_file(from_cmdline, &buf1);
1152 if(err < 0){
1153 printk("Couldn't stat '%s', err = %d\n", from_cmdline, -err);
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001154 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 }
1156 err = os_stat_file(from_cow, &buf2);
1157 if(err < 0){
1158 printk("Couldn't stat '%s', err = %d\n", from_cow, -err);
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001159 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 }
1161 if((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino))
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001162 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163
1164 printk("Backing file mismatch - \"%s\" requested,\n"
1165 "\"%s\" specified in COW header of \"%s\"\n",
1166 from_cmdline, from_cow, cow);
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001167 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168}
1169
1170static int backing_file_mismatch(char *file, __u64 size, time_t mtime)
1171{
1172 unsigned long modtime;
Paolo 'Blaisorblade' Giarrussofe1db502006-02-24 13:03:58 -08001173 unsigned long long actual;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 int err;
1175
1176 err = os_file_modtime(file, &modtime);
1177 if(err < 0){
1178 printk("Failed to get modification time of backing file "
1179 "\"%s\", err = %d\n", file, -err);
1180 return(err);
1181 }
1182
1183 err = os_file_size(file, &actual);
1184 if(err < 0){
1185 printk("Failed to get size of backing file \"%s\", "
1186 "err = %d\n", file, -err);
1187 return(err);
1188 }
1189
1190 if(actual != size){
1191 /*__u64 can be a long on AMD64 and with %lu GCC complains; so
1192 * the typecast.*/
1193 printk("Size mismatch (%llu vs %llu) of COW header vs backing "
1194 "file\n", (unsigned long long) size, actual);
1195 return(-EINVAL);
1196 }
1197 if(modtime != mtime){
1198 printk("mtime mismatch (%ld vs %ld) of COW header vs backing "
1199 "file\n", mtime, modtime);
1200 return(-EINVAL);
1201 }
1202 return(0);
1203}
1204
1205int read_cow_bitmap(int fd, void *buf, int offset, int len)
1206{
1207 int err;
1208
1209 err = os_seek_file(fd, offset);
1210 if(err < 0)
1211 return(err);
1212
1213 err = os_read_file(fd, buf, len);
1214 if(err < 0)
1215 return(err);
1216
1217 return(0);
1218}
1219
Jeff Dike6c29256c2006-03-27 01:14:37 -08001220int open_ubd_file(char *file, struct openflags *openflags, int shared,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 char **backing_file_out, int *bitmap_offset_out,
1222 unsigned long *bitmap_len_out, int *data_offset_out,
1223 int *create_cow_out)
1224{
1225 time_t mtime;
1226 unsigned long long size;
1227 __u32 version, align;
1228 char *backing_file;
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001229 int fd, err, sectorsize, asked_switch, mode = 0644;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230
1231 fd = os_open_file(file, *openflags, mode);
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001232 if (fd < 0) {
1233 if ((fd == -ENOENT) && (create_cow_out != NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 *create_cow_out = 1;
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001235 if (!openflags->w ||
1236 ((fd != -EROFS) && (fd != -EACCES)))
1237 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238 openflags->w = 0;
1239 fd = os_open_file(file, *openflags, mode);
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001240 if (fd < 0)
1241 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 }
1243
Jeff Dike6c29256c2006-03-27 01:14:37 -08001244 if(shared)
1245 printk("Not locking \"%s\" on the host\n", file);
1246 else {
1247 err = os_lock_file(fd, openflags->w);
1248 if(err < 0){
1249 printk("Failed to lock '%s', err = %d\n", file, -err);
1250 goto out_close;
1251 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 }
1253
Andreas Mohrd6e05ed2006-06-26 18:35:02 +02001254 /* Successful return case! */
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001255 if(backing_file_out == NULL)
1256 return(fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257
1258 err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime,
1259 &size, &sectorsize, &align, bitmap_offset_out);
1260 if(err && (*backing_file_out != NULL)){
1261 printk("Failed to read COW header from COW file \"%s\", "
1262 "errno = %d\n", file, -err);
1263 goto out_close;
1264 }
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001265 if(err)
1266 return(fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001268 asked_switch = path_requires_switch(*backing_file_out, backing_file, file);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001270 /* Allow switching only if no mismatch. */
1271 if (asked_switch && !backing_file_mismatch(*backing_file_out, size, mtime)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 printk("Switching backing file to '%s'\n", *backing_file_out);
1273 err = write_cow_header(file, fd, *backing_file_out,
1274 sectorsize, align, &size);
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001275 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 printk("Switch failed, errno = %d\n", -err);
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001277 goto out_close;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 }
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001279 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 *backing_file_out = backing_file;
1281 err = backing_file_mismatch(*backing_file_out, size, mtime);
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001282 if (err)
1283 goto out_close;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284 }
1285
1286 cow_sizes(version, size, sectorsize, align, *bitmap_offset_out,
1287 bitmap_len_out, data_offset_out);
1288
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001289 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 out_close:
1291 os_close_file(fd);
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001292 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293}
1294
1295int create_cow_file(char *cow_file, char *backing_file, struct openflags flags,
1296 int sectorsize, int alignment, int *bitmap_offset_out,
1297 unsigned long *bitmap_len_out, int *data_offset_out)
1298{
1299 int err, fd;
1300
1301 flags.c = 1;
Jeff Dike6c29256c2006-03-27 01:14:37 -08001302 fd = open_ubd_file(cow_file, &flags, 0, NULL, NULL, NULL, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 if(fd < 0){
1304 err = fd;
1305 printk("Open of COW file '%s' failed, errno = %d\n", cow_file,
1306 -err);
1307 goto out;
1308 }
1309
1310 err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment,
1311 bitmap_offset_out, bitmap_len_out,
1312 data_offset_out);
1313 if(!err)
1314 return(fd);
1315 os_close_file(fd);
1316 out:
1317 return(err);
1318}
1319
Jeff Dike91acb212005-10-10 23:10:32 -04001320static int update_bitmap(struct io_thread_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321{
Jeff Dike91acb212005-10-10 23:10:32 -04001322 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323
Jeff Dike91acb212005-10-10 23:10:32 -04001324 if(req->cow_offset == -1)
1325 return(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326
Jeff Dike91acb212005-10-10 23:10:32 -04001327 n = os_seek_file(req->fds[1], req->cow_offset);
1328 if(n < 0){
1329 printk("do_io - bitmap lseek failed : err = %d\n", -n);
1330 return(1);
1331 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332
Jeff Dike91acb212005-10-10 23:10:32 -04001333 n = os_write_file(req->fds[1], &req->bitmap_words,
1334 sizeof(req->bitmap_words));
1335 if(n != sizeof(req->bitmap_words)){
1336 printk("do_io - bitmap update failed, err = %d fd = %d\n", -n,
1337 req->fds[1]);
1338 return(1);
1339 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340
Jeff Dike91acb212005-10-10 23:10:32 -04001341 return(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342}
Jeff Dike91acb212005-10-10 23:10:32 -04001343
1344void do_io(struct io_thread_req *req)
1345{
1346 char *buf;
1347 unsigned long len;
1348 int n, nsectors, start, end, bit;
1349 int err;
1350 __u64 off;
1351
1352 nsectors = req->length / req->sectorsize;
1353 start = 0;
1354 do {
1355 bit = ubd_test_bit(start, (unsigned char *) &req->sector_mask);
1356 end = start;
1357 while((end < nsectors) &&
1358 (ubd_test_bit(end, (unsigned char *)
1359 &req->sector_mask) == bit))
1360 end++;
1361
1362 off = req->offset + req->offsets[bit] +
1363 start * req->sectorsize;
1364 len = (end - start) * req->sectorsize;
1365 buf = &req->buffer[start * req->sectorsize];
1366
1367 err = os_seek_file(req->fds[bit], off);
1368 if(err < 0){
1369 printk("do_io - lseek failed : err = %d\n", -err);
1370 req->error = 1;
1371 return;
1372 }
1373 if(req->op == UBD_READ){
1374 n = 0;
1375 do {
1376 buf = &buf[n];
1377 len -= n;
1378 n = os_read_file(req->fds[bit], buf, len);
1379 if (n < 0) {
1380 printk("do_io - read failed, err = %d "
1381 "fd = %d\n", -n, req->fds[bit]);
1382 req->error = 1;
1383 return;
1384 }
1385 } while((n < len) && (n != 0));
1386 if (n < len) memset(&buf[n], 0, len - n);
1387 } else {
1388 n = os_write_file(req->fds[bit], buf, len);
1389 if(n != len){
1390 printk("do_io - write failed err = %d "
1391 "fd = %d\n", -n, req->fds[bit]);
1392 req->error = 1;
1393 return;
1394 }
1395 }
1396
1397 start = end;
1398 } while(start < nsectors);
1399
1400 req->error = update_bitmap(req);
1401}
1402
1403/* Changed in start_io_thread, which is serialized by being called only
1404 * from ubd_init, which is an initcall.
1405 */
1406int kernel_fd = -1;
1407
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001408/* Only changed by the io thread. XXX: currently unused. */
1409static int io_count = 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001410
1411int io_thread(void *arg)
1412{
1413 struct io_thread_req req;
1414 int n;
1415
1416 ignore_sigwinch_sig();
1417 while(1){
1418 n = os_read_file(kernel_fd, &req, sizeof(req));
1419 if(n != sizeof(req)){
1420 if(n < 0)
1421 printk("io_thread - read failed, fd = %d, "
1422 "err = %d\n", kernel_fd, -n);
1423 else {
1424 printk("io_thread - short read, fd = %d, "
1425 "length = %d\n", kernel_fd, n);
1426 }
1427 continue;
1428 }
1429 io_count++;
1430 do_io(&req);
1431 n = os_write_file(kernel_fd, &req, sizeof(req));
1432 if(n != sizeof(req))
1433 printk("io_thread - write failed, fd = %d, err = %d\n",
1434 kernel_fd, -n);
1435 }
Jeff Dike91acb212005-10-10 23:10:32 -04001436
Jeff Dike1b57e9c2006-01-06 00:18:49 -08001437 return 0;
1438}