blob: f98d26e513813483dc27681ce75f180e7566f4ae [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
Paolo 'Blaisorblade' Giarrusso2fe30a32006-10-30 22:07:09 -0800112/* XXX - this made sense in 2.4 days, now it's only used as a boolean, and
113 * probably it doesn't make sense even for that. */
114static int do_ubd;
Jeff Dike91acb212005-10-10 23:10:32 -0400115
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116static int ubd_open(struct inode * inode, struct file * filp);
117static int ubd_release(struct inode * inode, struct file * file);
118static int ubd_ioctl(struct inode * inode, struct file * file,
119 unsigned int cmd, unsigned long arg);
Christoph Hellwiga885c8c2006-01-08 01:02:50 -0800120static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121
Paolo 'Blaisorblade' Giarrusso97d88ac2006-10-30 22:07:03 -0800122#define MAX_DEV (16)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124static struct block_device_operations ubd_blops = {
125 .owner = THIS_MODULE,
126 .open = ubd_open,
127 .release = ubd_release,
128 .ioctl = ubd_ioctl,
Christoph Hellwiga885c8c2006-01-08 01:02:50 -0800129 .getgeo = ubd_getgeo,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130};
131
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132/* Protected by ubd_lock */
133static int fake_major = MAJOR_NR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134static struct gendisk *ubd_gendisk[MAX_DEV];
135static struct gendisk *fake_gendisk[MAX_DEV];
Jeff Dike6c29256c2006-03-27 01:14:37 -0800136
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137#ifdef CONFIG_BLK_DEV_UBD_SYNC
138#define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 1, .c = 0, \
139 .cl = 1 })
140#else
141#define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 0, .c = 0, \
142 .cl = 1 })
143#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144static struct openflags global_openflags = OPEN_FLAGS;
145
146struct cow {
Paolo 'Blaisorblade' Giarrusso2a9d32f2006-10-30 22:07:04 -0800147 /* backing file name */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 char *file;
Paolo 'Blaisorblade' Giarrusso2a9d32f2006-10-30 22:07:04 -0800149 /* backing file fd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 int fd;
151 unsigned long *bitmap;
152 unsigned long bitmap_len;
153 int bitmap_offset;
154 int data_offset;
155};
156
157struct ubd {
Paolo 'Blaisorblade' Giarrusso2a9d32f2006-10-30 22:07:04 -0800158 /* name (and fd, below) of the file opened for writing, either the
159 * backing or the cow file. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 char *file;
161 int count;
162 int fd;
163 __u64 size;
164 struct openflags boot_openflags;
165 struct openflags openflags;
Paolo 'Blaisorblade' Giarrusso84e945e2006-10-30 22:07:10 -0800166 unsigned shared:1;
167 unsigned no_cow:1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 struct cow cow;
169 struct platform_device pdev;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800170 struct request_queue *queue;
171 spinlock_t lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172};
173
174#define DEFAULT_COW { \
175 .file = NULL, \
176 .fd = -1, \
177 .bitmap = NULL, \
178 .bitmap_offset = 0, \
179 .data_offset = 0, \
180}
181
182#define DEFAULT_UBD { \
183 .file = NULL, \
184 .count = 0, \
185 .fd = -1, \
186 .size = -1, \
187 .boot_openflags = OPEN_FLAGS, \
188 .openflags = OPEN_FLAGS, \
189 .no_cow = 0, \
Jeff Dike6c29256c2006-03-27 01:14:37 -0800190 .shared = 0, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 .cow = DEFAULT_COW, \
Jeff Dike62f96cb2007-02-10 01:44:16 -0800192 .lock = SPIN_LOCK_UNLOCKED, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193}
194
Jeff Dikeb8831a12007-02-10 01:44:17 -0800195/* Protected by ubd_lock */
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800196struct ubd ubd_devs[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_UBD };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198/* Only changed by fake_ide_setup which is a setup */
199static int fake_ide = 0;
200static struct proc_dir_entry *proc_ide_root = NULL;
201static struct proc_dir_entry *proc_ide = NULL;
202
203static void make_proc_ide(void)
204{
205 proc_ide_root = proc_mkdir("ide", NULL);
206 proc_ide = proc_mkdir("ide0", proc_ide_root);
207}
208
209static int proc_ide_read_media(char *page, char **start, off_t off, int count,
210 int *eof, void *data)
211{
212 int len;
213
214 strcpy(page, "disk\n");
215 len = strlen("disk\n");
216 len -= off;
217 if (len < count){
218 *eof = 1;
219 if (len <= 0) return 0;
220 }
221 else len = count;
222 *start = page + off;
223 return len;
224}
225
226static void make_ide_entries(char *dev_name)
227{
228 struct proc_dir_entry *dir, *ent;
229 char name[64];
230
231 if(proc_ide_root == NULL) make_proc_ide();
232
233 dir = proc_mkdir(dev_name, proc_ide);
234 if(!dir) return;
235
236 ent = create_proc_entry("media", S_IFREG|S_IRUGO, dir);
237 if(!ent) return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 ent->data = NULL;
239 ent->read_proc = proc_ide_read_media;
240 ent->write_proc = NULL;
241 sprintf(name,"ide0/%s", dev_name);
242 proc_symlink(dev_name, proc_ide_root, name);
243}
244
245static int fake_ide_setup(char *str)
246{
247 fake_ide = 1;
248 return(1);
249}
250
251__setup("fake_ide", fake_ide_setup);
252
253__uml_help(fake_ide_setup,
254"fake_ide\n"
255" Create ide0 entries that map onto ubd devices.\n\n"
256);
257
258static int parse_unit(char **ptr)
259{
260 char *str = *ptr, *end;
261 int n = -1;
262
263 if(isdigit(*str)) {
264 n = simple_strtoul(str, &end, 0);
265 if(end == str)
266 return(-1);
267 *ptr = end;
268 }
Paolo 'Blaisorblade' Giarrusso97d88ac2006-10-30 22:07:03 -0800269 else if (('a' <= *str) && (*str <= 'z')) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 n = *str - 'a';
271 str++;
272 *ptr = str;
273 }
274 return(n);
275}
276
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800277/* If *index_out == -1 at exit, the passed option was a general one;
278 * otherwise, the str pointer is used (and owned) inside ubd_devs array, so it
279 * should not be freed on exit.
280 */
Jeff Dikef28169d2007-02-10 01:43:53 -0800281static int ubd_setup_common(char *str, int *index_out, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800283 struct ubd *ubd_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 struct openflags flags = global_openflags;
285 char *backing_file;
Jeff Dikeb8831a12007-02-10 01:44:17 -0800286 int n, err = 0, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287
288 if(index_out) *index_out = -1;
289 n = *str;
290 if(n == '='){
291 char *end;
292 int major;
293
294 str++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 if(!strcmp(str, "sync")){
296 global_openflags = of_sync(global_openflags);
Jeff Dikeb8831a12007-02-10 01:44:17 -0800297 goto out1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 }
299
Jeff Dikef28169d2007-02-10 01:43:53 -0800300 err = -EINVAL;
Jeff Dikeb8831a12007-02-10 01:44:17 -0800301 major = simple_strtoul(str, &end, 0);
302 if((*end != '\0') || (end == str)){
303 *error_out = "Didn't parse major number";
304 goto out1;
305 }
306
Jeff Dikef28169d2007-02-10 01:43:53 -0800307 mutex_lock(&ubd_lock);
308 if(fake_major != MAJOR_NR){
309 *error_out = "Can't assign a fake major twice";
310 goto out1;
311 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800312
Jeff Dikef28169d2007-02-10 01:43:53 -0800313 fake_major = major;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314
315 printk(KERN_INFO "Setting extra ubd major number to %d\n",
316 major);
Jeff Dikef28169d2007-02-10 01:43:53 -0800317 err = 0;
318 out1:
319 mutex_unlock(&ubd_lock);
320 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 }
322
323 n = parse_unit(&str);
324 if(n < 0){
Jeff Dikef28169d2007-02-10 01:43:53 -0800325 *error_out = "Couldn't parse device number";
326 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 }
328 if(n >= MAX_DEV){
Jeff Dikef28169d2007-02-10 01:43:53 -0800329 *error_out = "Device number out of range";
330 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 }
332
Jeff Dikef28169d2007-02-10 01:43:53 -0800333 err = -EBUSY;
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800334 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800336 ubd_dev = &ubd_devs[n];
337 if(ubd_dev->file != NULL){
Jeff Dikef28169d2007-02-10 01:43:53 -0800338 *error_out = "Device is already configured";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 goto out;
340 }
341
342 if (index_out)
343 *index_out = n;
344
Jeff Dikef28169d2007-02-10 01:43:53 -0800345 err = -EINVAL;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800346 for (i = 0; i < sizeof("rscd="); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 switch (*str) {
348 case 'r':
349 flags.w = 0;
350 break;
351 case 's':
352 flags.s = 1;
353 break;
354 case 'd':
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800355 ubd_dev->no_cow = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 break;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800357 case 'c':
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800358 ubd_dev->shared = 1;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800359 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 case '=':
361 str++;
362 goto break_loop;
363 default:
Jeff Dikef28169d2007-02-10 01:43:53 -0800364 *error_out = "Expected '=' or flag letter "
365 "(r, s, c, or d)";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 goto out;
367 }
368 str++;
369 }
370
Jeff Dikef28169d2007-02-10 01:43:53 -0800371 if (*str == '=')
372 *error_out = "Too many flags specified";
373 else
374 *error_out = "Missing '='";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 goto out;
376
377break_loop:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 backing_file = strchr(str, ',');
379
Jeff Dikef28169d2007-02-10 01:43:53 -0800380 if (backing_file == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 backing_file = strchr(str, ':');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382
Jeff Dikef28169d2007-02-10 01:43:53 -0800383 if(backing_file != NULL){
384 if(ubd_dev->no_cow){
385 *error_out = "Can't specify both 'd' and a cow file";
386 goto out;
387 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 else {
389 *backing_file = '\0';
390 backing_file++;
391 }
392 }
Jeff Dikef28169d2007-02-10 01:43:53 -0800393 err = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800394 ubd_dev->file = str;
395 ubd_dev->cow.file = backing_file;
396 ubd_dev->boot_openflags = flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800398 mutex_unlock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -0800399 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400}
401
402static int ubd_setup(char *str)
403{
Jeff Dikef28169d2007-02-10 01:43:53 -0800404 char *error;
405 int err;
406
407 err = ubd_setup_common(str, NULL, &error);
408 if(err)
409 printk(KERN_ERR "Failed to initialize device with \"%s\" : "
410 "%s\n", str, error);
411 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412}
413
414__setup("ubd", ubd_setup);
415__uml_help(ubd_setup,
416"ubd<n><flags>=<filename>[(:|,)<filename2>]\n"
417" This is used to associate a device with a file in the underlying\n"
418" filesystem. When specifying two filenames, the first one is the\n"
419" COW name and the second is the backing file name. As separator you can\n"
420" use either a ':' or a ',': the first one allows writing things like;\n"
421" ubd0=~/Uml/root_cow:~/Uml/root_backing_file\n"
422" while with a ',' the shell would not expand the 2nd '~'.\n"
Jeff Dikef28169d2007-02-10 01:43:53 -0800423" When using only one filename, UML will detect whether to treat it like\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424" a COW file or a backing file. To override this detection, add the 'd'\n"
425" flag:\n"
426" ubd0d=BackingFile\n"
427" Usually, there is a filesystem in the file, but \n"
428" that's not required. Swap devices containing swap files can be\n"
429" specified like this. Also, a file which doesn't contain a\n"
430" filesystem can have its contents read in the virtual \n"
431" machine by running 'dd' on the device. <n> must be in the range\n"
432" 0 to 7. Appending an 'r' to the number will cause that device\n"
433" to be mounted read-only. For example ubd1r=./ext_fs. Appending\n"
434" an 's' will cause data to be written to disk on the host immediately.\n\n"
435);
436
437static int udb_setup(char *str)
438{
439 printk("udb%s specified on command line is almost certainly a ubd -> "
440 "udb TYPO\n", str);
441 return(1);
442}
443
444__setup("udb", udb_setup);
445__uml_help(udb_setup,
446"udb\n"
Jeff Dike0894e272005-05-28 15:51:55 -0700447" This option is here solely to catch ubd -> udb typos, which can be\n"
448" to impossible to catch visually unless you specifically look for\n"
449" them. The only result of any option starting with 'udb' is an error\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450" in the boot output.\n\n"
451);
452
453static int fakehd_set = 0;
454static int fakehd(char *str)
455{
456 printk(KERN_INFO "fakehd : Changing ubd name to \"hd\".\n");
457 fakehd_set = 1;
458 return 1;
459}
460
461__setup("fakehd", fakehd);
462__uml_help(fakehd,
463"fakehd\n"
464" Change the ubd device name to \"hd\".\n\n"
465);
466
467static void do_ubd_request(request_queue_t * q);
Jeff Dike91acb212005-10-10 23:10:32 -0400468
469/* Only changed by ubd_init, which is an initcall. */
470int thread_fd = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472/* call ubd_finish if you need to serialize */
Jeff Dike91acb212005-10-10 23:10:32 -0400473static void __ubd_finish(struct request *req, int error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474{
Jeff Dike91acb212005-10-10 23:10:32 -0400475 int nsect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476
Jeff Dike91acb212005-10-10 23:10:32 -0400477 if(error){
478 end_request(req, 0);
479 return;
480 }
481 nsect = req->current_nr_sectors;
482 req->sector += nsect;
483 req->buffer += nsect << 9;
484 req->errors = 0;
485 req->nr_sectors -= nsect;
486 req->current_nr_sectors = 0;
487 end_request(req, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488}
489
Paolo 'Blaisorblade' Giarrusso33f775e2006-10-30 22:07:08 -0800490/* Callable only from interrupt context - otherwise you need to do
491 * spin_lock_irq()/spin_lock_irqsave() */
Jeff Dike91acb212005-10-10 23:10:32 -0400492static inline void ubd_finish(struct request *req, int error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493{
Jeff Dike62f96cb2007-02-10 01:44:16 -0800494 struct ubd *dev = req->rq_disk->private_data;
495
496 spin_lock(&dev->lock);
Jeff Dike91acb212005-10-10 23:10:32 -0400497 __ubd_finish(req, error);
Jeff Dike62f96cb2007-02-10 01:44:16 -0800498 spin_unlock(&dev->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499}
500
Paolo 'Blaisorblade' Giarrusso2fe30a32006-10-30 22:07:09 -0800501/* XXX - move this inside ubd_intr. */
Jeff Dike62f96cb2007-02-10 01:44:16 -0800502/* Called without dev->lock held, and only in interrupt context. */
Jeff Dike91acb212005-10-10 23:10:32 -0400503static void ubd_handler(void)
504{
505 struct io_thread_req req;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800506 struct request *rq;
507 struct ubd *dev;
Jeff Dike91acb212005-10-10 23:10:32 -0400508 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509
Paolo 'Blaisorblade' Giarrusso2fe30a32006-10-30 22:07:09 -0800510 do_ubd = 0;
Jeff Dike91acb212005-10-10 23:10:32 -0400511 n = os_read_file(thread_fd, &req, sizeof(req));
512 if(n != sizeof(req)){
513 printk(KERN_ERR "Pid %d - spurious interrupt in ubd_handler, "
514 "err = %d\n", os_getpid(), -n);
Jeff Dike91acb212005-10-10 23:10:32 -0400515 return;
516 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800517
Jeff Dike62f96cb2007-02-10 01:44:16 -0800518 rq = req.req;
519 dev = rq->rq_disk->private_data;
520
Jeff Dike91acb212005-10-10 23:10:32 -0400521 ubd_finish(rq, req.error);
Jeff Dike62f96cb2007-02-10 01:44:16 -0800522 reactivate_fd(thread_fd, UBD_IRQ);
523 spin_lock(&dev->lock);
524 do_ubd_request(dev->queue);
525 spin_unlock(&dev->lock);
Jeff Dike91acb212005-10-10 23:10:32 -0400526}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527
Al Viro7bea96f2006-10-08 22:49:34 +0100528static irqreturn_t ubd_intr(int irq, void *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529{
Jeff Dike91acb212005-10-10 23:10:32 -0400530 ubd_handler();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 return(IRQ_HANDLED);
532}
533
Jeff Dike91acb212005-10-10 23:10:32 -0400534/* Only changed by ubd_init, which is an initcall. */
535static int io_pid = -1;
536
537void kill_io_thread(void)
538{
Jeff Dike6c29256c2006-03-27 01:14:37 -0800539 if(io_pid != -1)
Jeff Dike91acb212005-10-10 23:10:32 -0400540 os_kill_process(io_pid, 1);
541}
542
543__uml_exitcall(kill_io_thread);
544
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800545static inline int ubd_file_size(struct ubd *ubd_dev, __u64 *size_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546{
547 char *file;
548
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800549 file = ubd_dev->cow.file ? ubd_dev->cow.file : ubd_dev->file;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 return(os_file_size(file, size_out));
551}
552
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800553static void ubd_close_dev(struct ubd *ubd_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800555 os_close_file(ubd_dev->fd);
556 if(ubd_dev->cow.file == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 return;
558
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800559 os_close_file(ubd_dev->cow.fd);
560 vfree(ubd_dev->cow.bitmap);
561 ubd_dev->cow.bitmap = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562}
563
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800564static int ubd_open_dev(struct ubd *ubd_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565{
566 struct openflags flags;
567 char **back_ptr;
568 int err, create_cow, *create_ptr;
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800569 int fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800571 ubd_dev->openflags = ubd_dev->boot_openflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 create_cow = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800573 create_ptr = (ubd_dev->cow.file != NULL) ? &create_cow : NULL;
574 back_ptr = ubd_dev->no_cow ? NULL : &ubd_dev->cow.file;
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800575
576 fd = open_ubd_file(ubd_dev->file, &ubd_dev->openflags, ubd_dev->shared,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800577 back_ptr, &ubd_dev->cow.bitmap_offset,
578 &ubd_dev->cow.bitmap_len, &ubd_dev->cow.data_offset,
Jeff Dike6c29256c2006-03-27 01:14:37 -0800579 create_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800581 if((fd == -ENOENT) && create_cow){
582 fd = create_cow_file(ubd_dev->file, ubd_dev->cow.file,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800583 ubd_dev->openflags, 1 << 9, PAGE_SIZE,
584 &ubd_dev->cow.bitmap_offset,
585 &ubd_dev->cow.bitmap_len,
586 &ubd_dev->cow.data_offset);
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800587 if(fd >= 0){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 printk(KERN_INFO "Creating \"%s\" as COW file for "
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800589 "\"%s\"\n", ubd_dev->file, ubd_dev->cow.file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 }
591 }
592
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800593 if(fd < 0){
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800594 printk("Failed to open '%s', errno = %d\n", ubd_dev->file,
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800595 -fd);
596 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 }
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800598 ubd_dev->fd = fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800600 if(ubd_dev->cow.file != NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 err = -ENOMEM;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800602 ubd_dev->cow.bitmap = (void *) vmalloc(ubd_dev->cow.bitmap_len);
603 if(ubd_dev->cow.bitmap == NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 printk(KERN_ERR "Failed to vmalloc COW bitmap\n");
605 goto error;
606 }
607 flush_tlb_kernel_vm();
608
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800609 err = read_cow_bitmap(ubd_dev->fd, ubd_dev->cow.bitmap,
610 ubd_dev->cow.bitmap_offset,
611 ubd_dev->cow.bitmap_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 if(err < 0)
613 goto error;
614
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800615 flags = ubd_dev->openflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 flags.w = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800617 err = open_ubd_file(ubd_dev->cow.file, &flags, ubd_dev->shared, NULL,
Jeff Dike6c29256c2006-03-27 01:14:37 -0800618 NULL, NULL, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 if(err < 0) goto error;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800620 ubd_dev->cow.fd = err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 }
622 return(0);
623 error:
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800624 os_close_file(ubd_dev->fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 return(err);
626}
627
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800628static int ubd_disk_register(int major, u64 size, int unit,
Jeff Dikeb8831a12007-02-10 01:44:17 -0800629 struct gendisk **disk_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630{
631 struct gendisk *disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632
633 disk = alloc_disk(1 << UBD_SHIFT);
634 if(disk == NULL)
635 return(-ENOMEM);
636
637 disk->major = major;
638 disk->first_minor = unit << UBD_SHIFT;
639 disk->fops = &ubd_blops;
640 set_capacity(disk, size / 512);
Greg Kroah-Hartmance7b0f42005-06-20 21:15:16 -0700641 if(major == MAJOR_NR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 sprintf(disk->disk_name, "ubd%c", 'a' + unit);
Greg Kroah-Hartmance7b0f42005-06-20 21:15:16 -0700643 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 sprintf(disk->disk_name, "ubd_fake%d", unit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645
646 /* sysfs register (not for ide fake devices) */
647 if (major == MAJOR_NR) {
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800648 ubd_devs[unit].pdev.id = unit;
649 ubd_devs[unit].pdev.name = DRIVER_NAME;
650 platform_device_register(&ubd_devs[unit].pdev);
651 disk->driverfs_dev = &ubd_devs[unit].pdev.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 }
653
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800654 disk->private_data = &ubd_devs[unit];
Jeff Dike62f96cb2007-02-10 01:44:16 -0800655 disk->queue = ubd_devs[unit].queue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 add_disk(disk);
657
658 *disk_out = disk;
659 return 0;
660}
661
662#define ROUND_BLOCK(n) ((n + ((1 << 9) - 1)) & (-1 << 9))
663
Jeff Dikef28169d2007-02-10 01:43:53 -0800664static int ubd_add(int n, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800666 struct ubd *ubd_dev = &ubd_devs[n];
Jeff Dikef28169d2007-02-10 01:43:53 -0800667 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800669 if(ubd_dev->file == NULL)
Jeff Dikeec7cf782005-09-03 15:57:29 -0700670 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800672 err = ubd_file_size(ubd_dev, &ubd_dev->size);
Jeff Dikef28169d2007-02-10 01:43:53 -0800673 if(err < 0){
674 *error_out = "Couldn't determine size of device's file";
Jeff Dike80c13742006-09-29 01:58:51 -0700675 goto out;
Jeff Dikef28169d2007-02-10 01:43:53 -0800676 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800678 ubd_dev->size = ROUND_BLOCK(ubd_dev->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679
Jeff Dike62f96cb2007-02-10 01:44:16 -0800680 err = -ENOMEM;
681 ubd_dev->queue = blk_init_queue(do_ubd_request, &ubd_dev->lock);
682 if (ubd_dev->queue == NULL) {
683 *error_out = "Failed to initialize device queue";
Jeff Dike80c13742006-09-29 01:58:51 -0700684 goto out;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800685 }
686 ubd_dev->queue->queuedata = ubd_dev;
687
688 err = ubd_disk_register(MAJOR_NR, ubd_dev->size, n, &ubd_gendisk[n]);
689 if(err){
690 *error_out = "Failed to register device";
691 goto out_cleanup;
692 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800693
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 if(fake_major != MAJOR_NR)
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800695 ubd_disk_register(fake_major, ubd_dev->size, n,
Jeff Dike62f96cb2007-02-10 01:44:16 -0800696 &fake_gendisk[n]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697
698 /* perhaps this should also be under the "if (fake_major)" above */
699 /* using the fake_disk->disk_name and also the fakehd_set name */
700 if (fake_ide)
701 make_ide_entries(ubd_gendisk[n]->disk_name);
702
Jeff Dikeec7cf782005-09-03 15:57:29 -0700703 err = 0;
Jeff Dikeec7cf782005-09-03 15:57:29 -0700704out:
705 return err;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800706
707out_cleanup:
708 blk_cleanup_queue(ubd_dev->queue);
709 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710}
711
Jeff Dikef28169d2007-02-10 01:43:53 -0800712static int ubd_config(char *str, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713{
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800714 int n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715
Jeff Dikef28169d2007-02-10 01:43:53 -0800716 /* This string is possibly broken up and stored, so it's only
717 * freed if ubd_setup_common fails, or if only general options
718 * were set.
719 */
Jeff Dike970d6e32006-01-06 00:18:48 -0800720 str = kstrdup(str, GFP_KERNEL);
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800721 if (str == NULL) {
Jeff Dikef28169d2007-02-10 01:43:53 -0800722 *error_out = "Failed to allocate memory";
723 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 }
Jeff Dikef28169d2007-02-10 01:43:53 -0800725
726 ret = ubd_setup_common(str, &n, error_out);
727 if (ret)
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800728 goto err_free;
Jeff Dikef28169d2007-02-10 01:43:53 -0800729
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800730 if (n == -1) {
731 ret = 0;
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800732 goto err_free;
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800733 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800735 mutex_lock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -0800736 ret = ubd_add(n, error_out);
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800737 if (ret)
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800738 ubd_devs[n].file = NULL;
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800739 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800741out:
742 return ret;
743
744err_free:
745 kfree(str);
746 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747}
748
749static int ubd_get_config(char *name, char *str, int size, char **error_out)
750{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800751 struct ubd *ubd_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 int n, len = 0;
753
754 n = parse_unit(&name);
755 if((n >= MAX_DEV) || (n < 0)){
756 *error_out = "ubd_get_config : device number out of range";
757 return(-1);
758 }
759
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800760 ubd_dev = &ubd_devs[n];
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800761 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800763 if(ubd_dev->file == NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 CONFIG_CHUNK(str, size, len, "", 1);
765 goto out;
766 }
767
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800768 CONFIG_CHUNK(str, size, len, ubd_dev->file, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800770 if(ubd_dev->cow.file != NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 CONFIG_CHUNK(str, size, len, ",", 0);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800772 CONFIG_CHUNK(str, size, len, ubd_dev->cow.file, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 }
774 else CONFIG_CHUNK(str, size, len, "", 1);
775
776 out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800777 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 return(len);
779}
780
Jeff Dike29d56cf2005-06-25 14:55:25 -0700781static int ubd_id(char **str, int *start_out, int *end_out)
782{
783 int n;
784
785 n = parse_unit(str);
786 *start_out = 0;
787 *end_out = MAX_DEV - 1;
788 return n;
789}
790
Jeff Dikef28169d2007-02-10 01:43:53 -0800791static int ubd_remove(int n, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800793 struct ubd *ubd_dev;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700794 int err = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800796 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797
798 if(ubd_gendisk[n] == NULL)
799 goto out;
800
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800801 ubd_dev = &ubd_devs[n];
Jeff Dike29d56cf2005-06-25 14:55:25 -0700802
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800803 if(ubd_dev->file == NULL)
Jeff Dike29d56cf2005-06-25 14:55:25 -0700804 goto out;
805
806 /* you cannot remove a open disk */
807 err = -EBUSY;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800808 if(ubd_dev->count > 0)
Jeff Dike29d56cf2005-06-25 14:55:25 -0700809 goto out;
810
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 del_gendisk(ubd_gendisk[n]);
812 put_disk(ubd_gendisk[n]);
813 ubd_gendisk[n] = NULL;
814
815 if(fake_gendisk[n] != NULL){
816 del_gendisk(fake_gendisk[n]);
817 put_disk(fake_gendisk[n]);
818 fake_gendisk[n] = NULL;
819 }
820
Jeff Dike62f96cb2007-02-10 01:44:16 -0800821 blk_cleanup_queue(ubd_dev->queue);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800822 platform_device_unregister(&ubd_dev->pdev);
823 *ubd_dev = ((struct ubd) DEFAULT_UBD);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 err = 0;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700825out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800826 mutex_unlock(&ubd_lock);
Jeff Dike29d56cf2005-06-25 14:55:25 -0700827 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828}
829
Jeff Dikef28169d2007-02-10 01:43:53 -0800830/* All these are called by mconsole in process context and without
Jeff Dikeb8831a12007-02-10 01:44:17 -0800831 * ubd-specific locks. The structure itself is const except for .list.
Jeff Dikef28169d2007-02-10 01:43:53 -0800832 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833static struct mc_device ubd_mc = {
Jeff Dike84f48d42007-02-10 01:44:01 -0800834 .list = LIST_HEAD_INIT(ubd_mc.list),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 .name = "ubd",
836 .config = ubd_config,
837 .get_config = ubd_get_config,
Jeff Dike29d56cf2005-06-25 14:55:25 -0700838 .id = ubd_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 .remove = ubd_remove,
840};
841
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800842static int __init ubd_mc_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843{
844 mconsole_register_dev(&ubd_mc);
845 return 0;
846}
847
848__initcall(ubd_mc_init);
849
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800850static int __init ubd0_init(void)
851{
852 struct ubd *ubd_dev = &ubd_devs[0];
853
Jeff Dikeb8831a12007-02-10 01:44:17 -0800854 mutex_lock(&ubd_lock);
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800855 if(ubd_dev->file == NULL)
856 ubd_dev->file = "root_fs";
Jeff Dikeb8831a12007-02-10 01:44:17 -0800857 mutex_unlock(&ubd_lock);
858
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800859 return(0);
860}
861
862__initcall(ubd0_init);
863
Jeff Dikeb8831a12007-02-10 01:44:17 -0800864/* Used in ubd_init, which is an initcall */
Russell King3ae5eae2005-11-09 22:32:44 +0000865static struct platform_driver ubd_driver = {
866 .driver = {
867 .name = DRIVER_NAME,
868 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869};
870
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800871static int __init ubd_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872{
Jeff Dikef28169d2007-02-10 01:43:53 -0800873 char *error;
874 int i, err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 if (register_blkdev(MAJOR_NR, "ubd"))
877 return -1;
878
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 if (fake_major != MAJOR_NR) {
880 char name[sizeof("ubd_nnn\0")];
881
882 snprintf(name, sizeof(name), "ubd_%d", fake_major);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 if (register_blkdev(fake_major, "ubd"))
884 return -1;
885 }
Russell King3ae5eae2005-11-09 22:32:44 +0000886 platform_driver_register(&ubd_driver);
Jeff Dikeb8831a12007-02-10 01:44:17 -0800887 mutex_lock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -0800888 for (i = 0; i < MAX_DEV; i++){
889 err = ubd_add(i, &error);
890 if(err)
891 printk(KERN_ERR "Failed to initialize ubd device %d :"
892 "%s\n", i, error);
893 }
Jeff Dikeb8831a12007-02-10 01:44:17 -0800894 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 return 0;
896}
897
898late_initcall(ubd_init);
899
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800900static int __init ubd_driver_init(void){
Jeff Dike91acb212005-10-10 23:10:32 -0400901 unsigned long stack;
902 int err;
903
904 /* Set by CONFIG_BLK_DEV_UBD_SYNC or ubd=sync.*/
905 if(global_openflags.s){
906 printk(KERN_INFO "ubd: Synchronous mode\n");
907 /* Letting ubd=sync be like using ubd#s= instead of ubd#= is
908 * enough. So use anyway the io thread. */
909 }
910 stack = alloc_stack(0, 0);
Jeff Dike6c29256c2006-03-27 01:14:37 -0800911 io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *),
Jeff Dike91acb212005-10-10 23:10:32 -0400912 &thread_fd);
913 if(io_pid < 0){
Jeff Dike6c29256c2006-03-27 01:14:37 -0800914 printk(KERN_ERR
Jeff Dike91acb212005-10-10 23:10:32 -0400915 "ubd : Failed to start I/O thread (errno = %d) - "
916 "falling back to synchronous I/O\n", -io_pid);
917 io_pid = -1;
918 return(0);
919 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800920 err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800921 IRQF_DISABLED, "ubd", ubd_devs);
Jeff Dike91acb212005-10-10 23:10:32 -0400922 if(err != 0)
923 printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err);
Jeff Dikef4c57a72006-03-31 02:30:10 -0800924 return 0;
Jeff Dike91acb212005-10-10 23:10:32 -0400925}
926
927device_initcall(ubd_driver_init);
928
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929static int ubd_open(struct inode *inode, struct file *filp)
930{
931 struct gendisk *disk = inode->i_bdev->bd_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800932 struct ubd *ubd_dev = disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 int err = 0;
934
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800935 if(ubd_dev->count == 0){
936 err = ubd_open_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 if(err){
938 printk(KERN_ERR "%s: Can't open \"%s\": errno = %d\n",
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800939 disk->disk_name, ubd_dev->file, -err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 goto out;
941 }
942 }
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800943 ubd_dev->count++;
944 set_disk_ro(disk, !ubd_dev->openflags.w);
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -0700945
946 /* This should no more be needed. And it didn't work anyway to exclude
947 * read-write remounting of filesystems.*/
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800948 /*if((filp->f_mode & FMODE_WRITE) && !ubd_dev->openflags.w){
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800949 if(--ubd_dev->count == 0) ubd_close_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 err = -EROFS;
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -0700951 }*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 out:
953 return(err);
954}
955
956static int ubd_release(struct inode * inode, struct file * file)
957{
958 struct gendisk *disk = inode->i_bdev->bd_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800959 struct ubd *ubd_dev = disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800961 if(--ubd_dev->count == 0)
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800962 ubd_close_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 return(0);
964}
965
Jeff Dike91acb212005-10-10 23:10:32 -0400966static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask,
967 __u64 *cow_offset, unsigned long *bitmap,
968 __u64 bitmap_offset, unsigned long *bitmap_words,
969 __u64 bitmap_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970{
Jeff Dike91acb212005-10-10 23:10:32 -0400971 __u64 sector = io_offset >> 9;
972 int i, update_bitmap = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973
Jeff Dike91acb212005-10-10 23:10:32 -0400974 for(i = 0; i < length >> 9; i++){
975 if(cow_mask != NULL)
976 ubd_set_bit(i, (unsigned char *) cow_mask);
977 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
978 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979
Jeff Dike91acb212005-10-10 23:10:32 -0400980 update_bitmap = 1;
981 ubd_set_bit(sector + i, (unsigned char *) bitmap);
982 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983
Jeff Dike91acb212005-10-10 23:10:32 -0400984 if(!update_bitmap)
985 return;
986
987 *cow_offset = sector / (sizeof(unsigned long) * 8);
988
989 /* This takes care of the case where we're exactly at the end of the
990 * device, and *cow_offset + 1 is off the end. So, just back it up
991 * by one word. Thanks to Lynn Kerby for the fix and James McMechan
992 * for the original diagnosis.
993 */
994 if(*cow_offset == ((bitmap_len + sizeof(unsigned long) - 1) /
995 sizeof(unsigned long) - 1))
996 (*cow_offset)--;
997
998 bitmap_words[0] = bitmap[*cow_offset];
999 bitmap_words[1] = bitmap[*cow_offset + 1];
1000
1001 *cow_offset *= sizeof(unsigned long);
1002 *cow_offset += bitmap_offset;
1003}
1004
1005static void cowify_req(struct io_thread_req *req, unsigned long *bitmap,
1006 __u64 bitmap_offset, __u64 bitmap_len)
1007{
1008 __u64 sector = req->offset >> 9;
1009 int i;
1010
1011 if(req->length > (sizeof(req->sector_mask) * 8) << 9)
1012 panic("Operation too long");
1013
1014 if(req->op == UBD_READ) {
1015 for(i = 0; i < req->length >> 9; i++){
1016 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
Jeff Dike6c29256c2006-03-27 01:14:37 -08001017 ubd_set_bit(i, (unsigned char *)
Jeff Dike91acb212005-10-10 23:10:32 -04001018 &req->sector_mask);
1019 }
1020 }
1021 else cowify_bitmap(req->offset, req->length, &req->sector_mask,
1022 &req->cow_offset, bitmap, bitmap_offset,
1023 req->bitmap_words, bitmap_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024}
1025
Jeff Dike62f96cb2007-02-10 01:44:16 -08001026/* Called with dev->lock held */
Jeff Dike91acb212005-10-10 23:10:32 -04001027static int prepare_request(struct request *req, struct io_thread_req *io_req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028{
1029 struct gendisk *disk = req->rq_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001030 struct ubd *ubd_dev = disk->private_data;
Jeff Dike91acb212005-10-10 23:10:32 -04001031 __u64 offset;
1032 int len;
1033
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -07001034 /* This should be impossible now */
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001035 if((rq_data_dir(req) == WRITE) && !ubd_dev->openflags.w){
Jeff Dike6c29256c2006-03-27 01:14:37 -08001036 printk("Write attempted on readonly ubd device %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 disk->disk_name);
Jeff Dike91acb212005-10-10 23:10:32 -04001038 end_request(req, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 return(1);
1040 }
1041
Jeff Dike91acb212005-10-10 23:10:32 -04001042 offset = ((__u64) req->sector) << 9;
1043 len = req->current_nr_sectors << 9;
1044
Jeff Dike62f96cb2007-02-10 01:44:16 -08001045 io_req->req = req;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001046 io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd : ubd_dev->fd;
1047 io_req->fds[1] = ubd_dev->fd;
Jeff Dike91acb212005-10-10 23:10:32 -04001048 io_req->cow_offset = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 io_req->offset = offset;
1050 io_req->length = len;
1051 io_req->error = 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001052 io_req->sector_mask = 0;
1053
1054 io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 io_req->offsets[0] = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001056 io_req->offsets[1] = ubd_dev->cow.data_offset;
Jeff Dike91acb212005-10-10 23:10:32 -04001057 io_req->buffer = req->buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 io_req->sectorsize = 1 << 9;
1059
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001060 if(ubd_dev->cow.file != NULL)
1061 cowify_req(io_req, ubd_dev->cow.bitmap, ubd_dev->cow.bitmap_offset,
1062 ubd_dev->cow.bitmap_len);
Jeff Dike91acb212005-10-10 23:10:32 -04001063
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 return(0);
1065}
1066
Jeff Dike62f96cb2007-02-10 01:44:16 -08001067/* Called with dev->lock held */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068static void do_ubd_request(request_queue_t *q)
1069{
1070 struct io_thread_req io_req;
1071 struct request *req;
Jeff Dike91acb212005-10-10 23:10:32 -04001072 int err, n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073
Jeff Dike91acb212005-10-10 23:10:32 -04001074 if(thread_fd == -1){
1075 while((req = elv_next_request(q)) != NULL){
1076 err = prepare_request(req, &io_req);
1077 if(!err){
1078 do_io(&io_req);
1079 __ubd_finish(req, io_req.error);
1080 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 }
1082 }
Jeff Dike91acb212005-10-10 23:10:32 -04001083 else {
1084 if(do_ubd || (req = elv_next_request(q)) == NULL)
1085 return;
1086 err = prepare_request(req, &io_req);
1087 if(!err){
Paolo 'Blaisorblade' Giarrusso2fe30a32006-10-30 22:07:09 -08001088 do_ubd = 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}