blob: eed95dc356e02579e2add440185696123e3f8cdb [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;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800177 int shared;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 int no_cow;
179 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;
581
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800582 ubd_dev->openflags = ubd_dev->boot_openflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 create_cow = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800584 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,
Jeff Dike6c29256c2006-03-27 01:14:37 -0800589 create_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800591 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){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 printk(KERN_INFO "Creating \"%s\" as COW file for "
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800599 "\"%s\"\n", ubd_dev->file, ubd_dev->cow.file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 }
601 }
602
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800603 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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 }
608
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800609 if(ubd_dev->cow.file != NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 err = -ENOMEM;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800611 ubd_dev->cow.bitmap = (void *) vmalloc(ubd_dev->cow.bitmap_len);
612 if(ubd_dev->cow.bitmap == NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 printk(KERN_ERR "Failed to vmalloc COW bitmap\n");
614 goto error;
615 }
616 flush_tlb_kernel_vm();
617
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800618 err = read_cow_bitmap(ubd_dev->fd, ubd_dev->cow.bitmap,
619 ubd_dev->cow.bitmap_offset,
620 ubd_dev->cow.bitmap_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 if(err < 0)
622 goto error;
623
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800624 flags = ubd_dev->openflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 flags.w = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800626 err = open_ubd_file(ubd_dev->cow.file, &flags, ubd_dev->shared, NULL,
Jeff Dike6c29256c2006-03-27 01:14:37 -0800627 NULL, NULL, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 if(err < 0) goto error;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800629 ubd_dev->cow.fd = err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 }
631 return(0);
632 error:
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800633 os_close_file(ubd_dev->fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 return(err);
635}
636
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800637static int ubd_disk_register(int major, u64 size, int unit,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 struct gendisk **disk_out)
639
640{
641 struct gendisk *disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642
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);
Greg Kroah-Hartmance7b0f42005-06-20 21:15:16 -0700651 if(major == MAJOR_NR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 sprintf(disk->disk_name, "ubd%c", 'a' + unit);
Greg Kroah-Hartmance7b0f42005-06-20 21:15:16 -0700653 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 sprintf(disk->disk_name, "ubd_fake%d", unit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655
656 /* sysfs register (not for ide fake devices) */
657 if (major == MAJOR_NR) {
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800658 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 }
663
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800664 disk->private_data = &ubd_devs[unit];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 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{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800676 struct ubd *ubd_dev = &ubd_devs[n];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 int err;
678
Jeff Dikeec7cf782005-09-03 15:57:29 -0700679 err = -ENODEV;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800680 if(ubd_dev->file == NULL)
Jeff Dikeec7cf782005-09-03 15:57:29 -0700681 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800683 err = ubd_file_size(ubd_dev, &ubd_dev->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 if(err < 0)
Jeff Dike80c13742006-09-29 01:58:51 -0700685 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800687 ubd_dev->size = ROUND_BLOCK(ubd_dev->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800689 err = ubd_disk_register(MAJOR_NR, ubd_dev->size, n, &ubd_gendisk[n]);
Jeff Dike6c29256c2006-03-27 01:14:37 -0800690 if(err)
Jeff Dike80c13742006-09-29 01:58:51 -0700691 goto out;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800692
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 if(fake_major != MAJOR_NR)
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800694 ubd_disk_register(fake_major, ubd_dev->size, n,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 &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
Jeff Dikeec7cf782005-09-03 15:57:29 -0700702 err = 0;
Jeff Dikeec7cf782005-09-03 15:57:29 -0700703out:
704 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705}
706
707static int ubd_config(char *str)
708{
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800709 int n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710
Jeff Dike970d6e32006-01-06 00:18:48 -0800711 str = kstrdup(str, GFP_KERNEL);
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800712 if (str == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 printk(KERN_ERR "ubd_config failed to strdup string\n");
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800714 ret = 1;
715 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 }
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800717 ret = ubd_setup_common(str, &n);
718 if (ret) {
719 ret = -1;
720 goto err_free;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 }
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800722 if (n == -1) {
723 ret = 0;
724 goto out;
725 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800727 mutex_lock(&ubd_lock);
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800728 ret = ubd_add(n);
729 if (ret)
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800730 ubd_devs[n].file = NULL;
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800731 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800733out:
734 return ret;
735
736err_free:
737 kfree(str);
738 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739}
740
741static int ubd_get_config(char *name, char *str, int size, char **error_out)
742{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800743 struct ubd *ubd_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 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
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800752 ubd_dev = &ubd_devs[n];
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800753 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800755 if(ubd_dev->file == NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 CONFIG_CHUNK(str, size, len, "", 1);
757 goto out;
758 }
759
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800760 CONFIG_CHUNK(str, size, len, ubd_dev->file, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800762 if(ubd_dev->cow.file != NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 CONFIG_CHUNK(str, size, len, ",", 0);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800764 CONFIG_CHUNK(str, size, len, ubd_dev->cow.file, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 }
766 else CONFIG_CHUNK(str, size, len, "", 1);
767
768 out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800769 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 return(len);
771}
772
Jeff Dike29d56cf2005-06-25 14:55:25 -0700773static 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)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800785 struct ubd *ubd_dev;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700786 int err = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800788 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789
790 if(ubd_gendisk[n] == NULL)
791 goto out;
792
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800793 ubd_dev = &ubd_devs[n];
Jeff Dike29d56cf2005-06-25 14:55:25 -0700794
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800795 if(ubd_dev->file == NULL)
Jeff Dike29d56cf2005-06-25 14:55:25 -0700796 goto out;
797
798 /* you cannot remove a open disk */
799 err = -EBUSY;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800800 if(ubd_dev->count > 0)
Jeff Dike29d56cf2005-06-25 14:55:25 -0700801 goto out;
802
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 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
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800813 platform_device_unregister(&ubd_dev->pdev);
814 *ubd_dev = ((struct ubd) DEFAULT_UBD);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 err = 0;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700816out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800817 mutex_unlock(&ubd_lock);
Jeff Dike29d56cf2005-06-25 14:55:25 -0700818 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819}
820
821static struct mc_device ubd_mc = {
822 .name = "ubd",
823 .config = ubd_config,
824 .get_config = ubd_get_config,
Jeff Dike29d56cf2005-06-25 14:55:25 -0700825 .id = ubd_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 .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
Russell King3ae5eae2005-11-09 22:32:44 +0000837static struct platform_driver ubd_driver = {
838 .driver = {
839 .name = DRIVER_NAME,
840 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841};
842
843int ubd_init(void)
844{
845 int i;
846
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 if (register_blkdev(fake_major, "ubd"))
861 return -1;
862 }
Russell King3ae5eae2005-11-09 22:32:44 +0000863 platform_driver_register(&ubd_driver);
Jeff Dike6c29256c2006-03-27 01:14:37 -0800864 for (i = 0; i < MAX_DEV; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 ubd_add(i);
866 return 0;
867}
868
869late_initcall(ubd_init);
870
Jeff Dike91acb212005-10-10 23:10:32 -0400871int 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);
Jeff Dike6c29256c2006-03-27 01:14:37 -0800882 io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *),
Jeff Dike91acb212005-10-10 23:10:32 -0400883 &thread_fd);
884 if(io_pid < 0){
Jeff Dike6c29256c2006-03-27 01:14:37 -0800885 printk(KERN_ERR
Jeff Dike91acb212005-10-10 23:10:32 -0400886 "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 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800891 err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800892 IRQF_DISABLED, "ubd", ubd_devs);
Jeff Dike91acb212005-10-10 23:10:32 -0400893 if(err != 0)
894 printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err);
Jeff Dikef4c57a72006-03-31 02:30:10 -0800895 return 0;
Jeff Dike91acb212005-10-10 23:10:32 -0400896}
897
898device_initcall(ubd_driver_init);
899
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900static int ubd_open(struct inode *inode, struct file *filp)
901{
902 struct gendisk *disk = inode->i_bdev->bd_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800903 struct ubd *ubd_dev = disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 int err = 0;
905
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800906 if(ubd_dev->count == 0){
907 err = ubd_open_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 if(err){
909 printk(KERN_ERR "%s: Can't open \"%s\": errno = %d\n",
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800910 disk->disk_name, ubd_dev->file, -err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 goto out;
912 }
913 }
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800914 ubd_dev->count++;
915 set_disk_ro(disk, !ubd_dev->openflags.w);
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -0700916
917 /* This should no more be needed. And it didn't work anyway to exclude
918 * read-write remounting of filesystems.*/
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800919 /*if((filp->f_mode & FMODE_WRITE) && !ubd_dev->openflags.w){
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800920 if(--ubd_dev->count == 0) ubd_close_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 err = -EROFS;
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -0700922 }*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 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;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800930 struct ubd *ubd_dev = disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800932 if(--ubd_dev->count == 0)
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800933 ubd_close_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 return(0);
935}
936
Jeff Dike91acb212005-10-10 23:10:32 -0400937static 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)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941{
Jeff Dike91acb212005-10-10 23:10:32 -0400942 __u64 sector = io_offset >> 9;
943 int i, update_bitmap = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944
Jeff Dike91acb212005-10-10 23:10:32 -0400945 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950
Jeff Dike91acb212005-10-10 23:10:32 -0400951 update_bitmap = 1;
952 ubd_set_bit(sector + i, (unsigned char *) bitmap);
953 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954
Jeff Dike91acb212005-10-10 23:10:32 -0400955 if(!update_bitmap)
956 return;
957
958 *cow_offset = sector / (sizeof(unsigned long) * 8);
959
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))
Jeff Dike6c29256c2006-03-27 01:14:37 -0800988 ubd_set_bit(i, (unsigned char *)
Jeff Dike91acb212005-10-10 23:10:32 -0400989 &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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995}
996
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997/* Called with ubd_io_lock held */
Jeff Dike91acb212005-10-10 23:10:32 -0400998static int prepare_request(struct request *req, struct io_thread_req *io_req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999{
1000 struct gendisk *disk = req->rq_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001001 struct ubd *ubd_dev = disk->private_data;
Jeff Dike91acb212005-10-10 23:10:32 -04001002 __u64 offset;
1003 int len;
1004
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -07001005 /* This should be impossible now */
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001006 if((rq_data_dir(req) == WRITE) && !ubd_dev->openflags.w){
Jeff Dike6c29256c2006-03-27 01:14:37 -08001007 printk("Write attempted on readonly ubd device %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 disk->disk_name);
Jeff Dike91acb212005-10-10 23:10:32 -04001009 end_request(req, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 return(1);
1011 }
1012
Jeff Dike91acb212005-10-10 23:10:32 -04001013 offset = ((__u64) req->sector) << 9;
1014 len = req->current_nr_sectors << 9;
1015
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001016 io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd : ubd_dev->fd;
1017 io_req->fds[1] = ubd_dev->fd;
Jeff Dike91acb212005-10-10 23:10:32 -04001018 io_req->cow_offset = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 io_req->offset = offset;
1020 io_req->length = len;
1021 io_req->error = 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001022 io_req->sector_mask = 0;
1023
1024 io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 io_req->offsets[0] = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001026 io_req->offsets[1] = ubd_dev->cow.data_offset;
Jeff Dike91acb212005-10-10 23:10:32 -04001027 io_req->buffer = req->buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 io_req->sectorsize = 1 << 9;
1029
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001030 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);
Jeff Dike91acb212005-10-10 23:10:32 -04001033
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 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;
Jeff Dike91acb212005-10-10 23:10:32 -04001042 int err, n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043
Jeff Dike91acb212005-10-10 23:10:32 -04001044 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 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 }
1052 }
Jeff Dike91acb212005-10-10 23:10:32 -04001053 else {
1054 if(do_ubd || (req = elv_next_request(q)) == NULL)
1055 return;
1056 err = prepare_request(req, &io_req);
1057 if(!err){
Paolo 'Blaisorblade' Giarrusso2fe30a32006-10-30 22:07:09 -08001058 do_ubd = 1;
Jeff Dike91acb212005-10-10 23:10:32 -04001059 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);
1064 }
1065 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066}
1067
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001068static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
1069{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001070 struct ubd *ubd_dev = bdev->bd_disk->private_data;
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001071
1072 geo->heads = 128;
1073 geo->sectors = 32;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001074 geo->cylinders = ubd_dev->size / (128 * 32 * 512);
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001075 return 0;
1076}
1077
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078static int ubd_ioctl(struct inode * inode, struct file * file,
1079 unsigned int cmd, unsigned long arg)
1080{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001081 struct ubd *ubd_dev = inode->i_bdev->bd_disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 struct hd_driveid ubd_id = {
1083 .cyls = 0,
1084 .heads = 128,
1085 .sectors = 32,
1086 };
1087
1088 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 struct cdrom_volctrl volume;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 case HDIO_GET_IDENTITY:
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001091 ubd_id.cyls = ubd_dev->size / (128 * 32 * 512);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 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
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001111static int path_requires_switch(char *from_cmdline, char *from_cow, char *cow)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112{
1113 struct uml_stat buf1, buf2;
1114 int err;
1115
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001116 if(from_cmdline == NULL)
1117 return 0;
1118 if(!strcmp(from_cmdline, from_cow))
1119 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120
1121 err = os_stat_file(from_cmdline, &buf1);
1122 if(err < 0){
1123 printk("Couldn't stat '%s', err = %d\n", from_cmdline, -err);
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001124 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 }
1126 err = os_stat_file(from_cow, &buf2);
1127 if(err < 0){
1128 printk("Couldn't stat '%s', err = %d\n", from_cow, -err);
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001129 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 }
1131 if((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino))
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001132 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133
1134 printk("Backing file mismatch - \"%s\" requested,\n"
1135 "\"%s\" specified in COW header of \"%s\"\n",
1136 from_cmdline, from_cow, cow);
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001137 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138}
1139
1140static int backing_file_mismatch(char *file, __u64 size, time_t mtime)
1141{
1142 unsigned long modtime;
Paolo 'Blaisorblade' Giarrussofe1db502006-02-24 13:03:58 -08001143 unsigned long long actual;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 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
Jeff Dike6c29256c2006-03-27 01:14:37 -08001190int open_ubd_file(char *file, struct openflags *openflags, int shared,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 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;
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001199 int fd, err, sectorsize, asked_switch, mode = 0644;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200
1201 fd = os_open_file(file, *openflags, mode);
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001202 if (fd < 0) {
1203 if ((fd == -ENOENT) && (create_cow_out != NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 *create_cow_out = 1;
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001205 if (!openflags->w ||
1206 ((fd != -EROFS) && (fd != -EACCES)))
1207 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 openflags->w = 0;
1209 fd = os_open_file(file, *openflags, mode);
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001210 if (fd < 0)
1211 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 }
1213
Jeff Dike6c29256c2006-03-27 01:14:37 -08001214 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 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 }
1223
Andreas Mohrd6e05ed2006-06-26 18:35:02 +02001224 /* Successful return case! */
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001225 if(backing_file_out == NULL)
1226 return(fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227
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 }
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001235 if(err)
1236 return(fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001238 asked_switch = path_requires_switch(*backing_file_out, backing_file, file);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001240 /* Allow switching only if no mismatch. */
1241 if (asked_switch && !backing_file_mismatch(*backing_file_out, size, mtime)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 printk("Switching backing file to '%s'\n", *backing_file_out);
1243 err = write_cow_header(file, fd, *backing_file_out,
1244 sectorsize, align, &size);
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001245 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 printk("Switch failed, errno = %d\n", -err);
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001247 goto out_close;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248 }
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001249 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 *backing_file_out = backing_file;
1251 err = backing_file_mismatch(*backing_file_out, size, mtime);
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001252 if (err)
1253 goto out_close;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 }
1255
1256 cow_sizes(version, size, sectorsize, align, *bitmap_offset_out,
1257 bitmap_len_out, data_offset_out);
1258
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001259 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 out_close:
1261 os_close_file(fd);
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001262 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263}
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;
Jeff Dike6c29256c2006-03-27 01:14:37 -08001272 fd = open_ubd_file(cow_file, &flags, 0, NULL, NULL, NULL, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 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
Jeff Dike91acb212005-10-10 23:10:32 -04001290static int update_bitmap(struct io_thread_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291{
Jeff Dike91acb212005-10-10 23:10:32 -04001292 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293
Jeff Dike91acb212005-10-10 23:10:32 -04001294 if(req->cow_offset == -1)
1295 return(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296
Jeff Dike91acb212005-10-10 23:10:32 -04001297 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 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302
Jeff Dike91acb212005-10-10 23:10:32 -04001303 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 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310
Jeff Dike91acb212005-10-10 23:10:32 -04001311 return(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312}
Jeff Dike91acb212005-10-10 23:10:32 -04001313
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);
1369
1370 req->error = update_bitmap(req);
1371}
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 }
Jeff Dike91acb212005-10-10 23:10:32 -04001406
Jeff Dike1b57e9c2006-01-06 00:18:49 -08001407 return 0;
1408}