blob: 460d669b47740e64e0ed59950a145248919fbf30 [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{
709 int n, err;
710
Jeff Dike970d6e32006-01-06 00:18:48 -0800711 str = kstrdup(str, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 if(str == NULL){
713 printk(KERN_ERR "ubd_config failed to strdup string\n");
714 return(1);
715 }
716 err = ubd_setup_common(str, &n);
717 if(err){
718 kfree(str);
719 return(-1);
720 }
721 if(n == -1) return(0);
722
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800723 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 err = ubd_add(n);
725 if(err)
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800726 ubd_devs[n].file = NULL;
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800727 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728
729 return(err);
730}
731
732static int ubd_get_config(char *name, char *str, int size, char **error_out)
733{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800734 struct ubd *ubd_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 int n, len = 0;
736
737 n = parse_unit(&name);
738 if((n >= MAX_DEV) || (n < 0)){
739 *error_out = "ubd_get_config : device number out of range";
740 return(-1);
741 }
742
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800743 ubd_dev = &ubd_devs[n];
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800744 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800746 if(ubd_dev->file == NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 CONFIG_CHUNK(str, size, len, "", 1);
748 goto out;
749 }
750
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800751 CONFIG_CHUNK(str, size, len, ubd_dev->file, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800753 if(ubd_dev->cow.file != NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 CONFIG_CHUNK(str, size, len, ",", 0);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800755 CONFIG_CHUNK(str, size, len, ubd_dev->cow.file, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 }
757 else CONFIG_CHUNK(str, size, len, "", 1);
758
759 out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800760 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 return(len);
762}
763
Jeff Dike29d56cf2005-06-25 14:55:25 -0700764static int ubd_id(char **str, int *start_out, int *end_out)
765{
766 int n;
767
768 n = parse_unit(str);
769 *start_out = 0;
770 *end_out = MAX_DEV - 1;
771 return n;
772}
773
774static int ubd_remove(int n)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800776 struct ubd *ubd_dev;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700777 int err = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800779 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780
781 if(ubd_gendisk[n] == NULL)
782 goto out;
783
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800784 ubd_dev = &ubd_devs[n];
Jeff Dike29d56cf2005-06-25 14:55:25 -0700785
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800786 if(ubd_dev->file == NULL)
Jeff Dike29d56cf2005-06-25 14:55:25 -0700787 goto out;
788
789 /* you cannot remove a open disk */
790 err = -EBUSY;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800791 if(ubd_dev->count > 0)
Jeff Dike29d56cf2005-06-25 14:55:25 -0700792 goto out;
793
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 del_gendisk(ubd_gendisk[n]);
795 put_disk(ubd_gendisk[n]);
796 ubd_gendisk[n] = NULL;
797
798 if(fake_gendisk[n] != NULL){
799 del_gendisk(fake_gendisk[n]);
800 put_disk(fake_gendisk[n]);
801 fake_gendisk[n] = NULL;
802 }
803
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800804 platform_device_unregister(&ubd_dev->pdev);
805 *ubd_dev = ((struct ubd) DEFAULT_UBD);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 err = 0;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700807out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800808 mutex_unlock(&ubd_lock);
Jeff Dike29d56cf2005-06-25 14:55:25 -0700809 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810}
811
812static struct mc_device ubd_mc = {
813 .name = "ubd",
814 .config = ubd_config,
815 .get_config = ubd_get_config,
Jeff Dike29d56cf2005-06-25 14:55:25 -0700816 .id = ubd_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 .remove = ubd_remove,
818};
819
820static int ubd_mc_init(void)
821{
822 mconsole_register_dev(&ubd_mc);
823 return 0;
824}
825
826__initcall(ubd_mc_init);
827
Russell King3ae5eae2005-11-09 22:32:44 +0000828static struct platform_driver ubd_driver = {
829 .driver = {
830 .name = DRIVER_NAME,
831 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832};
833
834int ubd_init(void)
835{
836 int i;
837
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 if (register_blkdev(MAJOR_NR, "ubd"))
839 return -1;
840
841 ubd_queue = blk_init_queue(do_ubd_request, &ubd_io_lock);
842 if (!ubd_queue) {
843 unregister_blkdev(MAJOR_NR, "ubd");
844 return -1;
845 }
846
847 if (fake_major != MAJOR_NR) {
848 char name[sizeof("ubd_nnn\0")];
849
850 snprintf(name, sizeof(name), "ubd_%d", fake_major);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 if (register_blkdev(fake_major, "ubd"))
852 return -1;
853 }
Russell King3ae5eae2005-11-09 22:32:44 +0000854 platform_driver_register(&ubd_driver);
Jeff Dike6c29256c2006-03-27 01:14:37 -0800855 for (i = 0; i < MAX_DEV; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 ubd_add(i);
857 return 0;
858}
859
860late_initcall(ubd_init);
861
Jeff Dike91acb212005-10-10 23:10:32 -0400862int ubd_driver_init(void){
863 unsigned long stack;
864 int err;
865
866 /* Set by CONFIG_BLK_DEV_UBD_SYNC or ubd=sync.*/
867 if(global_openflags.s){
868 printk(KERN_INFO "ubd: Synchronous mode\n");
869 /* Letting ubd=sync be like using ubd#s= instead of ubd#= is
870 * enough. So use anyway the io thread. */
871 }
872 stack = alloc_stack(0, 0);
Jeff Dike6c29256c2006-03-27 01:14:37 -0800873 io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *),
Jeff Dike91acb212005-10-10 23:10:32 -0400874 &thread_fd);
875 if(io_pid < 0){
Jeff Dike6c29256c2006-03-27 01:14:37 -0800876 printk(KERN_ERR
Jeff Dike91acb212005-10-10 23:10:32 -0400877 "ubd : Failed to start I/O thread (errno = %d) - "
878 "falling back to synchronous I/O\n", -io_pid);
879 io_pid = -1;
880 return(0);
881 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800882 err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800883 IRQF_DISABLED, "ubd", ubd_devs);
Jeff Dike91acb212005-10-10 23:10:32 -0400884 if(err != 0)
885 printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err);
Jeff Dikef4c57a72006-03-31 02:30:10 -0800886 return 0;
Jeff Dike91acb212005-10-10 23:10:32 -0400887}
888
889device_initcall(ubd_driver_init);
890
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891static int ubd_open(struct inode *inode, struct file *filp)
892{
893 struct gendisk *disk = inode->i_bdev->bd_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800894 struct ubd *ubd_dev = disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 int err = 0;
896
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800897 if(ubd_dev->count == 0){
898 err = ubd_open_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 if(err){
900 printk(KERN_ERR "%s: Can't open \"%s\": errno = %d\n",
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800901 disk->disk_name, ubd_dev->file, -err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 goto out;
903 }
904 }
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800905 ubd_dev->count++;
906 set_disk_ro(disk, !ubd_dev->openflags.w);
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -0700907
908 /* This should no more be needed. And it didn't work anyway to exclude
909 * read-write remounting of filesystems.*/
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800910 /*if((filp->f_mode & FMODE_WRITE) && !ubd_dev->openflags.w){
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800911 if(--ubd_dev->count == 0) ubd_close_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 err = -EROFS;
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -0700913 }*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 out:
915 return(err);
916}
917
918static int ubd_release(struct inode * inode, struct file * file)
919{
920 struct gendisk *disk = inode->i_bdev->bd_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800921 struct ubd *ubd_dev = disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800923 if(--ubd_dev->count == 0)
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800924 ubd_close_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 return(0);
926}
927
Jeff Dike91acb212005-10-10 23:10:32 -0400928static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask,
929 __u64 *cow_offset, unsigned long *bitmap,
930 __u64 bitmap_offset, unsigned long *bitmap_words,
931 __u64 bitmap_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932{
Jeff Dike91acb212005-10-10 23:10:32 -0400933 __u64 sector = io_offset >> 9;
934 int i, update_bitmap = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935
Jeff Dike91acb212005-10-10 23:10:32 -0400936 for(i = 0; i < length >> 9; i++){
937 if(cow_mask != NULL)
938 ubd_set_bit(i, (unsigned char *) cow_mask);
939 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
940 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941
Jeff Dike91acb212005-10-10 23:10:32 -0400942 update_bitmap = 1;
943 ubd_set_bit(sector + i, (unsigned char *) bitmap);
944 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945
Jeff Dike91acb212005-10-10 23:10:32 -0400946 if(!update_bitmap)
947 return;
948
949 *cow_offset = sector / (sizeof(unsigned long) * 8);
950
951 /* This takes care of the case where we're exactly at the end of the
952 * device, and *cow_offset + 1 is off the end. So, just back it up
953 * by one word. Thanks to Lynn Kerby for the fix and James McMechan
954 * for the original diagnosis.
955 */
956 if(*cow_offset == ((bitmap_len + sizeof(unsigned long) - 1) /
957 sizeof(unsigned long) - 1))
958 (*cow_offset)--;
959
960 bitmap_words[0] = bitmap[*cow_offset];
961 bitmap_words[1] = bitmap[*cow_offset + 1];
962
963 *cow_offset *= sizeof(unsigned long);
964 *cow_offset += bitmap_offset;
965}
966
967static void cowify_req(struct io_thread_req *req, unsigned long *bitmap,
968 __u64 bitmap_offset, __u64 bitmap_len)
969{
970 __u64 sector = req->offset >> 9;
971 int i;
972
973 if(req->length > (sizeof(req->sector_mask) * 8) << 9)
974 panic("Operation too long");
975
976 if(req->op == UBD_READ) {
977 for(i = 0; i < req->length >> 9; i++){
978 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
Jeff Dike6c29256c2006-03-27 01:14:37 -0800979 ubd_set_bit(i, (unsigned char *)
Jeff Dike91acb212005-10-10 23:10:32 -0400980 &req->sector_mask);
981 }
982 }
983 else cowify_bitmap(req->offset, req->length, &req->sector_mask,
984 &req->cow_offset, bitmap, bitmap_offset,
985 req->bitmap_words, bitmap_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986}
987
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988/* Called with ubd_io_lock held */
Jeff Dike91acb212005-10-10 23:10:32 -0400989static int prepare_request(struct request *req, struct io_thread_req *io_req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990{
991 struct gendisk *disk = req->rq_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800992 struct ubd *ubd_dev = disk->private_data;
Jeff Dike91acb212005-10-10 23:10:32 -0400993 __u64 offset;
994 int len;
995
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -0700996 /* This should be impossible now */
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800997 if((rq_data_dir(req) == WRITE) && !ubd_dev->openflags.w){
Jeff Dike6c29256c2006-03-27 01:14:37 -0800998 printk("Write attempted on readonly ubd device %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 disk->disk_name);
Jeff Dike91acb212005-10-10 23:10:32 -04001000 end_request(req, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 return(1);
1002 }
1003
Jeff Dike91acb212005-10-10 23:10:32 -04001004 offset = ((__u64) req->sector) << 9;
1005 len = req->current_nr_sectors << 9;
1006
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001007 io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd : ubd_dev->fd;
1008 io_req->fds[1] = ubd_dev->fd;
Jeff Dike91acb212005-10-10 23:10:32 -04001009 io_req->cow_offset = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 io_req->offset = offset;
1011 io_req->length = len;
1012 io_req->error = 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001013 io_req->sector_mask = 0;
1014
1015 io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 io_req->offsets[0] = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001017 io_req->offsets[1] = ubd_dev->cow.data_offset;
Jeff Dike91acb212005-10-10 23:10:32 -04001018 io_req->buffer = req->buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 io_req->sectorsize = 1 << 9;
1020
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001021 if(ubd_dev->cow.file != NULL)
1022 cowify_req(io_req, ubd_dev->cow.bitmap, ubd_dev->cow.bitmap_offset,
1023 ubd_dev->cow.bitmap_len);
Jeff Dike91acb212005-10-10 23:10:32 -04001024
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 return(0);
1026}
1027
1028/* Called with ubd_io_lock held */
1029static void do_ubd_request(request_queue_t *q)
1030{
1031 struct io_thread_req io_req;
1032 struct request *req;
Jeff Dike91acb212005-10-10 23:10:32 -04001033 int err, n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034
Jeff Dike91acb212005-10-10 23:10:32 -04001035 if(thread_fd == -1){
1036 while((req = elv_next_request(q)) != NULL){
1037 err = prepare_request(req, &io_req);
1038 if(!err){
1039 do_io(&io_req);
1040 __ubd_finish(req, io_req.error);
1041 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 }
1043 }
Jeff Dike91acb212005-10-10 23:10:32 -04001044 else {
1045 if(do_ubd || (req = elv_next_request(q)) == NULL)
1046 return;
1047 err = prepare_request(req, &io_req);
1048 if(!err){
Paolo 'Blaisorblade' Giarrusso2fe30a32006-10-30 22:07:09 -08001049 do_ubd = 1;
Jeff Dike91acb212005-10-10 23:10:32 -04001050 n = os_write_file(thread_fd, (char *) &io_req,
1051 sizeof(io_req));
1052 if(n != sizeof(io_req))
1053 printk("write to io thread failed, "
1054 "errno = %d\n", -n);
1055 }
1056 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057}
1058
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001059static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
1060{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001061 struct ubd *ubd_dev = bdev->bd_disk->private_data;
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001062
1063 geo->heads = 128;
1064 geo->sectors = 32;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001065 geo->cylinders = ubd_dev->size / (128 * 32 * 512);
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001066 return 0;
1067}
1068
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069static int ubd_ioctl(struct inode * inode, struct file * file,
1070 unsigned int cmd, unsigned long arg)
1071{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001072 struct ubd *ubd_dev = inode->i_bdev->bd_disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 struct hd_driveid ubd_id = {
1074 .cyls = 0,
1075 .heads = 128,
1076 .sectors = 32,
1077 };
1078
1079 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 struct cdrom_volctrl volume;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 case HDIO_GET_IDENTITY:
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001082 ubd_id.cyls = ubd_dev->size / (128 * 32 * 512);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 if(copy_to_user((char __user *) arg, (char *) &ubd_id,
1084 sizeof(ubd_id)))
1085 return(-EFAULT);
1086 return(0);
1087
1088 case CDROMVOLREAD:
1089 if(copy_from_user(&volume, (char __user *) arg, sizeof(volume)))
1090 return(-EFAULT);
1091 volume.channel0 = 255;
1092 volume.channel1 = 255;
1093 volume.channel2 = 255;
1094 volume.channel3 = 255;
1095 if(copy_to_user((char __user *) arg, &volume, sizeof(volume)))
1096 return(-EFAULT);
1097 return(0);
1098 }
1099 return(-EINVAL);
1100}
1101
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001102static int path_requires_switch(char *from_cmdline, char *from_cow, char *cow)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103{
1104 struct uml_stat buf1, buf2;
1105 int err;
1106
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001107 if(from_cmdline == NULL)
1108 return 0;
1109 if(!strcmp(from_cmdline, from_cow))
1110 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111
1112 err = os_stat_file(from_cmdline, &buf1);
1113 if(err < 0){
1114 printk("Couldn't stat '%s', err = %d\n", from_cmdline, -err);
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001115 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 }
1117 err = os_stat_file(from_cow, &buf2);
1118 if(err < 0){
1119 printk("Couldn't stat '%s', err = %d\n", from_cow, -err);
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001120 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 }
1122 if((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino))
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001123 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124
1125 printk("Backing file mismatch - \"%s\" requested,\n"
1126 "\"%s\" specified in COW header of \"%s\"\n",
1127 from_cmdline, from_cow, cow);
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001128 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129}
1130
1131static int backing_file_mismatch(char *file, __u64 size, time_t mtime)
1132{
1133 unsigned long modtime;
Paolo 'Blaisorblade' Giarrussofe1db502006-02-24 13:03:58 -08001134 unsigned long long actual;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 int err;
1136
1137 err = os_file_modtime(file, &modtime);
1138 if(err < 0){
1139 printk("Failed to get modification time of backing file "
1140 "\"%s\", err = %d\n", file, -err);
1141 return(err);
1142 }
1143
1144 err = os_file_size(file, &actual);
1145 if(err < 0){
1146 printk("Failed to get size of backing file \"%s\", "
1147 "err = %d\n", file, -err);
1148 return(err);
1149 }
1150
1151 if(actual != size){
1152 /*__u64 can be a long on AMD64 and with %lu GCC complains; so
1153 * the typecast.*/
1154 printk("Size mismatch (%llu vs %llu) of COW header vs backing "
1155 "file\n", (unsigned long long) size, actual);
1156 return(-EINVAL);
1157 }
1158 if(modtime != mtime){
1159 printk("mtime mismatch (%ld vs %ld) of COW header vs backing "
1160 "file\n", mtime, modtime);
1161 return(-EINVAL);
1162 }
1163 return(0);
1164}
1165
1166int read_cow_bitmap(int fd, void *buf, int offset, int len)
1167{
1168 int err;
1169
1170 err = os_seek_file(fd, offset);
1171 if(err < 0)
1172 return(err);
1173
1174 err = os_read_file(fd, buf, len);
1175 if(err < 0)
1176 return(err);
1177
1178 return(0);
1179}
1180
Jeff Dike6c29256c2006-03-27 01:14:37 -08001181int open_ubd_file(char *file, struct openflags *openflags, int shared,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 char **backing_file_out, int *bitmap_offset_out,
1183 unsigned long *bitmap_len_out, int *data_offset_out,
1184 int *create_cow_out)
1185{
1186 time_t mtime;
1187 unsigned long long size;
1188 __u32 version, align;
1189 char *backing_file;
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001190 int fd, err, sectorsize, asked_switch, mode = 0644;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191
1192 fd = os_open_file(file, *openflags, mode);
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001193 if (fd < 0) {
1194 if ((fd == -ENOENT) && (create_cow_out != NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 *create_cow_out = 1;
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001196 if (!openflags->w ||
1197 ((fd != -EROFS) && (fd != -EACCES)))
1198 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199 openflags->w = 0;
1200 fd = os_open_file(file, *openflags, mode);
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001201 if (fd < 0)
1202 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 }
1204
Jeff Dike6c29256c2006-03-27 01:14:37 -08001205 if(shared)
1206 printk("Not locking \"%s\" on the host\n", file);
1207 else {
1208 err = os_lock_file(fd, openflags->w);
1209 if(err < 0){
1210 printk("Failed to lock '%s', err = %d\n", file, -err);
1211 goto out_close;
1212 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 }
1214
Andreas Mohrd6e05ed2006-06-26 18:35:02 +02001215 /* Successful return case! */
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001216 if(backing_file_out == NULL)
1217 return(fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218
1219 err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime,
1220 &size, &sectorsize, &align, bitmap_offset_out);
1221 if(err && (*backing_file_out != NULL)){
1222 printk("Failed to read COW header from COW file \"%s\", "
1223 "errno = %d\n", file, -err);
1224 goto out_close;
1225 }
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001226 if(err)
1227 return(fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001229 asked_switch = path_requires_switch(*backing_file_out, backing_file, file);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001231 /* Allow switching only if no mismatch. */
1232 if (asked_switch && !backing_file_mismatch(*backing_file_out, size, mtime)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233 printk("Switching backing file to '%s'\n", *backing_file_out);
1234 err = write_cow_header(file, fd, *backing_file_out,
1235 sectorsize, align, &size);
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001236 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 printk("Switch failed, errno = %d\n", -err);
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001238 goto out_close;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 }
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001240 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 *backing_file_out = backing_file;
1242 err = backing_file_mismatch(*backing_file_out, size, mtime);
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001243 if (err)
1244 goto out_close;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 }
1246
1247 cow_sizes(version, size, sectorsize, align, *bitmap_offset_out,
1248 bitmap_len_out, data_offset_out);
1249
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001250 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 out_close:
1252 os_close_file(fd);
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001253 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254}
1255
1256int create_cow_file(char *cow_file, char *backing_file, struct openflags flags,
1257 int sectorsize, int alignment, int *bitmap_offset_out,
1258 unsigned long *bitmap_len_out, int *data_offset_out)
1259{
1260 int err, fd;
1261
1262 flags.c = 1;
Jeff Dike6c29256c2006-03-27 01:14:37 -08001263 fd = open_ubd_file(cow_file, &flags, 0, NULL, NULL, NULL, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 if(fd < 0){
1265 err = fd;
1266 printk("Open of COW file '%s' failed, errno = %d\n", cow_file,
1267 -err);
1268 goto out;
1269 }
1270
1271 err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment,
1272 bitmap_offset_out, bitmap_len_out,
1273 data_offset_out);
1274 if(!err)
1275 return(fd);
1276 os_close_file(fd);
1277 out:
1278 return(err);
1279}
1280
Jeff Dike91acb212005-10-10 23:10:32 -04001281static int update_bitmap(struct io_thread_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282{
Jeff Dike91acb212005-10-10 23:10:32 -04001283 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284
Jeff Dike91acb212005-10-10 23:10:32 -04001285 if(req->cow_offset == -1)
1286 return(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287
Jeff Dike91acb212005-10-10 23:10:32 -04001288 n = os_seek_file(req->fds[1], req->cow_offset);
1289 if(n < 0){
1290 printk("do_io - bitmap lseek failed : err = %d\n", -n);
1291 return(1);
1292 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293
Jeff Dike91acb212005-10-10 23:10:32 -04001294 n = os_write_file(req->fds[1], &req->bitmap_words,
1295 sizeof(req->bitmap_words));
1296 if(n != sizeof(req->bitmap_words)){
1297 printk("do_io - bitmap update failed, err = %d fd = %d\n", -n,
1298 req->fds[1]);
1299 return(1);
1300 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301
Jeff Dike91acb212005-10-10 23:10:32 -04001302 return(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303}
Jeff Dike91acb212005-10-10 23:10:32 -04001304
1305void do_io(struct io_thread_req *req)
1306{
1307 char *buf;
1308 unsigned long len;
1309 int n, nsectors, start, end, bit;
1310 int err;
1311 __u64 off;
1312
1313 nsectors = req->length / req->sectorsize;
1314 start = 0;
1315 do {
1316 bit = ubd_test_bit(start, (unsigned char *) &req->sector_mask);
1317 end = start;
1318 while((end < nsectors) &&
1319 (ubd_test_bit(end, (unsigned char *)
1320 &req->sector_mask) == bit))
1321 end++;
1322
1323 off = req->offset + req->offsets[bit] +
1324 start * req->sectorsize;
1325 len = (end - start) * req->sectorsize;
1326 buf = &req->buffer[start * req->sectorsize];
1327
1328 err = os_seek_file(req->fds[bit], off);
1329 if(err < 0){
1330 printk("do_io - lseek failed : err = %d\n", -err);
1331 req->error = 1;
1332 return;
1333 }
1334 if(req->op == UBD_READ){
1335 n = 0;
1336 do {
1337 buf = &buf[n];
1338 len -= n;
1339 n = os_read_file(req->fds[bit], buf, len);
1340 if (n < 0) {
1341 printk("do_io - read failed, err = %d "
1342 "fd = %d\n", -n, req->fds[bit]);
1343 req->error = 1;
1344 return;
1345 }
1346 } while((n < len) && (n != 0));
1347 if (n < len) memset(&buf[n], 0, len - n);
1348 } else {
1349 n = os_write_file(req->fds[bit], buf, len);
1350 if(n != len){
1351 printk("do_io - write failed err = %d "
1352 "fd = %d\n", -n, req->fds[bit]);
1353 req->error = 1;
1354 return;
1355 }
1356 }
1357
1358 start = end;
1359 } while(start < nsectors);
1360
1361 req->error = update_bitmap(req);
1362}
1363
1364/* Changed in start_io_thread, which is serialized by being called only
1365 * from ubd_init, which is an initcall.
1366 */
1367int kernel_fd = -1;
1368
1369/* Only changed by the io thread */
1370int io_count = 0;
1371
1372int io_thread(void *arg)
1373{
1374 struct io_thread_req req;
1375 int n;
1376
1377 ignore_sigwinch_sig();
1378 while(1){
1379 n = os_read_file(kernel_fd, &req, sizeof(req));
1380 if(n != sizeof(req)){
1381 if(n < 0)
1382 printk("io_thread - read failed, fd = %d, "
1383 "err = %d\n", kernel_fd, -n);
1384 else {
1385 printk("io_thread - short read, fd = %d, "
1386 "length = %d\n", kernel_fd, n);
1387 }
1388 continue;
1389 }
1390 io_count++;
1391 do_io(&req);
1392 n = os_write_file(kernel_fd, &req, sizeof(req));
1393 if(n != sizeof(req))
1394 printk("io_thread - write failed, fd = %d, err = %d\n",
1395 kernel_fd, -n);
1396 }
Jeff Dike91acb212005-10-10 23:10:32 -04001397
Jeff Dike1b57e9c2006-01-06 00:18:49 -08001398 return 0;
1399}