blob: 3a93c6f772fa3aa0bac0de3d6f3ec977dc545a3b [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{
1076 struct hd_geometry __user *loc = (struct hd_geometry __user *) arg;
1077 struct ubd *dev = inode->i_bdev->bd_disk->private_data;
1078 struct hd_driveid ubd_id = {
1079 .cyls = 0,
1080 .heads = 128,
1081 .sectors = 32,
1082 };
1083
1084 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 struct cdrom_volctrl volume;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 case HDIO_GET_IDENTITY:
1087 ubd_id.cyls = dev->size / (128 * 32 * 512);
1088 if(copy_to_user((char __user *) arg, (char *) &ubd_id,
1089 sizeof(ubd_id)))
1090 return(-EFAULT);
1091 return(0);
1092
1093 case CDROMVOLREAD:
1094 if(copy_from_user(&volume, (char __user *) arg, sizeof(volume)))
1095 return(-EFAULT);
1096 volume.channel0 = 255;
1097 volume.channel1 = 255;
1098 volume.channel2 = 255;
1099 volume.channel3 = 255;
1100 if(copy_to_user((char __user *) arg, &volume, sizeof(volume)))
1101 return(-EFAULT);
1102 return(0);
1103 }
1104 return(-EINVAL);
1105}
1106
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107static int same_backing_files(char *from_cmdline, char *from_cow, char *cow)
1108{
1109 struct uml_stat buf1, buf2;
1110 int err;
1111
1112 if(from_cmdline == NULL) return(1);
1113 if(!strcmp(from_cmdline, from_cow)) return(1);
1114
1115 err = os_stat_file(from_cmdline, &buf1);
1116 if(err < 0){
1117 printk("Couldn't stat '%s', err = %d\n", from_cmdline, -err);
1118 return(1);
1119 }
1120 err = os_stat_file(from_cow, &buf2);
1121 if(err < 0){
1122 printk("Couldn't stat '%s', err = %d\n", from_cow, -err);
1123 return(1);
1124 }
1125 if((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino))
1126 return(1);
1127
1128 printk("Backing file mismatch - \"%s\" requested,\n"
1129 "\"%s\" specified in COW header of \"%s\"\n",
1130 from_cmdline, from_cow, cow);
1131 return(0);
1132}
1133
1134static int backing_file_mismatch(char *file, __u64 size, time_t mtime)
1135{
1136 unsigned long modtime;
1137 long long actual;
1138 int err;
1139
1140 err = os_file_modtime(file, &modtime);
1141 if(err < 0){
1142 printk("Failed to get modification time of backing file "
1143 "\"%s\", err = %d\n", file, -err);
1144 return(err);
1145 }
1146
1147 err = os_file_size(file, &actual);
1148 if(err < 0){
1149 printk("Failed to get size of backing file \"%s\", "
1150 "err = %d\n", file, -err);
1151 return(err);
1152 }
1153
1154 if(actual != size){
1155 /*__u64 can be a long on AMD64 and with %lu GCC complains; so
1156 * the typecast.*/
1157 printk("Size mismatch (%llu vs %llu) of COW header vs backing "
1158 "file\n", (unsigned long long) size, actual);
1159 return(-EINVAL);
1160 }
1161 if(modtime != mtime){
1162 printk("mtime mismatch (%ld vs %ld) of COW header vs backing "
1163 "file\n", mtime, modtime);
1164 return(-EINVAL);
1165 }
1166 return(0);
1167}
1168
1169int read_cow_bitmap(int fd, void *buf, int offset, int len)
1170{
1171 int err;
1172
1173 err = os_seek_file(fd, offset);
1174 if(err < 0)
1175 return(err);
1176
1177 err = os_read_file(fd, buf, len);
1178 if(err < 0)
1179 return(err);
1180
1181 return(0);
1182}
1183
1184int open_ubd_file(char *file, struct openflags *openflags,
1185 char **backing_file_out, int *bitmap_offset_out,
1186 unsigned long *bitmap_len_out, int *data_offset_out,
1187 int *create_cow_out)
1188{
1189 time_t mtime;
1190 unsigned long long size;
1191 __u32 version, align;
1192 char *backing_file;
1193 int fd, err, sectorsize, same, mode = 0644;
1194
1195 fd = os_open_file(file, *openflags, mode);
1196 if(fd < 0){
1197 if((fd == -ENOENT) && (create_cow_out != NULL))
1198 *create_cow_out = 1;
1199 if(!openflags->w ||
1200 ((fd != -EROFS) && (fd != -EACCES))) return(fd);
1201 openflags->w = 0;
1202 fd = os_open_file(file, *openflags, mode);
1203 if(fd < 0)
1204 return(fd);
1205 }
1206
1207 err = os_lock_file(fd, openflags->w);
1208 if(err < 0){
1209 printk("Failed to lock '%s', err = %d\n", file, -err);
1210 goto out_close;
1211 }
1212
1213 if(backing_file_out == NULL) return(fd);
1214
1215 err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime,
1216 &size, &sectorsize, &align, bitmap_offset_out);
1217 if(err && (*backing_file_out != NULL)){
1218 printk("Failed to read COW header from COW file \"%s\", "
1219 "errno = %d\n", file, -err);
1220 goto out_close;
1221 }
1222 if(err) return(fd);
1223
1224 if(backing_file_out == NULL) return(fd);
1225
1226 same = same_backing_files(*backing_file_out, backing_file, file);
1227
1228 if(!same && !backing_file_mismatch(*backing_file_out, size, mtime)){
1229 printk("Switching backing file to '%s'\n", *backing_file_out);
1230 err = write_cow_header(file, fd, *backing_file_out,
1231 sectorsize, align, &size);
1232 if(err){
1233 printk("Switch failed, errno = %d\n", -err);
1234 return(err);
1235 }
1236 }
1237 else {
1238 *backing_file_out = backing_file;
1239 err = backing_file_mismatch(*backing_file_out, size, mtime);
1240 if(err) goto out_close;
1241 }
1242
1243 cow_sizes(version, size, sectorsize, align, *bitmap_offset_out,
1244 bitmap_len_out, data_offset_out);
1245
1246 return(fd);
1247 out_close:
1248 os_close_file(fd);
1249 return(err);
1250}
1251
1252int create_cow_file(char *cow_file, char *backing_file, struct openflags flags,
1253 int sectorsize, int alignment, int *bitmap_offset_out,
1254 unsigned long *bitmap_len_out, int *data_offset_out)
1255{
1256 int err, fd;
1257
1258 flags.c = 1;
1259 fd = open_ubd_file(cow_file, &flags, NULL, NULL, NULL, NULL, NULL);
1260 if(fd < 0){
1261 err = fd;
1262 printk("Open of COW file '%s' failed, errno = %d\n", cow_file,
1263 -err);
1264 goto out;
1265 }
1266
1267 err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment,
1268 bitmap_offset_out, bitmap_len_out,
1269 data_offset_out);
1270 if(!err)
1271 return(fd);
1272 os_close_file(fd);
1273 out:
1274 return(err);
1275}
1276
Jeff Dike91acb212005-10-10 23:10:32 -04001277static int update_bitmap(struct io_thread_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278{
Jeff Dike91acb212005-10-10 23:10:32 -04001279 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280
Jeff Dike91acb212005-10-10 23:10:32 -04001281 if(req->cow_offset == -1)
1282 return(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283
Jeff Dike91acb212005-10-10 23:10:32 -04001284 n = os_seek_file(req->fds[1], req->cow_offset);
1285 if(n < 0){
1286 printk("do_io - bitmap lseek failed : err = %d\n", -n);
1287 return(1);
1288 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289
Jeff Dike91acb212005-10-10 23:10:32 -04001290 n = os_write_file(req->fds[1], &req->bitmap_words,
1291 sizeof(req->bitmap_words));
1292 if(n != sizeof(req->bitmap_words)){
1293 printk("do_io - bitmap update failed, err = %d fd = %d\n", -n,
1294 req->fds[1]);
1295 return(1);
1296 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297
Jeff Dike91acb212005-10-10 23:10:32 -04001298 return(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299}
Jeff Dike91acb212005-10-10 23:10:32 -04001300
1301void do_io(struct io_thread_req *req)
1302{
1303 char *buf;
1304 unsigned long len;
1305 int n, nsectors, start, end, bit;
1306 int err;
1307 __u64 off;
1308
1309 nsectors = req->length / req->sectorsize;
1310 start = 0;
1311 do {
1312 bit = ubd_test_bit(start, (unsigned char *) &req->sector_mask);
1313 end = start;
1314 while((end < nsectors) &&
1315 (ubd_test_bit(end, (unsigned char *)
1316 &req->sector_mask) == bit))
1317 end++;
1318
1319 off = req->offset + req->offsets[bit] +
1320 start * req->sectorsize;
1321 len = (end - start) * req->sectorsize;
1322 buf = &req->buffer[start * req->sectorsize];
1323
1324 err = os_seek_file(req->fds[bit], off);
1325 if(err < 0){
1326 printk("do_io - lseek failed : err = %d\n", -err);
1327 req->error = 1;
1328 return;
1329 }
1330 if(req->op == UBD_READ){
1331 n = 0;
1332 do {
1333 buf = &buf[n];
1334 len -= n;
1335 n = os_read_file(req->fds[bit], buf, len);
1336 if (n < 0) {
1337 printk("do_io - read failed, err = %d "
1338 "fd = %d\n", -n, req->fds[bit]);
1339 req->error = 1;
1340 return;
1341 }
1342 } while((n < len) && (n != 0));
1343 if (n < len) memset(&buf[n], 0, len - n);
1344 } else {
1345 n = os_write_file(req->fds[bit], buf, len);
1346 if(n != len){
1347 printk("do_io - write failed err = %d "
1348 "fd = %d\n", -n, req->fds[bit]);
1349 req->error = 1;
1350 return;
1351 }
1352 }
1353
1354 start = end;
1355 } while(start < nsectors);
1356
1357 req->error = update_bitmap(req);
1358}
1359
1360/* Changed in start_io_thread, which is serialized by being called only
1361 * from ubd_init, which is an initcall.
1362 */
1363int kernel_fd = -1;
1364
1365/* Only changed by the io thread */
1366int io_count = 0;
1367
1368int io_thread(void *arg)
1369{
1370 struct io_thread_req req;
1371 int n;
1372
1373 ignore_sigwinch_sig();
1374 while(1){
1375 n = os_read_file(kernel_fd, &req, sizeof(req));
1376 if(n != sizeof(req)){
1377 if(n < 0)
1378 printk("io_thread - read failed, fd = %d, "
1379 "err = %d\n", kernel_fd, -n);
1380 else {
1381 printk("io_thread - short read, fd = %d, "
1382 "length = %d\n", kernel_fd, n);
1383 }
1384 continue;
1385 }
1386 io_count++;
1387 do_io(&req);
1388 n = os_write_file(kernel_fd, &req, sizeof(req));
1389 if(n != sizeof(req))
1390 printk("io_thread - write failed, fd = %d, err = %d\n",
1391 kernel_fd, -n);
1392 }
Jeff Dike91acb212005-10-10 23:10:32 -04001393
Jeff Dike1b57e9c2006-01-06 00:18:49 -08001394 return 0;
1395}