blob: 125a63fd3a4549e74096a62306719e6619d17d35 [file] [log] [blame]
Jeff Dike6c29256c2006-03-27 01:14:37 -08001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 * 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
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include "linux/module.h"
24#include "linux/blkdev.h"
25#include "linux/hdreg.h"
26#include "linux/init.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070027#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"
Russell Kingd052d1b2005-10-29 19:07:23 +010036#include "linux/platform_device.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#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"
Linus Torvalds1da177e2005-04-16 15:20:36 -070051#include "os.h"
52#include "mem.h"
53#include "mem_kern.h"
54#include "cow.h"
55
Jeff Dike7b9014c2005-05-20 13:59:11 -070056enum ubd_req { UBD_READ, UBD_WRITE };
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
58struct io_thread_req {
Jeff Dike91acb212005-10-10 23:10:32 -040059 enum ubd_req op;
Linus Torvalds1da177e2005-04-16 15:20:36 -070060 int fds[2];
61 unsigned long offsets[2];
62 unsigned long long offset;
63 unsigned long length;
64 char *buffer;
65 int sectorsize;
Jeff Dike91acb212005-10-10 23:10:32 -040066 unsigned long sector_mask;
67 unsigned long long cow_offset;
68 unsigned long bitmap_words[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -070069 int error;
70};
71
Jeff Dike6c29256c2006-03-27 01:14:37 -080072extern int open_ubd_file(char *file, struct openflags *openflags, int shared,
Linus Torvalds1da177e2005-04-16 15:20:36 -070073 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);
Jeff Dike91acb212005-10-10 23:10:32 -040082extern void do_io(struct io_thread_req *req);
Linus Torvalds1da177e2005-04-16 15:20:36 -070083
Jeff Dike91acb212005-10-10 23:10:32 -040084static inline int ubd_test_bit(__u64 bit, unsigned char *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -070085{
86 __u64 n;
87 int bits, off;
88
Jeff Dike91acb212005-10-10 23:10:32 -040089 bits = sizeof(data[0]) * 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -070090 n = bit / bits;
91 off = bit % bits;
Jeff Dike91acb212005-10-10 23:10:32 -040092 return((data[n] & (1 << off)) != 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070093}
94
Jeff Dike91acb212005-10-10 23:10:32 -040095static inline void ubd_set_bit(__u64 bit, unsigned char *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -070096{
97 __u64 n;
98 int bits, off;
99
Jeff Dike91acb212005-10-10 23:10:32 -0400100 bits = sizeof(data[0]) * 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 n = bit / bits;
102 off = bit % bits;
Jeff Dike91acb212005-10-10 23:10:32 -0400103 data[n] |= (1 << off);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104}
105/*End stuff from ubd_user.h*/
106
107#define DRIVER_NAME "uml-blkdev"
108
Paolo 'Blaisorblade' Giarrusso33f775e2006-10-30 22:07:08 -0800109/* Can be taken in interrupt context, and is passed to the block layer to lock
110 * the request queue. Kernel side code knows that. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111static DEFINE_SPINLOCK(ubd_io_lock);
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800112
113static DEFINE_MUTEX(ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114
Paolo 'Blaisorblade' Giarrusso2fe30a32006-10-30 22:07:09 -0800115/* 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;
Jeff Dike91acb212005-10-10 23:10:32 -0400118
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119static 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);
Christoph Hellwiga885c8c2006-01-08 01:02:50 -0800123static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124
Paolo 'Blaisorblade' Giarrusso97d88ac2006-10-30 22:07:03 -0800125#define MAX_DEV (16)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127static struct block_device_operations ubd_blops = {
128 .owner = THIS_MODULE,
129 .open = ubd_open,
130 .release = ubd_release,
131 .ioctl = ubd_ioctl,
Christoph Hellwiga885c8c2006-01-08 01:02:50 -0800132 .getgeo = ubd_getgeo,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133};
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];
Jeff Dike6c29256c2006-03-27 01:14:37 -0800143
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144#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 {
Paolo 'Blaisorblade' Giarrusso2a9d32f2006-10-30 22:07:04 -0800158 /* backing file name */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 char *file;
Paolo 'Blaisorblade' Giarrusso2a9d32f2006-10-30 22:07:04 -0800160 /* backing file fd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 int fd;
162 unsigned long *bitmap;
163 unsigned long bitmap_len;
164 int bitmap_offset;
165 int data_offset;
166};
167
168struct ubd {
Paolo 'Blaisorblade' Giarrusso2a9d32f2006-10-30 22:07:04 -0800169 /* name (and fd, below) of the file opened for writing, either the
170 * backing or the cow file. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 char *file;
172 int count;
173 int fd;
174 __u64 size;
175 struct openflags boot_openflags;
176 struct openflags openflags;
Paolo 'Blaisorblade' Giarrusso84e945e2006-10-30 22:07:10 -0800177 unsigned shared:1;
178 unsigned no_cow:1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 struct cow cow;
180 struct platform_device pdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181};
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, \
Jeff Dike6c29256c2006-03-27 01:14:37 -0800199 .shared = 0, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 .cow = DEFAULT_COW, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201}
202
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800203struct ubd ubd_devs[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_UBD };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204
205static int ubd0_init(void)
206{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800207 struct ubd *ubd_dev = &ubd_devs[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800209 if(ubd_dev->file == NULL)
210 ubd_dev->file = "root_fs";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 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 }
Paolo 'Blaisorblade' Giarrusso97d88ac2006-10-30 22:07:03 -0800288 else if (('a' <= *str) && (*str <= 'z')) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 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{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800298 struct ubd *ubd_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 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++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 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)){
Jeff Dike6c29256c2006-03-27 01:14:37 -0800316 printk(KERN_ERR
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 "ubd_setup : didn't parse major number\n");
318 return(1);
319 }
320
321 err = 1;
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800322 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 if(fake_major != MAJOR_NR){
324 printk(KERN_ERR "Can't assign a fake major twice\n");
325 goto out1;
326 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800327
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 fake_major = major;
329
330 printk(KERN_INFO "Setting extra ubd major number to %d\n",
331 major);
332 err = 0;
333 out1:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800334 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 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;
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800351 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800353 ubd_dev = &ubd_devs[n];
354 if(ubd_dev->file != NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 printk(KERN_ERR "ubd_setup : device already configured\n");
356 goto out;
357 }
358
359 if (index_out)
360 *index_out = n;
361
Jeff Dike6c29256c2006-03-27 01:14:37 -0800362 for (i = 0; i < sizeof("rscd="); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 switch (*str) {
364 case 'r':
365 flags.w = 0;
366 break;
367 case 's':
368 flags.s = 1;
369 break;
370 case 'd':
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800371 ubd_dev->no_cow = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 break;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800373 case 'c':
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800374 ubd_dev->shared = 1;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800375 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 case '=':
377 str++;
378 goto break_loop;
379 default:
Jeff Dike6c29256c2006-03-27 01:14:37 -0800380 printk(KERN_ERR "ubd_setup : Expected '=' or flag letter (r, s, c, or d)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 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){
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800401 if(ubd_dev->no_cow)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 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 }
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800409 ubd_dev->file = str;
410 ubd_dev->cow.file = backing_file;
411 ubd_dev->boot_openflags = flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800413 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 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"
Jeff Dike0894e272005-05-28 15:51:55 -0700456" 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"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459" 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);
Jeff Dike91acb212005-10-10 23:10:32 -0400477
478/* Only changed by ubd_init, which is an initcall. */
479int thread_fd = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480
481/* Changed by ubd_handler, which is serialized because interrupts only
482 * happen on CPU 0.
483 */
484int intr_count = 0;
485
486/* call ubd_finish if you need to serialize */
Jeff Dike91acb212005-10-10 23:10:32 -0400487static void __ubd_finish(struct request *req, int error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488{
Jeff Dike91acb212005-10-10 23:10:32 -0400489 int nsect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490
Jeff Dike91acb212005-10-10 23:10:32 -0400491 if(error){
492 end_request(req, 0);
493 return;
494 }
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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502}
503
Paolo 'Blaisorblade' Giarrusso33f775e2006-10-30 22:07:08 -0800504/* Callable only from interrupt context - otherwise you need to do
505 * spin_lock_irq()/spin_lock_irqsave() */
Jeff Dike91acb212005-10-10 23:10:32 -0400506static inline void ubd_finish(struct request *req, int error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507{
Jeff Dike91acb212005-10-10 23:10:32 -0400508 spin_lock(&ubd_io_lock);
509 __ubd_finish(req, error);
510 spin_unlock(&ubd_io_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511}
512
Paolo 'Blaisorblade' Giarrusso2fe30a32006-10-30 22:07:09 -0800513/* XXX - move this inside ubd_intr. */
Paolo 'Blaisorblade' Giarrusso33f775e2006-10-30 22:07:08 -0800514/* Called without ubd_io_lock held, and only in interrupt context. */
Jeff Dike91acb212005-10-10 23:10:32 -0400515static void ubd_handler(void)
516{
517 struct io_thread_req req;
518 struct request *rq = elv_next_request(ubd_queue);
519 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520
Paolo 'Blaisorblade' Giarrusso2fe30a32006-10-30 22:07:09 -0800521 do_ubd = 0;
Jeff Dike91acb212005-10-10 23:10:32 -0400522 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 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800532
Jeff Dike91acb212005-10-10 23:10:32 -0400533 ubd_finish(rq, req.error);
534 reactivate_fd(thread_fd, UBD_IRQ);
Paolo 'Blaisorblade' Giarrusso33f775e2006-10-30 22:07:08 -0800535 spin_lock(&ubd_io_lock);
Jeff Dike91acb212005-10-10 23:10:32 -0400536 do_ubd_request(ubd_queue);
Paolo 'Blaisorblade' Giarrusso33f775e2006-10-30 22:07:08 -0800537 spin_unlock(&ubd_io_lock);
Jeff Dike91acb212005-10-10 23:10:32 -0400538}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539
Al Viro7bea96f2006-10-08 22:49:34 +0100540static irqreturn_t ubd_intr(int irq, void *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541{
Jeff Dike91acb212005-10-10 23:10:32 -0400542 ubd_handler();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 return(IRQ_HANDLED);
544}
545
Jeff Dike91acb212005-10-10 23:10:32 -0400546/* Only changed by ubd_init, which is an initcall. */
547static int io_pid = -1;
548
549void kill_io_thread(void)
550{
Jeff Dike6c29256c2006-03-27 01:14:37 -0800551 if(io_pid != -1)
Jeff Dike91acb212005-10-10 23:10:32 -0400552 os_kill_process(io_pid, 1);
553}
554
555__uml_exitcall(kill_io_thread);
556
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800557static int ubd_file_size(struct ubd *ubd_dev, __u64 *size_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558{
559 char *file;
560
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800561 file = ubd_dev->cow.file ? ubd_dev->cow.file : ubd_dev->file;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 return(os_file_size(file, size_out));
563}
564
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800565static void ubd_close_dev(struct ubd *ubd_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800567 os_close_file(ubd_dev->fd);
568 if(ubd_dev->cow.file == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 return;
570
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800571 os_close_file(ubd_dev->cow.fd);
572 vfree(ubd_dev->cow.bitmap);
573 ubd_dev->cow.bitmap = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574}
575
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800576static int ubd_open_dev(struct ubd *ubd_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577{
578 struct openflags flags;
579 char **back_ptr;
580 int err, create_cow, *create_ptr;
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800581 int fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800583 ubd_dev->openflags = ubd_dev->boot_openflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 create_cow = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800585 create_ptr = (ubd_dev->cow.file != NULL) ? &create_cow : NULL;
586 back_ptr = ubd_dev->no_cow ? NULL : &ubd_dev->cow.file;
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800587
588 fd = open_ubd_file(ubd_dev->file, &ubd_dev->openflags, ubd_dev->shared,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800589 back_ptr, &ubd_dev->cow.bitmap_offset,
590 &ubd_dev->cow.bitmap_len, &ubd_dev->cow.data_offset,
Jeff Dike6c29256c2006-03-27 01:14:37 -0800591 create_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800593 if((fd == -ENOENT) && create_cow){
594 fd = create_cow_file(ubd_dev->file, ubd_dev->cow.file,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800595 ubd_dev->openflags, 1 << 9, PAGE_SIZE,
596 &ubd_dev->cow.bitmap_offset,
597 &ubd_dev->cow.bitmap_len,
598 &ubd_dev->cow.data_offset);
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800599 if(fd >= 0){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 printk(KERN_INFO "Creating \"%s\" as COW file for "
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800601 "\"%s\"\n", ubd_dev->file, ubd_dev->cow.file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 }
603 }
604
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800605 if(fd < 0){
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800606 printk("Failed to open '%s', errno = %d\n", ubd_dev->file,
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800607 -fd);
608 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 }
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800610 ubd_dev->fd = fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800612 if(ubd_dev->cow.file != NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 err = -ENOMEM;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800614 ubd_dev->cow.bitmap = (void *) vmalloc(ubd_dev->cow.bitmap_len);
615 if(ubd_dev->cow.bitmap == NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 printk(KERN_ERR "Failed to vmalloc COW bitmap\n");
617 goto error;
618 }
619 flush_tlb_kernel_vm();
620
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800621 err = read_cow_bitmap(ubd_dev->fd, ubd_dev->cow.bitmap,
622 ubd_dev->cow.bitmap_offset,
623 ubd_dev->cow.bitmap_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 if(err < 0)
625 goto error;
626
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800627 flags = ubd_dev->openflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 flags.w = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800629 err = open_ubd_file(ubd_dev->cow.file, &flags, ubd_dev->shared, NULL,
Jeff Dike6c29256c2006-03-27 01:14:37 -0800630 NULL, NULL, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 if(err < 0) goto error;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800632 ubd_dev->cow.fd = err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 }
634 return(0);
635 error:
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800636 os_close_file(ubd_dev->fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 return(err);
638}
639
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800640static int ubd_disk_register(int major, u64 size, int unit,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 struct gendisk **disk_out)
642
643{
644 struct gendisk *disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645
646 disk = alloc_disk(1 << UBD_SHIFT);
647 if(disk == NULL)
648 return(-ENOMEM);
649
650 disk->major = major;
651 disk->first_minor = unit << UBD_SHIFT;
652 disk->fops = &ubd_blops;
653 set_capacity(disk, size / 512);
Greg Kroah-Hartmance7b0f42005-06-20 21:15:16 -0700654 if(major == MAJOR_NR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 sprintf(disk->disk_name, "ubd%c", 'a' + unit);
Greg Kroah-Hartmance7b0f42005-06-20 21:15:16 -0700656 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 sprintf(disk->disk_name, "ubd_fake%d", unit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658
659 /* sysfs register (not for ide fake devices) */
660 if (major == MAJOR_NR) {
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800661 ubd_devs[unit].pdev.id = unit;
662 ubd_devs[unit].pdev.name = DRIVER_NAME;
663 platform_device_register(&ubd_devs[unit].pdev);
664 disk->driverfs_dev = &ubd_devs[unit].pdev.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 }
666
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800667 disk->private_data = &ubd_devs[unit];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 disk->queue = ubd_queue;
669 add_disk(disk);
670
671 *disk_out = disk;
672 return 0;
673}
674
675#define ROUND_BLOCK(n) ((n + ((1 << 9) - 1)) & (-1 << 9))
676
677static int ubd_add(int n)
678{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800679 struct ubd *ubd_dev = &ubd_devs[n];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 int err;
681
Jeff Dikeec7cf782005-09-03 15:57:29 -0700682 err = -ENODEV;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800683 if(ubd_dev->file == NULL)
Jeff Dikeec7cf782005-09-03 15:57:29 -0700684 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800686 err = ubd_file_size(ubd_dev, &ubd_dev->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 if(err < 0)
Jeff Dike80c13742006-09-29 01:58:51 -0700688 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800690 ubd_dev->size = ROUND_BLOCK(ubd_dev->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800692 err = ubd_disk_register(MAJOR_NR, ubd_dev->size, n, &ubd_gendisk[n]);
Jeff Dike6c29256c2006-03-27 01:14:37 -0800693 if(err)
Jeff Dike80c13742006-09-29 01:58:51 -0700694 goto out;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800695
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 if(fake_major != MAJOR_NR)
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800697 ubd_disk_register(fake_major, ubd_dev->size, n,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 &fake_gendisk[n]);
699
700 /* perhaps this should also be under the "if (fake_major)" above */
701 /* using the fake_disk->disk_name and also the fakehd_set name */
702 if (fake_ide)
703 make_ide_entries(ubd_gendisk[n]->disk_name);
704
Jeff Dikeec7cf782005-09-03 15:57:29 -0700705 err = 0;
Jeff Dikeec7cf782005-09-03 15:57:29 -0700706out:
707 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708}
709
710static int ubd_config(char *str)
711{
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800712 int n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713
Jeff Dike970d6e32006-01-06 00:18:48 -0800714 str = kstrdup(str, GFP_KERNEL);
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800715 if (str == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 printk(KERN_ERR "ubd_config failed to strdup string\n");
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800717 ret = 1;
718 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 }
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800720 ret = ubd_setup_common(str, &n);
721 if (ret) {
722 ret = -1;
723 goto err_free;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 }
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800725 if (n == -1) {
726 ret = 0;
727 goto out;
728 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800730 mutex_lock(&ubd_lock);
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800731 ret = ubd_add(n);
732 if (ret)
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800733 ubd_devs[n].file = NULL;
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800734 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800736out:
737 return ret;
738
739err_free:
740 kfree(str);
741 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742}
743
744static int ubd_get_config(char *name, char *str, int size, char **error_out)
745{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800746 struct ubd *ubd_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 int n, len = 0;
748
749 n = parse_unit(&name);
750 if((n >= MAX_DEV) || (n < 0)){
751 *error_out = "ubd_get_config : device number out of range";
752 return(-1);
753 }
754
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800755 ubd_dev = &ubd_devs[n];
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800756 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800758 if(ubd_dev->file == NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 CONFIG_CHUNK(str, size, len, "", 1);
760 goto out;
761 }
762
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800763 CONFIG_CHUNK(str, size, len, ubd_dev->file, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800765 if(ubd_dev->cow.file != NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 CONFIG_CHUNK(str, size, len, ",", 0);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800767 CONFIG_CHUNK(str, size, len, ubd_dev->cow.file, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 }
769 else CONFIG_CHUNK(str, size, len, "", 1);
770
771 out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800772 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 return(len);
774}
775
Jeff Dike29d56cf2005-06-25 14:55:25 -0700776static int ubd_id(char **str, int *start_out, int *end_out)
777{
778 int n;
779
780 n = parse_unit(str);
781 *start_out = 0;
782 *end_out = MAX_DEV - 1;
783 return n;
784}
785
786static int ubd_remove(int n)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800788 struct ubd *ubd_dev;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700789 int err = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800791 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792
793 if(ubd_gendisk[n] == NULL)
794 goto out;
795
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800796 ubd_dev = &ubd_devs[n];
Jeff Dike29d56cf2005-06-25 14:55:25 -0700797
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800798 if(ubd_dev->file == NULL)
Jeff Dike29d56cf2005-06-25 14:55:25 -0700799 goto out;
800
801 /* you cannot remove a open disk */
802 err = -EBUSY;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800803 if(ubd_dev->count > 0)
Jeff Dike29d56cf2005-06-25 14:55:25 -0700804 goto out;
805
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 del_gendisk(ubd_gendisk[n]);
807 put_disk(ubd_gendisk[n]);
808 ubd_gendisk[n] = NULL;
809
810 if(fake_gendisk[n] != NULL){
811 del_gendisk(fake_gendisk[n]);
812 put_disk(fake_gendisk[n]);
813 fake_gendisk[n] = NULL;
814 }
815
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800816 platform_device_unregister(&ubd_dev->pdev);
817 *ubd_dev = ((struct ubd) DEFAULT_UBD);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 err = 0;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700819out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800820 mutex_unlock(&ubd_lock);
Jeff Dike29d56cf2005-06-25 14:55:25 -0700821 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822}
823
824static struct mc_device ubd_mc = {
825 .name = "ubd",
826 .config = ubd_config,
827 .get_config = ubd_get_config,
Jeff Dike29d56cf2005-06-25 14:55:25 -0700828 .id = ubd_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 .remove = ubd_remove,
830};
831
832static int ubd_mc_init(void)
833{
834 mconsole_register_dev(&ubd_mc);
835 return 0;
836}
837
838__initcall(ubd_mc_init);
839
Russell King3ae5eae2005-11-09 22:32:44 +0000840static struct platform_driver ubd_driver = {
841 .driver = {
842 .name = DRIVER_NAME,
843 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844};
845
846int ubd_init(void)
847{
848 int i;
849
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 if (register_blkdev(MAJOR_NR, "ubd"))
851 return -1;
852
853 ubd_queue = blk_init_queue(do_ubd_request, &ubd_io_lock);
854 if (!ubd_queue) {
855 unregister_blkdev(MAJOR_NR, "ubd");
856 return -1;
857 }
858
859 if (fake_major != MAJOR_NR) {
860 char name[sizeof("ubd_nnn\0")];
861
862 snprintf(name, sizeof(name), "ubd_%d", fake_major);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 if (register_blkdev(fake_major, "ubd"))
864 return -1;
865 }
Russell King3ae5eae2005-11-09 22:32:44 +0000866 platform_driver_register(&ubd_driver);
Jeff Dike6c29256c2006-03-27 01:14:37 -0800867 for (i = 0; i < MAX_DEV; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 ubd_add(i);
869 return 0;
870}
871
872late_initcall(ubd_init);
873
Jeff Dike91acb212005-10-10 23:10:32 -0400874int ubd_driver_init(void){
875 unsigned long stack;
876 int err;
877
878 /* Set by CONFIG_BLK_DEV_UBD_SYNC or ubd=sync.*/
879 if(global_openflags.s){
880 printk(KERN_INFO "ubd: Synchronous mode\n");
881 /* Letting ubd=sync be like using ubd#s= instead of ubd#= is
882 * enough. So use anyway the io thread. */
883 }
884 stack = alloc_stack(0, 0);
Jeff Dike6c29256c2006-03-27 01:14:37 -0800885 io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *),
Jeff Dike91acb212005-10-10 23:10:32 -0400886 &thread_fd);
887 if(io_pid < 0){
Jeff Dike6c29256c2006-03-27 01:14:37 -0800888 printk(KERN_ERR
Jeff Dike91acb212005-10-10 23:10:32 -0400889 "ubd : Failed to start I/O thread (errno = %d) - "
890 "falling back to synchronous I/O\n", -io_pid);
891 io_pid = -1;
892 return(0);
893 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800894 err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800895 IRQF_DISABLED, "ubd", ubd_devs);
Jeff Dike91acb212005-10-10 23:10:32 -0400896 if(err != 0)
897 printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err);
Jeff Dikef4c57a72006-03-31 02:30:10 -0800898 return 0;
Jeff Dike91acb212005-10-10 23:10:32 -0400899}
900
901device_initcall(ubd_driver_init);
902
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903static int ubd_open(struct inode *inode, struct file *filp)
904{
905 struct gendisk *disk = inode->i_bdev->bd_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800906 struct ubd *ubd_dev = disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 int err = 0;
908
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800909 if(ubd_dev->count == 0){
910 err = ubd_open_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 if(err){
912 printk(KERN_ERR "%s: Can't open \"%s\": errno = %d\n",
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800913 disk->disk_name, ubd_dev->file, -err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 goto out;
915 }
916 }
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800917 ubd_dev->count++;
918 set_disk_ro(disk, !ubd_dev->openflags.w);
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -0700919
920 /* This should no more be needed. And it didn't work anyway to exclude
921 * read-write remounting of filesystems.*/
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800922 /*if((filp->f_mode & FMODE_WRITE) && !ubd_dev->openflags.w){
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800923 if(--ubd_dev->count == 0) ubd_close_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 err = -EROFS;
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -0700925 }*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 out:
927 return(err);
928}
929
930static int ubd_release(struct inode * inode, struct file * file)
931{
932 struct gendisk *disk = inode->i_bdev->bd_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800933 struct ubd *ubd_dev = disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800935 if(--ubd_dev->count == 0)
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800936 ubd_close_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 return(0);
938}
939
Jeff Dike91acb212005-10-10 23:10:32 -0400940static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask,
941 __u64 *cow_offset, unsigned long *bitmap,
942 __u64 bitmap_offset, unsigned long *bitmap_words,
943 __u64 bitmap_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944{
Jeff Dike91acb212005-10-10 23:10:32 -0400945 __u64 sector = io_offset >> 9;
946 int i, update_bitmap = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947
Jeff Dike91acb212005-10-10 23:10:32 -0400948 for(i = 0; i < length >> 9; i++){
949 if(cow_mask != NULL)
950 ubd_set_bit(i, (unsigned char *) cow_mask);
951 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
952 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953
Jeff Dike91acb212005-10-10 23:10:32 -0400954 update_bitmap = 1;
955 ubd_set_bit(sector + i, (unsigned char *) bitmap);
956 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957
Jeff Dike91acb212005-10-10 23:10:32 -0400958 if(!update_bitmap)
959 return;
960
961 *cow_offset = sector / (sizeof(unsigned long) * 8);
962
963 /* This takes care of the case where we're exactly at the end of the
964 * device, and *cow_offset + 1 is off the end. So, just back it up
965 * by one word. Thanks to Lynn Kerby for the fix and James McMechan
966 * for the original diagnosis.
967 */
968 if(*cow_offset == ((bitmap_len + sizeof(unsigned long) - 1) /
969 sizeof(unsigned long) - 1))
970 (*cow_offset)--;
971
972 bitmap_words[0] = bitmap[*cow_offset];
973 bitmap_words[1] = bitmap[*cow_offset + 1];
974
975 *cow_offset *= sizeof(unsigned long);
976 *cow_offset += bitmap_offset;
977}
978
979static void cowify_req(struct io_thread_req *req, unsigned long *bitmap,
980 __u64 bitmap_offset, __u64 bitmap_len)
981{
982 __u64 sector = req->offset >> 9;
983 int i;
984
985 if(req->length > (sizeof(req->sector_mask) * 8) << 9)
986 panic("Operation too long");
987
988 if(req->op == UBD_READ) {
989 for(i = 0; i < req->length >> 9; i++){
990 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
Jeff Dike6c29256c2006-03-27 01:14:37 -0800991 ubd_set_bit(i, (unsigned char *)
Jeff Dike91acb212005-10-10 23:10:32 -0400992 &req->sector_mask);
993 }
994 }
995 else cowify_bitmap(req->offset, req->length, &req->sector_mask,
996 &req->cow_offset, bitmap, bitmap_offset,
997 req->bitmap_words, bitmap_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998}
999
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000/* Called with ubd_io_lock held */
Jeff Dike91acb212005-10-10 23:10:32 -04001001static int prepare_request(struct request *req, struct io_thread_req *io_req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002{
1003 struct gendisk *disk = req->rq_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001004 struct ubd *ubd_dev = disk->private_data;
Jeff Dike91acb212005-10-10 23:10:32 -04001005 __u64 offset;
1006 int len;
1007
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -07001008 /* This should be impossible now */
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001009 if((rq_data_dir(req) == WRITE) && !ubd_dev->openflags.w){
Jeff Dike6c29256c2006-03-27 01:14:37 -08001010 printk("Write attempted on readonly ubd device %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 disk->disk_name);
Jeff Dike91acb212005-10-10 23:10:32 -04001012 end_request(req, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 return(1);
1014 }
1015
Jeff Dike91acb212005-10-10 23:10:32 -04001016 offset = ((__u64) req->sector) << 9;
1017 len = req->current_nr_sectors << 9;
1018
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001019 io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd : ubd_dev->fd;
1020 io_req->fds[1] = ubd_dev->fd;
Jeff Dike91acb212005-10-10 23:10:32 -04001021 io_req->cow_offset = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 io_req->offset = offset;
1023 io_req->length = len;
1024 io_req->error = 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001025 io_req->sector_mask = 0;
1026
1027 io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 io_req->offsets[0] = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001029 io_req->offsets[1] = ubd_dev->cow.data_offset;
Jeff Dike91acb212005-10-10 23:10:32 -04001030 io_req->buffer = req->buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 io_req->sectorsize = 1 << 9;
1032
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001033 if(ubd_dev->cow.file != NULL)
1034 cowify_req(io_req, ubd_dev->cow.bitmap, ubd_dev->cow.bitmap_offset,
1035 ubd_dev->cow.bitmap_len);
Jeff Dike91acb212005-10-10 23:10:32 -04001036
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 return(0);
1038}
1039
1040/* Called with ubd_io_lock held */
1041static void do_ubd_request(request_queue_t *q)
1042{
1043 struct io_thread_req io_req;
1044 struct request *req;
Jeff Dike91acb212005-10-10 23:10:32 -04001045 int err, n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046
Jeff Dike91acb212005-10-10 23:10:32 -04001047 if(thread_fd == -1){
1048 while((req = elv_next_request(q)) != NULL){
1049 err = prepare_request(req, &io_req);
1050 if(!err){
1051 do_io(&io_req);
1052 __ubd_finish(req, io_req.error);
1053 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 }
1055 }
Jeff Dike91acb212005-10-10 23:10:32 -04001056 else {
1057 if(do_ubd || (req = elv_next_request(q)) == NULL)
1058 return;
1059 err = prepare_request(req, &io_req);
1060 if(!err){
Paolo 'Blaisorblade' Giarrusso2fe30a32006-10-30 22:07:09 -08001061 do_ubd = 1;
Jeff Dike91acb212005-10-10 23:10:32 -04001062 n = os_write_file(thread_fd, (char *) &io_req,
1063 sizeof(io_req));
1064 if(n != sizeof(io_req))
1065 printk("write to io thread failed, "
1066 "errno = %d\n", -n);
1067 }
1068 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069}
1070
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001071static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
1072{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001073 struct ubd *ubd_dev = bdev->bd_disk->private_data;
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001074
1075 geo->heads = 128;
1076 geo->sectors = 32;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001077 geo->cylinders = ubd_dev->size / (128 * 32 * 512);
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001078 return 0;
1079}
1080
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081static int ubd_ioctl(struct inode * inode, struct file * file,
1082 unsigned int cmd, unsigned long arg)
1083{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001084 struct ubd *ubd_dev = inode->i_bdev->bd_disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 struct hd_driveid ubd_id = {
1086 .cyls = 0,
1087 .heads = 128,
1088 .sectors = 32,
1089 };
1090
1091 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 struct cdrom_volctrl volume;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 case HDIO_GET_IDENTITY:
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001094 ubd_id.cyls = ubd_dev->size / (128 * 32 * 512);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 if(copy_to_user((char __user *) arg, (char *) &ubd_id,
1096 sizeof(ubd_id)))
1097 return(-EFAULT);
1098 return(0);
1099
1100 case CDROMVOLREAD:
1101 if(copy_from_user(&volume, (char __user *) arg, sizeof(volume)))
1102 return(-EFAULT);
1103 volume.channel0 = 255;
1104 volume.channel1 = 255;
1105 volume.channel2 = 255;
1106 volume.channel3 = 255;
1107 if(copy_to_user((char __user *) arg, &volume, sizeof(volume)))
1108 return(-EFAULT);
1109 return(0);
1110 }
1111 return(-EINVAL);
1112}
1113
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001114static int path_requires_switch(char *from_cmdline, char *from_cow, char *cow)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115{
1116 struct uml_stat buf1, buf2;
1117 int err;
1118
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001119 if(from_cmdline == NULL)
1120 return 0;
1121 if(!strcmp(from_cmdline, from_cow))
1122 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123
1124 err = os_stat_file(from_cmdline, &buf1);
1125 if(err < 0){
1126 printk("Couldn't stat '%s', err = %d\n", from_cmdline, -err);
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001127 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 }
1129 err = os_stat_file(from_cow, &buf2);
1130 if(err < 0){
1131 printk("Couldn't stat '%s', err = %d\n", from_cow, -err);
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001132 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 }
1134 if((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino))
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001135 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136
1137 printk("Backing file mismatch - \"%s\" requested,\n"
1138 "\"%s\" specified in COW header of \"%s\"\n",
1139 from_cmdline, from_cow, cow);
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001140 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141}
1142
1143static int backing_file_mismatch(char *file, __u64 size, time_t mtime)
1144{
1145 unsigned long modtime;
Paolo 'Blaisorblade' Giarrussofe1db502006-02-24 13:03:58 -08001146 unsigned long long actual;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 int err;
1148
1149 err = os_file_modtime(file, &modtime);
1150 if(err < 0){
1151 printk("Failed to get modification time of backing file "
1152 "\"%s\", err = %d\n", file, -err);
1153 return(err);
1154 }
1155
1156 err = os_file_size(file, &actual);
1157 if(err < 0){
1158 printk("Failed to get size of backing file \"%s\", "
1159 "err = %d\n", file, -err);
1160 return(err);
1161 }
1162
1163 if(actual != size){
1164 /*__u64 can be a long on AMD64 and with %lu GCC complains; so
1165 * the typecast.*/
1166 printk("Size mismatch (%llu vs %llu) of COW header vs backing "
1167 "file\n", (unsigned long long) size, actual);
1168 return(-EINVAL);
1169 }
1170 if(modtime != mtime){
1171 printk("mtime mismatch (%ld vs %ld) of COW header vs backing "
1172 "file\n", mtime, modtime);
1173 return(-EINVAL);
1174 }
1175 return(0);
1176}
1177
1178int read_cow_bitmap(int fd, void *buf, int offset, int len)
1179{
1180 int err;
1181
1182 err = os_seek_file(fd, offset);
1183 if(err < 0)
1184 return(err);
1185
1186 err = os_read_file(fd, buf, len);
1187 if(err < 0)
1188 return(err);
1189
1190 return(0);
1191}
1192
Jeff Dike6c29256c2006-03-27 01:14:37 -08001193int open_ubd_file(char *file, struct openflags *openflags, int shared,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 char **backing_file_out, int *bitmap_offset_out,
1195 unsigned long *bitmap_len_out, int *data_offset_out,
1196 int *create_cow_out)
1197{
1198 time_t mtime;
1199 unsigned long long size;
1200 __u32 version, align;
1201 char *backing_file;
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001202 int fd, err, sectorsize, asked_switch, mode = 0644;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203
1204 fd = os_open_file(file, *openflags, mode);
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001205 if (fd < 0) {
1206 if ((fd == -ENOENT) && (create_cow_out != NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 *create_cow_out = 1;
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001208 if (!openflags->w ||
1209 ((fd != -EROFS) && (fd != -EACCES)))
1210 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 openflags->w = 0;
1212 fd = os_open_file(file, *openflags, mode);
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001213 if (fd < 0)
1214 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215 }
1216
Jeff Dike6c29256c2006-03-27 01:14:37 -08001217 if(shared)
1218 printk("Not locking \"%s\" on the host\n", file);
1219 else {
1220 err = os_lock_file(fd, openflags->w);
1221 if(err < 0){
1222 printk("Failed to lock '%s', err = %d\n", file, -err);
1223 goto out_close;
1224 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 }
1226
Andreas Mohrd6e05ed2006-06-26 18:35:02 +02001227 /* Successful return case! */
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001228 if(backing_file_out == NULL)
1229 return(fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230
1231 err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime,
1232 &size, &sectorsize, &align, bitmap_offset_out);
1233 if(err && (*backing_file_out != NULL)){
1234 printk("Failed to read COW header from COW file \"%s\", "
1235 "errno = %d\n", file, -err);
1236 goto out_close;
1237 }
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001238 if(err)
1239 return(fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001241 asked_switch = path_requires_switch(*backing_file_out, backing_file, file);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001243 /* Allow switching only if no mismatch. */
1244 if (asked_switch && !backing_file_mismatch(*backing_file_out, size, mtime)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 printk("Switching backing file to '%s'\n", *backing_file_out);
1246 err = write_cow_header(file, fd, *backing_file_out,
1247 sectorsize, align, &size);
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001248 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249 printk("Switch failed, errno = %d\n", -err);
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001250 goto out_close;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 }
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001252 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 *backing_file_out = backing_file;
1254 err = backing_file_mismatch(*backing_file_out, size, mtime);
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001255 if (err)
1256 goto out_close;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 }
1258
1259 cow_sizes(version, size, sectorsize, align, *bitmap_offset_out,
1260 bitmap_len_out, data_offset_out);
1261
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001262 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 out_close:
1264 os_close_file(fd);
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001265 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266}
1267
1268int create_cow_file(char *cow_file, char *backing_file, struct openflags flags,
1269 int sectorsize, int alignment, int *bitmap_offset_out,
1270 unsigned long *bitmap_len_out, int *data_offset_out)
1271{
1272 int err, fd;
1273
1274 flags.c = 1;
Jeff Dike6c29256c2006-03-27 01:14:37 -08001275 fd = open_ubd_file(cow_file, &flags, 0, NULL, NULL, NULL, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 if(fd < 0){
1277 err = fd;
1278 printk("Open of COW file '%s' failed, errno = %d\n", cow_file,
1279 -err);
1280 goto out;
1281 }
1282
1283 err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment,
1284 bitmap_offset_out, bitmap_len_out,
1285 data_offset_out);
1286 if(!err)
1287 return(fd);
1288 os_close_file(fd);
1289 out:
1290 return(err);
1291}
1292
Jeff Dike91acb212005-10-10 23:10:32 -04001293static int update_bitmap(struct io_thread_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294{
Jeff Dike91acb212005-10-10 23:10:32 -04001295 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296
Jeff Dike91acb212005-10-10 23:10:32 -04001297 if(req->cow_offset == -1)
1298 return(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299
Jeff Dike91acb212005-10-10 23:10:32 -04001300 n = os_seek_file(req->fds[1], req->cow_offset);
1301 if(n < 0){
1302 printk("do_io - bitmap lseek failed : err = %d\n", -n);
1303 return(1);
1304 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305
Jeff Dike91acb212005-10-10 23:10:32 -04001306 n = os_write_file(req->fds[1], &req->bitmap_words,
1307 sizeof(req->bitmap_words));
1308 if(n != sizeof(req->bitmap_words)){
1309 printk("do_io - bitmap update failed, err = %d fd = %d\n", -n,
1310 req->fds[1]);
1311 return(1);
1312 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313
Jeff Dike91acb212005-10-10 23:10:32 -04001314 return(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315}
Jeff Dike91acb212005-10-10 23:10:32 -04001316
1317void do_io(struct io_thread_req *req)
1318{
1319 char *buf;
1320 unsigned long len;
1321 int n, nsectors, start, end, bit;
1322 int err;
1323 __u64 off;
1324
1325 nsectors = req->length / req->sectorsize;
1326 start = 0;
1327 do {
1328 bit = ubd_test_bit(start, (unsigned char *) &req->sector_mask);
1329 end = start;
1330 while((end < nsectors) &&
1331 (ubd_test_bit(end, (unsigned char *)
1332 &req->sector_mask) == bit))
1333 end++;
1334
1335 off = req->offset + req->offsets[bit] +
1336 start * req->sectorsize;
1337 len = (end - start) * req->sectorsize;
1338 buf = &req->buffer[start * req->sectorsize];
1339
1340 err = os_seek_file(req->fds[bit], off);
1341 if(err < 0){
1342 printk("do_io - lseek failed : err = %d\n", -err);
1343 req->error = 1;
1344 return;
1345 }
1346 if(req->op == UBD_READ){
1347 n = 0;
1348 do {
1349 buf = &buf[n];
1350 len -= n;
1351 n = os_read_file(req->fds[bit], buf, len);
1352 if (n < 0) {
1353 printk("do_io - read failed, err = %d "
1354 "fd = %d\n", -n, req->fds[bit]);
1355 req->error = 1;
1356 return;
1357 }
1358 } while((n < len) && (n != 0));
1359 if (n < len) memset(&buf[n], 0, len - n);
1360 } else {
1361 n = os_write_file(req->fds[bit], buf, len);
1362 if(n != len){
1363 printk("do_io - write failed err = %d "
1364 "fd = %d\n", -n, req->fds[bit]);
1365 req->error = 1;
1366 return;
1367 }
1368 }
1369
1370 start = end;
1371 } while(start < nsectors);
1372
1373 req->error = update_bitmap(req);
1374}
1375
1376/* Changed in start_io_thread, which is serialized by being called only
1377 * from ubd_init, which is an initcall.
1378 */
1379int kernel_fd = -1;
1380
1381/* Only changed by the io thread */
1382int io_count = 0;
1383
1384int io_thread(void *arg)
1385{
1386 struct io_thread_req req;
1387 int n;
1388
1389 ignore_sigwinch_sig();
1390 while(1){
1391 n = os_read_file(kernel_fd, &req, sizeof(req));
1392 if(n != sizeof(req)){
1393 if(n < 0)
1394 printk("io_thread - read failed, fd = %d, "
1395 "err = %d\n", kernel_fd, -n);
1396 else {
1397 printk("io_thread - short read, fd = %d, "
1398 "length = %d\n", kernel_fd, n);
1399 }
1400 continue;
1401 }
1402 io_count++;
1403 do_io(&req);
1404 n = os_write_file(kernel_fd, &req, sizeof(req));
1405 if(n != sizeof(req))
1406 printk("io_thread - write failed, fd = %d, err = %d\n",
1407 kernel_fd, -n);
1408 }
Jeff Dike91acb212005-10-10 23:10:32 -04001409
Jeff Dike1b57e9c2006-01-06 00:18:49 -08001410 return 0;
1411}