blob: da0badcd7551de2bad7e2a970532eb0497deedd9 [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;
238 ent->nlink = 1;
239 ent->data = NULL;
240 ent->read_proc = proc_ide_read_media;
241 ent->write_proc = NULL;
242 sprintf(name,"ide0/%s", dev_name);
243 proc_symlink(dev_name, proc_ide_root, name);
244}
245
246static int fake_ide_setup(char *str)
247{
248 fake_ide = 1;
249 return(1);
250}
251
252__setup("fake_ide", fake_ide_setup);
253
254__uml_help(fake_ide_setup,
255"fake_ide\n"
256" Create ide0 entries that map onto ubd devices.\n\n"
257);
258
259static int parse_unit(char **ptr)
260{
261 char *str = *ptr, *end;
262 int n = -1;
263
264 if(isdigit(*str)) {
265 n = simple_strtoul(str, &end, 0);
266 if(end == str)
267 return(-1);
268 *ptr = end;
269 }
Paolo 'Blaisorblade' Giarrusso97d88ac2006-10-30 22:07:03 -0800270 else if (('a' <= *str) && (*str <= 'z')) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 n = *str - 'a';
272 str++;
273 *ptr = str;
274 }
275 return(n);
276}
277
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800278/* If *index_out == -1 at exit, the passed option was a general one;
279 * otherwise, the str pointer is used (and owned) inside ubd_devs array, so it
280 * should not be freed on exit.
281 */
Jeff Dikef28169d2007-02-10 01:43:53 -0800282static int ubd_setup_common(char *str, int *index_out, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800284 struct ubd *ubd_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 struct openflags flags = global_openflags;
286 char *backing_file;
Jeff Dikeb8831a12007-02-10 01:44:17 -0800287 int n, err = 0, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288
289 if(index_out) *index_out = -1;
290 n = *str;
291 if(n == '='){
292 char *end;
293 int major;
294
295 str++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 if(!strcmp(str, "sync")){
297 global_openflags = of_sync(global_openflags);
Jeff Dikeb8831a12007-02-10 01:44:17 -0800298 goto out1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 }
300
Jeff Dikef28169d2007-02-10 01:43:53 -0800301 err = -EINVAL;
Jeff Dikeb8831a12007-02-10 01:44:17 -0800302 major = simple_strtoul(str, &end, 0);
303 if((*end != '\0') || (end == str)){
304 *error_out = "Didn't parse major number";
305 goto out1;
306 }
307
Jeff Dikef28169d2007-02-10 01:43:53 -0800308 mutex_lock(&ubd_lock);
309 if(fake_major != MAJOR_NR){
310 *error_out = "Can't assign a fake major twice";
311 goto out1;
312 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800313
Jeff Dikef28169d2007-02-10 01:43:53 -0800314 fake_major = major;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315
316 printk(KERN_INFO "Setting extra ubd major number to %d\n",
317 major);
Jeff Dikef28169d2007-02-10 01:43:53 -0800318 err = 0;
319 out1:
320 mutex_unlock(&ubd_lock);
321 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 }
323
324 n = parse_unit(&str);
325 if(n < 0){
Jeff Dikef28169d2007-02-10 01:43:53 -0800326 *error_out = "Couldn't parse device number";
327 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 }
329 if(n >= MAX_DEV){
Jeff Dikef28169d2007-02-10 01:43:53 -0800330 *error_out = "Device number out of range";
331 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 }
333
Jeff Dikef28169d2007-02-10 01:43:53 -0800334 err = -EBUSY;
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800335 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800337 ubd_dev = &ubd_devs[n];
338 if(ubd_dev->file != NULL){
Jeff Dikef28169d2007-02-10 01:43:53 -0800339 *error_out = "Device is already configured";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 goto out;
341 }
342
343 if (index_out)
344 *index_out = n;
345
Jeff Dikef28169d2007-02-10 01:43:53 -0800346 err = -EINVAL;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800347 for (i = 0; i < sizeof("rscd="); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 switch (*str) {
349 case 'r':
350 flags.w = 0;
351 break;
352 case 's':
353 flags.s = 1;
354 break;
355 case 'd':
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800356 ubd_dev->no_cow = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 break;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800358 case 'c':
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800359 ubd_dev->shared = 1;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800360 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 case '=':
362 str++;
363 goto break_loop;
364 default:
Jeff Dikef28169d2007-02-10 01:43:53 -0800365 *error_out = "Expected '=' or flag letter "
366 "(r, s, c, or d)";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 goto out;
368 }
369 str++;
370 }
371
Jeff Dikef28169d2007-02-10 01:43:53 -0800372 if (*str == '=')
373 *error_out = "Too many flags specified";
374 else
375 *error_out = "Missing '='";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 goto out;
377
378break_loop:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 backing_file = strchr(str, ',');
380
Jeff Dikef28169d2007-02-10 01:43:53 -0800381 if (backing_file == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 backing_file = strchr(str, ':');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383
Jeff Dikef28169d2007-02-10 01:43:53 -0800384 if(backing_file != NULL){
385 if(ubd_dev->no_cow){
386 *error_out = "Can't specify both 'd' and a cow file";
387 goto out;
388 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 else {
390 *backing_file = '\0';
391 backing_file++;
392 }
393 }
Jeff Dikef28169d2007-02-10 01:43:53 -0800394 err = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800395 ubd_dev->file = str;
396 ubd_dev->cow.file = backing_file;
397 ubd_dev->boot_openflags = flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800399 mutex_unlock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -0800400 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401}
402
403static int ubd_setup(char *str)
404{
Jeff Dikef28169d2007-02-10 01:43:53 -0800405 char *error;
406 int err;
407
408 err = ubd_setup_common(str, NULL, &error);
409 if(err)
410 printk(KERN_ERR "Failed to initialize device with \"%s\" : "
411 "%s\n", str, error);
412 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413}
414
415__setup("ubd", ubd_setup);
416__uml_help(ubd_setup,
417"ubd<n><flags>=<filename>[(:|,)<filename2>]\n"
418" This is used to associate a device with a file in the underlying\n"
419" filesystem. When specifying two filenames, the first one is the\n"
420" COW name and the second is the backing file name. As separator you can\n"
421" use either a ':' or a ',': the first one allows writing things like;\n"
422" ubd0=~/Uml/root_cow:~/Uml/root_backing_file\n"
423" while with a ',' the shell would not expand the 2nd '~'.\n"
Jeff Dikef28169d2007-02-10 01:43:53 -0800424" When using only one filename, UML will detect whether to treat it like\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425" a COW file or a backing file. To override this detection, add the 'd'\n"
426" flag:\n"
427" ubd0d=BackingFile\n"
428" Usually, there is a filesystem in the file, but \n"
429" that's not required. Swap devices containing swap files can be\n"
430" specified like this. Also, a file which doesn't contain a\n"
431" filesystem can have its contents read in the virtual \n"
432" machine by running 'dd' on the device. <n> must be in the range\n"
433" 0 to 7. Appending an 'r' to the number will cause that device\n"
434" to be mounted read-only. For example ubd1r=./ext_fs. Appending\n"
435" an 's' will cause data to be written to disk on the host immediately.\n\n"
436);
437
438static int udb_setup(char *str)
439{
440 printk("udb%s specified on command line is almost certainly a ubd -> "
441 "udb TYPO\n", str);
442 return(1);
443}
444
445__setup("udb", udb_setup);
446__uml_help(udb_setup,
447"udb\n"
Jeff Dike0894e272005-05-28 15:51:55 -0700448" This option is here solely to catch ubd -> udb typos, which can be\n"
449" to impossible to catch visually unless you specifically look for\n"
450" them. The only result of any option starting with 'udb' is an error\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451" in the boot output.\n\n"
452);
453
454static int fakehd_set = 0;
455static int fakehd(char *str)
456{
457 printk(KERN_INFO "fakehd : Changing ubd name to \"hd\".\n");
458 fakehd_set = 1;
459 return 1;
460}
461
462__setup("fakehd", fakehd);
463__uml_help(fakehd,
464"fakehd\n"
465" Change the ubd device name to \"hd\".\n\n"
466);
467
468static void do_ubd_request(request_queue_t * q);
Jeff Dike91acb212005-10-10 23:10:32 -0400469
470/* Only changed by ubd_init, which is an initcall. */
471int thread_fd = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473/* call ubd_finish if you need to serialize */
Jeff Dike91acb212005-10-10 23:10:32 -0400474static void __ubd_finish(struct request *req, int error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475{
Jeff Dike91acb212005-10-10 23:10:32 -0400476 int nsect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477
Jeff Dike91acb212005-10-10 23:10:32 -0400478 if(error){
479 end_request(req, 0);
480 return;
481 }
482 nsect = req->current_nr_sectors;
483 req->sector += nsect;
484 req->buffer += nsect << 9;
485 req->errors = 0;
486 req->nr_sectors -= nsect;
487 req->current_nr_sectors = 0;
488 end_request(req, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489}
490
Paolo 'Blaisorblade' Giarrusso33f775e2006-10-30 22:07:08 -0800491/* Callable only from interrupt context - otherwise you need to do
492 * spin_lock_irq()/spin_lock_irqsave() */
Jeff Dike91acb212005-10-10 23:10:32 -0400493static inline void ubd_finish(struct request *req, int error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494{
Jeff Dike62f96cb2007-02-10 01:44:16 -0800495 struct ubd *dev = req->rq_disk->private_data;
496
497 spin_lock(&dev->lock);
Jeff Dike91acb212005-10-10 23:10:32 -0400498 __ubd_finish(req, error);
Jeff Dike62f96cb2007-02-10 01:44:16 -0800499 spin_unlock(&dev->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500}
501
Paolo 'Blaisorblade' Giarrusso2fe30a32006-10-30 22:07:09 -0800502/* XXX - move this inside ubd_intr. */
Jeff Dike62f96cb2007-02-10 01:44:16 -0800503/* Called without dev->lock held, and only in interrupt context. */
Jeff Dike91acb212005-10-10 23:10:32 -0400504static void ubd_handler(void)
505{
506 struct io_thread_req req;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800507 struct request *rq;
508 struct ubd *dev;
Jeff Dike91acb212005-10-10 23:10:32 -0400509 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510
Paolo 'Blaisorblade' Giarrusso2fe30a32006-10-30 22:07:09 -0800511 do_ubd = 0;
Jeff Dike91acb212005-10-10 23:10:32 -0400512 n = os_read_file(thread_fd, &req, sizeof(req));
513 if(n != sizeof(req)){
514 printk(KERN_ERR "Pid %d - spurious interrupt in ubd_handler, "
515 "err = %d\n", os_getpid(), -n);
Jeff Dike91acb212005-10-10 23:10:32 -0400516 return;
517 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800518
Jeff Dike62f96cb2007-02-10 01:44:16 -0800519 rq = req.req;
520 dev = rq->rq_disk->private_data;
521
Jeff Dike91acb212005-10-10 23:10:32 -0400522 ubd_finish(rq, req.error);
Jeff Dike62f96cb2007-02-10 01:44:16 -0800523 reactivate_fd(thread_fd, UBD_IRQ);
524 spin_lock(&dev->lock);
525 do_ubd_request(dev->queue);
526 spin_unlock(&dev->lock);
Jeff Dike91acb212005-10-10 23:10:32 -0400527}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528
Al Viro7bea96f2006-10-08 22:49:34 +0100529static irqreturn_t ubd_intr(int irq, void *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530{
Jeff Dike91acb212005-10-10 23:10:32 -0400531 ubd_handler();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 return(IRQ_HANDLED);
533}
534
Jeff Dike91acb212005-10-10 23:10:32 -0400535/* Only changed by ubd_init, which is an initcall. */
536static int io_pid = -1;
537
538void kill_io_thread(void)
539{
Jeff Dike6c29256c2006-03-27 01:14:37 -0800540 if(io_pid != -1)
Jeff Dike91acb212005-10-10 23:10:32 -0400541 os_kill_process(io_pid, 1);
542}
543
544__uml_exitcall(kill_io_thread);
545
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800546static inline int ubd_file_size(struct ubd *ubd_dev, __u64 *size_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547{
548 char *file;
549
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800550 file = ubd_dev->cow.file ? ubd_dev->cow.file : ubd_dev->file;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 return(os_file_size(file, size_out));
552}
553
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800554static void ubd_close_dev(struct ubd *ubd_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800556 os_close_file(ubd_dev->fd);
557 if(ubd_dev->cow.file == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 return;
559
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800560 os_close_file(ubd_dev->cow.fd);
561 vfree(ubd_dev->cow.bitmap);
562 ubd_dev->cow.bitmap = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563}
564
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800565static int ubd_open_dev(struct ubd *ubd_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566{
567 struct openflags flags;
568 char **back_ptr;
569 int err, create_cow, *create_ptr;
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800570 int fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800572 ubd_dev->openflags = ubd_dev->boot_openflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 create_cow = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800574 create_ptr = (ubd_dev->cow.file != NULL) ? &create_cow : NULL;
575 back_ptr = ubd_dev->no_cow ? NULL : &ubd_dev->cow.file;
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800576
577 fd = open_ubd_file(ubd_dev->file, &ubd_dev->openflags, ubd_dev->shared,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800578 back_ptr, &ubd_dev->cow.bitmap_offset,
579 &ubd_dev->cow.bitmap_len, &ubd_dev->cow.data_offset,
Jeff Dike6c29256c2006-03-27 01:14:37 -0800580 create_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800582 if((fd == -ENOENT) && create_cow){
583 fd = create_cow_file(ubd_dev->file, ubd_dev->cow.file,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800584 ubd_dev->openflags, 1 << 9, PAGE_SIZE,
585 &ubd_dev->cow.bitmap_offset,
586 &ubd_dev->cow.bitmap_len,
587 &ubd_dev->cow.data_offset);
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800588 if(fd >= 0){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 printk(KERN_INFO "Creating \"%s\" as COW file for "
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800590 "\"%s\"\n", ubd_dev->file, ubd_dev->cow.file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 }
592 }
593
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800594 if(fd < 0){
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800595 printk("Failed to open '%s', errno = %d\n", ubd_dev->file,
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800596 -fd);
597 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 }
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800599 ubd_dev->fd = fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800601 if(ubd_dev->cow.file != NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 err = -ENOMEM;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800603 ubd_dev->cow.bitmap = (void *) vmalloc(ubd_dev->cow.bitmap_len);
604 if(ubd_dev->cow.bitmap == NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 printk(KERN_ERR "Failed to vmalloc COW bitmap\n");
606 goto error;
607 }
608 flush_tlb_kernel_vm();
609
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800610 err = read_cow_bitmap(ubd_dev->fd, ubd_dev->cow.bitmap,
611 ubd_dev->cow.bitmap_offset,
612 ubd_dev->cow.bitmap_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 if(err < 0)
614 goto error;
615
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800616 flags = ubd_dev->openflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 flags.w = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800618 err = open_ubd_file(ubd_dev->cow.file, &flags, ubd_dev->shared, NULL,
Jeff Dike6c29256c2006-03-27 01:14:37 -0800619 NULL, NULL, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 if(err < 0) goto error;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800621 ubd_dev->cow.fd = err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 }
623 return(0);
624 error:
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800625 os_close_file(ubd_dev->fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 return(err);
627}
628
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800629static int ubd_disk_register(int major, u64 size, int unit,
Jeff Dikeb8831a12007-02-10 01:44:17 -0800630 struct gendisk **disk_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631{
632 struct gendisk *disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633
634 disk = alloc_disk(1 << UBD_SHIFT);
635 if(disk == NULL)
636 return(-ENOMEM);
637
638 disk->major = major;
639 disk->first_minor = unit << UBD_SHIFT;
640 disk->fops = &ubd_blops;
641 set_capacity(disk, size / 512);
Greg Kroah-Hartmance7b0f42005-06-20 21:15:16 -0700642 if(major == MAJOR_NR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 sprintf(disk->disk_name, "ubd%c", 'a' + unit);
Greg Kroah-Hartmance7b0f42005-06-20 21:15:16 -0700644 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 sprintf(disk->disk_name, "ubd_fake%d", unit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646
647 /* sysfs register (not for ide fake devices) */
648 if (major == MAJOR_NR) {
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800649 ubd_devs[unit].pdev.id = unit;
650 ubd_devs[unit].pdev.name = DRIVER_NAME;
651 platform_device_register(&ubd_devs[unit].pdev);
652 disk->driverfs_dev = &ubd_devs[unit].pdev.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 }
654
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800655 disk->private_data = &ubd_devs[unit];
Jeff Dike62f96cb2007-02-10 01:44:16 -0800656 disk->queue = ubd_devs[unit].queue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 add_disk(disk);
658
659 *disk_out = disk;
660 return 0;
661}
662
663#define ROUND_BLOCK(n) ((n + ((1 << 9) - 1)) & (-1 << 9))
664
Jeff Dikef28169d2007-02-10 01:43:53 -0800665static int ubd_add(int n, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800667 struct ubd *ubd_dev = &ubd_devs[n];
Jeff Dikef28169d2007-02-10 01:43:53 -0800668 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800670 if(ubd_dev->file == NULL)
Jeff Dikeec7cf782005-09-03 15:57:29 -0700671 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800673 err = ubd_file_size(ubd_dev, &ubd_dev->size);
Jeff Dikef28169d2007-02-10 01:43:53 -0800674 if(err < 0){
675 *error_out = "Couldn't determine size of device's file";
Jeff Dike80c13742006-09-29 01:58:51 -0700676 goto out;
Jeff Dikef28169d2007-02-10 01:43:53 -0800677 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800679 ubd_dev->size = ROUND_BLOCK(ubd_dev->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680
Jeff Dike62f96cb2007-02-10 01:44:16 -0800681 err = -ENOMEM;
682 ubd_dev->queue = blk_init_queue(do_ubd_request, &ubd_dev->lock);
683 if (ubd_dev->queue == NULL) {
684 *error_out = "Failed to initialize device queue";
Jeff Dike80c13742006-09-29 01:58:51 -0700685 goto out;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800686 }
687 ubd_dev->queue->queuedata = ubd_dev;
688
689 err = ubd_disk_register(MAJOR_NR, ubd_dev->size, n, &ubd_gendisk[n]);
690 if(err){
691 *error_out = "Failed to register device";
692 goto out_cleanup;
693 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800694
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 if(fake_major != MAJOR_NR)
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800696 ubd_disk_register(fake_major, ubd_dev->size, n,
Jeff Dike62f96cb2007-02-10 01:44:16 -0800697 &fake_gendisk[n]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698
699 /* perhaps this should also be under the "if (fake_major)" above */
700 /* using the fake_disk->disk_name and also the fakehd_set name */
701 if (fake_ide)
702 make_ide_entries(ubd_gendisk[n]->disk_name);
703
Jeff Dikeec7cf782005-09-03 15:57:29 -0700704 err = 0;
Jeff Dikeec7cf782005-09-03 15:57:29 -0700705out:
706 return err;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800707
708out_cleanup:
709 blk_cleanup_queue(ubd_dev->queue);
710 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711}
712
Jeff Dikef28169d2007-02-10 01:43:53 -0800713static int ubd_config(char *str, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714{
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800715 int n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716
Jeff Dikef28169d2007-02-10 01:43:53 -0800717 /* This string is possibly broken up and stored, so it's only
718 * freed if ubd_setup_common fails, or if only general options
719 * were set.
720 */
Jeff Dike970d6e32006-01-06 00:18:48 -0800721 str = kstrdup(str, GFP_KERNEL);
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800722 if (str == NULL) {
Jeff Dikef28169d2007-02-10 01:43:53 -0800723 *error_out = "Failed to allocate memory";
724 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 }
Jeff Dikef28169d2007-02-10 01:43:53 -0800726
727 ret = ubd_setup_common(str, &n, error_out);
728 if (ret)
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800729 goto err_free;
Jeff Dikef28169d2007-02-10 01:43:53 -0800730
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800731 if (n == -1) {
732 ret = 0;
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800733 goto err_free;
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800734 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800736 mutex_lock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -0800737 ret = ubd_add(n, error_out);
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800738 if (ret)
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800739 ubd_devs[n].file = NULL;
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800740 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800742out:
743 return ret;
744
745err_free:
746 kfree(str);
747 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748}
749
750static int ubd_get_config(char *name, char *str, int size, char **error_out)
751{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800752 struct ubd *ubd_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 int n, len = 0;
754
755 n = parse_unit(&name);
756 if((n >= MAX_DEV) || (n < 0)){
757 *error_out = "ubd_get_config : device number out of range";
758 return(-1);
759 }
760
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800761 ubd_dev = &ubd_devs[n];
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800762 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800764 if(ubd_dev->file == NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 CONFIG_CHUNK(str, size, len, "", 1);
766 goto out;
767 }
768
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800769 CONFIG_CHUNK(str, size, len, ubd_dev->file, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800771 if(ubd_dev->cow.file != NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 CONFIG_CHUNK(str, size, len, ",", 0);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800773 CONFIG_CHUNK(str, size, len, ubd_dev->cow.file, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 }
775 else CONFIG_CHUNK(str, size, len, "", 1);
776
777 out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800778 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 return(len);
780}
781
Jeff Dike29d56cf2005-06-25 14:55:25 -0700782static int ubd_id(char **str, int *start_out, int *end_out)
783{
784 int n;
785
786 n = parse_unit(str);
787 *start_out = 0;
788 *end_out = MAX_DEV - 1;
789 return n;
790}
791
Jeff Dikef28169d2007-02-10 01:43:53 -0800792static int ubd_remove(int n, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800794 struct ubd *ubd_dev;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700795 int err = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800797 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798
799 if(ubd_gendisk[n] == NULL)
800 goto out;
801
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800802 ubd_dev = &ubd_devs[n];
Jeff Dike29d56cf2005-06-25 14:55:25 -0700803
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800804 if(ubd_dev->file == NULL)
Jeff Dike29d56cf2005-06-25 14:55:25 -0700805 goto out;
806
807 /* you cannot remove a open disk */
808 err = -EBUSY;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800809 if(ubd_dev->count > 0)
Jeff Dike29d56cf2005-06-25 14:55:25 -0700810 goto out;
811
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 del_gendisk(ubd_gendisk[n]);
813 put_disk(ubd_gendisk[n]);
814 ubd_gendisk[n] = NULL;
815
816 if(fake_gendisk[n] != NULL){
817 del_gendisk(fake_gendisk[n]);
818 put_disk(fake_gendisk[n]);
819 fake_gendisk[n] = NULL;
820 }
821
Jeff Dike62f96cb2007-02-10 01:44:16 -0800822 blk_cleanup_queue(ubd_dev->queue);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800823 platform_device_unregister(&ubd_dev->pdev);
824 *ubd_dev = ((struct ubd) DEFAULT_UBD);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 err = 0;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700826out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800827 mutex_unlock(&ubd_lock);
Jeff Dike29d56cf2005-06-25 14:55:25 -0700828 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829}
830
Jeff Dikef28169d2007-02-10 01:43:53 -0800831/* All these are called by mconsole in process context and without
Jeff Dikeb8831a12007-02-10 01:44:17 -0800832 * ubd-specific locks. The structure itself is const except for .list.
Jeff Dikef28169d2007-02-10 01:43:53 -0800833 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834static struct mc_device ubd_mc = {
Jeff Dike84f48d42007-02-10 01:44:01 -0800835 .list = LIST_HEAD_INIT(ubd_mc.list),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 .name = "ubd",
837 .config = ubd_config,
838 .get_config = ubd_get_config,
Jeff Dike29d56cf2005-06-25 14:55:25 -0700839 .id = ubd_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 .remove = ubd_remove,
841};
842
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800843static int __init ubd_mc_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844{
845 mconsole_register_dev(&ubd_mc);
846 return 0;
847}
848
849__initcall(ubd_mc_init);
850
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800851static int __init ubd0_init(void)
852{
853 struct ubd *ubd_dev = &ubd_devs[0];
854
Jeff Dikeb8831a12007-02-10 01:44:17 -0800855 mutex_lock(&ubd_lock);
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800856 if(ubd_dev->file == NULL)
857 ubd_dev->file = "root_fs";
Jeff Dikeb8831a12007-02-10 01:44:17 -0800858 mutex_unlock(&ubd_lock);
859
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800860 return(0);
861}
862
863__initcall(ubd0_init);
864
Jeff Dikeb8831a12007-02-10 01:44:17 -0800865/* Used in ubd_init, which is an initcall */
Russell King3ae5eae2005-11-09 22:32:44 +0000866static struct platform_driver ubd_driver = {
867 .driver = {
868 .name = DRIVER_NAME,
869 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870};
871
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800872static int __init ubd_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873{
Jeff Dikef28169d2007-02-10 01:43:53 -0800874 char *error;
875 int i, err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 if (register_blkdev(MAJOR_NR, "ubd"))
878 return -1;
879
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 if (fake_major != MAJOR_NR) {
881 char name[sizeof("ubd_nnn\0")];
882
883 snprintf(name, sizeof(name), "ubd_%d", fake_major);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 if (register_blkdev(fake_major, "ubd"))
885 return -1;
886 }
Russell King3ae5eae2005-11-09 22:32:44 +0000887 platform_driver_register(&ubd_driver);
Jeff Dikeb8831a12007-02-10 01:44:17 -0800888 mutex_lock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -0800889 for (i = 0; i < MAX_DEV; i++){
890 err = ubd_add(i, &error);
891 if(err)
892 printk(KERN_ERR "Failed to initialize ubd device %d :"
893 "%s\n", i, error);
894 }
Jeff Dikeb8831a12007-02-10 01:44:17 -0800895 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 return 0;
897}
898
899late_initcall(ubd_init);
900
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800901static int __init ubd_driver_init(void){
Jeff Dike91acb212005-10-10 23:10:32 -0400902 unsigned long stack;
903 int err;
904
905 /* Set by CONFIG_BLK_DEV_UBD_SYNC or ubd=sync.*/
906 if(global_openflags.s){
907 printk(KERN_INFO "ubd: Synchronous mode\n");
908 /* Letting ubd=sync be like using ubd#s= instead of ubd#= is
909 * enough. So use anyway the io thread. */
910 }
911 stack = alloc_stack(0, 0);
Jeff Dike6c29256c2006-03-27 01:14:37 -0800912 io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *),
Jeff Dike91acb212005-10-10 23:10:32 -0400913 &thread_fd);
914 if(io_pid < 0){
Jeff Dike6c29256c2006-03-27 01:14:37 -0800915 printk(KERN_ERR
Jeff Dike91acb212005-10-10 23:10:32 -0400916 "ubd : Failed to start I/O thread (errno = %d) - "
917 "falling back to synchronous I/O\n", -io_pid);
918 io_pid = -1;
919 return(0);
920 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800921 err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800922 IRQF_DISABLED, "ubd", ubd_devs);
Jeff Dike91acb212005-10-10 23:10:32 -0400923 if(err != 0)
924 printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err);
Jeff Dikef4c57a72006-03-31 02:30:10 -0800925 return 0;
Jeff Dike91acb212005-10-10 23:10:32 -0400926}
927
928device_initcall(ubd_driver_init);
929
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930static int ubd_open(struct inode *inode, struct file *filp)
931{
932 struct gendisk *disk = inode->i_bdev->bd_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800933 struct ubd *ubd_dev = disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 int err = 0;
935
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800936 if(ubd_dev->count == 0){
937 err = ubd_open_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 if(err){
939 printk(KERN_ERR "%s: Can't open \"%s\": errno = %d\n",
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800940 disk->disk_name, ubd_dev->file, -err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 goto out;
942 }
943 }
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800944 ubd_dev->count++;
945 set_disk_ro(disk, !ubd_dev->openflags.w);
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -0700946
947 /* This should no more be needed. And it didn't work anyway to exclude
948 * read-write remounting of filesystems.*/
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800949 /*if((filp->f_mode & FMODE_WRITE) && !ubd_dev->openflags.w){
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800950 if(--ubd_dev->count == 0) ubd_close_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 err = -EROFS;
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -0700952 }*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 out:
954 return(err);
955}
956
957static int ubd_release(struct inode * inode, struct file * file)
958{
959 struct gendisk *disk = inode->i_bdev->bd_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800960 struct ubd *ubd_dev = disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800962 if(--ubd_dev->count == 0)
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800963 ubd_close_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 return(0);
965}
966
Jeff Dike91acb212005-10-10 23:10:32 -0400967static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask,
968 __u64 *cow_offset, unsigned long *bitmap,
969 __u64 bitmap_offset, unsigned long *bitmap_words,
970 __u64 bitmap_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971{
Jeff Dike91acb212005-10-10 23:10:32 -0400972 __u64 sector = io_offset >> 9;
973 int i, update_bitmap = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974
Jeff Dike91acb212005-10-10 23:10:32 -0400975 for(i = 0; i < length >> 9; i++){
976 if(cow_mask != NULL)
977 ubd_set_bit(i, (unsigned char *) cow_mask);
978 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
979 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980
Jeff Dike91acb212005-10-10 23:10:32 -0400981 update_bitmap = 1;
982 ubd_set_bit(sector + i, (unsigned char *) bitmap);
983 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984
Jeff Dike91acb212005-10-10 23:10:32 -0400985 if(!update_bitmap)
986 return;
987
988 *cow_offset = sector / (sizeof(unsigned long) * 8);
989
990 /* This takes care of the case where we're exactly at the end of the
991 * device, and *cow_offset + 1 is off the end. So, just back it up
992 * by one word. Thanks to Lynn Kerby for the fix and James McMechan
993 * for the original diagnosis.
994 */
995 if(*cow_offset == ((bitmap_len + sizeof(unsigned long) - 1) /
996 sizeof(unsigned long) - 1))
997 (*cow_offset)--;
998
999 bitmap_words[0] = bitmap[*cow_offset];
1000 bitmap_words[1] = bitmap[*cow_offset + 1];
1001
1002 *cow_offset *= sizeof(unsigned long);
1003 *cow_offset += bitmap_offset;
1004}
1005
1006static void cowify_req(struct io_thread_req *req, unsigned long *bitmap,
1007 __u64 bitmap_offset, __u64 bitmap_len)
1008{
1009 __u64 sector = req->offset >> 9;
1010 int i;
1011
1012 if(req->length > (sizeof(req->sector_mask) * 8) << 9)
1013 panic("Operation too long");
1014
1015 if(req->op == UBD_READ) {
1016 for(i = 0; i < req->length >> 9; i++){
1017 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
Jeff Dike6c29256c2006-03-27 01:14:37 -08001018 ubd_set_bit(i, (unsigned char *)
Jeff Dike91acb212005-10-10 23:10:32 -04001019 &req->sector_mask);
1020 }
1021 }
1022 else cowify_bitmap(req->offset, req->length, &req->sector_mask,
1023 &req->cow_offset, bitmap, bitmap_offset,
1024 req->bitmap_words, bitmap_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025}
1026
Jeff Dike62f96cb2007-02-10 01:44:16 -08001027/* Called with dev->lock held */
Jeff Dike91acb212005-10-10 23:10:32 -04001028static int prepare_request(struct request *req, struct io_thread_req *io_req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029{
1030 struct gendisk *disk = req->rq_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001031 struct ubd *ubd_dev = disk->private_data;
Jeff Dike91acb212005-10-10 23:10:32 -04001032 __u64 offset;
1033 int len;
1034
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -07001035 /* This should be impossible now */
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001036 if((rq_data_dir(req) == WRITE) && !ubd_dev->openflags.w){
Jeff Dike6c29256c2006-03-27 01:14:37 -08001037 printk("Write attempted on readonly ubd device %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 disk->disk_name);
Jeff Dike91acb212005-10-10 23:10:32 -04001039 end_request(req, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 return(1);
1041 }
1042
Jeff Dike91acb212005-10-10 23:10:32 -04001043 offset = ((__u64) req->sector) << 9;
1044 len = req->current_nr_sectors << 9;
1045
Jeff Dike62f96cb2007-02-10 01:44:16 -08001046 io_req->req = req;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001047 io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd : ubd_dev->fd;
1048 io_req->fds[1] = ubd_dev->fd;
Jeff Dike91acb212005-10-10 23:10:32 -04001049 io_req->cow_offset = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 io_req->offset = offset;
1051 io_req->length = len;
1052 io_req->error = 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001053 io_req->sector_mask = 0;
1054
1055 io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 io_req->offsets[0] = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001057 io_req->offsets[1] = ubd_dev->cow.data_offset;
Jeff Dike91acb212005-10-10 23:10:32 -04001058 io_req->buffer = req->buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 io_req->sectorsize = 1 << 9;
1060
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001061 if(ubd_dev->cow.file != NULL)
1062 cowify_req(io_req, ubd_dev->cow.bitmap, ubd_dev->cow.bitmap_offset,
1063 ubd_dev->cow.bitmap_len);
Jeff Dike91acb212005-10-10 23:10:32 -04001064
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 return(0);
1066}
1067
Jeff Dike62f96cb2007-02-10 01:44:16 -08001068/* Called with dev->lock held */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069static void do_ubd_request(request_queue_t *q)
1070{
1071 struct io_thread_req io_req;
1072 struct request *req;
Jeff Dike91acb212005-10-10 23:10:32 -04001073 int err, n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074
Jeff Dike91acb212005-10-10 23:10:32 -04001075 if(thread_fd == -1){
1076 while((req = elv_next_request(q)) != NULL){
1077 err = prepare_request(req, &io_req);
1078 if(!err){
1079 do_io(&io_req);
1080 __ubd_finish(req, io_req.error);
1081 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 }
1083 }
Jeff Dike91acb212005-10-10 23:10:32 -04001084 else {
1085 if(do_ubd || (req = elv_next_request(q)) == NULL)
1086 return;
1087 err = prepare_request(req, &io_req);
1088 if(!err){
Paolo 'Blaisorblade' Giarrusso2fe30a32006-10-30 22:07:09 -08001089 do_ubd = 1;
Jeff Dike91acb212005-10-10 23:10:32 -04001090 n = os_write_file(thread_fd, (char *) &io_req,
1091 sizeof(io_req));
1092 if(n != sizeof(io_req))
1093 printk("write to io thread failed, "
1094 "errno = %d\n", -n);
1095 }
1096 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097}
1098
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001099static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
1100{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001101 struct ubd *ubd_dev = bdev->bd_disk->private_data;
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001102
1103 geo->heads = 128;
1104 geo->sectors = 32;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001105 geo->cylinders = ubd_dev->size / (128 * 32 * 512);
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001106 return 0;
1107}
1108
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109static int ubd_ioctl(struct inode * inode, struct file * file,
1110 unsigned int cmd, unsigned long arg)
1111{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001112 struct ubd *ubd_dev = inode->i_bdev->bd_disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 struct hd_driveid ubd_id = {
1114 .cyls = 0,
1115 .heads = 128,
1116 .sectors = 32,
1117 };
1118
1119 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 struct cdrom_volctrl volume;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 case HDIO_GET_IDENTITY:
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001122 ubd_id.cyls = ubd_dev->size / (128 * 32 * 512);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 if(copy_to_user((char __user *) arg, (char *) &ubd_id,
1124 sizeof(ubd_id)))
1125 return(-EFAULT);
1126 return(0);
Jeff Dikeb8831a12007-02-10 01:44:17 -08001127
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 case CDROMVOLREAD:
1129 if(copy_from_user(&volume, (char __user *) arg, sizeof(volume)))
1130 return(-EFAULT);
1131 volume.channel0 = 255;
1132 volume.channel1 = 255;
1133 volume.channel2 = 255;
1134 volume.channel3 = 255;
1135 if(copy_to_user((char __user *) arg, &volume, sizeof(volume)))
1136 return(-EFAULT);
1137 return(0);
1138 }
1139 return(-EINVAL);
1140}
1141
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001142static int path_requires_switch(char *from_cmdline, char *from_cow, char *cow)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143{
1144 struct uml_stat buf1, buf2;
1145 int err;
1146
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001147 if(from_cmdline == NULL)
1148 return 0;
1149 if(!strcmp(from_cmdline, from_cow))
1150 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151
1152 err = os_stat_file(from_cmdline, &buf1);
1153 if(err < 0){
1154 printk("Couldn't stat '%s', err = %d\n", from_cmdline, -err);
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001155 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 }
1157 err = os_stat_file(from_cow, &buf2);
1158 if(err < 0){
1159 printk("Couldn't stat '%s', err = %d\n", from_cow, -err);
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001160 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 }
1162 if((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino))
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001163 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164
1165 printk("Backing file mismatch - \"%s\" requested,\n"
1166 "\"%s\" specified in COW header of \"%s\"\n",
1167 from_cmdline, from_cow, cow);
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001168 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169}
1170
1171static int backing_file_mismatch(char *file, __u64 size, time_t mtime)
1172{
1173 unsigned long modtime;
Paolo 'Blaisorblade' Giarrussofe1db502006-02-24 13:03:58 -08001174 unsigned long long actual;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 int err;
1176
1177 err = os_file_modtime(file, &modtime);
1178 if(err < 0){
1179 printk("Failed to get modification time of backing file "
1180 "\"%s\", err = %d\n", file, -err);
1181 return(err);
1182 }
1183
1184 err = os_file_size(file, &actual);
1185 if(err < 0){
1186 printk("Failed to get size of backing file \"%s\", "
1187 "err = %d\n", file, -err);
1188 return(err);
1189 }
1190
1191 if(actual != size){
1192 /*__u64 can be a long on AMD64 and with %lu GCC complains; so
1193 * the typecast.*/
1194 printk("Size mismatch (%llu vs %llu) of COW header vs backing "
1195 "file\n", (unsigned long long) size, actual);
1196 return(-EINVAL);
1197 }
1198 if(modtime != mtime){
1199 printk("mtime mismatch (%ld vs %ld) of COW header vs backing "
1200 "file\n", mtime, modtime);
1201 return(-EINVAL);
1202 }
1203 return(0);
1204}
1205
1206int read_cow_bitmap(int fd, void *buf, int offset, int len)
1207{
1208 int err;
1209
1210 err = os_seek_file(fd, offset);
1211 if(err < 0)
1212 return(err);
1213
1214 err = os_read_file(fd, buf, len);
1215 if(err < 0)
1216 return(err);
1217
1218 return(0);
1219}
1220
Jeff Dike6c29256c2006-03-27 01:14:37 -08001221int open_ubd_file(char *file, struct openflags *openflags, int shared,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 char **backing_file_out, int *bitmap_offset_out,
1223 unsigned long *bitmap_len_out, int *data_offset_out,
1224 int *create_cow_out)
1225{
1226 time_t mtime;
1227 unsigned long long size;
1228 __u32 version, align;
1229 char *backing_file;
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001230 int fd, err, sectorsize, asked_switch, mode = 0644;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231
1232 fd = os_open_file(file, *openflags, mode);
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001233 if (fd < 0) {
1234 if ((fd == -ENOENT) && (create_cow_out != NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 *create_cow_out = 1;
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001236 if (!openflags->w ||
1237 ((fd != -EROFS) && (fd != -EACCES)))
1238 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 openflags->w = 0;
1240 fd = os_open_file(file, *openflags, mode);
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001241 if (fd < 0)
1242 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 }
1244
Jeff Dike6c29256c2006-03-27 01:14:37 -08001245 if(shared)
1246 printk("Not locking \"%s\" on the host\n", file);
1247 else {
1248 err = os_lock_file(fd, openflags->w);
1249 if(err < 0){
1250 printk("Failed to lock '%s', err = %d\n", file, -err);
1251 goto out_close;
1252 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 }
1254
Andreas Mohrd6e05ed2006-06-26 18:35:02 +02001255 /* Successful return case! */
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001256 if(backing_file_out == NULL)
1257 return(fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258
1259 err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime,
1260 &size, &sectorsize, &align, bitmap_offset_out);
1261 if(err && (*backing_file_out != NULL)){
1262 printk("Failed to read COW header from COW file \"%s\", "
1263 "errno = %d\n", file, -err);
1264 goto out_close;
1265 }
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001266 if(err)
1267 return(fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001269 asked_switch = path_requires_switch(*backing_file_out, backing_file, file);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001271 /* Allow switching only if no mismatch. */
1272 if (asked_switch && !backing_file_mismatch(*backing_file_out, size, mtime)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 printk("Switching backing file to '%s'\n", *backing_file_out);
1274 err = write_cow_header(file, fd, *backing_file_out,
1275 sectorsize, align, &size);
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001276 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 printk("Switch failed, errno = %d\n", -err);
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001278 goto out_close;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279 }
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001280 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 *backing_file_out = backing_file;
1282 err = backing_file_mismatch(*backing_file_out, size, mtime);
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001283 if (err)
1284 goto out_close;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285 }
1286
1287 cow_sizes(version, size, sectorsize, align, *bitmap_offset_out,
1288 bitmap_len_out, data_offset_out);
1289
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001290 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291 out_close:
1292 os_close_file(fd);
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001293 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294}
1295
1296int create_cow_file(char *cow_file, char *backing_file, struct openflags flags,
1297 int sectorsize, int alignment, int *bitmap_offset_out,
1298 unsigned long *bitmap_len_out, int *data_offset_out)
1299{
1300 int err, fd;
1301
1302 flags.c = 1;
Jeff Dike6c29256c2006-03-27 01:14:37 -08001303 fd = open_ubd_file(cow_file, &flags, 0, NULL, NULL, NULL, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 if(fd < 0){
1305 err = fd;
1306 printk("Open of COW file '%s' failed, errno = %d\n", cow_file,
1307 -err);
1308 goto out;
1309 }
1310
1311 err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment,
1312 bitmap_offset_out, bitmap_len_out,
1313 data_offset_out);
1314 if(!err)
1315 return(fd);
1316 os_close_file(fd);
1317 out:
1318 return(err);
1319}
1320
Jeff Dike91acb212005-10-10 23:10:32 -04001321static int update_bitmap(struct io_thread_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322{
Jeff Dike91acb212005-10-10 23:10:32 -04001323 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324
Jeff Dike91acb212005-10-10 23:10:32 -04001325 if(req->cow_offset == -1)
1326 return(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327
Jeff Dike91acb212005-10-10 23:10:32 -04001328 n = os_seek_file(req->fds[1], req->cow_offset);
1329 if(n < 0){
1330 printk("do_io - bitmap lseek failed : err = %d\n", -n);
1331 return(1);
1332 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333
Jeff Dike91acb212005-10-10 23:10:32 -04001334 n = os_write_file(req->fds[1], &req->bitmap_words,
1335 sizeof(req->bitmap_words));
1336 if(n != sizeof(req->bitmap_words)){
1337 printk("do_io - bitmap update failed, err = %d fd = %d\n", -n,
1338 req->fds[1]);
1339 return(1);
1340 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341
Jeff Dike91acb212005-10-10 23:10:32 -04001342 return(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343}
Jeff Dike91acb212005-10-10 23:10:32 -04001344
1345void do_io(struct io_thread_req *req)
1346{
1347 char *buf;
1348 unsigned long len;
1349 int n, nsectors, start, end, bit;
1350 int err;
1351 __u64 off;
1352
1353 nsectors = req->length / req->sectorsize;
1354 start = 0;
1355 do {
1356 bit = ubd_test_bit(start, (unsigned char *) &req->sector_mask);
1357 end = start;
1358 while((end < nsectors) &&
1359 (ubd_test_bit(end, (unsigned char *)
1360 &req->sector_mask) == bit))
1361 end++;
1362
1363 off = req->offset + req->offsets[bit] +
1364 start * req->sectorsize;
1365 len = (end - start) * req->sectorsize;
1366 buf = &req->buffer[start * req->sectorsize];
1367
1368 err = os_seek_file(req->fds[bit], off);
1369 if(err < 0){
1370 printk("do_io - lseek failed : err = %d\n", -err);
1371 req->error = 1;
1372 return;
1373 }
1374 if(req->op == UBD_READ){
1375 n = 0;
1376 do {
1377 buf = &buf[n];
1378 len -= n;
1379 n = os_read_file(req->fds[bit], buf, len);
1380 if (n < 0) {
1381 printk("do_io - read failed, err = %d "
1382 "fd = %d\n", -n, req->fds[bit]);
1383 req->error = 1;
1384 return;
1385 }
1386 } while((n < len) && (n != 0));
1387 if (n < len) memset(&buf[n], 0, len - n);
1388 } else {
1389 n = os_write_file(req->fds[bit], buf, len);
1390 if(n != len){
1391 printk("do_io - write failed err = %d "
1392 "fd = %d\n", -n, req->fds[bit]);
1393 req->error = 1;
1394 return;
1395 }
1396 }
1397
1398 start = end;
1399 } while(start < nsectors);
1400
1401 req->error = update_bitmap(req);
1402}
1403
1404/* Changed in start_io_thread, which is serialized by being called only
1405 * from ubd_init, which is an initcall.
1406 */
1407int kernel_fd = -1;
1408
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001409/* Only changed by the io thread. XXX: currently unused. */
1410static int io_count = 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001411
1412int io_thread(void *arg)
1413{
1414 struct io_thread_req req;
1415 int n;
1416
1417 ignore_sigwinch_sig();
1418 while(1){
1419 n = os_read_file(kernel_fd, &req, sizeof(req));
1420 if(n != sizeof(req)){
1421 if(n < 0)
1422 printk("io_thread - read failed, fd = %d, "
1423 "err = %d\n", kernel_fd, -n);
1424 else {
1425 printk("io_thread - short read, fd = %d, "
1426 "length = %d\n", kernel_fd, n);
1427 }
1428 continue;
1429 }
1430 io_count++;
1431 do_io(&req);
1432 n = os_write_file(kernel_fd, &req, sizeof(req));
1433 if(n != sizeof(req))
1434 printk("io_thread - write failed, fd = %d, err = %d\n",
1435 kernel_fd, -n);
1436 }
Jeff Dike91acb212005-10-10 23:10:32 -04001437
Jeff Dike1b57e9c2006-01-06 00:18:49 -08001438 return 0;
1439}