blob: 6cd8988e8fd087e1be4ecf2c8a4eee247a34f9e9 [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
Jeff Dike91acb212005-10-10 23:10:32 -0400115static void (*do_ubd)(void);
116
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117static int ubd_open(struct inode * inode, struct file * filp);
118static int ubd_release(struct inode * inode, struct file * file);
119static int ubd_ioctl(struct inode * inode, struct file * file,
120 unsigned int cmd, unsigned long arg);
Christoph Hellwiga885c8c2006-01-08 01:02:50 -0800121static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122
Paolo 'Blaisorblade' Giarrusso97d88ac2006-10-30 22:07:03 -0800123#define MAX_DEV (16)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125static struct block_device_operations ubd_blops = {
126 .owner = THIS_MODULE,
127 .open = ubd_open,
128 .release = ubd_release,
129 .ioctl = ubd_ioctl,
Christoph Hellwiga885c8c2006-01-08 01:02:50 -0800130 .getgeo = ubd_getgeo,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131};
132
133/* Protected by the queue_lock */
134static request_queue_t *ubd_queue;
135
136/* Protected by ubd_lock */
137static int fake_major = MAJOR_NR;
138
139static struct gendisk *ubd_gendisk[MAX_DEV];
140static struct gendisk *fake_gendisk[MAX_DEV];
Jeff Dike6c29256c2006-03-27 01:14:37 -0800141
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142#ifdef CONFIG_BLK_DEV_UBD_SYNC
143#define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 1, .c = 0, \
144 .cl = 1 })
145#else
146#define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 0, .c = 0, \
147 .cl = 1 })
148#endif
149
150/* Not protected - changed only in ubd_setup_common and then only to
151 * to enable O_SYNC.
152 */
153static struct openflags global_openflags = OPEN_FLAGS;
154
155struct cow {
Paolo 'Blaisorblade' Giarrusso2a9d32f2006-10-30 22:07:04 -0800156 /* backing file name */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 char *file;
Paolo 'Blaisorblade' Giarrusso2a9d32f2006-10-30 22:07:04 -0800158 /* backing file fd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 int fd;
160 unsigned long *bitmap;
161 unsigned long bitmap_len;
162 int bitmap_offset;
163 int data_offset;
164};
165
166struct ubd {
Paolo 'Blaisorblade' Giarrusso2a9d32f2006-10-30 22:07:04 -0800167 /* name (and fd, below) of the file opened for writing, either the
168 * backing or the cow file. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169 char *file;
170 int count;
171 int fd;
172 __u64 size;
173 struct openflags boot_openflags;
174 struct openflags openflags;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800175 int shared;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 int no_cow;
177 struct cow cow;
178 struct platform_device pdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179};
180
181#define DEFAULT_COW { \
182 .file = NULL, \
183 .fd = -1, \
184 .bitmap = NULL, \
185 .bitmap_offset = 0, \
186 .data_offset = 0, \
187}
188
189#define DEFAULT_UBD { \
190 .file = NULL, \
191 .count = 0, \
192 .fd = -1, \
193 .size = -1, \
194 .boot_openflags = OPEN_FLAGS, \
195 .openflags = OPEN_FLAGS, \
196 .no_cow = 0, \
Jeff Dike6c29256c2006-03-27 01:14:37 -0800197 .shared = 0, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 .cow = DEFAULT_COW, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199}
200
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800201struct ubd ubd_devs[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_UBD };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202
203static int ubd0_init(void)
204{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800205 struct ubd *ubd_dev = &ubd_devs[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800207 if(ubd_dev->file == NULL)
208 ubd_dev->file = "root_fs";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 return(0);
210}
211
212__initcall(ubd0_init);
213
214/* Only changed by fake_ide_setup which is a setup */
215static int fake_ide = 0;
216static struct proc_dir_entry *proc_ide_root = NULL;
217static struct proc_dir_entry *proc_ide = NULL;
218
219static void make_proc_ide(void)
220{
221 proc_ide_root = proc_mkdir("ide", NULL);
222 proc_ide = proc_mkdir("ide0", proc_ide_root);
223}
224
225static int proc_ide_read_media(char *page, char **start, off_t off, int count,
226 int *eof, void *data)
227{
228 int len;
229
230 strcpy(page, "disk\n");
231 len = strlen("disk\n");
232 len -= off;
233 if (len < count){
234 *eof = 1;
235 if (len <= 0) return 0;
236 }
237 else len = count;
238 *start = page + off;
239 return len;
240}
241
242static void make_ide_entries(char *dev_name)
243{
244 struct proc_dir_entry *dir, *ent;
245 char name[64];
246
247 if(proc_ide_root == NULL) make_proc_ide();
248
249 dir = proc_mkdir(dev_name, proc_ide);
250 if(!dir) return;
251
252 ent = create_proc_entry("media", S_IFREG|S_IRUGO, dir);
253 if(!ent) return;
254 ent->nlink = 1;
255 ent->data = NULL;
256 ent->read_proc = proc_ide_read_media;
257 ent->write_proc = NULL;
258 sprintf(name,"ide0/%s", dev_name);
259 proc_symlink(dev_name, proc_ide_root, name);
260}
261
262static int fake_ide_setup(char *str)
263{
264 fake_ide = 1;
265 return(1);
266}
267
268__setup("fake_ide", fake_ide_setup);
269
270__uml_help(fake_ide_setup,
271"fake_ide\n"
272" Create ide0 entries that map onto ubd devices.\n\n"
273);
274
275static int parse_unit(char **ptr)
276{
277 char *str = *ptr, *end;
278 int n = -1;
279
280 if(isdigit(*str)) {
281 n = simple_strtoul(str, &end, 0);
282 if(end == str)
283 return(-1);
284 *ptr = end;
285 }
Paolo 'Blaisorblade' Giarrusso97d88ac2006-10-30 22:07:03 -0800286 else if (('a' <= *str) && (*str <= 'z')) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 n = *str - 'a';
288 str++;
289 *ptr = str;
290 }
291 return(n);
292}
293
294static int ubd_setup_common(char *str, int *index_out)
295{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800296 struct ubd *ubd_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 struct openflags flags = global_openflags;
298 char *backing_file;
299 int n, err, i;
300
301 if(index_out) *index_out = -1;
302 n = *str;
303 if(n == '='){
304 char *end;
305 int major;
306
307 str++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 if(!strcmp(str, "sync")){
309 global_openflags = of_sync(global_openflags);
310 return(0);
311 }
312 major = simple_strtoul(str, &end, 0);
313 if((*end != '\0') || (end == str)){
Jeff Dike6c29256c2006-03-27 01:14:37 -0800314 printk(KERN_ERR
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 "ubd_setup : didn't parse major number\n");
316 return(1);
317 }
318
319 err = 1;
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800320 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 if(fake_major != MAJOR_NR){
322 printk(KERN_ERR "Can't assign a fake major twice\n");
323 goto out1;
324 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800325
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 fake_major = major;
327
328 printk(KERN_INFO "Setting extra ubd major number to %d\n",
329 major);
330 err = 0;
331 out1:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800332 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 return(err);
334 }
335
336 n = parse_unit(&str);
337 if(n < 0){
338 printk(KERN_ERR "ubd_setup : couldn't parse unit number "
339 "'%s'\n", str);
340 return(1);
341 }
342 if(n >= MAX_DEV){
343 printk(KERN_ERR "ubd_setup : index %d out of range "
344 "(%d devices, from 0 to %d)\n", n, MAX_DEV, MAX_DEV - 1);
345 return(1);
346 }
347
348 err = 1;
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800349 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800351 ubd_dev = &ubd_devs[n];
352 if(ubd_dev->file != NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 printk(KERN_ERR "ubd_setup : device already configured\n");
354 goto out;
355 }
356
357 if (index_out)
358 *index_out = n;
359
Jeff Dike6c29256c2006-03-27 01:14:37 -0800360 for (i = 0; i < sizeof("rscd="); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 switch (*str) {
362 case 'r':
363 flags.w = 0;
364 break;
365 case 's':
366 flags.s = 1;
367 break;
368 case 'd':
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800369 ubd_dev->no_cow = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 break;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800371 case 'c':
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800372 ubd_dev->shared = 1;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800373 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 case '=':
375 str++;
376 goto break_loop;
377 default:
Jeff Dike6c29256c2006-03-27 01:14:37 -0800378 printk(KERN_ERR "ubd_setup : Expected '=' or flag letter (r, s, c, or d)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 goto out;
380 }
381 str++;
382 }
383
384 if (*str == '=')
385 printk(KERN_ERR "ubd_setup : Too many flags specified\n");
386 else
387 printk(KERN_ERR "ubd_setup : Expected '='\n");
388 goto out;
389
390break_loop:
391 err = 0;
392 backing_file = strchr(str, ',');
393
394 if (!backing_file) {
395 backing_file = strchr(str, ':');
396 }
397
398 if(backing_file){
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800399 if(ubd_dev->no_cow)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 printk(KERN_ERR "Can't specify both 'd' and a "
401 "cow file\n");
402 else {
403 *backing_file = '\0';
404 backing_file++;
405 }
406 }
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800407 ubd_dev->file = str;
408 ubd_dev->cow.file = backing_file;
409 ubd_dev->boot_openflags = flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800411 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 return(err);
413}
414
415static int ubd_setup(char *str)
416{
417 ubd_setup_common(str, NULL);
418 return(1);
419}
420
421__setup("ubd", ubd_setup);
422__uml_help(ubd_setup,
423"ubd<n><flags>=<filename>[(:|,)<filename2>]\n"
424" This is used to associate a device with a file in the underlying\n"
425" filesystem. When specifying two filenames, the first one is the\n"
426" COW name and the second is the backing file name. As separator you can\n"
427" use either a ':' or a ',': the first one allows writing things like;\n"
428" ubd0=~/Uml/root_cow:~/Uml/root_backing_file\n"
429" while with a ',' the shell would not expand the 2nd '~'.\n"
430" When using only one filename, UML will detect whether to thread it like\n"
431" a COW file or a backing file. To override this detection, add the 'd'\n"
432" flag:\n"
433" ubd0d=BackingFile\n"
434" Usually, there is a filesystem in the file, but \n"
435" that's not required. Swap devices containing swap files can be\n"
436" specified like this. Also, a file which doesn't contain a\n"
437" filesystem can have its contents read in the virtual \n"
438" machine by running 'dd' on the device. <n> must be in the range\n"
439" 0 to 7. Appending an 'r' to the number will cause that device\n"
440" to be mounted read-only. For example ubd1r=./ext_fs. Appending\n"
441" an 's' will cause data to be written to disk on the host immediately.\n\n"
442);
443
444static int udb_setup(char *str)
445{
446 printk("udb%s specified on command line is almost certainly a ubd -> "
447 "udb TYPO\n", str);
448 return(1);
449}
450
451__setup("udb", udb_setup);
452__uml_help(udb_setup,
453"udb\n"
Jeff Dike0894e272005-05-28 15:51:55 -0700454" This option is here solely to catch ubd -> udb typos, which can be\n"
455" to impossible to catch visually unless you specifically look for\n"
456" them. The only result of any option starting with 'udb' is an error\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457" in the boot output.\n\n"
458);
459
460static int fakehd_set = 0;
461static int fakehd(char *str)
462{
463 printk(KERN_INFO "fakehd : Changing ubd name to \"hd\".\n");
464 fakehd_set = 1;
465 return 1;
466}
467
468__setup("fakehd", fakehd);
469__uml_help(fakehd,
470"fakehd\n"
471" Change the ubd device name to \"hd\".\n\n"
472);
473
474static void do_ubd_request(request_queue_t * q);
Jeff Dike91acb212005-10-10 23:10:32 -0400475
476/* Only changed by ubd_init, which is an initcall. */
477int thread_fd = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478
479/* Changed by ubd_handler, which is serialized because interrupts only
480 * happen on CPU 0.
481 */
482int intr_count = 0;
483
484/* call ubd_finish if you need to serialize */
Jeff Dike91acb212005-10-10 23:10:32 -0400485static void __ubd_finish(struct request *req, int error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486{
Jeff Dike91acb212005-10-10 23:10:32 -0400487 int nsect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488
Jeff Dike91acb212005-10-10 23:10:32 -0400489 if(error){
490 end_request(req, 0);
491 return;
492 }
493 nsect = req->current_nr_sectors;
494 req->sector += nsect;
495 req->buffer += nsect << 9;
496 req->errors = 0;
497 req->nr_sectors -= nsect;
498 req->current_nr_sectors = 0;
499 end_request(req, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500}
501
Paolo 'Blaisorblade' Giarrusso33f775e2006-10-30 22:07:08 -0800502/* Callable only from interrupt context - otherwise you need to do
503 * spin_lock_irq()/spin_lock_irqsave() */
Jeff Dike91acb212005-10-10 23:10:32 -0400504static inline void ubd_finish(struct request *req, int error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505{
Jeff Dike91acb212005-10-10 23:10:32 -0400506 spin_lock(&ubd_io_lock);
507 __ubd_finish(req, error);
508 spin_unlock(&ubd_io_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509}
510
Paolo 'Blaisorblade' Giarrusso33f775e2006-10-30 22:07:08 -0800511/* Called without ubd_io_lock held, and only in interrupt context. */
Jeff Dike91acb212005-10-10 23:10:32 -0400512static void ubd_handler(void)
513{
514 struct io_thread_req req;
515 struct request *rq = elv_next_request(ubd_queue);
516 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517
Jeff Dike91acb212005-10-10 23:10:32 -0400518 do_ubd = NULL;
519 intr_count++;
520 n = os_read_file(thread_fd, &req, sizeof(req));
521 if(n != sizeof(req)){
522 printk(KERN_ERR "Pid %d - spurious interrupt in ubd_handler, "
523 "err = %d\n", os_getpid(), -n);
524 spin_lock(&ubd_io_lock);
525 end_request(rq, 0);
526 spin_unlock(&ubd_io_lock);
527 return;
528 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800529
Jeff Dike91acb212005-10-10 23:10:32 -0400530 ubd_finish(rq, req.error);
531 reactivate_fd(thread_fd, UBD_IRQ);
Paolo 'Blaisorblade' Giarrusso33f775e2006-10-30 22:07:08 -0800532 spin_lock(&ubd_io_lock);
Jeff Dike91acb212005-10-10 23:10:32 -0400533 do_ubd_request(ubd_queue);
Paolo 'Blaisorblade' Giarrusso33f775e2006-10-30 22:07:08 -0800534 spin_unlock(&ubd_io_lock);
Jeff Dike91acb212005-10-10 23:10:32 -0400535}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536
Al Viro7bea96f2006-10-08 22:49:34 +0100537static irqreturn_t ubd_intr(int irq, void *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538{
Jeff Dike91acb212005-10-10 23:10:32 -0400539 ubd_handler();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 return(IRQ_HANDLED);
541}
542
Jeff Dike91acb212005-10-10 23:10:32 -0400543/* Only changed by ubd_init, which is an initcall. */
544static int io_pid = -1;
545
546void kill_io_thread(void)
547{
Jeff Dike6c29256c2006-03-27 01:14:37 -0800548 if(io_pid != -1)
Jeff Dike91acb212005-10-10 23:10:32 -0400549 os_kill_process(io_pid, 1);
550}
551
552__uml_exitcall(kill_io_thread);
553
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800554static int ubd_file_size(struct ubd *ubd_dev, __u64 *size_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555{
556 char *file;
557
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800558 file = ubd_dev->cow.file ? ubd_dev->cow.file : ubd_dev->file;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 return(os_file_size(file, size_out));
560}
561
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800562static void ubd_close_dev(struct ubd *ubd_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800564 os_close_file(ubd_dev->fd);
565 if(ubd_dev->cow.file == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 return;
567
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800568 os_close_file(ubd_dev->cow.fd);
569 vfree(ubd_dev->cow.bitmap);
570 ubd_dev->cow.bitmap = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571}
572
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800573static int ubd_open_dev(struct ubd *ubd_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574{
575 struct openflags flags;
576 char **back_ptr;
577 int err, create_cow, *create_ptr;
578
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800579 ubd_dev->openflags = ubd_dev->boot_openflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 create_cow = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800581 create_ptr = (ubd_dev->cow.file != NULL) ? &create_cow : NULL;
582 back_ptr = ubd_dev->no_cow ? NULL : &ubd_dev->cow.file;
583 ubd_dev->fd = open_ubd_file(ubd_dev->file, &ubd_dev->openflags, ubd_dev->shared,
584 back_ptr, &ubd_dev->cow.bitmap_offset,
585 &ubd_dev->cow.bitmap_len, &ubd_dev->cow.data_offset,
Jeff Dike6c29256c2006-03-27 01:14:37 -0800586 create_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800588 if((ubd_dev->fd == -ENOENT) && create_cow){
589 ubd_dev->fd = create_cow_file(ubd_dev->file, ubd_dev->cow.file,
590 ubd_dev->openflags, 1 << 9, PAGE_SIZE,
591 &ubd_dev->cow.bitmap_offset,
592 &ubd_dev->cow.bitmap_len,
593 &ubd_dev->cow.data_offset);
594 if(ubd_dev->fd >= 0){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 printk(KERN_INFO "Creating \"%s\" as COW file for "
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800596 "\"%s\"\n", ubd_dev->file, ubd_dev->cow.file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 }
598 }
599
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800600 if(ubd_dev->fd < 0){
601 printk("Failed to open '%s', errno = %d\n", ubd_dev->file,
602 -ubd_dev->fd);
603 return(ubd_dev->fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 }
605
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800606 if(ubd_dev->cow.file != NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 err = -ENOMEM;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800608 ubd_dev->cow.bitmap = (void *) vmalloc(ubd_dev->cow.bitmap_len);
609 if(ubd_dev->cow.bitmap == NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 printk(KERN_ERR "Failed to vmalloc COW bitmap\n");
611 goto error;
612 }
613 flush_tlb_kernel_vm();
614
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800615 err = read_cow_bitmap(ubd_dev->fd, ubd_dev->cow.bitmap,
616 ubd_dev->cow.bitmap_offset,
617 ubd_dev->cow.bitmap_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 if(err < 0)
619 goto error;
620
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800621 flags = ubd_dev->openflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 flags.w = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800623 err = open_ubd_file(ubd_dev->cow.file, &flags, ubd_dev->shared, NULL,
Jeff Dike6c29256c2006-03-27 01:14:37 -0800624 NULL, NULL, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 if(err < 0) goto error;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800626 ubd_dev->cow.fd = err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 }
628 return(0);
629 error:
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800630 os_close_file(ubd_dev->fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 return(err);
632}
633
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800634static int ubd_disk_register(int major, u64 size, int unit,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 struct gendisk **disk_out)
636
637{
638 struct gendisk *disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639
640 disk = alloc_disk(1 << UBD_SHIFT);
641 if(disk == NULL)
642 return(-ENOMEM);
643
644 disk->major = major;
645 disk->first_minor = unit << UBD_SHIFT;
646 disk->fops = &ubd_blops;
647 set_capacity(disk, size / 512);
Greg Kroah-Hartmance7b0f462005-06-20 21:15:16 -0700648 if(major == MAJOR_NR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 sprintf(disk->disk_name, "ubd%c", 'a' + unit);
Greg Kroah-Hartmance7b0f462005-06-20 21:15:16 -0700650 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 sprintf(disk->disk_name, "ubd_fake%d", unit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652
653 /* sysfs register (not for ide fake devices) */
654 if (major == MAJOR_NR) {
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800655 ubd_devs[unit].pdev.id = unit;
656 ubd_devs[unit].pdev.name = DRIVER_NAME;
657 platform_device_register(&ubd_devs[unit].pdev);
658 disk->driverfs_dev = &ubd_devs[unit].pdev.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 }
660
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800661 disk->private_data = &ubd_devs[unit];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 disk->queue = ubd_queue;
663 add_disk(disk);
664
665 *disk_out = disk;
666 return 0;
667}
668
669#define ROUND_BLOCK(n) ((n + ((1 << 9) - 1)) & (-1 << 9))
670
671static int ubd_add(int n)
672{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800673 struct ubd *ubd_dev = &ubd_devs[n];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 int err;
675
Jeff Dikeec7cf782005-09-03 15:57:29 -0700676 err = -ENODEV;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800677 if(ubd_dev->file == NULL)
Jeff Dikeec7cf782005-09-03 15:57:29 -0700678 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800680 err = ubd_file_size(ubd_dev, &ubd_dev->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 if(err < 0)
Jeff Dike80c13742006-09-29 01:58:51 -0700682 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800684 ubd_dev->size = ROUND_BLOCK(ubd_dev->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800686 err = ubd_disk_register(MAJOR_NR, ubd_dev->size, n, &ubd_gendisk[n]);
Jeff Dike6c29256c2006-03-27 01:14:37 -0800687 if(err)
Jeff Dike80c13742006-09-29 01:58:51 -0700688 goto out;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800689
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 if(fake_major != MAJOR_NR)
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800691 ubd_disk_register(fake_major, ubd_dev->size, n,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 &fake_gendisk[n]);
693
694 /* perhaps this should also be under the "if (fake_major)" above */
695 /* using the fake_disk->disk_name and also the fakehd_set name */
696 if (fake_ide)
697 make_ide_entries(ubd_gendisk[n]->disk_name);
698
Jeff Dikeec7cf782005-09-03 15:57:29 -0700699 err = 0;
Jeff Dikeec7cf782005-09-03 15:57:29 -0700700out:
701 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702}
703
704static int ubd_config(char *str)
705{
706 int n, err;
707
Jeff Dike970d6e32006-01-06 00:18:48 -0800708 str = kstrdup(str, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 if(str == NULL){
710 printk(KERN_ERR "ubd_config failed to strdup string\n");
711 return(1);
712 }
713 err = ubd_setup_common(str, &n);
714 if(err){
715 kfree(str);
716 return(-1);
717 }
718 if(n == -1) return(0);
719
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800720 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 err = ubd_add(n);
722 if(err)
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800723 ubd_devs[n].file = NULL;
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800724 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725
726 return(err);
727}
728
729static int ubd_get_config(char *name, char *str, int size, char **error_out)
730{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800731 struct ubd *ubd_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 int n, len = 0;
733
734 n = parse_unit(&name);
735 if((n >= MAX_DEV) || (n < 0)){
736 *error_out = "ubd_get_config : device number out of range";
737 return(-1);
738 }
739
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800740 ubd_dev = &ubd_devs[n];
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800741 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800743 if(ubd_dev->file == NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 CONFIG_CHUNK(str, size, len, "", 1);
745 goto out;
746 }
747
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800748 CONFIG_CHUNK(str, size, len, ubd_dev->file, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800750 if(ubd_dev->cow.file != NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 CONFIG_CHUNK(str, size, len, ",", 0);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800752 CONFIG_CHUNK(str, size, len, ubd_dev->cow.file, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 }
754 else CONFIG_CHUNK(str, size, len, "", 1);
755
756 out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800757 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 return(len);
759}
760
Jeff Dike29d56cf2005-06-25 14:55:25 -0700761static int ubd_id(char **str, int *start_out, int *end_out)
762{
763 int n;
764
765 n = parse_unit(str);
766 *start_out = 0;
767 *end_out = MAX_DEV - 1;
768 return n;
769}
770
771static int ubd_remove(int n)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800773 struct ubd *ubd_dev;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700774 int err = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800776 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777
778 if(ubd_gendisk[n] == NULL)
779 goto out;
780
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800781 ubd_dev = &ubd_devs[n];
Jeff Dike29d56cf2005-06-25 14:55:25 -0700782
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800783 if(ubd_dev->file == NULL)
Jeff Dike29d56cf2005-06-25 14:55:25 -0700784 goto out;
785
786 /* you cannot remove a open disk */
787 err = -EBUSY;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800788 if(ubd_dev->count > 0)
Jeff Dike29d56cf2005-06-25 14:55:25 -0700789 goto out;
790
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 del_gendisk(ubd_gendisk[n]);
792 put_disk(ubd_gendisk[n]);
793 ubd_gendisk[n] = NULL;
794
795 if(fake_gendisk[n] != NULL){
796 del_gendisk(fake_gendisk[n]);
797 put_disk(fake_gendisk[n]);
798 fake_gendisk[n] = NULL;
799 }
800
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800801 platform_device_unregister(&ubd_dev->pdev);
802 *ubd_dev = ((struct ubd) DEFAULT_UBD);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 err = 0;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700804out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800805 mutex_unlock(&ubd_lock);
Jeff Dike29d56cf2005-06-25 14:55:25 -0700806 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807}
808
809static struct mc_device ubd_mc = {
810 .name = "ubd",
811 .config = ubd_config,
812 .get_config = ubd_get_config,
Jeff Dike29d56cf2005-06-25 14:55:25 -0700813 .id = ubd_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 .remove = ubd_remove,
815};
816
817static int ubd_mc_init(void)
818{
819 mconsole_register_dev(&ubd_mc);
820 return 0;
821}
822
823__initcall(ubd_mc_init);
824
Russell King3ae5eae2005-11-09 22:32:44 +0000825static struct platform_driver ubd_driver = {
826 .driver = {
827 .name = DRIVER_NAME,
828 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829};
830
831int ubd_init(void)
832{
833 int i;
834
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 if (register_blkdev(MAJOR_NR, "ubd"))
836 return -1;
837
838 ubd_queue = blk_init_queue(do_ubd_request, &ubd_io_lock);
839 if (!ubd_queue) {
840 unregister_blkdev(MAJOR_NR, "ubd");
841 return -1;
842 }
843
844 if (fake_major != MAJOR_NR) {
845 char name[sizeof("ubd_nnn\0")];
846
847 snprintf(name, sizeof(name), "ubd_%d", fake_major);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 if (register_blkdev(fake_major, "ubd"))
849 return -1;
850 }
Russell King3ae5eae2005-11-09 22:32:44 +0000851 platform_driver_register(&ubd_driver);
Jeff Dike6c29256c2006-03-27 01:14:37 -0800852 for (i = 0; i < MAX_DEV; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 ubd_add(i);
854 return 0;
855}
856
857late_initcall(ubd_init);
858
Jeff Dike91acb212005-10-10 23:10:32 -0400859int ubd_driver_init(void){
860 unsigned long stack;
861 int err;
862
863 /* Set by CONFIG_BLK_DEV_UBD_SYNC or ubd=sync.*/
864 if(global_openflags.s){
865 printk(KERN_INFO "ubd: Synchronous mode\n");
866 /* Letting ubd=sync be like using ubd#s= instead of ubd#= is
867 * enough. So use anyway the io thread. */
868 }
869 stack = alloc_stack(0, 0);
Jeff Dike6c29256c2006-03-27 01:14:37 -0800870 io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *),
Jeff Dike91acb212005-10-10 23:10:32 -0400871 &thread_fd);
872 if(io_pid < 0){
Jeff Dike6c29256c2006-03-27 01:14:37 -0800873 printk(KERN_ERR
Jeff Dike91acb212005-10-10 23:10:32 -0400874 "ubd : Failed to start I/O thread (errno = %d) - "
875 "falling back to synchronous I/O\n", -io_pid);
876 io_pid = -1;
877 return(0);
878 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800879 err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800880 IRQF_DISABLED, "ubd", ubd_devs);
Jeff Dike91acb212005-10-10 23:10:32 -0400881 if(err != 0)
882 printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err);
Jeff Dikef4c57a72006-03-31 02:30:10 -0800883 return 0;
Jeff Dike91acb212005-10-10 23:10:32 -0400884}
885
886device_initcall(ubd_driver_init);
887
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888static int ubd_open(struct inode *inode, struct file *filp)
889{
890 struct gendisk *disk = inode->i_bdev->bd_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800891 struct ubd *ubd_dev = disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 int err = 0;
893
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800894 if(ubd_dev->count == 0){
895 err = ubd_open_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 if(err){
897 printk(KERN_ERR "%s: Can't open \"%s\": errno = %d\n",
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800898 disk->disk_name, ubd_dev->file, -err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 goto out;
900 }
901 }
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800902 ubd_dev->count++;
903 set_disk_ro(disk, !ubd_dev->openflags.w);
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -0700904
905 /* This should no more be needed. And it didn't work anyway to exclude
906 * read-write remounting of filesystems.*/
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800907 /*if((filp->f_mode & FMODE_WRITE) && !ubd_dev->openflags.w){
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800908 if(--ubd_dev->count == 0) ubd_close_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 err = -EROFS;
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -0700910 }*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 out:
912 return(err);
913}
914
915static int ubd_release(struct inode * inode, struct file * file)
916{
917 struct gendisk *disk = inode->i_bdev->bd_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800918 struct ubd *ubd_dev = disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800920 if(--ubd_dev->count == 0)
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800921 ubd_close_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 return(0);
923}
924
Jeff Dike91acb212005-10-10 23:10:32 -0400925static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask,
926 __u64 *cow_offset, unsigned long *bitmap,
927 __u64 bitmap_offset, unsigned long *bitmap_words,
928 __u64 bitmap_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929{
Jeff Dike91acb212005-10-10 23:10:32 -0400930 __u64 sector = io_offset >> 9;
931 int i, update_bitmap = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932
Jeff Dike91acb212005-10-10 23:10:32 -0400933 for(i = 0; i < length >> 9; i++){
934 if(cow_mask != NULL)
935 ubd_set_bit(i, (unsigned char *) cow_mask);
936 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
937 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938
Jeff Dike91acb212005-10-10 23:10:32 -0400939 update_bitmap = 1;
940 ubd_set_bit(sector + i, (unsigned char *) bitmap);
941 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942
Jeff Dike91acb212005-10-10 23:10:32 -0400943 if(!update_bitmap)
944 return;
945
946 *cow_offset = sector / (sizeof(unsigned long) * 8);
947
948 /* This takes care of the case where we're exactly at the end of the
949 * device, and *cow_offset + 1 is off the end. So, just back it up
950 * by one word. Thanks to Lynn Kerby for the fix and James McMechan
951 * for the original diagnosis.
952 */
953 if(*cow_offset == ((bitmap_len + sizeof(unsigned long) - 1) /
954 sizeof(unsigned long) - 1))
955 (*cow_offset)--;
956
957 bitmap_words[0] = bitmap[*cow_offset];
958 bitmap_words[1] = bitmap[*cow_offset + 1];
959
960 *cow_offset *= sizeof(unsigned long);
961 *cow_offset += bitmap_offset;
962}
963
964static void cowify_req(struct io_thread_req *req, unsigned long *bitmap,
965 __u64 bitmap_offset, __u64 bitmap_len)
966{
967 __u64 sector = req->offset >> 9;
968 int i;
969
970 if(req->length > (sizeof(req->sector_mask) * 8) << 9)
971 panic("Operation too long");
972
973 if(req->op == UBD_READ) {
974 for(i = 0; i < req->length >> 9; i++){
975 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
Jeff Dike6c29256c2006-03-27 01:14:37 -0800976 ubd_set_bit(i, (unsigned char *)
Jeff Dike91acb212005-10-10 23:10:32 -0400977 &req->sector_mask);
978 }
979 }
980 else cowify_bitmap(req->offset, req->length, &req->sector_mask,
981 &req->cow_offset, bitmap, bitmap_offset,
982 req->bitmap_words, bitmap_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983}
984
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985/* Called with ubd_io_lock held */
Jeff Dike91acb212005-10-10 23:10:32 -0400986static int prepare_request(struct request *req, struct io_thread_req *io_req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987{
988 struct gendisk *disk = req->rq_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800989 struct ubd *ubd_dev = disk->private_data;
Jeff Dike91acb212005-10-10 23:10:32 -0400990 __u64 offset;
991 int len;
992
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -0700993 /* This should be impossible now */
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800994 if((rq_data_dir(req) == WRITE) && !ubd_dev->openflags.w){
Jeff Dike6c29256c2006-03-27 01:14:37 -0800995 printk("Write attempted on readonly ubd device %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 disk->disk_name);
Jeff Dike91acb212005-10-10 23:10:32 -0400997 end_request(req, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 return(1);
999 }
1000
Jeff Dike91acb212005-10-10 23:10:32 -04001001 offset = ((__u64) req->sector) << 9;
1002 len = req->current_nr_sectors << 9;
1003
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001004 io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd : ubd_dev->fd;
1005 io_req->fds[1] = ubd_dev->fd;
Jeff Dike91acb212005-10-10 23:10:32 -04001006 io_req->cow_offset = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 io_req->offset = offset;
1008 io_req->length = len;
1009 io_req->error = 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001010 io_req->sector_mask = 0;
1011
1012 io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 io_req->offsets[0] = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001014 io_req->offsets[1] = ubd_dev->cow.data_offset;
Jeff Dike91acb212005-10-10 23:10:32 -04001015 io_req->buffer = req->buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 io_req->sectorsize = 1 << 9;
1017
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001018 if(ubd_dev->cow.file != NULL)
1019 cowify_req(io_req, ubd_dev->cow.bitmap, ubd_dev->cow.bitmap_offset,
1020 ubd_dev->cow.bitmap_len);
Jeff Dike91acb212005-10-10 23:10:32 -04001021
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 return(0);
1023}
1024
1025/* Called with ubd_io_lock held */
1026static void do_ubd_request(request_queue_t *q)
1027{
1028 struct io_thread_req io_req;
1029 struct request *req;
Jeff Dike91acb212005-10-10 23:10:32 -04001030 int err, n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031
Jeff Dike91acb212005-10-10 23:10:32 -04001032 if(thread_fd == -1){
1033 while((req = elv_next_request(q)) != NULL){
1034 err = prepare_request(req, &io_req);
1035 if(!err){
1036 do_io(&io_req);
1037 __ubd_finish(req, io_req.error);
1038 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 }
1040 }
Jeff Dike91acb212005-10-10 23:10:32 -04001041 else {
1042 if(do_ubd || (req = elv_next_request(q)) == NULL)
1043 return;
1044 err = prepare_request(req, &io_req);
1045 if(!err){
1046 do_ubd = ubd_handler;
1047 n = os_write_file(thread_fd, (char *) &io_req,
1048 sizeof(io_req));
1049 if(n != sizeof(io_req))
1050 printk("write to io thread failed, "
1051 "errno = %d\n", -n);
1052 }
1053 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054}
1055
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001056static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
1057{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001058 struct ubd *ubd_dev = bdev->bd_disk->private_data;
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001059
1060 geo->heads = 128;
1061 geo->sectors = 32;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001062 geo->cylinders = ubd_dev->size / (128 * 32 * 512);
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001063 return 0;
1064}
1065
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066static int ubd_ioctl(struct inode * inode, struct file * file,
1067 unsigned int cmd, unsigned long arg)
1068{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001069 struct ubd *ubd_dev = inode->i_bdev->bd_disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 struct hd_driveid ubd_id = {
1071 .cyls = 0,
1072 .heads = 128,
1073 .sectors = 32,
1074 };
1075
1076 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 struct cdrom_volctrl volume;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 case HDIO_GET_IDENTITY:
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001079 ubd_id.cyls = ubd_dev->size / (128 * 32 * 512);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 if(copy_to_user((char __user *) arg, (char *) &ubd_id,
1081 sizeof(ubd_id)))
1082 return(-EFAULT);
1083 return(0);
1084
1085 case CDROMVOLREAD:
1086 if(copy_from_user(&volume, (char __user *) arg, sizeof(volume)))
1087 return(-EFAULT);
1088 volume.channel0 = 255;
1089 volume.channel1 = 255;
1090 volume.channel2 = 255;
1091 volume.channel3 = 255;
1092 if(copy_to_user((char __user *) arg, &volume, sizeof(volume)))
1093 return(-EFAULT);
1094 return(0);
1095 }
1096 return(-EINVAL);
1097}
1098
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001099static int path_requires_switch(char *from_cmdline, char *from_cow, char *cow)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100{
1101 struct uml_stat buf1, buf2;
1102 int err;
1103
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001104 if(from_cmdline == NULL)
1105 return 0;
1106 if(!strcmp(from_cmdline, from_cow))
1107 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108
1109 err = os_stat_file(from_cmdline, &buf1);
1110 if(err < 0){
1111 printk("Couldn't stat '%s', err = %d\n", from_cmdline, -err);
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001112 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 }
1114 err = os_stat_file(from_cow, &buf2);
1115 if(err < 0){
1116 printk("Couldn't stat '%s', err = %d\n", from_cow, -err);
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001117 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 }
1119 if((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino))
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001120 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121
1122 printk("Backing file mismatch - \"%s\" requested,\n"
1123 "\"%s\" specified in COW header of \"%s\"\n",
1124 from_cmdline, from_cow, cow);
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001125 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126}
1127
1128static int backing_file_mismatch(char *file, __u64 size, time_t mtime)
1129{
1130 unsigned long modtime;
Paolo 'Blaisorblade' Giarrussofe1db502006-02-24 13:03:58 -08001131 unsigned long long actual;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 int err;
1133
1134 err = os_file_modtime(file, &modtime);
1135 if(err < 0){
1136 printk("Failed to get modification time of backing file "
1137 "\"%s\", err = %d\n", file, -err);
1138 return(err);
1139 }
1140
1141 err = os_file_size(file, &actual);
1142 if(err < 0){
1143 printk("Failed to get size of backing file \"%s\", "
1144 "err = %d\n", file, -err);
1145 return(err);
1146 }
1147
1148 if(actual != size){
1149 /*__u64 can be a long on AMD64 and with %lu GCC complains; so
1150 * the typecast.*/
1151 printk("Size mismatch (%llu vs %llu) of COW header vs backing "
1152 "file\n", (unsigned long long) size, actual);
1153 return(-EINVAL);
1154 }
1155 if(modtime != mtime){
1156 printk("mtime mismatch (%ld vs %ld) of COW header vs backing "
1157 "file\n", mtime, modtime);
1158 return(-EINVAL);
1159 }
1160 return(0);
1161}
1162
1163int read_cow_bitmap(int fd, void *buf, int offset, int len)
1164{
1165 int err;
1166
1167 err = os_seek_file(fd, offset);
1168 if(err < 0)
1169 return(err);
1170
1171 err = os_read_file(fd, buf, len);
1172 if(err < 0)
1173 return(err);
1174
1175 return(0);
1176}
1177
Jeff Dike6c29256c2006-03-27 01:14:37 -08001178int open_ubd_file(char *file, struct openflags *openflags, int shared,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 char **backing_file_out, int *bitmap_offset_out,
1180 unsigned long *bitmap_len_out, int *data_offset_out,
1181 int *create_cow_out)
1182{
1183 time_t mtime;
1184 unsigned long long size;
1185 __u32 version, align;
1186 char *backing_file;
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001187 int fd, err, sectorsize, asked_switch, mode = 0644;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188
1189 fd = os_open_file(file, *openflags, mode);
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001190 if (fd < 0) {
1191 if ((fd == -ENOENT) && (create_cow_out != NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 *create_cow_out = 1;
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001193 if (!openflags->w ||
1194 ((fd != -EROFS) && (fd != -EACCES)))
1195 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 openflags->w = 0;
1197 fd = os_open_file(file, *openflags, mode);
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001198 if (fd < 0)
1199 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 }
1201
Jeff Dike6c29256c2006-03-27 01:14:37 -08001202 if(shared)
1203 printk("Not locking \"%s\" on the host\n", file);
1204 else {
1205 err = os_lock_file(fd, openflags->w);
1206 if(err < 0){
1207 printk("Failed to lock '%s', err = %d\n", file, -err);
1208 goto out_close;
1209 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 }
1211
Andreas Mohrd6e05ed2006-06-26 18:35:02 +02001212 /* Successful return case! */
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001213 if(backing_file_out == NULL)
1214 return(fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215
1216 err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime,
1217 &size, &sectorsize, &align, bitmap_offset_out);
1218 if(err && (*backing_file_out != NULL)){
1219 printk("Failed to read COW header from COW file \"%s\", "
1220 "errno = %d\n", file, -err);
1221 goto out_close;
1222 }
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001223 if(err)
1224 return(fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001226 asked_switch = path_requires_switch(*backing_file_out, backing_file, file);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001228 /* Allow switching only if no mismatch. */
1229 if (asked_switch && !backing_file_mismatch(*backing_file_out, size, mtime)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 printk("Switching backing file to '%s'\n", *backing_file_out);
1231 err = write_cow_header(file, fd, *backing_file_out,
1232 sectorsize, align, &size);
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001233 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 printk("Switch failed, errno = %d\n", -err);
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001235 goto out_close;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 }
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001237 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238 *backing_file_out = backing_file;
1239 err = backing_file_mismatch(*backing_file_out, size, mtime);
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001240 if (err)
1241 goto out_close;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 }
1243
1244 cow_sizes(version, size, sectorsize, align, *bitmap_offset_out,
1245 bitmap_len_out, data_offset_out);
1246
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001247 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248 out_close:
1249 os_close_file(fd);
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001250 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251}
1252
1253int create_cow_file(char *cow_file, char *backing_file, struct openflags flags,
1254 int sectorsize, int alignment, int *bitmap_offset_out,
1255 unsigned long *bitmap_len_out, int *data_offset_out)
1256{
1257 int err, fd;
1258
1259 flags.c = 1;
Jeff Dike6c29256c2006-03-27 01:14:37 -08001260 fd = open_ubd_file(cow_file, &flags, 0, NULL, NULL, NULL, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 if(fd < 0){
1262 err = fd;
1263 printk("Open of COW file '%s' failed, errno = %d\n", cow_file,
1264 -err);
1265 goto out;
1266 }
1267
1268 err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment,
1269 bitmap_offset_out, bitmap_len_out,
1270 data_offset_out);
1271 if(!err)
1272 return(fd);
1273 os_close_file(fd);
1274 out:
1275 return(err);
1276}
1277
Jeff Dike91acb212005-10-10 23:10:32 -04001278static int update_bitmap(struct io_thread_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279{
Jeff Dike91acb212005-10-10 23:10:32 -04001280 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281
Jeff Dike91acb212005-10-10 23:10:32 -04001282 if(req->cow_offset == -1)
1283 return(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284
Jeff Dike91acb212005-10-10 23:10:32 -04001285 n = os_seek_file(req->fds[1], req->cow_offset);
1286 if(n < 0){
1287 printk("do_io - bitmap lseek failed : err = %d\n", -n);
1288 return(1);
1289 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290
Jeff Dike91acb212005-10-10 23:10:32 -04001291 n = os_write_file(req->fds[1], &req->bitmap_words,
1292 sizeof(req->bitmap_words));
1293 if(n != sizeof(req->bitmap_words)){
1294 printk("do_io - bitmap update failed, err = %d fd = %d\n", -n,
1295 req->fds[1]);
1296 return(1);
1297 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298
Jeff Dike91acb212005-10-10 23:10:32 -04001299 return(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300}
Jeff Dike91acb212005-10-10 23:10:32 -04001301
1302void do_io(struct io_thread_req *req)
1303{
1304 char *buf;
1305 unsigned long len;
1306 int n, nsectors, start, end, bit;
1307 int err;
1308 __u64 off;
1309
1310 nsectors = req->length / req->sectorsize;
1311 start = 0;
1312 do {
1313 bit = ubd_test_bit(start, (unsigned char *) &req->sector_mask);
1314 end = start;
1315 while((end < nsectors) &&
1316 (ubd_test_bit(end, (unsigned char *)
1317 &req->sector_mask) == bit))
1318 end++;
1319
1320 off = req->offset + req->offsets[bit] +
1321 start * req->sectorsize;
1322 len = (end - start) * req->sectorsize;
1323 buf = &req->buffer[start * req->sectorsize];
1324
1325 err = os_seek_file(req->fds[bit], off);
1326 if(err < 0){
1327 printk("do_io - lseek failed : err = %d\n", -err);
1328 req->error = 1;
1329 return;
1330 }
1331 if(req->op == UBD_READ){
1332 n = 0;
1333 do {
1334 buf = &buf[n];
1335 len -= n;
1336 n = os_read_file(req->fds[bit], buf, len);
1337 if (n < 0) {
1338 printk("do_io - read failed, err = %d "
1339 "fd = %d\n", -n, req->fds[bit]);
1340 req->error = 1;
1341 return;
1342 }
1343 } while((n < len) && (n != 0));
1344 if (n < len) memset(&buf[n], 0, len - n);
1345 } else {
1346 n = os_write_file(req->fds[bit], buf, len);
1347 if(n != len){
1348 printk("do_io - write failed err = %d "
1349 "fd = %d\n", -n, req->fds[bit]);
1350 req->error = 1;
1351 return;
1352 }
1353 }
1354
1355 start = end;
1356 } while(start < nsectors);
1357
1358 req->error = update_bitmap(req);
1359}
1360
1361/* Changed in start_io_thread, which is serialized by being called only
1362 * from ubd_init, which is an initcall.
1363 */
1364int kernel_fd = -1;
1365
1366/* Only changed by the io thread */
1367int io_count = 0;
1368
1369int io_thread(void *arg)
1370{
1371 struct io_thread_req req;
1372 int n;
1373
1374 ignore_sigwinch_sig();
1375 while(1){
1376 n = os_read_file(kernel_fd, &req, sizeof(req));
1377 if(n != sizeof(req)){
1378 if(n < 0)
1379 printk("io_thread - read failed, fd = %d, "
1380 "err = %d\n", kernel_fd, -n);
1381 else {
1382 printk("io_thread - short read, fd = %d, "
1383 "length = %d\n", kernel_fd, n);
1384 }
1385 continue;
1386 }
1387 io_count++;
1388 do_io(&req);
1389 n = os_write_file(kernel_fd, &req, sizeof(req));
1390 if(n != sizeof(req))
1391 printk("io_thread - write failed, fd = %d, err = %d\n",
1392 kernel_fd, -n);
1393 }
Jeff Dike91acb212005-10-10 23:10:32 -04001394
Jeff Dike1b57e9c2006-01-06 00:18:49 -08001395 return 0;
1396}