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