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