[PATCH] uml: locking documentation
[deliverable/linux.git] / arch / um / drivers / ubd_kern.c
CommitLineData
6c29256c 1/*
1da177e4
LT
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"
1da177e4
LT
28#include "linux/cdrom.h"
29#include "linux/proc_fs.h"
30#include "linux/ctype.h"
31#include "linux/capability.h"
32#include "linux/mm.h"
33#include "linux/vmalloc.h"
34#include "linux/blkpg.h"
35#include "linux/genhd.h"
36#include "linux/spinlock.h"
d052d1be 37#include "linux/platform_device.h"
1da177e4
LT
38#include "asm/segment.h"
39#include "asm/uaccess.h"
40#include "asm/irq.h"
41#include "asm/types.h"
42#include "asm/tlbflush.h"
43#include "user_util.h"
44#include "mem_user.h"
45#include "kern_util.h"
46#include "kern.h"
47#include "mconsole_kern.h"
48#include "init.h"
49#include "irq_user.h"
50#include "irq_kern.h"
51#include "ubd_user.h"
1da177e4
LT
52#include "os.h"
53#include "mem.h"
54#include "mem_kern.h"
55#include "cow.h"
56
7b9014c1 57enum ubd_req { UBD_READ, UBD_WRITE };
1da177e4
LT
58
59struct io_thread_req {
91acb21f 60 enum ubd_req op;
1da177e4
LT
61 int fds[2];
62 unsigned long offsets[2];
63 unsigned long long offset;
64 unsigned long length;
65 char *buffer;
66 int sectorsize;
91acb21f
JD
67 unsigned long sector_mask;
68 unsigned long long cow_offset;
69 unsigned long bitmap_words[2];
1da177e4
LT
70 int error;
71};
72
6c29256c 73extern int open_ubd_file(char *file, struct openflags *openflags, int shared,
1da177e4
LT
74 char **backing_file_out, int *bitmap_offset_out,
75 unsigned long *bitmap_len_out, int *data_offset_out,
76 int *create_cow_out);
77extern int create_cow_file(char *cow_file, char *backing_file,
78 struct openflags flags, int sectorsize,
79 int alignment, int *bitmap_offset_out,
80 unsigned long *bitmap_len_out,
81 int *data_offset_out);
82extern int read_cow_bitmap(int fd, void *buf, int offset, int len);
91acb21f 83extern void do_io(struct io_thread_req *req);
1da177e4 84
91acb21f 85static inline int ubd_test_bit(__u64 bit, unsigned char *data)
1da177e4
LT
86{
87 __u64 n;
88 int bits, off;
89
91acb21f 90 bits = sizeof(data[0]) * 8;
1da177e4
LT
91 n = bit / bits;
92 off = bit % bits;
91acb21f 93 return((data[n] & (1 << off)) != 0);
1da177e4
LT
94}
95
91acb21f 96static inline void ubd_set_bit(__u64 bit, unsigned char *data)
1da177e4
LT
97{
98 __u64 n;
99 int bits, off;
100
91acb21f 101 bits = sizeof(data[0]) * 8;
1da177e4
LT
102 n = bit / bits;
103 off = bit % bits;
91acb21f 104 data[n] |= (1 << off);
1da177e4
LT
105}
106/*End stuff from ubd_user.h*/
107
108#define DRIVER_NAME "uml-blkdev"
109
110static DEFINE_SPINLOCK(ubd_io_lock);
111static DEFINE_SPINLOCK(ubd_lock);
112
91acb21f
JD
113static void (*do_ubd)(void);
114
1da177e4
LT
115static int ubd_open(struct inode * inode, struct file * filp);
116static int ubd_release(struct inode * inode, struct file * file);
117static int ubd_ioctl(struct inode * inode, struct file * file,
118 unsigned int cmd, unsigned long arg);
a885c8c4 119static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo);
1da177e4
LT
120
121#define MAX_DEV (8)
122
1da177e4
LT
123static struct block_device_operations ubd_blops = {
124 .owner = THIS_MODULE,
125 .open = ubd_open,
126 .release = ubd_release,
127 .ioctl = ubd_ioctl,
a885c8c4 128 .getgeo = ubd_getgeo,
1da177e4
LT
129};
130
131/* Protected by the queue_lock */
132static request_queue_t *ubd_queue;
133
134/* Protected by ubd_lock */
135static int fake_major = MAJOR_NR;
136
137static struct gendisk *ubd_gendisk[MAX_DEV];
138static struct gendisk *fake_gendisk[MAX_DEV];
6c29256c 139
1da177e4
LT
140#ifdef CONFIG_BLK_DEV_UBD_SYNC
141#define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 1, .c = 0, \
142 .cl = 1 })
143#else
144#define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 0, .c = 0, \
145 .cl = 1 })
146#endif
147
148/* Not protected - changed only in ubd_setup_common and then only to
149 * to enable O_SYNC.
150 */
151static struct openflags global_openflags = OPEN_FLAGS;
152
153struct cow {
2c49be99 154 /* This is the backing file, actually */
1da177e4
LT
155 char *file;
156 int fd;
157 unsigned long *bitmap;
158 unsigned long bitmap_len;
159 int bitmap_offset;
160 int data_offset;
161};
162
163struct ubd {
164 char *file;
165 int count;
166 int fd;
167 __u64 size;
168 struct openflags boot_openflags;
169 struct openflags openflags;
6c29256c 170 int shared;
1da177e4
LT
171 int no_cow;
172 struct cow cow;
173 struct platform_device pdev;
1da177e4
LT
174};
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, \
6c29256c 192 .shared = 0, \
1da177e4 193 .cow = DEFAULT_COW, \
1da177e4
LT
194}
195
196struct ubd ubd_dev[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_UBD };
197
198static int ubd0_init(void)
199{
200 struct ubd *dev = &ubd_dev[0];
201
202 if(dev->file == NULL)
203 dev->file = "root_fs";
204 return(0);
205}
206
207__initcall(ubd0_init);
208
209/* Only changed by fake_ide_setup which is a setup */
210static int fake_ide = 0;
211static struct proc_dir_entry *proc_ide_root = NULL;
212static struct proc_dir_entry *proc_ide = NULL;
213
214static void make_proc_ide(void)
215{
216 proc_ide_root = proc_mkdir("ide", NULL);
217 proc_ide = proc_mkdir("ide0", proc_ide_root);
218}
219
220static int proc_ide_read_media(char *page, char **start, off_t off, int count,
221 int *eof, void *data)
222{
223 int len;
224
225 strcpy(page, "disk\n");
226 len = strlen("disk\n");
227 len -= off;
228 if (len < count){
229 *eof = 1;
230 if (len <= 0) return 0;
231 }
232 else len = count;
233 *start = page + off;
234 return len;
235}
236
237static void make_ide_entries(char *dev_name)
238{
239 struct proc_dir_entry *dir, *ent;
240 char name[64];
241
242 if(proc_ide_root == NULL) make_proc_ide();
243
244 dir = proc_mkdir(dev_name, proc_ide);
245 if(!dir) return;
246
247 ent = create_proc_entry("media", S_IFREG|S_IRUGO, dir);
248 if(!ent) return;
249 ent->nlink = 1;
250 ent->data = NULL;
251 ent->read_proc = proc_ide_read_media;
252 ent->write_proc = NULL;
253 sprintf(name,"ide0/%s", dev_name);
254 proc_symlink(dev_name, proc_ide_root, name);
255}
256
257static int fake_ide_setup(char *str)
258{
259 fake_ide = 1;
260 return(1);
261}
262
263__setup("fake_ide", fake_ide_setup);
264
265__uml_help(fake_ide_setup,
266"fake_ide\n"
267" Create ide0 entries that map onto ubd devices.\n\n"
268);
269
270static int parse_unit(char **ptr)
271{
272 char *str = *ptr, *end;
273 int n = -1;
274
275 if(isdigit(*str)) {
276 n = simple_strtoul(str, &end, 0);
277 if(end == str)
278 return(-1);
279 *ptr = end;
280 }
281 else if (('a' <= *str) && (*str <= 'h')) {
282 n = *str - 'a';
283 str++;
284 *ptr = str;
285 }
286 return(n);
287}
288
289static int ubd_setup_common(char *str, int *index_out)
290{
291 struct ubd *dev;
292 struct openflags flags = global_openflags;
293 char *backing_file;
294 int n, err, i;
295
296 if(index_out) *index_out = -1;
297 n = *str;
298 if(n == '='){
299 char *end;
300 int major;
301
302 str++;
1da177e4
LT
303 if(!strcmp(str, "sync")){
304 global_openflags = of_sync(global_openflags);
305 return(0);
306 }
307 major = simple_strtoul(str, &end, 0);
308 if((*end != '\0') || (end == str)){
6c29256c 309 printk(KERN_ERR
1da177e4
LT
310 "ubd_setup : didn't parse major number\n");
311 return(1);
312 }
313
314 err = 1;
315 spin_lock(&ubd_lock);
316 if(fake_major != MAJOR_NR){
317 printk(KERN_ERR "Can't assign a fake major twice\n");
318 goto out1;
319 }
6c29256c 320
1da177e4
LT
321 fake_major = major;
322
323 printk(KERN_INFO "Setting extra ubd major number to %d\n",
324 major);
325 err = 0;
326 out1:
327 spin_unlock(&ubd_lock);
328 return(err);
329 }
330
331 n = parse_unit(&str);
332 if(n < 0){
333 printk(KERN_ERR "ubd_setup : couldn't parse unit number "
334 "'%s'\n", str);
335 return(1);
336 }
337 if(n >= MAX_DEV){
338 printk(KERN_ERR "ubd_setup : index %d out of range "
339 "(%d devices, from 0 to %d)\n", n, MAX_DEV, MAX_DEV - 1);
340 return(1);
341 }
342
343 err = 1;
344 spin_lock(&ubd_lock);
345
346 dev = &ubd_dev[n];
347 if(dev->file != NULL){
348 printk(KERN_ERR "ubd_setup : device already configured\n");
349 goto out;
350 }
351
352 if (index_out)
353 *index_out = n;
354
6c29256c 355 for (i = 0; i < sizeof("rscd="); i++) {
1da177e4
LT
356 switch (*str) {
357 case 'r':
358 flags.w = 0;
359 break;
360 case 's':
361 flags.s = 1;
362 break;
363 case 'd':
364 dev->no_cow = 1;
365 break;
6c29256c
JD
366 case 'c':
367 dev->shared = 1;
368 break;
1da177e4
LT
369 case '=':
370 str++;
371 goto break_loop;
372 default:
6c29256c 373 printk(KERN_ERR "ubd_setup : Expected '=' or flag letter (r, s, c, or d)\n");
1da177e4
LT
374 goto out;
375 }
376 str++;
377 }
378
379 if (*str == '=')
380 printk(KERN_ERR "ubd_setup : Too many flags specified\n");
381 else
382 printk(KERN_ERR "ubd_setup : Expected '='\n");
383 goto out;
384
385break_loop:
386 err = 0;
387 backing_file = strchr(str, ',');
388
389 if (!backing_file) {
390 backing_file = strchr(str, ':');
391 }
392
393 if(backing_file){
394 if(dev->no_cow)
395 printk(KERN_ERR "Can't specify both 'd' and a "
396 "cow file\n");
397 else {
398 *backing_file = '\0';
399 backing_file++;
400 }
401 }
402 dev->file = str;
403 dev->cow.file = backing_file;
404 dev->boot_openflags = flags;
405out:
406 spin_unlock(&ubd_lock);
407 return(err);
408}
409
410static int ubd_setup(char *str)
411{
412 ubd_setup_common(str, NULL);
413 return(1);
414}
415
416__setup("ubd", ubd_setup);
417__uml_help(ubd_setup,
418"ubd<n><flags>=<filename>[(:|,)<filename2>]\n"
419" This is used to associate a device with a file in the underlying\n"
420" filesystem. When specifying two filenames, the first one is the\n"
421" COW name and the second is the backing file name. As separator you can\n"
422" use either a ':' or a ',': the first one allows writing things like;\n"
423" ubd0=~/Uml/root_cow:~/Uml/root_backing_file\n"
424" while with a ',' the shell would not expand the 2nd '~'.\n"
425" When using only one filename, UML will detect whether to thread it like\n"
426" a COW file or a backing file. To override this detection, add the 'd'\n"
427" flag:\n"
428" ubd0d=BackingFile\n"
429" Usually, there is a filesystem in the file, but \n"
430" that's not required. Swap devices containing swap files can be\n"
431" specified like this. Also, a file which doesn't contain a\n"
432" filesystem can have its contents read in the virtual \n"
433" machine by running 'dd' on the device. <n> must be in the range\n"
434" 0 to 7. Appending an 'r' to the number will cause that device\n"
435" to be mounted read-only. For example ubd1r=./ext_fs. Appending\n"
436" an 's' will cause data to be written to disk on the host immediately.\n\n"
437);
438
439static int udb_setup(char *str)
440{
441 printk("udb%s specified on command line is almost certainly a ubd -> "
442 "udb TYPO\n", str);
443 return(1);
444}
445
446__setup("udb", udb_setup);
447__uml_help(udb_setup,
448"udb\n"
0894e27e
JD
449" This option is here solely to catch ubd -> udb typos, which can be\n"
450" to impossible to catch visually unless you specifically look for\n"
451" them. The only result of any option starting with 'udb' is an error\n"
1da177e4
LT
452" in the boot output.\n\n"
453);
454
455static int fakehd_set = 0;
456static int fakehd(char *str)
457{
458 printk(KERN_INFO "fakehd : Changing ubd name to \"hd\".\n");
459 fakehd_set = 1;
460 return 1;
461}
462
463__setup("fakehd", fakehd);
464__uml_help(fakehd,
465"fakehd\n"
466" Change the ubd device name to \"hd\".\n\n"
467);
468
469static void do_ubd_request(request_queue_t * q);
91acb21f
JD
470
471/* Only changed by ubd_init, which is an initcall. */
472int thread_fd = -1;
1da177e4
LT
473
474/* Changed by ubd_handler, which is serialized because interrupts only
475 * happen on CPU 0.
476 */
477int intr_count = 0;
478
91acb21f
JD
479/* call ubd_finish if you need to serialize */
480static void __ubd_finish(struct request *req, int error)
1da177e4 481{
91acb21f
JD
482 int nsect;
483
484 if(error){
485 end_request(req, 0);
486 return;
1da177e4 487 }
91acb21f
JD
488 nsect = req->current_nr_sectors;
489 req->sector += nsect;
490 req->buffer += nsect << 9;
491 req->errors = 0;
492 req->nr_sectors -= nsect;
493 req->current_nr_sectors = 0;
494 end_request(req, 1);
1da177e4
LT
495}
496
91acb21f 497static inline void ubd_finish(struct request *req, int error)
1da177e4 498{
91acb21f
JD
499 spin_lock(&ubd_io_lock);
500 __ubd_finish(req, error);
501 spin_unlock(&ubd_io_lock);
1da177e4
LT
502}
503
91acb21f
JD
504/* Called without ubd_io_lock held */
505static void ubd_handler(void)
1da177e4 506{
91acb21f
JD
507 struct io_thread_req req;
508 struct request *rq = elv_next_request(ubd_queue);
509 int n;
510
511 do_ubd = NULL;
512 intr_count++;
513 n = os_read_file(thread_fd, &req, sizeof(req));
514 if(n != sizeof(req)){
515 printk(KERN_ERR "Pid %d - spurious interrupt in ubd_handler, "
516 "err = %d\n", os_getpid(), -n);
517 spin_lock(&ubd_io_lock);
518 end_request(rq, 0);
519 spin_unlock(&ubd_io_lock);
520 return;
521 }
6c29256c 522
91acb21f
JD
523 ubd_finish(rq, req.error);
524 reactivate_fd(thread_fd, UBD_IRQ);
525 do_ubd_request(ubd_queue);
1da177e4
LT
526}
527
528static irqreturn_t ubd_intr(int irq, void *dev, struct pt_regs *unused)
529{
91acb21f
JD
530 ubd_handler();
531 return(IRQ_HANDLED);
532}
09ace81c 533
91acb21f
JD
534/* Only changed by ubd_init, which is an initcall. */
535static int io_pid = -1;
09ace81c 536
91acb21f
JD
537void kill_io_thread(void)
538{
6c29256c 539 if(io_pid != -1)
91acb21f 540 os_kill_process(io_pid, 1);
09ace81c 541}
1da177e4 542
91acb21f
JD
543__uml_exitcall(kill_io_thread);
544
1da177e4
LT
545static int ubd_file_size(struct ubd *dev, __u64 *size_out)
546{
547 char *file;
548
549 file = dev->cow.file ? dev->cow.file : dev->file;
550 return(os_file_size(file, size_out));
551}
552
553static void ubd_close(struct ubd *dev)
554{
1da177e4
LT
555 os_close_file(dev->fd);
556 if(dev->cow.file == NULL)
557 return;
558
1da177e4
LT
559 os_close_file(dev->cow.fd);
560 vfree(dev->cow.bitmap);
561 dev->cow.bitmap = NULL;
562}
563
564static int ubd_open_dev(struct ubd *dev)
565{
566 struct openflags flags;
567 char **back_ptr;
568 int err, create_cow, *create_ptr;
569
570 dev->openflags = dev->boot_openflags;
571 create_cow = 0;
572 create_ptr = (dev->cow.file != NULL) ? &create_cow : NULL;
573 back_ptr = dev->no_cow ? NULL : &dev->cow.file;
6c29256c
JD
574 dev->fd = open_ubd_file(dev->file, &dev->openflags, dev->shared,
575 back_ptr, &dev->cow.bitmap_offset,
576 &dev->cow.bitmap_len, &dev->cow.data_offset,
577 create_ptr);
1da177e4
LT
578
579 if((dev->fd == -ENOENT) && create_cow){
6c29256c 580 dev->fd = create_cow_file(dev->file, dev->cow.file,
1da177e4 581 dev->openflags, 1 << 9, PAGE_SIZE,
6c29256c 582 &dev->cow.bitmap_offset,
1da177e4
LT
583 &dev->cow.bitmap_len,
584 &dev->cow.data_offset);
585 if(dev->fd >= 0){
586 printk(KERN_INFO "Creating \"%s\" as COW file for "
587 "\"%s\"\n", dev->file, dev->cow.file);
588 }
589 }
590
591 if(dev->fd < 0){
592 printk("Failed to open '%s', errno = %d\n", dev->file,
593 -dev->fd);
594 return(dev->fd);
595 }
596
597 if(dev->cow.file != NULL){
598 err = -ENOMEM;
599 dev->cow.bitmap = (void *) vmalloc(dev->cow.bitmap_len);
600 if(dev->cow.bitmap == NULL){
601 printk(KERN_ERR "Failed to vmalloc COW bitmap\n");
602 goto error;
603 }
604 flush_tlb_kernel_vm();
605
6c29256c
JD
606 err = read_cow_bitmap(dev->fd, dev->cow.bitmap,
607 dev->cow.bitmap_offset,
1da177e4
LT
608 dev->cow.bitmap_len);
609 if(err < 0)
610 goto error;
611
612 flags = dev->openflags;
613 flags.w = 0;
6c29256c
JD
614 err = open_ubd_file(dev->cow.file, &flags, dev->shared, NULL,
615 NULL, NULL, NULL, NULL);
1da177e4
LT
616 if(err < 0) goto error;
617 dev->cow.fd = err;
618 }
619 return(0);
620 error:
621 os_close_file(dev->fd);
622 return(err);
623}
624
625static int ubd_new_disk(int major, u64 size, int unit,
626 struct gendisk **disk_out)
627
628{
629 struct gendisk *disk;
1da177e4
LT
630
631 disk = alloc_disk(1 << UBD_SHIFT);
632 if(disk == NULL)
633 return(-ENOMEM);
634
635 disk->major = major;
636 disk->first_minor = unit << UBD_SHIFT;
637 disk->fops = &ubd_blops;
638 set_capacity(disk, size / 512);
ce7b0f46 639 if(major == MAJOR_NR)
1da177e4 640 sprintf(disk->disk_name, "ubd%c", 'a' + unit);
ce7b0f46 641 else
1da177e4 642 sprintf(disk->disk_name, "ubd_fake%d", unit);
1da177e4
LT
643
644 /* sysfs register (not for ide fake devices) */
645 if (major == MAJOR_NR) {
646 ubd_dev[unit].pdev.id = unit;
647 ubd_dev[unit].pdev.name = DRIVER_NAME;
648 platform_device_register(&ubd_dev[unit].pdev);
649 disk->driverfs_dev = &ubd_dev[unit].pdev.dev;
650 }
651
652 disk->private_data = &ubd_dev[unit];
653 disk->queue = ubd_queue;
654 add_disk(disk);
655
656 *disk_out = disk;
657 return 0;
658}
659
660#define ROUND_BLOCK(n) ((n + ((1 << 9) - 1)) & (-1 << 9))
661
662static int ubd_add(int n)
663{
664 struct ubd *dev = &ubd_dev[n];
665 int err;
666
ec7cf783 667 err = -ENODEV;
1da177e4 668 if(dev->file == NULL)
ec7cf783 669 goto out;
1da177e4
LT
670
671 if (ubd_open_dev(dev))
ec7cf783 672 goto out;
1da177e4
LT
673
674 err = ubd_file_size(dev, &dev->size);
675 if(err < 0)
ec7cf783 676 goto out_close;
1da177e4
LT
677
678 dev->size = ROUND_BLOCK(dev->size);
679
680 err = ubd_new_disk(MAJOR_NR, dev->size, n, &ubd_gendisk[n]);
6c29256c 681 if(err)
ec7cf783 682 goto out_close;
6c29256c 683
1da177e4 684 if(fake_major != MAJOR_NR)
6c29256c 685 ubd_new_disk(fake_major, dev->size, n,
1da177e4
LT
686 &fake_gendisk[n]);
687
688 /* perhaps this should also be under the "if (fake_major)" above */
689 /* using the fake_disk->disk_name and also the fakehd_set name */
690 if (fake_ide)
691 make_ide_entries(ubd_gendisk[n]->disk_name);
692
ec7cf783
JD
693 err = 0;
694out_close:
1da177e4 695 ubd_close(dev);
ec7cf783
JD
696out:
697 return err;
1da177e4
LT
698}
699
700static int ubd_config(char *str)
701{
702 int n, err;
703
970d6e3a 704 str = kstrdup(str, GFP_KERNEL);
1da177e4
LT
705 if(str == NULL){
706 printk(KERN_ERR "ubd_config failed to strdup string\n");
707 return(1);
708 }
709 err = ubd_setup_common(str, &n);
710 if(err){
711 kfree(str);
712 return(-1);
713 }
714 if(n == -1) return(0);
715
716 spin_lock(&ubd_lock);
717 err = ubd_add(n);
718 if(err)
719 ubd_dev[n].file = NULL;
720 spin_unlock(&ubd_lock);
721
722 return(err);
723}
724
725static int ubd_get_config(char *name, char *str, int size, char **error_out)
726{
727 struct ubd *dev;
728 int n, len = 0;
729
730 n = parse_unit(&name);
731 if((n >= MAX_DEV) || (n < 0)){
732 *error_out = "ubd_get_config : device number out of range";
733 return(-1);
734 }
735
736 dev = &ubd_dev[n];
737 spin_lock(&ubd_lock);
738
739 if(dev->file == NULL){
740 CONFIG_CHUNK(str, size, len, "", 1);
741 goto out;
742 }
743
744 CONFIG_CHUNK(str, size, len, dev->file, 0);
745
746 if(dev->cow.file != NULL){
747 CONFIG_CHUNK(str, size, len, ",", 0);
748 CONFIG_CHUNK(str, size, len, dev->cow.file, 1);
749 }
750 else CONFIG_CHUNK(str, size, len, "", 1);
751
752 out:
753 spin_unlock(&ubd_lock);
754 return(len);
755}
756
29d56cfe
JD
757static int ubd_id(char **str, int *start_out, int *end_out)
758{
759 int n;
760
761 n = parse_unit(str);
762 *start_out = 0;
763 *end_out = MAX_DEV - 1;
764 return n;
765}
766
767static int ubd_remove(int n)
1da177e4
LT
768{
769 struct ubd *dev;
29d56cfe 770 int err = -ENODEV;
1da177e4 771
29d56cfe 772 spin_lock(&ubd_lock);
1da177e4 773
29d56cfe
JD
774 if(ubd_gendisk[n] == NULL)
775 goto out;
1da177e4
LT
776
777 dev = &ubd_dev[n];
1da177e4 778
29d56cfe
JD
779 if(dev->file == NULL)
780 goto out;
1da177e4 781
29d56cfe
JD
782 /* you cannot remove a open disk */
783 err = -EBUSY;
784 if(dev->count > 0)
1da177e4
LT
785 goto out;
786
787 del_gendisk(ubd_gendisk[n]);
788 put_disk(ubd_gendisk[n]);
789 ubd_gendisk[n] = NULL;
790
791 if(fake_gendisk[n] != NULL){
792 del_gendisk(fake_gendisk[n]);
793 put_disk(fake_gendisk[n]);
794 fake_gendisk[n] = NULL;
795 }
796
797 platform_device_unregister(&dev->pdev);
798 *dev = ((struct ubd) DEFAULT_UBD);
799 err = 0;
29d56cfe
JD
800out:
801 spin_unlock(&ubd_lock);
802 return err;
1da177e4
LT
803}
804
805static struct mc_device ubd_mc = {
806 .name = "ubd",
807 .config = ubd_config,
808 .get_config = ubd_get_config,
29d56cfe 809 .id = ubd_id,
1da177e4
LT
810 .remove = ubd_remove,
811};
812
813static int ubd_mc_init(void)
814{
815 mconsole_register_dev(&ubd_mc);
816 return 0;
817}
818
819__initcall(ubd_mc_init);
820
3ae5eaec
RK
821static struct platform_driver ubd_driver = {
822 .driver = {
823 .name = DRIVER_NAME,
824 },
1da177e4
LT
825};
826
827int ubd_init(void)
828{
829 int i;
830
1da177e4
LT
831 if (register_blkdev(MAJOR_NR, "ubd"))
832 return -1;
833
834 ubd_queue = blk_init_queue(do_ubd_request, &ubd_io_lock);
835 if (!ubd_queue) {
836 unregister_blkdev(MAJOR_NR, "ubd");
837 return -1;
838 }
839
840 if (fake_major != MAJOR_NR) {
841 char name[sizeof("ubd_nnn\0")];
842
843 snprintf(name, sizeof(name), "ubd_%d", fake_major);
1da177e4
LT
844 if (register_blkdev(fake_major, "ubd"))
845 return -1;
846 }
3ae5eaec 847 platform_driver_register(&ubd_driver);
6c29256c 848 for (i = 0; i < MAX_DEV; i++)
1da177e4
LT
849 ubd_add(i);
850 return 0;
851}
852
853late_initcall(ubd_init);
854
91acb21f
JD
855int ubd_driver_init(void){
856 unsigned long stack;
857 int err;
858
859 /* Set by CONFIG_BLK_DEV_UBD_SYNC or ubd=sync.*/
860 if(global_openflags.s){
861 printk(KERN_INFO "ubd: Synchronous mode\n");
862 /* Letting ubd=sync be like using ubd#s= instead of ubd#= is
863 * enough. So use anyway the io thread. */
864 }
865 stack = alloc_stack(0, 0);
6c29256c 866 io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *),
91acb21f
JD
867 &thread_fd);
868 if(io_pid < 0){
6c29256c 869 printk(KERN_ERR
91acb21f
JD
870 "ubd : Failed to start I/O thread (errno = %d) - "
871 "falling back to synchronous I/O\n", -io_pid);
872 io_pid = -1;
873 return(0);
874 }
6c29256c 875 err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr,
bd6aa650 876 IRQF_DISABLED, "ubd", ubd_dev);
91acb21f
JD
877 if(err != 0)
878 printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err);
f4c57a78 879 return 0;
91acb21f
JD
880}
881
882device_initcall(ubd_driver_init);
883
1da177e4
LT
884static int ubd_open(struct inode *inode, struct file *filp)
885{
886 struct gendisk *disk = inode->i_bdev->bd_disk;
887 struct ubd *dev = disk->private_data;
888 int err = 0;
889
890 if(dev->count == 0){
891 err = ubd_open_dev(dev);
892 if(err){
893 printk(KERN_ERR "%s: Can't open \"%s\": errno = %d\n",
894 disk->disk_name, dev->file, -err);
895 goto out;
896 }
897 }
898 dev->count++;
2c49be99
PBG
899 set_disk_ro(disk, !dev->openflags.w);
900
901 /* This should no more be needed. And it didn't work anyway to exclude
902 * read-write remounting of filesystems.*/
903 /*if((filp->f_mode & FMODE_WRITE) && !dev->openflags.w){
1da177e4
LT
904 if(--dev->count == 0) ubd_close(dev);
905 err = -EROFS;
2c49be99 906 }*/
1da177e4
LT
907 out:
908 return(err);
909}
910
911static int ubd_release(struct inode * inode, struct file * file)
912{
913 struct gendisk *disk = inode->i_bdev->bd_disk;
914 struct ubd *dev = disk->private_data;
915
916 if(--dev->count == 0)
917 ubd_close(dev);
918 return(0);
919}
920
91acb21f
JD
921static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask,
922 __u64 *cow_offset, unsigned long *bitmap,
923 __u64 bitmap_offset, unsigned long *bitmap_words,
924 __u64 bitmap_len)
1da177e4 925{
91acb21f
JD
926 __u64 sector = io_offset >> 9;
927 int i, update_bitmap = 0;
928
929 for(i = 0; i < length >> 9; i++){
930 if(cow_mask != NULL)
931 ubd_set_bit(i, (unsigned char *) cow_mask);
932 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
933 continue;
1da177e4 934
91acb21f
JD
935 update_bitmap = 1;
936 ubd_set_bit(sector + i, (unsigned char *) bitmap);
937 }
938
939 if(!update_bitmap)
940 return;
1da177e4 941
91acb21f 942 *cow_offset = sector / (sizeof(unsigned long) * 8);
1da177e4 943
91acb21f
JD
944 /* This takes care of the case where we're exactly at the end of the
945 * device, and *cow_offset + 1 is off the end. So, just back it up
946 * by one word. Thanks to Lynn Kerby for the fix and James McMechan
947 * for the original diagnosis.
948 */
949 if(*cow_offset == ((bitmap_len + sizeof(unsigned long) - 1) /
950 sizeof(unsigned long) - 1))
951 (*cow_offset)--;
952
953 bitmap_words[0] = bitmap[*cow_offset];
954 bitmap_words[1] = bitmap[*cow_offset + 1];
955
956 *cow_offset *= sizeof(unsigned long);
957 *cow_offset += bitmap_offset;
958}
959
960static void cowify_req(struct io_thread_req *req, unsigned long *bitmap,
961 __u64 bitmap_offset, __u64 bitmap_len)
962{
963 __u64 sector = req->offset >> 9;
964 int i;
965
966 if(req->length > (sizeof(req->sector_mask) * 8) << 9)
967 panic("Operation too long");
968
969 if(req->op == UBD_READ) {
970 for(i = 0; i < req->length >> 9; i++){
971 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
6c29256c 972 ubd_set_bit(i, (unsigned char *)
91acb21f
JD
973 &req->sector_mask);
974 }
975 }
976 else cowify_bitmap(req->offset, req->length, &req->sector_mask,
977 &req->cow_offset, bitmap, bitmap_offset,
978 req->bitmap_words, bitmap_len);
1da177e4
LT
979}
980
1da177e4 981/* Called with ubd_io_lock held */
91acb21f 982static int prepare_request(struct request *req, struct io_thread_req *io_req)
1da177e4
LT
983{
984 struct gendisk *disk = req->rq_disk;
985 struct ubd *dev = disk->private_data;
91acb21f
JD
986 __u64 offset;
987 int len;
988
989 if(req->rq_status == RQ_INACTIVE) return(1);
1da177e4 990
2c49be99 991 /* This should be impossible now */
1da177e4 992 if((rq_data_dir(req) == WRITE) && !dev->openflags.w){
6c29256c 993 printk("Write attempted on readonly ubd device %s\n",
1da177e4 994 disk->disk_name);
91acb21f 995 end_request(req, 0);
1da177e4
LT
996 return(1);
997 }
998
91acb21f
JD
999 offset = ((__u64) req->sector) << 9;
1000 len = req->current_nr_sectors << 9;
1001
1da177e4
LT
1002 io_req->fds[0] = (dev->cow.file != NULL) ? dev->cow.fd : dev->fd;
1003 io_req->fds[1] = dev->fd;
91acb21f 1004 io_req->cow_offset = -1;
1da177e4
LT
1005 io_req->offset = offset;
1006 io_req->length = len;
1007 io_req->error = 0;
91acb21f
JD
1008 io_req->sector_mask = 0;
1009
1010 io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE;
1da177e4
LT
1011 io_req->offsets[0] = 0;
1012 io_req->offsets[1] = dev->cow.data_offset;
91acb21f 1013 io_req->buffer = req->buffer;
1da177e4
LT
1014 io_req->sectorsize = 1 << 9;
1015
91acb21f
JD
1016 if(dev->cow.file != NULL)
1017 cowify_req(io_req, dev->cow.bitmap, dev->cow.bitmap_offset,
1018 dev->cow.bitmap_len);
1019
1da177e4
LT
1020 return(0);
1021}
1022
1023/* Called with ubd_io_lock held */
1024static void do_ubd_request(request_queue_t *q)
1025{
1026 struct io_thread_req io_req;
1027 struct request *req;
91acb21f
JD
1028 int err, n;
1029
1030 if(thread_fd == -1){
1031 while((req = elv_next_request(q)) != NULL){
1032 err = prepare_request(req, &io_req);
1033 if(!err){
1034 do_io(&io_req);
1035 __ubd_finish(req, io_req.error);
1036 }
1037 }
1038 }
1039 else {
1040 if(do_ubd || (req = elv_next_request(q)) == NULL)
1041 return;
1042 err = prepare_request(req, &io_req);
1043 if(!err){
1044 do_ubd = ubd_handler;
1045 n = os_write_file(thread_fd, (char *) &io_req,
1046 sizeof(io_req));
1047 if(n != sizeof(io_req))
1048 printk("write to io thread failed, "
1049 "errno = %d\n", -n);
1da177e4
LT
1050 }
1051 }
1052}
1053
a885c8c4
CH
1054static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
1055{
1056 struct ubd *dev = bdev->bd_disk->private_data;
1057
1058 geo->heads = 128;
1059 geo->sectors = 32;
1060 geo->cylinders = dev->size / (128 * 32 * 512);
1061 return 0;
1062}
1063
1da177e4
LT
1064static int ubd_ioctl(struct inode * inode, struct file * file,
1065 unsigned int cmd, unsigned long arg)
1066{
1da177e4
LT
1067 struct ubd *dev = inode->i_bdev->bd_disk->private_data;
1068 struct hd_driveid ubd_id = {
1069 .cyls = 0,
1070 .heads = 128,
1071 .sectors = 32,
1072 };
1073
1074 switch (cmd) {
1da177e4 1075 struct cdrom_volctrl volume;
1da177e4
LT
1076 case HDIO_GET_IDENTITY:
1077 ubd_id.cyls = dev->size / (128 * 32 * 512);
1078 if(copy_to_user((char __user *) arg, (char *) &ubd_id,
1079 sizeof(ubd_id)))
1080 return(-EFAULT);
1081 return(0);
1082
1083 case CDROMVOLREAD:
1084 if(copy_from_user(&volume, (char __user *) arg, sizeof(volume)))
1085 return(-EFAULT);
1086 volume.channel0 = 255;
1087 volume.channel1 = 255;
1088 volume.channel2 = 255;
1089 volume.channel3 = 255;
1090 if(copy_to_user((char __user *) arg, &volume, sizeof(volume)))
1091 return(-EFAULT);
1092 return(0);
1093 }
1094 return(-EINVAL);
1095}
1096
4833aff7 1097static int path_requires_switch(char *from_cmdline, char *from_cow, char *cow)
1da177e4
LT
1098{
1099 struct uml_stat buf1, buf2;
1100 int err;
1101
4833aff7
PBG
1102 if(from_cmdline == NULL)
1103 return 0;
1104 if(!strcmp(from_cmdline, from_cow))
1105 return 0;
1da177e4
LT
1106
1107 err = os_stat_file(from_cmdline, &buf1);
1108 if(err < 0){
1109 printk("Couldn't stat '%s', err = %d\n", from_cmdline, -err);
4833aff7 1110 return 0;
1da177e4
LT
1111 }
1112 err = os_stat_file(from_cow, &buf2);
1113 if(err < 0){
1114 printk("Couldn't stat '%s', err = %d\n", from_cow, -err);
4833aff7 1115 return 1;
1da177e4
LT
1116 }
1117 if((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino))
4833aff7 1118 return 0;
1da177e4
LT
1119
1120 printk("Backing file mismatch - \"%s\" requested,\n"
1121 "\"%s\" specified in COW header of \"%s\"\n",
1122 from_cmdline, from_cow, cow);
4833aff7 1123 return 1;
1da177e4
LT
1124}
1125
1126static int backing_file_mismatch(char *file, __u64 size, time_t mtime)
1127{
1128 unsigned long modtime;
fe1db50c 1129 unsigned long long actual;
1da177e4
LT
1130 int err;
1131
1132 err = os_file_modtime(file, &modtime);
1133 if(err < 0){
1134 printk("Failed to get modification time of backing file "
1135 "\"%s\", err = %d\n", file, -err);
1136 return(err);
1137 }
1138
1139 err = os_file_size(file, &actual);
1140 if(err < 0){
1141 printk("Failed to get size of backing file \"%s\", "
1142 "err = %d\n", file, -err);
1143 return(err);
1144 }
1145
1146 if(actual != size){
1147 /*__u64 can be a long on AMD64 and with %lu GCC complains; so
1148 * the typecast.*/
1149 printk("Size mismatch (%llu vs %llu) of COW header vs backing "
1150 "file\n", (unsigned long long) size, actual);
1151 return(-EINVAL);
1152 }
1153 if(modtime != mtime){
1154 printk("mtime mismatch (%ld vs %ld) of COW header vs backing "
1155 "file\n", mtime, modtime);
1156 return(-EINVAL);
1157 }
1158 return(0);
1159}
1160
1161int read_cow_bitmap(int fd, void *buf, int offset, int len)
1162{
1163 int err;
1164
1165 err = os_seek_file(fd, offset);
1166 if(err < 0)
1167 return(err);
1168
1169 err = os_read_file(fd, buf, len);
1170 if(err < 0)
1171 return(err);
1172
1173 return(0);
1174}
1175
6c29256c 1176int open_ubd_file(char *file, struct openflags *openflags, int shared,
1da177e4
LT
1177 char **backing_file_out, int *bitmap_offset_out,
1178 unsigned long *bitmap_len_out, int *data_offset_out,
1179 int *create_cow_out)
1180{
1181 time_t mtime;
1182 unsigned long long size;
1183 __u32 version, align;
1184 char *backing_file;
4833aff7 1185 int fd, err, sectorsize, asked_switch, mode = 0644;
1da177e4
LT
1186
1187 fd = os_open_file(file, *openflags, mode);
a374a48f
PBG
1188 if (fd < 0) {
1189 if ((fd == -ENOENT) && (create_cow_out != NULL))
1da177e4 1190 *create_cow_out = 1;
a374a48f
PBG
1191 if (!openflags->w ||
1192 ((fd != -EROFS) && (fd != -EACCES)))
1193 return fd;
1da177e4
LT
1194 openflags->w = 0;
1195 fd = os_open_file(file, *openflags, mode);
a374a48f
PBG
1196 if (fd < 0)
1197 return fd;
1da177e4
LT
1198 }
1199
6c29256c
JD
1200 if(shared)
1201 printk("Not locking \"%s\" on the host\n", file);
1202 else {
1203 err = os_lock_file(fd, openflags->w);
1204 if(err < 0){
1205 printk("Failed to lock '%s', err = %d\n", file, -err);
1206 goto out_close;
1207 }
1da177e4
LT
1208 }
1209
d6e05edc 1210 /* Successful return case! */
a374a48f
PBG
1211 if(backing_file_out == NULL)
1212 return(fd);
1da177e4
LT
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 }
a374a48f
PBG
1221 if(err)
1222 return(fd);
1da177e4 1223
4833aff7 1224 asked_switch = path_requires_switch(*backing_file_out, backing_file, file);
1da177e4 1225
4833aff7
PBG
1226 /* Allow switching only if no mismatch. */
1227 if (asked_switch && !backing_file_mismatch(*backing_file_out, size, mtime)) {
1da177e4
LT
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);
a374a48f 1231 if (err) {
1da177e4 1232 printk("Switch failed, errno = %d\n", -err);
4833aff7 1233 goto out_close;
1da177e4 1234 }
a374a48f 1235 } else {
1da177e4
LT
1236 *backing_file_out = backing_file;
1237 err = backing_file_mismatch(*backing_file_out, size, mtime);
a374a48f
PBG
1238 if (err)
1239 goto out_close;
1da177e4
LT
1240 }
1241
1242 cow_sizes(version, size, sectorsize, align, *bitmap_offset_out,
1243 bitmap_len_out, data_offset_out);
1244
a374a48f 1245 return fd;
1da177e4
LT
1246 out_close:
1247 os_close_file(fd);
a374a48f 1248 return err;
1da177e4
LT
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;
6c29256c 1258 fd = open_ubd_file(cow_file, &flags, 0, NULL, NULL, NULL, NULL, NULL);
1da177e4
LT
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
91acb21f 1276static int update_bitmap(struct io_thread_req *req)
1da177e4 1277{
91acb21f 1278 int n;
1da177e4 1279
91acb21f
JD
1280 if(req->cow_offset == -1)
1281 return(0);
1da177e4 1282
91acb21f
JD
1283 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 }
1da177e4 1288
91acb21f
JD
1289 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 }
1da177e4 1296
91acb21f
JD
1297 return(0);
1298}
1da177e4 1299
91acb21f
JD
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);
1da177e4 1355
91acb21f 1356 req->error = update_bitmap(req);
1da177e4 1357}
91acb21f
JD
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 }
91acb21f 1392
1b57e9c2
JD
1393 return 0;
1394}
This page took 0.218331 seconds and 5 git commands to generate.