blob: c171d0aa5e9dbab4cee755ef713f245a6882e49c [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * 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
23#include "linux/config.h"
24#include "linux/module.h"
25#include "linux/blkdev.h"
26#include "linux/hdreg.h"
27#include "linux/init.h"
28#include "linux/devfs_fs_kernel.h"
29#include "linux/cdrom.h"
30#include "linux/proc_fs.h"
31#include "linux/ctype.h"
32#include "linux/capability.h"
33#include "linux/mm.h"
34#include "linux/vmalloc.h"
35#include "linux/blkpg.h"
36#include "linux/genhd.h"
37#include "linux/spinlock.h"
Russell Kingd052d1b2005-10-29 19:07:23 +010038#include "linux/platform_device.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include "asm/segment.h"
40#include "asm/uaccess.h"
41#include "asm/irq.h"
42#include "asm/types.h"
43#include "asm/tlbflush.h"
44#include "user_util.h"
45#include "mem_user.h"
46#include "kern_util.h"
47#include "kern.h"
48#include "mconsole_kern.h"
49#include "init.h"
50#include "irq_user.h"
51#include "irq_kern.h"
52#include "ubd_user.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070053#include "os.h"
54#include "mem.h"
55#include "mem_kern.h"
56#include "cow.h"
57
Jeff Dike7b9014c2005-05-20 13:59:11 -070058enum ubd_req { UBD_READ, UBD_WRITE };
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
60struct io_thread_req {
Jeff Dike91acb212005-10-10 23:10:32 -040061 enum ubd_req op;
Linus Torvalds1da177e2005-04-16 15:20:36 -070062 int fds[2];
63 unsigned long offsets[2];
64 unsigned long long offset;
65 unsigned long length;
66 char *buffer;
67 int sectorsize;
Jeff Dike91acb212005-10-10 23:10:32 -040068 unsigned long sector_mask;
69 unsigned long long cow_offset;
70 unsigned long bitmap_words[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -070071 int error;
72};
73
74extern int open_ubd_file(char *file, struct openflags *openflags,
75 char **backing_file_out, int *bitmap_offset_out,
76 unsigned long *bitmap_len_out, int *data_offset_out,
77 int *create_cow_out);
78extern int create_cow_file(char *cow_file, char *backing_file,
79 struct openflags flags, int sectorsize,
80 int alignment, int *bitmap_offset_out,
81 unsigned long *bitmap_len_out,
82 int *data_offset_out);
83extern int read_cow_bitmap(int fd, void *buf, int offset, int len);
Jeff Dike91acb212005-10-10 23:10:32 -040084extern void do_io(struct io_thread_req *req);
Linus Torvalds1da177e2005-04-16 15:20:36 -070085
Jeff Dike91acb212005-10-10 23:10:32 -040086static inline int ubd_test_bit(__u64 bit, unsigned char *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -070087{
88 __u64 n;
89 int bits, off;
90
Jeff Dike91acb212005-10-10 23:10:32 -040091 bits = sizeof(data[0]) * 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -070092 n = bit / bits;
93 off = bit % bits;
Jeff Dike91acb212005-10-10 23:10:32 -040094 return((data[n] & (1 << off)) != 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070095}
96
Jeff Dike91acb212005-10-10 23:10:32 -040097static inline void ubd_set_bit(__u64 bit, unsigned char *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -070098{
99 __u64 n;
100 int bits, off;
101
Jeff Dike91acb212005-10-10 23:10:32 -0400102 bits = sizeof(data[0]) * 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 n = bit / bits;
104 off = bit % bits;
Jeff Dike91acb212005-10-10 23:10:32 -0400105 data[n] |= (1 << off);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106}
107/*End stuff from ubd_user.h*/
108
109#define DRIVER_NAME "uml-blkdev"
110
111static DEFINE_SPINLOCK(ubd_io_lock);
112static DEFINE_SPINLOCK(ubd_lock);
113
Jeff Dike91acb212005-10-10 23:10:32 -0400114static void (*do_ubd)(void);
115
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
122#define MAX_DEV (8)
123
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
132/* Protected by the queue_lock */
133static request_queue_t *ubd_queue;
134
135/* Protected by ubd_lock */
136static int fake_major = MAJOR_NR;
137
138static struct gendisk *ubd_gendisk[MAX_DEV];
139static struct gendisk *fake_gendisk[MAX_DEV];
140
141#ifdef CONFIG_BLK_DEV_UBD_SYNC
142#define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 1, .c = 0, \
143 .cl = 1 })
144#else
145#define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 0, .c = 0, \
146 .cl = 1 })
147#endif
148
149/* Not protected - changed only in ubd_setup_common and then only to
150 * to enable O_SYNC.
151 */
152static struct openflags global_openflags = OPEN_FLAGS;
153
154struct cow {
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -0700155 /* This is the backing file, actually */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 char *file;
157 int fd;
158 unsigned long *bitmap;
159 unsigned long bitmap_len;
160 int bitmap_offset;
161 int data_offset;
162};
163
164struct ubd {
165 char *file;
166 int count;
167 int fd;
168 __u64 size;
169 struct openflags boot_openflags;
170 struct openflags openflags;
171 int no_cow;
172 struct cow cow;
173 struct platform_device pdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174};
175
176#define DEFAULT_COW { \
177 .file = NULL, \
178 .fd = -1, \
179 .bitmap = NULL, \
180 .bitmap_offset = 0, \
181 .data_offset = 0, \
182}
183
184#define DEFAULT_UBD { \
185 .file = NULL, \
186 .count = 0, \
187 .fd = -1, \
188 .size = -1, \
189 .boot_openflags = OPEN_FLAGS, \
190 .openflags = OPEN_FLAGS, \
191 .no_cow = 0, \
192 .cow = DEFAULT_COW, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193}
194
195struct ubd ubd_dev[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_UBD };
196
197static int ubd0_init(void)
198{
199 struct ubd *dev = &ubd_dev[0];
200
201 if(dev->file == NULL)
202 dev->file = "root_fs";
203 return(0);
204}
205
206__initcall(ubd0_init);
207
208/* Only changed by fake_ide_setup which is a setup */
209static int fake_ide = 0;
210static struct proc_dir_entry *proc_ide_root = NULL;
211static struct proc_dir_entry *proc_ide = NULL;
212
213static void make_proc_ide(void)
214{
215 proc_ide_root = proc_mkdir("ide", NULL);
216 proc_ide = proc_mkdir("ide0", proc_ide_root);
217}
218
219static int proc_ide_read_media(char *page, char **start, off_t off, int count,
220 int *eof, void *data)
221{
222 int len;
223
224 strcpy(page, "disk\n");
225 len = strlen("disk\n");
226 len -= off;
227 if (len < count){
228 *eof = 1;
229 if (len <= 0) return 0;
230 }
231 else len = count;
232 *start = page + off;
233 return len;
234}
235
236static void make_ide_entries(char *dev_name)
237{
238 struct proc_dir_entry *dir, *ent;
239 char name[64];
240
241 if(proc_ide_root == NULL) make_proc_ide();
242
243 dir = proc_mkdir(dev_name, proc_ide);
244 if(!dir) return;
245
246 ent = create_proc_entry("media", S_IFREG|S_IRUGO, dir);
247 if(!ent) return;
248 ent->nlink = 1;
249 ent->data = NULL;
250 ent->read_proc = proc_ide_read_media;
251 ent->write_proc = NULL;
252 sprintf(name,"ide0/%s", dev_name);
253 proc_symlink(dev_name, proc_ide_root, name);
254}
255
256static int fake_ide_setup(char *str)
257{
258 fake_ide = 1;
259 return(1);
260}
261
262__setup("fake_ide", fake_ide_setup);
263
264__uml_help(fake_ide_setup,
265"fake_ide\n"
266" Create ide0 entries that map onto ubd devices.\n\n"
267);
268
269static int parse_unit(char **ptr)
270{
271 char *str = *ptr, *end;
272 int n = -1;
273
274 if(isdigit(*str)) {
275 n = simple_strtoul(str, &end, 0);
276 if(end == str)
277 return(-1);
278 *ptr = end;
279 }
280 else if (('a' <= *str) && (*str <= 'h')) {
281 n = *str - 'a';
282 str++;
283 *ptr = str;
284 }
285 return(n);
286}
287
288static int ubd_setup_common(char *str, int *index_out)
289{
290 struct ubd *dev;
291 struct openflags flags = global_openflags;
292 char *backing_file;
293 int n, err, i;
294
295 if(index_out) *index_out = -1;
296 n = *str;
297 if(n == '='){
298 char *end;
299 int major;
300
301 str++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 if(!strcmp(str, "sync")){
303 global_openflags = of_sync(global_openflags);
304 return(0);
305 }
306 major = simple_strtoul(str, &end, 0);
307 if((*end != '\0') || (end == str)){
308 printk(KERN_ERR
309 "ubd_setup : didn't parse major number\n");
310 return(1);
311 }
312
313 err = 1;
314 spin_lock(&ubd_lock);
315 if(fake_major != MAJOR_NR){
316 printk(KERN_ERR "Can't assign a fake major twice\n");
317 goto out1;
318 }
319
320 fake_major = major;
321
322 printk(KERN_INFO "Setting extra ubd major number to %d\n",
323 major);
324 err = 0;
325 out1:
326 spin_unlock(&ubd_lock);
327 return(err);
328 }
329
330 n = parse_unit(&str);
331 if(n < 0){
332 printk(KERN_ERR "ubd_setup : couldn't parse unit number "
333 "'%s'\n", str);
334 return(1);
335 }
336 if(n >= MAX_DEV){
337 printk(KERN_ERR "ubd_setup : index %d out of range "
338 "(%d devices, from 0 to %d)\n", n, MAX_DEV, MAX_DEV - 1);
339 return(1);
340 }
341
342 err = 1;
343 spin_lock(&ubd_lock);
344
345 dev = &ubd_dev[n];
346 if(dev->file != NULL){
347 printk(KERN_ERR "ubd_setup : device already configured\n");
348 goto out;
349 }
350
351 if (index_out)
352 *index_out = n;
353
354 for (i = 0; i < 4; i++) {
355 switch (*str) {
356 case 'r':
357 flags.w = 0;
358 break;
359 case 's':
360 flags.s = 1;
361 break;
362 case 'd':
363 dev->no_cow = 1;
364 break;
365 case '=':
366 str++;
367 goto break_loop;
368 default:
369 printk(KERN_ERR "ubd_setup : Expected '=' or flag letter (r,s or d)\n");
370 goto out;
371 }
372 str++;
373 }
374
375 if (*str == '=')
376 printk(KERN_ERR "ubd_setup : Too many flags specified\n");
377 else
378 printk(KERN_ERR "ubd_setup : Expected '='\n");
379 goto out;
380
381break_loop:
382 err = 0;
383 backing_file = strchr(str, ',');
384
385 if (!backing_file) {
386 backing_file = strchr(str, ':');
387 }
388
389 if(backing_file){
390 if(dev->no_cow)
391 printk(KERN_ERR "Can't specify both 'd' and a "
392 "cow file\n");
393 else {
394 *backing_file = '\0';
395 backing_file++;
396 }
397 }
398 dev->file = str;
399 dev->cow.file = backing_file;
400 dev->boot_openflags = flags;
401out:
402 spin_unlock(&ubd_lock);
403 return(err);
404}
405
406static int ubd_setup(char *str)
407{
408 ubd_setup_common(str, NULL);
409 return(1);
410}
411
412__setup("ubd", ubd_setup);
413__uml_help(ubd_setup,
414"ubd<n><flags>=<filename>[(:|,)<filename2>]\n"
415" This is used to associate a device with a file in the underlying\n"
416" filesystem. When specifying two filenames, the first one is the\n"
417" COW name and the second is the backing file name. As separator you can\n"
418" use either a ':' or a ',': the first one allows writing things like;\n"
419" ubd0=~/Uml/root_cow:~/Uml/root_backing_file\n"
420" while with a ',' the shell would not expand the 2nd '~'.\n"
421" When using only one filename, UML will detect whether to thread it like\n"
422" a COW file or a backing file. To override this detection, add the 'd'\n"
423" flag:\n"
424" ubd0d=BackingFile\n"
425" Usually, there is a filesystem in the file, but \n"
426" that's not required. Swap devices containing swap files can be\n"
427" specified like this. Also, a file which doesn't contain a\n"
428" filesystem can have its contents read in the virtual \n"
429" machine by running 'dd' on the device. <n> must be in the range\n"
430" 0 to 7. Appending an 'r' to the number will cause that device\n"
431" to be mounted read-only. For example ubd1r=./ext_fs. Appending\n"
432" an 's' will cause data to be written to disk on the host immediately.\n\n"
433);
434
435static int udb_setup(char *str)
436{
437 printk("udb%s specified on command line is almost certainly a ubd -> "
438 "udb TYPO\n", str);
439 return(1);
440}
441
442__setup("udb", udb_setup);
443__uml_help(udb_setup,
444"udb\n"
Jeff Dike0894e272005-05-28 15:51:55 -0700445" This option is here solely to catch ubd -> udb typos, which can be\n"
446" to impossible to catch visually unless you specifically look for\n"
447" them. The only result of any option starting with 'udb' is an error\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448" in the boot output.\n\n"
449);
450
451static int fakehd_set = 0;
452static int fakehd(char *str)
453{
454 printk(KERN_INFO "fakehd : Changing ubd name to \"hd\".\n");
455 fakehd_set = 1;
456 return 1;
457}
458
459__setup("fakehd", fakehd);
460__uml_help(fakehd,
461"fakehd\n"
462" Change the ubd device name to \"hd\".\n\n"
463);
464
465static void do_ubd_request(request_queue_t * q);
Jeff Dike91acb212005-10-10 23:10:32 -0400466
467/* Only changed by ubd_init, which is an initcall. */
468int thread_fd = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469
470/* Changed by ubd_handler, which is serialized because interrupts only
471 * happen on CPU 0.
472 */
473int intr_count = 0;
474
475/* call ubd_finish if you need to serialize */
Jeff Dike91acb212005-10-10 23:10:32 -0400476static void __ubd_finish(struct request *req, int error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477{
Jeff Dike91acb212005-10-10 23:10:32 -0400478 int nsect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479
Jeff Dike91acb212005-10-10 23:10:32 -0400480 if(error){
481 end_request(req, 0);
482 return;
483 }
484 nsect = req->current_nr_sectors;
485 req->sector += nsect;
486 req->buffer += nsect << 9;
487 req->errors = 0;
488 req->nr_sectors -= nsect;
489 req->current_nr_sectors = 0;
490 end_request(req, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491}
492
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 Dike91acb212005-10-10 23:10:32 -0400495 spin_lock(&ubd_io_lock);
496 __ubd_finish(req, error);
497 spin_unlock(&ubd_io_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498}
499
Jeff Dike91acb212005-10-10 23:10:32 -0400500/* Called without ubd_io_lock held */
501static void ubd_handler(void)
502{
503 struct io_thread_req req;
504 struct request *rq = elv_next_request(ubd_queue);
505 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506
Jeff Dike91acb212005-10-10 23:10:32 -0400507 do_ubd = NULL;
508 intr_count++;
509 n = os_read_file(thread_fd, &req, sizeof(req));
510 if(n != sizeof(req)){
511 printk(KERN_ERR "Pid %d - spurious interrupt in ubd_handler, "
512 "err = %d\n", os_getpid(), -n);
513 spin_lock(&ubd_io_lock);
514 end_request(rq, 0);
515 spin_unlock(&ubd_io_lock);
516 return;
517 }
518
519 ubd_finish(rq, req.error);
520 reactivate_fd(thread_fd, UBD_IRQ);
521 do_ubd_request(ubd_queue);
522}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523
524static irqreturn_t ubd_intr(int irq, void *dev, struct pt_regs *unused)
525{
Jeff Dike91acb212005-10-10 23:10:32 -0400526 ubd_handler();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 return(IRQ_HANDLED);
528}
529
Jeff Dike91acb212005-10-10 23:10:32 -0400530/* Only changed by ubd_init, which is an initcall. */
531static int io_pid = -1;
532
533void kill_io_thread(void)
534{
535 if(io_pid != -1)
536 os_kill_process(io_pid, 1);
537}
538
539__uml_exitcall(kill_io_thread);
540
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541static int ubd_file_size(struct ubd *dev, __u64 *size_out)
542{
543 char *file;
544
545 file = dev->cow.file ? dev->cow.file : dev->file;
546 return(os_file_size(file, size_out));
547}
548
549static void ubd_close(struct ubd *dev)
550{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 os_close_file(dev->fd);
552 if(dev->cow.file == NULL)
553 return;
554
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 os_close_file(dev->cow.fd);
556 vfree(dev->cow.bitmap);
557 dev->cow.bitmap = NULL;
558}
559
560static int ubd_open_dev(struct ubd *dev)
561{
562 struct openflags flags;
563 char **back_ptr;
564 int err, create_cow, *create_ptr;
565
566 dev->openflags = dev->boot_openflags;
567 create_cow = 0;
568 create_ptr = (dev->cow.file != NULL) ? &create_cow : NULL;
569 back_ptr = dev->no_cow ? NULL : &dev->cow.file;
570 dev->fd = open_ubd_file(dev->file, &dev->openflags, back_ptr,
571 &dev->cow.bitmap_offset, &dev->cow.bitmap_len,
572 &dev->cow.data_offset, create_ptr);
573
574 if((dev->fd == -ENOENT) && create_cow){
Jeff Dike91acb212005-10-10 23:10:32 -0400575 dev->fd = create_cow_file(dev->file, dev->cow.file,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 dev->openflags, 1 << 9, PAGE_SIZE,
577 &dev->cow.bitmap_offset,
578 &dev->cow.bitmap_len,
579 &dev->cow.data_offset);
580 if(dev->fd >= 0){
581 printk(KERN_INFO "Creating \"%s\" as COW file for "
582 "\"%s\"\n", dev->file, dev->cow.file);
583 }
584 }
585
586 if(dev->fd < 0){
587 printk("Failed to open '%s', errno = %d\n", dev->file,
588 -dev->fd);
589 return(dev->fd);
590 }
591
592 if(dev->cow.file != NULL){
593 err = -ENOMEM;
594 dev->cow.bitmap = (void *) vmalloc(dev->cow.bitmap_len);
595 if(dev->cow.bitmap == NULL){
596 printk(KERN_ERR "Failed to vmalloc COW bitmap\n");
597 goto error;
598 }
599 flush_tlb_kernel_vm();
600
601 err = read_cow_bitmap(dev->fd, dev->cow.bitmap,
602 dev->cow.bitmap_offset,
603 dev->cow.bitmap_len);
604 if(err < 0)
605 goto error;
606
607 flags = dev->openflags;
608 flags.w = 0;
609 err = open_ubd_file(dev->cow.file, &flags, NULL, NULL, NULL,
610 NULL, NULL);
611 if(err < 0) goto error;
612 dev->cow.fd = err;
613 }
614 return(0);
615 error:
616 os_close_file(dev->fd);
617 return(err);
618}
619
620static int ubd_new_disk(int major, u64 size, int unit,
621 struct gendisk **disk_out)
622
623{
624 struct gendisk *disk;
625 char from[sizeof("ubd/nnnnn\0")], to[sizeof("discnnnnn/disc\0")];
626 int err;
627
628 disk = alloc_disk(1 << UBD_SHIFT);
629 if(disk == NULL)
630 return(-ENOMEM);
631
632 disk->major = major;
633 disk->first_minor = unit << UBD_SHIFT;
634 disk->fops = &ubd_blops;
635 set_capacity(disk, size / 512);
636 if(major == MAJOR_NR){
637 sprintf(disk->disk_name, "ubd%c", 'a' + unit);
638 sprintf(disk->devfs_name, "ubd/disc%d", unit);
639 sprintf(from, "ubd/%d", unit);
640 sprintf(to, "disc%d/disc", unit);
641 err = devfs_mk_symlink(from, to);
642 if(err)
643 printk("ubd_new_disk failed to make link from %s to "
644 "%s, error = %d\n", from, to, err);
645 }
646 else {
647 sprintf(disk->disk_name, "ubd_fake%d", unit);
648 sprintf(disk->devfs_name, "ubd_fake/disc%d", unit);
649 }
650
651 /* sysfs register (not for ide fake devices) */
652 if (major == MAJOR_NR) {
653 ubd_dev[unit].pdev.id = unit;
654 ubd_dev[unit].pdev.name = DRIVER_NAME;
655 platform_device_register(&ubd_dev[unit].pdev);
656 disk->driverfs_dev = &ubd_dev[unit].pdev.dev;
657 }
658
659 disk->private_data = &ubd_dev[unit];
660 disk->queue = ubd_queue;
661 add_disk(disk);
662
663 *disk_out = disk;
664 return 0;
665}
666
667#define ROUND_BLOCK(n) ((n + ((1 << 9) - 1)) & (-1 << 9))
668
669static int ubd_add(int n)
670{
671 struct ubd *dev = &ubd_dev[n];
672 int err;
673
Jeff Dikeec7cf782005-09-03 15:57:29 -0700674 err = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 if(dev->file == NULL)
Jeff Dikeec7cf782005-09-03 15:57:29 -0700676 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677
678 if (ubd_open_dev(dev))
Jeff Dikeec7cf782005-09-03 15:57:29 -0700679 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680
681 err = ubd_file_size(dev, &dev->size);
682 if(err < 0)
Jeff Dikeec7cf782005-09-03 15:57:29 -0700683 goto out_close;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684
685 dev->size = ROUND_BLOCK(dev->size);
686
687 err = ubd_new_disk(MAJOR_NR, dev->size, n, &ubd_gendisk[n]);
688 if(err)
Jeff Dikeec7cf782005-09-03 15:57:29 -0700689 goto out_close;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690
691 if(fake_major != MAJOR_NR)
692 ubd_new_disk(fake_major, dev->size, n,
693 &fake_gendisk[n]);
694
695 /* perhaps this should also be under the "if (fake_major)" above */
696 /* using the fake_disk->disk_name and also the fakehd_set name */
697 if (fake_ide)
698 make_ide_entries(ubd_gendisk[n]->disk_name);
699
Jeff Dikeec7cf782005-09-03 15:57:29 -0700700 err = 0;
701out_close:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 ubd_close(dev);
Jeff Dikeec7cf782005-09-03 15:57:29 -0700703out:
704 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705}
706
707static int ubd_config(char *str)
708{
709 int n, err;
710
Jeff Dike970d6e32006-01-06 00:18:48 -0800711 str = kstrdup(str, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 if(str == NULL){
713 printk(KERN_ERR "ubd_config failed to strdup string\n");
714 return(1);
715 }
716 err = ubd_setup_common(str, &n);
717 if(err){
718 kfree(str);
719 return(-1);
720 }
721 if(n == -1) return(0);
722
723 spin_lock(&ubd_lock);
724 err = ubd_add(n);
725 if(err)
726 ubd_dev[n].file = NULL;
727 spin_unlock(&ubd_lock);
728
729 return(err);
730}
731
732static int ubd_get_config(char *name, char *str, int size, char **error_out)
733{
734 struct ubd *dev;
735 int n, len = 0;
736
737 n = parse_unit(&name);
738 if((n >= MAX_DEV) || (n < 0)){
739 *error_out = "ubd_get_config : device number out of range";
740 return(-1);
741 }
742
743 dev = &ubd_dev[n];
744 spin_lock(&ubd_lock);
745
746 if(dev->file == NULL){
747 CONFIG_CHUNK(str, size, len, "", 1);
748 goto out;
749 }
750
751 CONFIG_CHUNK(str, size, len, dev->file, 0);
752
753 if(dev->cow.file != NULL){
754 CONFIG_CHUNK(str, size, len, ",", 0);
755 CONFIG_CHUNK(str, size, len, dev->cow.file, 1);
756 }
757 else CONFIG_CHUNK(str, size, len, "", 1);
758
759 out:
760 spin_unlock(&ubd_lock);
761 return(len);
762}
763
Jeff Dike29d56cf2005-06-25 14:55:25 -0700764static int ubd_id(char **str, int *start_out, int *end_out)
765{
766 int n;
767
768 n = parse_unit(str);
769 *start_out = 0;
770 *end_out = MAX_DEV - 1;
771 return n;
772}
773
774static int ubd_remove(int n)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775{
776 struct ubd *dev;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700777 int err = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778
Jeff Dike29d56cf2005-06-25 14:55:25 -0700779 spin_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780
781 if(ubd_gendisk[n] == NULL)
782 goto out;
783
Jeff Dike29d56cf2005-06-25 14:55:25 -0700784 dev = &ubd_dev[n];
785
786 if(dev->file == NULL)
787 goto out;
788
789 /* you cannot remove a open disk */
790 err = -EBUSY;
791 if(dev->count > 0)
792 goto out;
793
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 del_gendisk(ubd_gendisk[n]);
795 put_disk(ubd_gendisk[n]);
796 ubd_gendisk[n] = NULL;
797
798 if(fake_gendisk[n] != NULL){
799 del_gendisk(fake_gendisk[n]);
800 put_disk(fake_gendisk[n]);
801 fake_gendisk[n] = NULL;
802 }
803
804 platform_device_unregister(&dev->pdev);
805 *dev = ((struct ubd) DEFAULT_UBD);
806 err = 0;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700807out:
808 spin_unlock(&ubd_lock);
809 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810}
811
812static struct mc_device ubd_mc = {
813 .name = "ubd",
814 .config = ubd_config,
815 .get_config = ubd_get_config,
Jeff Dike29d56cf2005-06-25 14:55:25 -0700816 .id = ubd_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 .remove = ubd_remove,
818};
819
820static int ubd_mc_init(void)
821{
822 mconsole_register_dev(&ubd_mc);
823 return 0;
824}
825
826__initcall(ubd_mc_init);
827
Russell King3ae5eae2005-11-09 22:32:44 +0000828static struct platform_driver ubd_driver = {
829 .driver = {
830 .name = DRIVER_NAME,
831 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832};
833
834int ubd_init(void)
835{
836 int i;
837
838 devfs_mk_dir("ubd");
839 if (register_blkdev(MAJOR_NR, "ubd"))
840 return -1;
841
842 ubd_queue = blk_init_queue(do_ubd_request, &ubd_io_lock);
843 if (!ubd_queue) {
844 unregister_blkdev(MAJOR_NR, "ubd");
845 return -1;
846 }
847
848 if (fake_major != MAJOR_NR) {
849 char name[sizeof("ubd_nnn\0")];
850
851 snprintf(name, sizeof(name), "ubd_%d", fake_major);
852 devfs_mk_dir(name);
853 if (register_blkdev(fake_major, "ubd"))
854 return -1;
855 }
Russell King3ae5eae2005-11-09 22:32:44 +0000856 platform_driver_register(&ubd_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 for (i = 0; i < MAX_DEV; i++)
858 ubd_add(i);
859 return 0;
860}
861
862late_initcall(ubd_init);
863
Jeff Dike91acb212005-10-10 23:10:32 -0400864int ubd_driver_init(void){
865 unsigned long stack;
866 int err;
867
868 /* Set by CONFIG_BLK_DEV_UBD_SYNC or ubd=sync.*/
869 if(global_openflags.s){
870 printk(KERN_INFO "ubd: Synchronous mode\n");
871 /* Letting ubd=sync be like using ubd#s= instead of ubd#= is
872 * enough. So use anyway the io thread. */
873 }
874 stack = alloc_stack(0, 0);
875 io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *),
876 &thread_fd);
877 if(io_pid < 0){
878 printk(KERN_ERR
879 "ubd : Failed to start I/O thread (errno = %d) - "
880 "falling back to synchronous I/O\n", -io_pid);
881 io_pid = -1;
882 return(0);
883 }
884 err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr,
885 SA_INTERRUPT, "ubd", ubd_dev);
886 if(err != 0)
887 printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err);
888 return(err);
889}
890
891device_initcall(ubd_driver_init);
892
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893static int ubd_open(struct inode *inode, struct file *filp)
894{
895 struct gendisk *disk = inode->i_bdev->bd_disk;
896 struct ubd *dev = disk->private_data;
897 int err = 0;
898
899 if(dev->count == 0){
900 err = ubd_open_dev(dev);
901 if(err){
902 printk(KERN_ERR "%s: Can't open \"%s\": errno = %d\n",
903 disk->disk_name, dev->file, -err);
904 goto out;
905 }
906 }
907 dev->count++;
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -0700908 set_disk_ro(disk, !dev->openflags.w);
909
910 /* This should no more be needed. And it didn't work anyway to exclude
911 * read-write remounting of filesystems.*/
912 /*if((filp->f_mode & FMODE_WRITE) && !dev->openflags.w){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 if(--dev->count == 0) ubd_close(dev);
914 err = -EROFS;
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -0700915 }*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 out:
917 return(err);
918}
919
920static int ubd_release(struct inode * inode, struct file * file)
921{
922 struct gendisk *disk = inode->i_bdev->bd_disk;
923 struct ubd *dev = disk->private_data;
924
925 if(--dev->count == 0)
926 ubd_close(dev);
927 return(0);
928}
929
Jeff Dike91acb212005-10-10 23:10:32 -0400930static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask,
931 __u64 *cow_offset, unsigned long *bitmap,
932 __u64 bitmap_offset, unsigned long *bitmap_words,
933 __u64 bitmap_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934{
Jeff Dike91acb212005-10-10 23:10:32 -0400935 __u64 sector = io_offset >> 9;
936 int i, update_bitmap = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937
Jeff Dike91acb212005-10-10 23:10:32 -0400938 for(i = 0; i < length >> 9; i++){
939 if(cow_mask != NULL)
940 ubd_set_bit(i, (unsigned char *) cow_mask);
941 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
942 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943
Jeff Dike91acb212005-10-10 23:10:32 -0400944 update_bitmap = 1;
945 ubd_set_bit(sector + i, (unsigned char *) bitmap);
946 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947
Jeff Dike91acb212005-10-10 23:10:32 -0400948 if(!update_bitmap)
949 return;
950
951 *cow_offset = sector / (sizeof(unsigned long) * 8);
952
953 /* This takes care of the case where we're exactly at the end of the
954 * device, and *cow_offset + 1 is off the end. So, just back it up
955 * by one word. Thanks to Lynn Kerby for the fix and James McMechan
956 * for the original diagnosis.
957 */
958 if(*cow_offset == ((bitmap_len + sizeof(unsigned long) - 1) /
959 sizeof(unsigned long) - 1))
960 (*cow_offset)--;
961
962 bitmap_words[0] = bitmap[*cow_offset];
963 bitmap_words[1] = bitmap[*cow_offset + 1];
964
965 *cow_offset *= sizeof(unsigned long);
966 *cow_offset += bitmap_offset;
967}
968
969static void cowify_req(struct io_thread_req *req, unsigned long *bitmap,
970 __u64 bitmap_offset, __u64 bitmap_len)
971{
972 __u64 sector = req->offset >> 9;
973 int i;
974
975 if(req->length > (sizeof(req->sector_mask) * 8) << 9)
976 panic("Operation too long");
977
978 if(req->op == UBD_READ) {
979 for(i = 0; i < req->length >> 9; i++){
980 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
981 ubd_set_bit(i, (unsigned char *)
982 &req->sector_mask);
983 }
984 }
985 else cowify_bitmap(req->offset, req->length, &req->sector_mask,
986 &req->cow_offset, bitmap, bitmap_offset,
987 req->bitmap_words, bitmap_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988}
989
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990/* Called with ubd_io_lock held */
Jeff Dike91acb212005-10-10 23:10:32 -0400991static int prepare_request(struct request *req, struct io_thread_req *io_req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992{
993 struct gendisk *disk = req->rq_disk;
994 struct ubd *dev = disk->private_data;
Jeff Dike91acb212005-10-10 23:10:32 -0400995 __u64 offset;
996 int len;
997
998 if(req->rq_status == RQ_INACTIVE) return(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -07001000 /* This should be impossible now */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 if((rq_data_dir(req) == WRITE) && !dev->openflags.w){
1002 printk("Write attempted on readonly ubd device %s\n",
1003 disk->disk_name);
Jeff Dike91acb212005-10-10 23:10:32 -04001004 end_request(req, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 return(1);
1006 }
1007
Jeff Dike91acb212005-10-10 23:10:32 -04001008 offset = ((__u64) req->sector) << 9;
1009 len = req->current_nr_sectors << 9;
1010
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 io_req->fds[0] = (dev->cow.file != NULL) ? dev->cow.fd : dev->fd;
1012 io_req->fds[1] = dev->fd;
Jeff Dike91acb212005-10-10 23:10:32 -04001013 io_req->cow_offset = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 io_req->offset = offset;
1015 io_req->length = len;
1016 io_req->error = 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001017 io_req->sector_mask = 0;
1018
1019 io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 io_req->offsets[0] = 0;
1021 io_req->offsets[1] = dev->cow.data_offset;
Jeff Dike91acb212005-10-10 23:10:32 -04001022 io_req->buffer = req->buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 io_req->sectorsize = 1 << 9;
1024
Jeff Dike91acb212005-10-10 23:10:32 -04001025 if(dev->cow.file != NULL)
1026 cowify_req(io_req, dev->cow.bitmap, dev->cow.bitmap_offset,
1027 dev->cow.bitmap_len);
1028
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 return(0);
1030}
1031
1032/* Called with ubd_io_lock held */
1033static void do_ubd_request(request_queue_t *q)
1034{
1035 struct io_thread_req io_req;
1036 struct request *req;
Jeff Dike91acb212005-10-10 23:10:32 -04001037 int err, n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038
Jeff Dike91acb212005-10-10 23:10:32 -04001039 if(thread_fd == -1){
1040 while((req = elv_next_request(q)) != NULL){
1041 err = prepare_request(req, &io_req);
1042 if(!err){
1043 do_io(&io_req);
1044 __ubd_finish(req, io_req.error);
1045 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 }
1047 }
Jeff Dike91acb212005-10-10 23:10:32 -04001048 else {
1049 if(do_ubd || (req = elv_next_request(q)) == NULL)
1050 return;
1051 err = prepare_request(req, &io_req);
1052 if(!err){
1053 do_ubd = ubd_handler;
1054 n = os_write_file(thread_fd, (char *) &io_req,
1055 sizeof(io_req));
1056 if(n != sizeof(io_req))
1057 printk("write to io thread failed, "
1058 "errno = %d\n", -n);
1059 }
1060 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061}
1062
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001063static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
1064{
1065 struct ubd *dev = bdev->bd_disk->private_data;
1066
1067 geo->heads = 128;
1068 geo->sectors = 32;
1069 geo->cylinders = dev->size / (128 * 32 * 512);
1070 return 0;
1071}
1072
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073static int ubd_ioctl(struct inode * inode, struct file * file,
1074 unsigned int cmd, unsigned long arg)
1075{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 struct ubd *dev = inode->i_bdev->bd_disk->private_data;
1077 struct hd_driveid ubd_id = {
1078 .cyls = 0,
1079 .heads = 128,
1080 .sectors = 32,
1081 };
1082
1083 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 struct cdrom_volctrl volume;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 case HDIO_GET_IDENTITY:
1086 ubd_id.cyls = dev->size / (128 * 32 * 512);
1087 if(copy_to_user((char __user *) arg, (char *) &ubd_id,
1088 sizeof(ubd_id)))
1089 return(-EFAULT);
1090 return(0);
1091
1092 case CDROMVOLREAD:
1093 if(copy_from_user(&volume, (char __user *) arg, sizeof(volume)))
1094 return(-EFAULT);
1095 volume.channel0 = 255;
1096 volume.channel1 = 255;
1097 volume.channel2 = 255;
1098 volume.channel3 = 255;
1099 if(copy_to_user((char __user *) arg, &volume, sizeof(volume)))
1100 return(-EFAULT);
1101 return(0);
1102 }
1103 return(-EINVAL);
1104}
1105
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001106static int path_requires_switch(char *from_cmdline, char *from_cow, char *cow)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107{
1108 struct uml_stat buf1, buf2;
1109 int err;
1110
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001111 if(from_cmdline == NULL)
1112 return 0;
1113 if(!strcmp(from_cmdline, from_cow))
1114 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115
1116 err = os_stat_file(from_cmdline, &buf1);
1117 if(err < 0){
1118 printk("Couldn't stat '%s', err = %d\n", from_cmdline, -err);
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001119 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 }
1121 err = os_stat_file(from_cow, &buf2);
1122 if(err < 0){
1123 printk("Couldn't stat '%s', err = %d\n", from_cow, -err);
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001124 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 }
1126 if((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino))
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001127 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128
1129 printk("Backing file mismatch - \"%s\" requested,\n"
1130 "\"%s\" specified in COW header of \"%s\"\n",
1131 from_cmdline, from_cow, cow);
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001132 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133}
1134
1135static int backing_file_mismatch(char *file, __u64 size, time_t mtime)
1136{
1137 unsigned long modtime;
1138 long long actual;
1139 int err;
1140
1141 err = os_file_modtime(file, &modtime);
1142 if(err < 0){
1143 printk("Failed to get modification time of backing file "
1144 "\"%s\", err = %d\n", file, -err);
1145 return(err);
1146 }
1147
1148 err = os_file_size(file, &actual);
1149 if(err < 0){
1150 printk("Failed to get size of backing file \"%s\", "
1151 "err = %d\n", file, -err);
1152 return(err);
1153 }
1154
1155 if(actual != size){
1156 /*__u64 can be a long on AMD64 and with %lu GCC complains; so
1157 * the typecast.*/
1158 printk("Size mismatch (%llu vs %llu) of COW header vs backing "
1159 "file\n", (unsigned long long) size, actual);
1160 return(-EINVAL);
1161 }
1162 if(modtime != mtime){
1163 printk("mtime mismatch (%ld vs %ld) of COW header vs backing "
1164 "file\n", mtime, modtime);
1165 return(-EINVAL);
1166 }
1167 return(0);
1168}
1169
1170int read_cow_bitmap(int fd, void *buf, int offset, int len)
1171{
1172 int err;
1173
1174 err = os_seek_file(fd, offset);
1175 if(err < 0)
1176 return(err);
1177
1178 err = os_read_file(fd, buf, len);
1179 if(err < 0)
1180 return(err);
1181
1182 return(0);
1183}
1184
1185int open_ubd_file(char *file, struct openflags *openflags,
1186 char **backing_file_out, int *bitmap_offset_out,
1187 unsigned long *bitmap_len_out, int *data_offset_out,
1188 int *create_cow_out)
1189{
1190 time_t mtime;
1191 unsigned long long size;
1192 __u32 version, align;
1193 char *backing_file;
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001194 int fd, err, sectorsize, asked_switch, mode = 0644;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195
1196 fd = os_open_file(file, *openflags, mode);
1197 if(fd < 0){
1198 if((fd == -ENOENT) && (create_cow_out != NULL))
1199 *create_cow_out = 1;
1200 if(!openflags->w ||
1201 ((fd != -EROFS) && (fd != -EACCES))) return(fd);
1202 openflags->w = 0;
1203 fd = os_open_file(file, *openflags, mode);
1204 if(fd < 0)
1205 return(fd);
1206 }
1207
1208 err = os_lock_file(fd, openflags->w);
1209 if(err < 0){
1210 printk("Failed to lock '%s', err = %d\n", file, -err);
1211 goto out_close;
1212 }
1213
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001214 /* Succesful return case! */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215 if(backing_file_out == NULL) return(fd);
1216
1217 err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime,
1218 &size, &sectorsize, &align, bitmap_offset_out);
1219 if(err && (*backing_file_out != NULL)){
1220 printk("Failed to read COW header from COW file \"%s\", "
1221 "errno = %d\n", file, -err);
1222 goto out_close;
1223 }
1224 if(err) return(fd);
1225
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001226 asked_switch = path_requires_switch(*backing_file_out, backing_file, file);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001228 /* Allow switching only if no mismatch. */
1229 if (asked_switch && !backing_file_mismatch(*backing_file_out, size, mtime)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 printk("Switching backing file to '%s'\n", *backing_file_out);
1231 err = write_cow_header(file, fd, *backing_file_out,
1232 sectorsize, align, &size);
1233 if(err){
1234 printk("Switch failed, errno = %d\n", -err);
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001235 goto out_close;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 }
1237 }
1238 else {
1239 *backing_file_out = backing_file;
1240 err = backing_file_mismatch(*backing_file_out, size, mtime);
1241 if(err) goto out_close;
1242 }
1243
1244 cow_sizes(version, size, sectorsize, align, *bitmap_offset_out,
1245 bitmap_len_out, data_offset_out);
1246
1247 return(fd);
1248 out_close:
1249 os_close_file(fd);
1250 return(err);
1251}
1252
1253int create_cow_file(char *cow_file, char *backing_file, struct openflags flags,
1254 int sectorsize, int alignment, int *bitmap_offset_out,
1255 unsigned long *bitmap_len_out, int *data_offset_out)
1256{
1257 int err, fd;
1258
1259 flags.c = 1;
1260 fd = open_ubd_file(cow_file, &flags, NULL, NULL, NULL, NULL, NULL);
1261 if(fd < 0){
1262 err = fd;
1263 printk("Open of COW file '%s' failed, errno = %d\n", cow_file,
1264 -err);
1265 goto out;
1266 }
1267
1268 err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment,
1269 bitmap_offset_out, bitmap_len_out,
1270 data_offset_out);
1271 if(!err)
1272 return(fd);
1273 os_close_file(fd);
1274 out:
1275 return(err);
1276}
1277
Jeff Dike91acb212005-10-10 23:10:32 -04001278static int update_bitmap(struct io_thread_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279{
Jeff Dike91acb212005-10-10 23:10:32 -04001280 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281
Jeff Dike91acb212005-10-10 23:10:32 -04001282 if(req->cow_offset == -1)
1283 return(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284
Jeff Dike91acb212005-10-10 23:10:32 -04001285 n = os_seek_file(req->fds[1], req->cow_offset);
1286 if(n < 0){
1287 printk("do_io - bitmap lseek failed : err = %d\n", -n);
1288 return(1);
1289 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290
Jeff Dike91acb212005-10-10 23:10:32 -04001291 n = os_write_file(req->fds[1], &req->bitmap_words,
1292 sizeof(req->bitmap_words));
1293 if(n != sizeof(req->bitmap_words)){
1294 printk("do_io - bitmap update failed, err = %d fd = %d\n", -n,
1295 req->fds[1]);
1296 return(1);
1297 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298
Jeff Dike91acb212005-10-10 23:10:32 -04001299 return(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300}
Jeff Dike91acb212005-10-10 23:10:32 -04001301
1302void do_io(struct io_thread_req *req)
1303{
1304 char *buf;
1305 unsigned long len;
1306 int n, nsectors, start, end, bit;
1307 int err;
1308 __u64 off;
1309
1310 nsectors = req->length / req->sectorsize;
1311 start = 0;
1312 do {
1313 bit = ubd_test_bit(start, (unsigned char *) &req->sector_mask);
1314 end = start;
1315 while((end < nsectors) &&
1316 (ubd_test_bit(end, (unsigned char *)
1317 &req->sector_mask) == bit))
1318 end++;
1319
1320 off = req->offset + req->offsets[bit] +
1321 start * req->sectorsize;
1322 len = (end - start) * req->sectorsize;
1323 buf = &req->buffer[start * req->sectorsize];
1324
1325 err = os_seek_file(req->fds[bit], off);
1326 if(err < 0){
1327 printk("do_io - lseek failed : err = %d\n", -err);
1328 req->error = 1;
1329 return;
1330 }
1331 if(req->op == UBD_READ){
1332 n = 0;
1333 do {
1334 buf = &buf[n];
1335 len -= n;
1336 n = os_read_file(req->fds[bit], buf, len);
1337 if (n < 0) {
1338 printk("do_io - read failed, err = %d "
1339 "fd = %d\n", -n, req->fds[bit]);
1340 req->error = 1;
1341 return;
1342 }
1343 } while((n < len) && (n != 0));
1344 if (n < len) memset(&buf[n], 0, len - n);
1345 } else {
1346 n = os_write_file(req->fds[bit], buf, len);
1347 if(n != len){
1348 printk("do_io - write failed err = %d "
1349 "fd = %d\n", -n, req->fds[bit]);
1350 req->error = 1;
1351 return;
1352 }
1353 }
1354
1355 start = end;
1356 } while(start < nsectors);
1357
1358 req->error = update_bitmap(req);
1359}
1360
1361/* Changed in start_io_thread, which is serialized by being called only
1362 * from ubd_init, which is an initcall.
1363 */
1364int kernel_fd = -1;
1365
1366/* Only changed by the io thread */
1367int io_count = 0;
1368
1369int io_thread(void *arg)
1370{
1371 struct io_thread_req req;
1372 int n;
1373
1374 ignore_sigwinch_sig();
1375 while(1){
1376 n = os_read_file(kernel_fd, &req, sizeof(req));
1377 if(n != sizeof(req)){
1378 if(n < 0)
1379 printk("io_thread - read failed, fd = %d, "
1380 "err = %d\n", kernel_fd, -n);
1381 else {
1382 printk("io_thread - short read, fd = %d, "
1383 "length = %d\n", kernel_fd, n);
1384 }
1385 continue;
1386 }
1387 io_count++;
1388 do_io(&req);
1389 n = os_write_file(kernel_fd, &req, sizeof(req));
1390 if(n != sizeof(req))
1391 printk("io_thread - write failed, fd = %d, err = %d\n",
1392 kernel_fd, -n);
1393 }
Jeff Dike91acb212005-10-10 23:10:32 -04001394
Jeff Dike1b57e9c2006-01-06 00:18:49 -08001395 return 0;
1396}