blob: bc458f57921b0f232d0f078bc5014424281e8617 [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
109static DEFINE_SPINLOCK(ubd_io_lock);
110static DEFINE_SPINLOCK(ubd_lock);
111
Jeff Dike91acb212005-10-10 23:10:32 -0400112static void (*do_ubd)(void);
113
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114static int ubd_open(struct inode * inode, struct file * filp);
115static int ubd_release(struct inode * inode, struct file * file);
116static int ubd_ioctl(struct inode * inode, struct file * file,
117 unsigned int cmd, unsigned long arg);
Christoph Hellwiga885c8c2006-01-08 01:02:50 -0800118static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119
120#define MAX_DEV (8)
121
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122static struct block_device_operations ubd_blops = {
123 .owner = THIS_MODULE,
124 .open = ubd_open,
125 .release = ubd_release,
126 .ioctl = ubd_ioctl,
Christoph Hellwiga885c8c2006-01-08 01:02:50 -0800127 .getgeo = ubd_getgeo,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128};
129
130/* Protected by the queue_lock */
131static request_queue_t *ubd_queue;
132
133/* Protected by ubd_lock */
134static int fake_major = MAJOR_NR;
135
136static struct gendisk *ubd_gendisk[MAX_DEV];
137static struct gendisk *fake_gendisk[MAX_DEV];
Jeff Dike6c29256c2006-03-27 01:14:37 -0800138
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139#ifdef CONFIG_BLK_DEV_UBD_SYNC
140#define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 1, .c = 0, \
141 .cl = 1 })
142#else
143#define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 0, .c = 0, \
144 .cl = 1 })
145#endif
146
147/* Not protected - changed only in ubd_setup_common and then only to
148 * to enable O_SYNC.
149 */
150static struct openflags global_openflags = OPEN_FLAGS;
151
152struct cow {
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -0700153 /* This is the backing file, actually */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 char *file;
155 int fd;
156 unsigned long *bitmap;
157 unsigned long bitmap_len;
158 int bitmap_offset;
159 int data_offset;
160};
161
162struct ubd {
163 char *file;
164 int count;
165 int fd;
166 __u64 size;
167 struct openflags boot_openflags;
168 struct openflags openflags;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800169 int shared;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 int no_cow;
171 struct cow cow;
172 struct platform_device pdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173};
174
175#define DEFAULT_COW { \
176 .file = NULL, \
177 .fd = -1, \
178 .bitmap = NULL, \
179 .bitmap_offset = 0, \
180 .data_offset = 0, \
181}
182
183#define DEFAULT_UBD { \
184 .file = NULL, \
185 .count = 0, \
186 .fd = -1, \
187 .size = -1, \
188 .boot_openflags = OPEN_FLAGS, \
189 .openflags = OPEN_FLAGS, \
190 .no_cow = 0, \
Jeff Dike6c29256c2006-03-27 01:14:37 -0800191 .shared = 0, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 .cow = DEFAULT_COW, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193}
194
195struct ubd ubd_dev[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_UBD };
196
197static int ubd0_init(void)
198{
199 struct ubd *dev = &ubd_dev[0];
200
201 if(dev->file == NULL)
202 dev->file = "root_fs";
203 return(0);
204}
205
206__initcall(ubd0_init);
207
208/* Only changed by fake_ide_setup which is a setup */
209static int fake_ide = 0;
210static struct proc_dir_entry *proc_ide_root = NULL;
211static struct proc_dir_entry *proc_ide = NULL;
212
213static void make_proc_ide(void)
214{
215 proc_ide_root = proc_mkdir("ide", NULL);
216 proc_ide = proc_mkdir("ide0", proc_ide_root);
217}
218
219static int proc_ide_read_media(char *page, char **start, off_t off, int count,
220 int *eof, void *data)
221{
222 int len;
223
224 strcpy(page, "disk\n");
225 len = strlen("disk\n");
226 len -= off;
227 if (len < count){
228 *eof = 1;
229 if (len <= 0) return 0;
230 }
231 else len = count;
232 *start = page + off;
233 return len;
234}
235
236static void make_ide_entries(char *dev_name)
237{
238 struct proc_dir_entry *dir, *ent;
239 char name[64];
240
241 if(proc_ide_root == NULL) make_proc_ide();
242
243 dir = proc_mkdir(dev_name, proc_ide);
244 if(!dir) return;
245
246 ent = create_proc_entry("media", S_IFREG|S_IRUGO, dir);
247 if(!ent) return;
248 ent->nlink = 1;
249 ent->data = NULL;
250 ent->read_proc = proc_ide_read_media;
251 ent->write_proc = NULL;
252 sprintf(name,"ide0/%s", dev_name);
253 proc_symlink(dev_name, proc_ide_root, name);
254}
255
256static int fake_ide_setup(char *str)
257{
258 fake_ide = 1;
259 return(1);
260}
261
262__setup("fake_ide", fake_ide_setup);
263
264__uml_help(fake_ide_setup,
265"fake_ide\n"
266" Create ide0 entries that map onto ubd devices.\n\n"
267);
268
269static int parse_unit(char **ptr)
270{
271 char *str = *ptr, *end;
272 int n = -1;
273
274 if(isdigit(*str)) {
275 n = simple_strtoul(str, &end, 0);
276 if(end == str)
277 return(-1);
278 *ptr = end;
279 }
280 else if (('a' <= *str) && (*str <= 'h')) {
281 n = *str - 'a';
282 str++;
283 *ptr = str;
284 }
285 return(n);
286}
287
288static int ubd_setup_common(char *str, int *index_out)
289{
290 struct ubd *dev;
291 struct openflags flags = global_openflags;
292 char *backing_file;
293 int n, err, i;
294
295 if(index_out) *index_out = -1;
296 n = *str;
297 if(n == '='){
298 char *end;
299 int major;
300
301 str++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 if(!strcmp(str, "sync")){
303 global_openflags = of_sync(global_openflags);
304 return(0);
305 }
306 major = simple_strtoul(str, &end, 0);
307 if((*end != '\0') || (end == str)){
Jeff Dike6c29256c2006-03-27 01:14:37 -0800308 printk(KERN_ERR
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 "ubd_setup : didn't parse major number\n");
310 return(1);
311 }
312
313 err = 1;
314 spin_lock(&ubd_lock);
315 if(fake_major != MAJOR_NR){
316 printk(KERN_ERR "Can't assign a fake major twice\n");
317 goto out1;
318 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800319
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 fake_major = major;
321
322 printk(KERN_INFO "Setting extra ubd major number to %d\n",
323 major);
324 err = 0;
325 out1:
326 spin_unlock(&ubd_lock);
327 return(err);
328 }
329
330 n = parse_unit(&str);
331 if(n < 0){
332 printk(KERN_ERR "ubd_setup : couldn't parse unit number "
333 "'%s'\n", str);
334 return(1);
335 }
336 if(n >= MAX_DEV){
337 printk(KERN_ERR "ubd_setup : index %d out of range "
338 "(%d devices, from 0 to %d)\n", n, MAX_DEV, MAX_DEV - 1);
339 return(1);
340 }
341
342 err = 1;
343 spin_lock(&ubd_lock);
344
345 dev = &ubd_dev[n];
346 if(dev->file != NULL){
347 printk(KERN_ERR "ubd_setup : device already configured\n");
348 goto out;
349 }
350
351 if (index_out)
352 *index_out = n;
353
Jeff Dike6c29256c2006-03-27 01:14:37 -0800354 for (i = 0; i < sizeof("rscd="); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 switch (*str) {
356 case 'r':
357 flags.w = 0;
358 break;
359 case 's':
360 flags.s = 1;
361 break;
362 case 'd':
363 dev->no_cow = 1;
364 break;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800365 case 'c':
366 dev->shared = 1;
367 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 case '=':
369 str++;
370 goto break_loop;
371 default:
Jeff Dike6c29256c2006-03-27 01:14:37 -0800372 printk(KERN_ERR "ubd_setup : Expected '=' or flag letter (r, s, c, or d)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 goto out;
374 }
375 str++;
376 }
377
378 if (*str == '=')
379 printk(KERN_ERR "ubd_setup : Too many flags specified\n");
380 else
381 printk(KERN_ERR "ubd_setup : Expected '='\n");
382 goto out;
383
384break_loop:
385 err = 0;
386 backing_file = strchr(str, ',');
387
388 if (!backing_file) {
389 backing_file = strchr(str, ':');
390 }
391
392 if(backing_file){
393 if(dev->no_cow)
394 printk(KERN_ERR "Can't specify both 'd' and a "
395 "cow file\n");
396 else {
397 *backing_file = '\0';
398 backing_file++;
399 }
400 }
401 dev->file = str;
402 dev->cow.file = backing_file;
403 dev->boot_openflags = flags;
404out:
405 spin_unlock(&ubd_lock);
406 return(err);
407}
408
409static int ubd_setup(char *str)
410{
411 ubd_setup_common(str, NULL);
412 return(1);
413}
414
415__setup("ubd", ubd_setup);
416__uml_help(ubd_setup,
417"ubd<n><flags>=<filename>[(:|,)<filename2>]\n"
418" This is used to associate a device with a file in the underlying\n"
419" filesystem. When specifying two filenames, the first one is the\n"
420" COW name and the second is the backing file name. As separator you can\n"
421" use either a ':' or a ',': the first one allows writing things like;\n"
422" ubd0=~/Uml/root_cow:~/Uml/root_backing_file\n"
423" while with a ',' the shell would not expand the 2nd '~'.\n"
424" When using only one filename, UML will detect whether to thread it like\n"
425" a COW file or a backing file. To override this detection, add the 'd'\n"
426" flag:\n"
427" ubd0d=BackingFile\n"
428" Usually, there is a filesystem in the file, but \n"
429" that's not required. Swap devices containing swap files can be\n"
430" specified like this. Also, a file which doesn't contain a\n"
431" filesystem can have its contents read in the virtual \n"
432" machine by running 'dd' on the device. <n> must be in the range\n"
433" 0 to 7. Appending an 'r' to the number will cause that device\n"
434" to be mounted read-only. For example ubd1r=./ext_fs. Appending\n"
435" an 's' will cause data to be written to disk on the host immediately.\n\n"
436);
437
438static int udb_setup(char *str)
439{
440 printk("udb%s specified on command line is almost certainly a ubd -> "
441 "udb TYPO\n", str);
442 return(1);
443}
444
445__setup("udb", udb_setup);
446__uml_help(udb_setup,
447"udb\n"
Jeff Dike0894e272005-05-28 15:51:55 -0700448" This option is here solely to catch ubd -> udb typos, which can be\n"
449" to impossible to catch visually unless you specifically look for\n"
450" them. The only result of any option starting with 'udb' is an error\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451" in the boot output.\n\n"
452);
453
454static int fakehd_set = 0;
455static int fakehd(char *str)
456{
457 printk(KERN_INFO "fakehd : Changing ubd name to \"hd\".\n");
458 fakehd_set = 1;
459 return 1;
460}
461
462__setup("fakehd", fakehd);
463__uml_help(fakehd,
464"fakehd\n"
465" Change the ubd device name to \"hd\".\n\n"
466);
467
468static void do_ubd_request(request_queue_t * q);
Jeff Dike91acb212005-10-10 23:10:32 -0400469
470/* Only changed by ubd_init, which is an initcall. */
471int thread_fd = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472
473/* Changed by ubd_handler, which is serialized because interrupts only
474 * happen on CPU 0.
475 */
476int intr_count = 0;
477
478/* call ubd_finish if you need to serialize */
Jeff Dike91acb212005-10-10 23:10:32 -0400479static void __ubd_finish(struct request *req, int error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480{
Jeff Dike91acb212005-10-10 23:10:32 -0400481 int nsect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482
Jeff Dike91acb212005-10-10 23:10:32 -0400483 if(error){
484 end_request(req, 0);
485 return;
486 }
487 nsect = req->current_nr_sectors;
488 req->sector += nsect;
489 req->buffer += nsect << 9;
490 req->errors = 0;
491 req->nr_sectors -= nsect;
492 req->current_nr_sectors = 0;
493 end_request(req, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494}
495
Jeff Dike91acb212005-10-10 23:10:32 -0400496static inline void ubd_finish(struct request *req, int error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497{
Jeff Dike91acb212005-10-10 23:10:32 -0400498 spin_lock(&ubd_io_lock);
499 __ubd_finish(req, error);
500 spin_unlock(&ubd_io_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501}
502
Jeff Dike91acb212005-10-10 23:10:32 -0400503/* Called without ubd_io_lock held */
504static void ubd_handler(void)
505{
506 struct io_thread_req req;
507 struct request *rq = elv_next_request(ubd_queue);
508 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509
Jeff Dike91acb212005-10-10 23:10:32 -0400510 do_ubd = NULL;
511 intr_count++;
512 n = os_read_file(thread_fd, &req, sizeof(req));
513 if(n != sizeof(req)){
514 printk(KERN_ERR "Pid %d - spurious interrupt in ubd_handler, "
515 "err = %d\n", os_getpid(), -n);
516 spin_lock(&ubd_io_lock);
517 end_request(rq, 0);
518 spin_unlock(&ubd_io_lock);
519 return;
520 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800521
Jeff Dike91acb212005-10-10 23:10:32 -0400522 ubd_finish(rq, req.error);
523 reactivate_fd(thread_fd, UBD_IRQ);
524 do_ubd_request(ubd_queue);
525}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526
Al Viro7bea96f2006-10-08 22:49:34 +0100527static irqreturn_t ubd_intr(int irq, void *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528{
Jeff Dike91acb212005-10-10 23:10:32 -0400529 ubd_handler();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 return(IRQ_HANDLED);
531}
532
Jeff Dike91acb212005-10-10 23:10:32 -0400533/* Only changed by ubd_init, which is an initcall. */
534static int io_pid = -1;
535
536void kill_io_thread(void)
537{
Jeff Dike6c29256c2006-03-27 01:14:37 -0800538 if(io_pid != -1)
Jeff Dike91acb212005-10-10 23:10:32 -0400539 os_kill_process(io_pid, 1);
540}
541
542__uml_exitcall(kill_io_thread);
543
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544static int ubd_file_size(struct ubd *dev, __u64 *size_out)
545{
546 char *file;
547
548 file = dev->cow.file ? dev->cow.file : dev->file;
549 return(os_file_size(file, size_out));
550}
551
552static void ubd_close(struct ubd *dev)
553{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 os_close_file(dev->fd);
555 if(dev->cow.file == NULL)
556 return;
557
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 os_close_file(dev->cow.fd);
559 vfree(dev->cow.bitmap);
560 dev->cow.bitmap = NULL;
561}
562
563static int ubd_open_dev(struct ubd *dev)
564{
565 struct openflags flags;
566 char **back_ptr;
567 int err, create_cow, *create_ptr;
568
569 dev->openflags = dev->boot_openflags;
570 create_cow = 0;
571 create_ptr = (dev->cow.file != NULL) ? &create_cow : NULL;
572 back_ptr = dev->no_cow ? NULL : &dev->cow.file;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800573 dev->fd = open_ubd_file(dev->file, &dev->openflags, dev->shared,
574 back_ptr, &dev->cow.bitmap_offset,
575 &dev->cow.bitmap_len, &dev->cow.data_offset,
576 create_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577
578 if((dev->fd == -ENOENT) && create_cow){
Jeff Dike6c29256c2006-03-27 01:14:37 -0800579 dev->fd = create_cow_file(dev->file, dev->cow.file,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 dev->openflags, 1 << 9, PAGE_SIZE,
Jeff Dike6c29256c2006-03-27 01:14:37 -0800581 &dev->cow.bitmap_offset,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 &dev->cow.bitmap_len,
583 &dev->cow.data_offset);
584 if(dev->fd >= 0){
585 printk(KERN_INFO "Creating \"%s\" as COW file for "
586 "\"%s\"\n", dev->file, dev->cow.file);
587 }
588 }
589
590 if(dev->fd < 0){
591 printk("Failed to open '%s', errno = %d\n", dev->file,
592 -dev->fd);
593 return(dev->fd);
594 }
595
596 if(dev->cow.file != NULL){
597 err = -ENOMEM;
598 dev->cow.bitmap = (void *) vmalloc(dev->cow.bitmap_len);
599 if(dev->cow.bitmap == NULL){
600 printk(KERN_ERR "Failed to vmalloc COW bitmap\n");
601 goto error;
602 }
603 flush_tlb_kernel_vm();
604
Jeff Dike6c29256c2006-03-27 01:14:37 -0800605 err = read_cow_bitmap(dev->fd, dev->cow.bitmap,
606 dev->cow.bitmap_offset,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 dev->cow.bitmap_len);
608 if(err < 0)
609 goto error;
610
611 flags = dev->openflags;
612 flags.w = 0;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800613 err = open_ubd_file(dev->cow.file, &flags, dev->shared, NULL,
614 NULL, NULL, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 if(err < 0) goto error;
616 dev->cow.fd = err;
617 }
618 return(0);
619 error:
620 os_close_file(dev->fd);
621 return(err);
622}
623
624static int ubd_new_disk(int major, u64 size, int unit,
625 struct gendisk **disk_out)
626
627{
628 struct gendisk *disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629
630 disk = alloc_disk(1 << UBD_SHIFT);
631 if(disk == NULL)
632 return(-ENOMEM);
633
634 disk->major = major;
635 disk->first_minor = unit << UBD_SHIFT;
636 disk->fops = &ubd_blops;
637 set_capacity(disk, size / 512);
Greg Kroah-Hartmance7b0f42005-06-20 21:15:16 -0700638 if(major == MAJOR_NR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 sprintf(disk->disk_name, "ubd%c", 'a' + unit);
Greg Kroah-Hartmance7b0f42005-06-20 21:15:16 -0700640 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 sprintf(disk->disk_name, "ubd_fake%d", unit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642
643 /* sysfs register (not for ide fake devices) */
644 if (major == MAJOR_NR) {
645 ubd_dev[unit].pdev.id = unit;
646 ubd_dev[unit].pdev.name = DRIVER_NAME;
647 platform_device_register(&ubd_dev[unit].pdev);
648 disk->driverfs_dev = &ubd_dev[unit].pdev.dev;
649 }
650
651 disk->private_data = &ubd_dev[unit];
652 disk->queue = ubd_queue;
653 add_disk(disk);
654
655 *disk_out = disk;
656 return 0;
657}
658
659#define ROUND_BLOCK(n) ((n + ((1 << 9) - 1)) & (-1 << 9))
660
661static int ubd_add(int n)
662{
663 struct ubd *dev = &ubd_dev[n];
664 int err;
665
Jeff Dikeec7cf782005-09-03 15:57:29 -0700666 err = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 if(dev->file == NULL)
Jeff Dikeec7cf782005-09-03 15:57:29 -0700668 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 err = ubd_file_size(dev, &dev->size);
671 if(err < 0)
Jeff Dike80c13742006-09-29 01:58:51 -0700672 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673
674 dev->size = ROUND_BLOCK(dev->size);
675
676 err = ubd_new_disk(MAJOR_NR, dev->size, n, &ubd_gendisk[n]);
Jeff Dike6c29256c2006-03-27 01:14:37 -0800677 if(err)
Jeff Dike80c13742006-09-29 01:58:51 -0700678 goto out;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800679
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 if(fake_major != MAJOR_NR)
Jeff Dike6c29256c2006-03-27 01:14:37 -0800681 ubd_new_disk(fake_major, dev->size, n,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 &fake_gendisk[n]);
683
684 /* perhaps this should also be under the "if (fake_major)" above */
685 /* using the fake_disk->disk_name and also the fakehd_set name */
686 if (fake_ide)
687 make_ide_entries(ubd_gendisk[n]->disk_name);
688
Jeff Dikeec7cf782005-09-03 15:57:29 -0700689 err = 0;
Jeff Dikeec7cf782005-09-03 15:57:29 -0700690out:
691 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692}
693
694static int ubd_config(char *str)
695{
696 int n, err;
697
Jeff Dike970d6e32006-01-06 00:18:48 -0800698 str = kstrdup(str, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 if(str == NULL){
700 printk(KERN_ERR "ubd_config failed to strdup string\n");
701 return(1);
702 }
703 err = ubd_setup_common(str, &n);
704 if(err){
705 kfree(str);
706 return(-1);
707 }
708 if(n == -1) return(0);
709
710 spin_lock(&ubd_lock);
711 err = ubd_add(n);
712 if(err)
713 ubd_dev[n].file = NULL;
714 spin_unlock(&ubd_lock);
715
716 return(err);
717}
718
719static int ubd_get_config(char *name, char *str, int size, char **error_out)
720{
721 struct ubd *dev;
722 int n, len = 0;
723
724 n = parse_unit(&name);
725 if((n >= MAX_DEV) || (n < 0)){
726 *error_out = "ubd_get_config : device number out of range";
727 return(-1);
728 }
729
730 dev = &ubd_dev[n];
731 spin_lock(&ubd_lock);
732
733 if(dev->file == NULL){
734 CONFIG_CHUNK(str, size, len, "", 1);
735 goto out;
736 }
737
738 CONFIG_CHUNK(str, size, len, dev->file, 0);
739
740 if(dev->cow.file != NULL){
741 CONFIG_CHUNK(str, size, len, ",", 0);
742 CONFIG_CHUNK(str, size, len, dev->cow.file, 1);
743 }
744 else CONFIG_CHUNK(str, size, len, "", 1);
745
746 out:
747 spin_unlock(&ubd_lock);
748 return(len);
749}
750
Jeff Dike29d56cf2005-06-25 14:55:25 -0700751static int ubd_id(char **str, int *start_out, int *end_out)
752{
753 int n;
754
755 n = parse_unit(str);
756 *start_out = 0;
757 *end_out = MAX_DEV - 1;
758 return n;
759}
760
761static int ubd_remove(int n)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762{
763 struct ubd *dev;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700764 int err = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765
Jeff Dike29d56cf2005-06-25 14:55:25 -0700766 spin_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767
768 if(ubd_gendisk[n] == NULL)
769 goto out;
770
Jeff Dike29d56cf2005-06-25 14:55:25 -0700771 dev = &ubd_dev[n];
772
773 if(dev->file == NULL)
774 goto out;
775
776 /* you cannot remove a open disk */
777 err = -EBUSY;
778 if(dev->count > 0)
779 goto out;
780
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 del_gendisk(ubd_gendisk[n]);
782 put_disk(ubd_gendisk[n]);
783 ubd_gendisk[n] = NULL;
784
785 if(fake_gendisk[n] != NULL){
786 del_gendisk(fake_gendisk[n]);
787 put_disk(fake_gendisk[n]);
788 fake_gendisk[n] = NULL;
789 }
790
791 platform_device_unregister(&dev->pdev);
792 *dev = ((struct ubd) DEFAULT_UBD);
793 err = 0;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700794out:
795 spin_unlock(&ubd_lock);
796 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797}
798
799static struct mc_device ubd_mc = {
800 .name = "ubd",
801 .config = ubd_config,
802 .get_config = ubd_get_config,
Jeff Dike29d56cf2005-06-25 14:55:25 -0700803 .id = ubd_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 .remove = ubd_remove,
805};
806
807static int ubd_mc_init(void)
808{
809 mconsole_register_dev(&ubd_mc);
810 return 0;
811}
812
813__initcall(ubd_mc_init);
814
Russell King3ae5eae2005-11-09 22:32:44 +0000815static struct platform_driver ubd_driver = {
816 .driver = {
817 .name = DRIVER_NAME,
818 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819};
820
821int ubd_init(void)
822{
823 int i;
824
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 if (register_blkdev(MAJOR_NR, "ubd"))
826 return -1;
827
828 ubd_queue = blk_init_queue(do_ubd_request, &ubd_io_lock);
829 if (!ubd_queue) {
830 unregister_blkdev(MAJOR_NR, "ubd");
831 return -1;
832 }
833
834 if (fake_major != MAJOR_NR) {
835 char name[sizeof("ubd_nnn\0")];
836
837 snprintf(name, sizeof(name), "ubd_%d", fake_major);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 if (register_blkdev(fake_major, "ubd"))
839 return -1;
840 }
Russell King3ae5eae2005-11-09 22:32:44 +0000841 platform_driver_register(&ubd_driver);
Jeff Dike6c29256c2006-03-27 01:14:37 -0800842 for (i = 0; i < MAX_DEV; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 ubd_add(i);
844 return 0;
845}
846
847late_initcall(ubd_init);
848
Jeff Dike91acb212005-10-10 23:10:32 -0400849int ubd_driver_init(void){
850 unsigned long stack;
851 int err;
852
853 /* Set by CONFIG_BLK_DEV_UBD_SYNC or ubd=sync.*/
854 if(global_openflags.s){
855 printk(KERN_INFO "ubd: Synchronous mode\n");
856 /* Letting ubd=sync be like using ubd#s= instead of ubd#= is
857 * enough. So use anyway the io thread. */
858 }
859 stack = alloc_stack(0, 0);
Jeff Dike6c29256c2006-03-27 01:14:37 -0800860 io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *),
Jeff Dike91acb212005-10-10 23:10:32 -0400861 &thread_fd);
862 if(io_pid < 0){
Jeff Dike6c29256c2006-03-27 01:14:37 -0800863 printk(KERN_ERR
Jeff Dike91acb212005-10-10 23:10:32 -0400864 "ubd : Failed to start I/O thread (errno = %d) - "
865 "falling back to synchronous I/O\n", -io_pid);
866 io_pid = -1;
867 return(0);
868 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800869 err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr,
Thomas Gleixnerbd6aa652006-07-01 19:29:27 -0700870 IRQF_DISABLED, "ubd", ubd_dev);
Jeff Dike91acb212005-10-10 23:10:32 -0400871 if(err != 0)
872 printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err);
Jeff Dikef4c57a72006-03-31 02:30:10 -0800873 return 0;
Jeff Dike91acb212005-10-10 23:10:32 -0400874}
875
876device_initcall(ubd_driver_init);
877
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878static int ubd_open(struct inode *inode, struct file *filp)
879{
880 struct gendisk *disk = inode->i_bdev->bd_disk;
881 struct ubd *dev = disk->private_data;
882 int err = 0;
883
884 if(dev->count == 0){
885 err = ubd_open_dev(dev);
886 if(err){
887 printk(KERN_ERR "%s: Can't open \"%s\": errno = %d\n",
888 disk->disk_name, dev->file, -err);
889 goto out;
890 }
891 }
892 dev->count++;
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -0700893 set_disk_ro(disk, !dev->openflags.w);
894
895 /* This should no more be needed. And it didn't work anyway to exclude
896 * read-write remounting of filesystems.*/
897 /*if((filp->f_mode & FMODE_WRITE) && !dev->openflags.w){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 if(--dev->count == 0) ubd_close(dev);
899 err = -EROFS;
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -0700900 }*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 out:
902 return(err);
903}
904
905static int ubd_release(struct inode * inode, struct file * file)
906{
907 struct gendisk *disk = inode->i_bdev->bd_disk;
908 struct ubd *dev = disk->private_data;
909
910 if(--dev->count == 0)
911 ubd_close(dev);
912 return(0);
913}
914
Jeff Dike91acb212005-10-10 23:10:32 -0400915static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask,
916 __u64 *cow_offset, unsigned long *bitmap,
917 __u64 bitmap_offset, unsigned long *bitmap_words,
918 __u64 bitmap_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919{
Jeff Dike91acb212005-10-10 23:10:32 -0400920 __u64 sector = io_offset >> 9;
921 int i, update_bitmap = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922
Jeff Dike91acb212005-10-10 23:10:32 -0400923 for(i = 0; i < length >> 9; i++){
924 if(cow_mask != NULL)
925 ubd_set_bit(i, (unsigned char *) cow_mask);
926 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
927 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928
Jeff Dike91acb212005-10-10 23:10:32 -0400929 update_bitmap = 1;
930 ubd_set_bit(sector + i, (unsigned char *) bitmap);
931 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932
Jeff Dike91acb212005-10-10 23:10:32 -0400933 if(!update_bitmap)
934 return;
935
936 *cow_offset = sector / (sizeof(unsigned long) * 8);
937
938 /* This takes care of the case where we're exactly at the end of the
939 * device, and *cow_offset + 1 is off the end. So, just back it up
940 * by one word. Thanks to Lynn Kerby for the fix and James McMechan
941 * for the original diagnosis.
942 */
943 if(*cow_offset == ((bitmap_len + sizeof(unsigned long) - 1) /
944 sizeof(unsigned long) - 1))
945 (*cow_offset)--;
946
947 bitmap_words[0] = bitmap[*cow_offset];
948 bitmap_words[1] = bitmap[*cow_offset + 1];
949
950 *cow_offset *= sizeof(unsigned long);
951 *cow_offset += bitmap_offset;
952}
953
954static void cowify_req(struct io_thread_req *req, unsigned long *bitmap,
955 __u64 bitmap_offset, __u64 bitmap_len)
956{
957 __u64 sector = req->offset >> 9;
958 int i;
959
960 if(req->length > (sizeof(req->sector_mask) * 8) << 9)
961 panic("Operation too long");
962
963 if(req->op == UBD_READ) {
964 for(i = 0; i < req->length >> 9; i++){
965 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
Jeff Dike6c29256c2006-03-27 01:14:37 -0800966 ubd_set_bit(i, (unsigned char *)
Jeff Dike91acb212005-10-10 23:10:32 -0400967 &req->sector_mask);
968 }
969 }
970 else cowify_bitmap(req->offset, req->length, &req->sector_mask,
971 &req->cow_offset, bitmap, bitmap_offset,
972 req->bitmap_words, bitmap_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973}
974
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975/* Called with ubd_io_lock held */
Jeff Dike91acb212005-10-10 23:10:32 -0400976static int prepare_request(struct request *req, struct io_thread_req *io_req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977{
978 struct gendisk *disk = req->rq_disk;
979 struct ubd *dev = disk->private_data;
Jeff Dike91acb212005-10-10 23:10:32 -0400980 __u64 offset;
981 int len;
982
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -0700983 /* This should be impossible now */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 if((rq_data_dir(req) == WRITE) && !dev->openflags.w){
Jeff Dike6c29256c2006-03-27 01:14:37 -0800985 printk("Write attempted on readonly ubd device %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 disk->disk_name);
Jeff Dike91acb212005-10-10 23:10:32 -0400987 end_request(req, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 return(1);
989 }
990
Jeff Dike91acb212005-10-10 23:10:32 -0400991 offset = ((__u64) req->sector) << 9;
992 len = req->current_nr_sectors << 9;
993
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 io_req->fds[0] = (dev->cow.file != NULL) ? dev->cow.fd : dev->fd;
995 io_req->fds[1] = dev->fd;
Jeff Dike91acb212005-10-10 23:10:32 -0400996 io_req->cow_offset = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 io_req->offset = offset;
998 io_req->length = len;
999 io_req->error = 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001000 io_req->sector_mask = 0;
1001
1002 io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 io_req->offsets[0] = 0;
1004 io_req->offsets[1] = dev->cow.data_offset;
Jeff Dike91acb212005-10-10 23:10:32 -04001005 io_req->buffer = req->buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 io_req->sectorsize = 1 << 9;
1007
Jeff Dike91acb212005-10-10 23:10:32 -04001008 if(dev->cow.file != NULL)
1009 cowify_req(io_req, dev->cow.bitmap, dev->cow.bitmap_offset,
1010 dev->cow.bitmap_len);
1011
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 return(0);
1013}
1014
1015/* Called with ubd_io_lock held */
1016static void do_ubd_request(request_queue_t *q)
1017{
1018 struct io_thread_req io_req;
1019 struct request *req;
Jeff Dike91acb212005-10-10 23:10:32 -04001020 int err, n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021
Jeff Dike91acb212005-10-10 23:10:32 -04001022 if(thread_fd == -1){
1023 while((req = elv_next_request(q)) != NULL){
1024 err = prepare_request(req, &io_req);
1025 if(!err){
1026 do_io(&io_req);
1027 __ubd_finish(req, io_req.error);
1028 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 }
1030 }
Jeff Dike91acb212005-10-10 23:10:32 -04001031 else {
1032 if(do_ubd || (req = elv_next_request(q)) == NULL)
1033 return;
1034 err = prepare_request(req, &io_req);
1035 if(!err){
1036 do_ubd = ubd_handler;
1037 n = os_write_file(thread_fd, (char *) &io_req,
1038 sizeof(io_req));
1039 if(n != sizeof(io_req))
1040 printk("write to io thread failed, "
1041 "errno = %d\n", -n);
1042 }
1043 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044}
1045
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001046static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
1047{
1048 struct ubd *dev = bdev->bd_disk->private_data;
1049
1050 geo->heads = 128;
1051 geo->sectors = 32;
1052 geo->cylinders = dev->size / (128 * 32 * 512);
1053 return 0;
1054}
1055
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056static int ubd_ioctl(struct inode * inode, struct file * file,
1057 unsigned int cmd, unsigned long arg)
1058{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 struct ubd *dev = inode->i_bdev->bd_disk->private_data;
1060 struct hd_driveid ubd_id = {
1061 .cyls = 0,
1062 .heads = 128,
1063 .sectors = 32,
1064 };
1065
1066 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 struct cdrom_volctrl volume;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 case HDIO_GET_IDENTITY:
1069 ubd_id.cyls = dev->size / (128 * 32 * 512);
1070 if(copy_to_user((char __user *) arg, (char *) &ubd_id,
1071 sizeof(ubd_id)))
1072 return(-EFAULT);
1073 return(0);
1074
1075 case CDROMVOLREAD:
1076 if(copy_from_user(&volume, (char __user *) arg, sizeof(volume)))
1077 return(-EFAULT);
1078 volume.channel0 = 255;
1079 volume.channel1 = 255;
1080 volume.channel2 = 255;
1081 volume.channel3 = 255;
1082 if(copy_to_user((char __user *) arg, &volume, sizeof(volume)))
1083 return(-EFAULT);
1084 return(0);
1085 }
1086 return(-EINVAL);
1087}
1088
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001089static int path_requires_switch(char *from_cmdline, char *from_cow, char *cow)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090{
1091 struct uml_stat buf1, buf2;
1092 int err;
1093
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001094 if(from_cmdline == NULL)
1095 return 0;
1096 if(!strcmp(from_cmdline, from_cow))
1097 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098
1099 err = os_stat_file(from_cmdline, &buf1);
1100 if(err < 0){
1101 printk("Couldn't stat '%s', err = %d\n", from_cmdline, -err);
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001102 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 }
1104 err = os_stat_file(from_cow, &buf2);
1105 if(err < 0){
1106 printk("Couldn't stat '%s', err = %d\n", from_cow, -err);
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001107 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 }
1109 if((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino))
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001110 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111
1112 printk("Backing file mismatch - \"%s\" requested,\n"
1113 "\"%s\" specified in COW header of \"%s\"\n",
1114 from_cmdline, from_cow, cow);
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001115 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116}
1117
1118static int backing_file_mismatch(char *file, __u64 size, time_t mtime)
1119{
1120 unsigned long modtime;
Paolo 'Blaisorblade' Giarrussofe1db502006-02-24 13:03:58 -08001121 unsigned long long actual;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 int err;
1123
1124 err = os_file_modtime(file, &modtime);
1125 if(err < 0){
1126 printk("Failed to get modification time of backing file "
1127 "\"%s\", err = %d\n", file, -err);
1128 return(err);
1129 }
1130
1131 err = os_file_size(file, &actual);
1132 if(err < 0){
1133 printk("Failed to get size of backing file \"%s\", "
1134 "err = %d\n", file, -err);
1135 return(err);
1136 }
1137
1138 if(actual != size){
1139 /*__u64 can be a long on AMD64 and with %lu GCC complains; so
1140 * the typecast.*/
1141 printk("Size mismatch (%llu vs %llu) of COW header vs backing "
1142 "file\n", (unsigned long long) size, actual);
1143 return(-EINVAL);
1144 }
1145 if(modtime != mtime){
1146 printk("mtime mismatch (%ld vs %ld) of COW header vs backing "
1147 "file\n", mtime, modtime);
1148 return(-EINVAL);
1149 }
1150 return(0);
1151}
1152
1153int read_cow_bitmap(int fd, void *buf, int offset, int len)
1154{
1155 int err;
1156
1157 err = os_seek_file(fd, offset);
1158 if(err < 0)
1159 return(err);
1160
1161 err = os_read_file(fd, buf, len);
1162 if(err < 0)
1163 return(err);
1164
1165 return(0);
1166}
1167
Jeff Dike6c29256c2006-03-27 01:14:37 -08001168int open_ubd_file(char *file, struct openflags *openflags, int shared,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 char **backing_file_out, int *bitmap_offset_out,
1170 unsigned long *bitmap_len_out, int *data_offset_out,
1171 int *create_cow_out)
1172{
1173 time_t mtime;
1174 unsigned long long size;
1175 __u32 version, align;
1176 char *backing_file;
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001177 int fd, err, sectorsize, asked_switch, mode = 0644;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178
1179 fd = os_open_file(file, *openflags, mode);
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001180 if (fd < 0) {
1181 if ((fd == -ENOENT) && (create_cow_out != NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 *create_cow_out = 1;
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001183 if (!openflags->w ||
1184 ((fd != -EROFS) && (fd != -EACCES)))
1185 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 openflags->w = 0;
1187 fd = os_open_file(file, *openflags, mode);
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001188 if (fd < 0)
1189 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 }
1191
Jeff Dike6c29256c2006-03-27 01:14:37 -08001192 if(shared)
1193 printk("Not locking \"%s\" on the host\n", file);
1194 else {
1195 err = os_lock_file(fd, openflags->w);
1196 if(err < 0){
1197 printk("Failed to lock '%s', err = %d\n", file, -err);
1198 goto out_close;
1199 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 }
1201
Andreas Mohrd6e05ed2006-06-26 18:35:02 +02001202 /* Successful return case! */
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001203 if(backing_file_out == NULL)
1204 return(fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205
1206 err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime,
1207 &size, &sectorsize, &align, bitmap_offset_out);
1208 if(err && (*backing_file_out != NULL)){
1209 printk("Failed to read COW header from COW file \"%s\", "
1210 "errno = %d\n", file, -err);
1211 goto out_close;
1212 }
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001213 if(err)
1214 return(fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001216 asked_switch = path_requires_switch(*backing_file_out, backing_file, file);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001218 /* Allow switching only if no mismatch. */
1219 if (asked_switch && !backing_file_mismatch(*backing_file_out, size, mtime)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 printk("Switching backing file to '%s'\n", *backing_file_out);
1221 err = write_cow_header(file, fd, *backing_file_out,
1222 sectorsize, align, &size);
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001223 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 printk("Switch failed, errno = %d\n", -err);
Paolo 'Blaisorblade' Giarrusso4833aff2006-01-18 17:43:00 -08001225 goto out_close;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 }
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001227 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 *backing_file_out = backing_file;
1229 err = backing_file_mismatch(*backing_file_out, size, mtime);
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001230 if (err)
1231 goto out_close;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 }
1233
1234 cow_sizes(version, size, sectorsize, align, *bitmap_offset_out,
1235 bitmap_len_out, data_offset_out);
1236
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001237 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238 out_close:
1239 os_close_file(fd);
Paolo 'Blaisorblade' Giarrussoa374a482006-01-18 17:43:01 -08001240 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241}
1242
1243int create_cow_file(char *cow_file, char *backing_file, struct openflags flags,
1244 int sectorsize, int alignment, int *bitmap_offset_out,
1245 unsigned long *bitmap_len_out, int *data_offset_out)
1246{
1247 int err, fd;
1248
1249 flags.c = 1;
Jeff Dike6c29256c2006-03-27 01:14:37 -08001250 fd = open_ubd_file(cow_file, &flags, 0, NULL, NULL, NULL, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 if(fd < 0){
1252 err = fd;
1253 printk("Open of COW file '%s' failed, errno = %d\n", cow_file,
1254 -err);
1255 goto out;
1256 }
1257
1258 err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment,
1259 bitmap_offset_out, bitmap_len_out,
1260 data_offset_out);
1261 if(!err)
1262 return(fd);
1263 os_close_file(fd);
1264 out:
1265 return(err);
1266}
1267
Jeff Dike91acb212005-10-10 23:10:32 -04001268static int update_bitmap(struct io_thread_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269{
Jeff Dike91acb212005-10-10 23:10:32 -04001270 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271
Jeff Dike91acb212005-10-10 23:10:32 -04001272 if(req->cow_offset == -1)
1273 return(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274
Jeff Dike91acb212005-10-10 23:10:32 -04001275 n = os_seek_file(req->fds[1], req->cow_offset);
1276 if(n < 0){
1277 printk("do_io - bitmap lseek failed : err = %d\n", -n);
1278 return(1);
1279 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280
Jeff Dike91acb212005-10-10 23:10:32 -04001281 n = os_write_file(req->fds[1], &req->bitmap_words,
1282 sizeof(req->bitmap_words));
1283 if(n != sizeof(req->bitmap_words)){
1284 printk("do_io - bitmap update failed, err = %d fd = %d\n", -n,
1285 req->fds[1]);
1286 return(1);
1287 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288
Jeff Dike91acb212005-10-10 23:10:32 -04001289 return(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290}
Jeff Dike91acb212005-10-10 23:10:32 -04001291
1292void do_io(struct io_thread_req *req)
1293{
1294 char *buf;
1295 unsigned long len;
1296 int n, nsectors, start, end, bit;
1297 int err;
1298 __u64 off;
1299
1300 nsectors = req->length / req->sectorsize;
1301 start = 0;
1302 do {
1303 bit = ubd_test_bit(start, (unsigned char *) &req->sector_mask);
1304 end = start;
1305 while((end < nsectors) &&
1306 (ubd_test_bit(end, (unsigned char *)
1307 &req->sector_mask) == bit))
1308 end++;
1309
1310 off = req->offset + req->offsets[bit] +
1311 start * req->sectorsize;
1312 len = (end - start) * req->sectorsize;
1313 buf = &req->buffer[start * req->sectorsize];
1314
1315 err = os_seek_file(req->fds[bit], off);
1316 if(err < 0){
1317 printk("do_io - lseek failed : err = %d\n", -err);
1318 req->error = 1;
1319 return;
1320 }
1321 if(req->op == UBD_READ){
1322 n = 0;
1323 do {
1324 buf = &buf[n];
1325 len -= n;
1326 n = os_read_file(req->fds[bit], buf, len);
1327 if (n < 0) {
1328 printk("do_io - read failed, err = %d "
1329 "fd = %d\n", -n, req->fds[bit]);
1330 req->error = 1;
1331 return;
1332 }
1333 } while((n < len) && (n != 0));
1334 if (n < len) memset(&buf[n], 0, len - n);
1335 } else {
1336 n = os_write_file(req->fds[bit], buf, len);
1337 if(n != len){
1338 printk("do_io - write failed err = %d "
1339 "fd = %d\n", -n, req->fds[bit]);
1340 req->error = 1;
1341 return;
1342 }
1343 }
1344
1345 start = end;
1346 } while(start < nsectors);
1347
1348 req->error = update_bitmap(req);
1349}
1350
1351/* Changed in start_io_thread, which is serialized by being called only
1352 * from ubd_init, which is an initcall.
1353 */
1354int kernel_fd = -1;
1355
1356/* Only changed by the io thread */
1357int io_count = 0;
1358
1359int io_thread(void *arg)
1360{
1361 struct io_thread_req req;
1362 int n;
1363
1364 ignore_sigwinch_sig();
1365 while(1){
1366 n = os_read_file(kernel_fd, &req, sizeof(req));
1367 if(n != sizeof(req)){
1368 if(n < 0)
1369 printk("io_thread - read failed, fd = %d, "
1370 "err = %d\n", kernel_fd, -n);
1371 else {
1372 printk("io_thread - short read, fd = %d, "
1373 "length = %d\n", kernel_fd, n);
1374 }
1375 continue;
1376 }
1377 io_count++;
1378 do_io(&req);
1379 n = os_write_file(kernel_fd, &req, sizeof(req));
1380 if(n != sizeof(req))
1381 printk("io_thread - write failed, fd = %d, err = %d\n",
1382 kernel_fd, -n);
1383 }
Jeff Dike91acb212005-10-10 23:10:32 -04001384
Jeff Dike1b57e9c2006-01-06 00:18:49 -08001385 return 0;
1386}