blob: d42f826a8ab9f009fe5f06d5133e0e8d578799f1 [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
Linus Torvalds1da177e2005-04-16 15:20:36 -070020#define UBD_SHIFT 4
21
Jeff Dikee16f5352007-06-08 13:46:54 -070022#include "linux/kernel.h"
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"
WANG Cong23464ff2007-10-24 13:07:11 +020037#include "linux/scatterlist.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include "asm/segment.h"
39#include "asm/uaccess.h"
40#include "asm/irq.h"
41#include "asm/types.h"
42#include "asm/tlbflush.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#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 Dike62f96cb2007-02-10 01:44:16 -080059 struct request *req;
Jeff Dike91acb212005-10-10 23:10:32 -040060 enum ubd_req op;
Linus Torvalds1da177e2005-04-16 15:20:36 -070061 int fds[2];
62 unsigned long offsets[2];
63 unsigned long long offset;
64 unsigned long length;
65 char *buffer;
66 int sectorsize;
Jeff Dike91acb212005-10-10 23:10:32 -040067 unsigned long sector_mask;
68 unsigned long long cow_offset;
69 unsigned long bitmap_words[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 int error;
71};
72
Jeff Dike91acb212005-10-10 23:10:32 -040073static inline int ubd_test_bit(__u64 bit, unsigned char *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -070074{
75 __u64 n;
76 int bits, off;
77
Jeff Dike91acb212005-10-10 23:10:32 -040078 bits = sizeof(data[0]) * 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -070079 n = bit / bits;
80 off = bit % bits;
Jeff Dikedc764e52007-05-06 14:51:41 -070081 return (data[n] & (1 << off)) != 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070082}
83
Jeff Dike91acb212005-10-10 23:10:32 -040084static inline void ubd_set_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 data[n] |= (1 << off);
Linus Torvalds1da177e2005-04-16 15:20:36 -070093}
94/*End stuff from ubd_user.h*/
95
96#define DRIVER_NAME "uml-blkdev"
97
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -080098static DEFINE_MUTEX(ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070099
Al Viroa625c992008-03-02 09:16:26 -0500100static int ubd_open(struct block_device *bdev, fmode_t mode);
101static int ubd_release(struct gendisk *disk, fmode_t mode);
102static int ubd_ioctl(struct block_device *bdev, fmode_t mode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 unsigned int cmd, unsigned long arg);
Christoph Hellwiga885c8c2006-01-08 01:02:50 -0800104static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105
Paolo 'Blaisorblade' Giarrusso97d88ac2006-10-30 22:07:03 -0800106#define MAX_DEV (16)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108static struct block_device_operations ubd_blops = {
109 .owner = THIS_MODULE,
Al Viroa625c992008-03-02 09:16:26 -0500110 .open = ubd_open,
111 .release = ubd_release,
112 .ioctl = ubd_ioctl,
Christoph Hellwiga885c8c2006-01-08 01:02:50 -0800113 .getgeo = ubd_getgeo,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114};
115
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116/* Protected by ubd_lock */
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700117static int fake_major = UBD_MAJOR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118static struct gendisk *ubd_gendisk[MAX_DEV];
119static struct gendisk *fake_gendisk[MAX_DEV];
Jeff Dike6c29256c2006-03-27 01:14:37 -0800120
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121#ifdef CONFIG_BLK_DEV_UBD_SYNC
122#define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 1, .c = 0, \
123 .cl = 1 })
124#else
125#define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 0, .c = 0, \
126 .cl = 1 })
127#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128static struct openflags global_openflags = OPEN_FLAGS;
129
130struct cow {
Paolo 'Blaisorblade' Giarrusso2a9d32f2006-10-30 22:07:04 -0800131 /* backing file name */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 char *file;
Paolo 'Blaisorblade' Giarrusso2a9d32f2006-10-30 22:07:04 -0800133 /* backing file fd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 int fd;
135 unsigned long *bitmap;
136 unsigned long bitmap_len;
137 int bitmap_offset;
Jeff Dikedc764e52007-05-06 14:51:41 -0700138 int data_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139};
140
Jeff Dikea0044bd2007-05-06 14:51:36 -0700141#define MAX_SG 64
142
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143struct ubd {
Jeff Dikea0044bd2007-05-06 14:51:36 -0700144 struct list_head restart;
Paolo 'Blaisorblade' Giarrusso2a9d32f2006-10-30 22:07:04 -0800145 /* name (and fd, below) of the file opened for writing, either the
146 * backing or the cow file. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 char *file;
148 int count;
149 int fd;
150 __u64 size;
151 struct openflags boot_openflags;
152 struct openflags openflags;
Paolo 'Blaisorblade' Giarrusso84e945e2006-10-30 22:07:10 -0800153 unsigned shared:1;
154 unsigned no_cow:1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 struct cow cow;
156 struct platform_device pdev;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800157 struct request_queue *queue;
158 spinlock_t lock;
Jeff Dikea0044bd2007-05-06 14:51:36 -0700159 struct scatterlist sg[MAX_SG];
160 struct request *request;
161 int start_sg, end_sg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162};
163
164#define DEFAULT_COW { \
165 .file = NULL, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700166 .fd = -1, \
167 .bitmap = NULL, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 .bitmap_offset = 0, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700169 .data_offset = 0, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170}
171
172#define DEFAULT_UBD { \
173 .file = NULL, \
174 .count = 0, \
175 .fd = -1, \
176 .size = -1, \
177 .boot_openflags = OPEN_FLAGS, \
178 .openflags = OPEN_FLAGS, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700179 .no_cow = 0, \
Jeff Dike6c29256c2006-03-27 01:14:37 -0800180 .shared = 0, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700181 .cow = DEFAULT_COW, \
Jeff Dike62f96cb2007-02-10 01:44:16 -0800182 .lock = SPIN_LOCK_UNLOCKED, \
Jeff Dikea0044bd2007-05-06 14:51:36 -0700183 .request = NULL, \
184 .start_sg = 0, \
185 .end_sg = 0, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186}
187
Jeff Dikeb8831a12007-02-10 01:44:17 -0800188/* Protected by ubd_lock */
WANG Cong5dc62b12008-04-28 02:13:58 -0700189static struct ubd ubd_devs[MAX_DEV] = { [0 ... MAX_DEV - 1] = DEFAULT_UBD };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191/* Only changed by fake_ide_setup which is a setup */
192static int fake_ide = 0;
193static struct proc_dir_entry *proc_ide_root = NULL;
194static struct proc_dir_entry *proc_ide = NULL;
195
196static void make_proc_ide(void)
197{
198 proc_ide_root = proc_mkdir("ide", NULL);
199 proc_ide = proc_mkdir("ide0", proc_ide_root);
200}
201
202static int proc_ide_read_media(char *page, char **start, off_t off, int count,
203 int *eof, void *data)
204{
205 int len;
206
207 strcpy(page, "disk\n");
208 len = strlen("disk\n");
209 len -= off;
210 if (len < count){
211 *eof = 1;
212 if (len <= 0) return 0;
213 }
214 else len = count;
215 *start = page + off;
216 return len;
217}
218
WANG Congc0a92902008-02-04 22:30:41 -0800219static void make_ide_entries(const char *dev_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220{
221 struct proc_dir_entry *dir, *ent;
222 char name[64];
223
224 if(proc_ide_root == NULL) make_proc_ide();
225
226 dir = proc_mkdir(dev_name, proc_ide);
227 if(!dir) return;
228
229 ent = create_proc_entry("media", S_IFREG|S_IRUGO, dir);
230 if(!ent) return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 ent->data = NULL;
232 ent->read_proc = proc_ide_read_media;
233 ent->write_proc = NULL;
WANG Congc0a92902008-02-04 22:30:41 -0800234 snprintf(name, sizeof(name), "ide0/%s", dev_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 proc_symlink(dev_name, proc_ide_root, name);
236}
237
238static int fake_ide_setup(char *str)
239{
240 fake_ide = 1;
Jeff Dikedc764e52007-05-06 14:51:41 -0700241 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242}
243
244__setup("fake_ide", fake_ide_setup);
245
246__uml_help(fake_ide_setup,
247"fake_ide\n"
248" Create ide0 entries that map onto ubd devices.\n\n"
249);
250
251static int parse_unit(char **ptr)
252{
253 char *str = *ptr, *end;
254 int n = -1;
255
256 if(isdigit(*str)) {
257 n = simple_strtoul(str, &end, 0);
258 if(end == str)
Jeff Dikedc764e52007-05-06 14:51:41 -0700259 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 *ptr = end;
261 }
Paolo 'Blaisorblade' Giarrusso97d88ac2006-10-30 22:07:03 -0800262 else if (('a' <= *str) && (*str <= 'z')) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 n = *str - 'a';
264 str++;
265 *ptr = str;
266 }
Jeff Dikedc764e52007-05-06 14:51:41 -0700267 return n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268}
269
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800270/* If *index_out == -1 at exit, the passed option was a general one;
271 * otherwise, the str pointer is used (and owned) inside ubd_devs array, so it
272 * should not be freed on exit.
273 */
Jeff Dikef28169d2007-02-10 01:43:53 -0800274static int ubd_setup_common(char *str, int *index_out, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800276 struct ubd *ubd_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 struct openflags flags = global_openflags;
278 char *backing_file;
Jeff Dikeb8831a12007-02-10 01:44:17 -0800279 int n, err = 0, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280
281 if(index_out) *index_out = -1;
282 n = *str;
283 if(n == '='){
284 char *end;
285 int major;
286
287 str++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 if(!strcmp(str, "sync")){
289 global_openflags = of_sync(global_openflags);
Jeff Dikeb8831a12007-02-10 01:44:17 -0800290 goto out1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 }
292
Jeff Dikef28169d2007-02-10 01:43:53 -0800293 err = -EINVAL;
Jeff Dikeb8831a12007-02-10 01:44:17 -0800294 major = simple_strtoul(str, &end, 0);
295 if((*end != '\0') || (end == str)){
296 *error_out = "Didn't parse major number";
297 goto out1;
298 }
299
Jeff Dikef28169d2007-02-10 01:43:53 -0800300 mutex_lock(&ubd_lock);
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700301 if (fake_major != UBD_MAJOR) {
Jeff Dikef28169d2007-02-10 01:43:53 -0800302 *error_out = "Can't assign a fake major twice";
303 goto out1;
304 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800305
Jeff Dikef28169d2007-02-10 01:43:53 -0800306 fake_major = major;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307
308 printk(KERN_INFO "Setting extra ubd major number to %d\n",
309 major);
Jeff Dikef28169d2007-02-10 01:43:53 -0800310 err = 0;
311 out1:
312 mutex_unlock(&ubd_lock);
313 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 }
315
316 n = parse_unit(&str);
317 if(n < 0){
Jeff Dikef28169d2007-02-10 01:43:53 -0800318 *error_out = "Couldn't parse device number";
319 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 }
321 if(n >= MAX_DEV){
Jeff Dikef28169d2007-02-10 01:43:53 -0800322 *error_out = "Device number out of range";
323 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 }
325
Jeff Dikef28169d2007-02-10 01:43:53 -0800326 err = -EBUSY;
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800327 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800329 ubd_dev = &ubd_devs[n];
330 if(ubd_dev->file != NULL){
Jeff Dikef28169d2007-02-10 01:43:53 -0800331 *error_out = "Device is already configured";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 goto out;
333 }
334
335 if (index_out)
336 *index_out = n;
337
Jeff Dikef28169d2007-02-10 01:43:53 -0800338 err = -EINVAL;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800339 for (i = 0; i < sizeof("rscd="); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 switch (*str) {
341 case 'r':
342 flags.w = 0;
343 break;
344 case 's':
345 flags.s = 1;
346 break;
347 case 'd':
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800348 ubd_dev->no_cow = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 break;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800350 case 'c':
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800351 ubd_dev->shared = 1;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800352 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 case '=':
354 str++;
355 goto break_loop;
356 default:
Jeff Dikef28169d2007-02-10 01:43:53 -0800357 *error_out = "Expected '=' or flag letter "
358 "(r, s, c, or d)";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 goto out;
360 }
361 str++;
362 }
363
Jeff Dikef28169d2007-02-10 01:43:53 -0800364 if (*str == '=')
365 *error_out = "Too many flags specified";
366 else
367 *error_out = "Missing '='";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 goto out;
369
370break_loop:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 backing_file = strchr(str, ',');
372
Jeff Dikef28169d2007-02-10 01:43:53 -0800373 if (backing_file == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 backing_file = strchr(str, ':');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375
Jeff Dikef28169d2007-02-10 01:43:53 -0800376 if(backing_file != NULL){
377 if(ubd_dev->no_cow){
378 *error_out = "Can't specify both 'd' and a cow file";
379 goto out;
380 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 else {
382 *backing_file = '\0';
383 backing_file++;
384 }
385 }
Jeff Dikef28169d2007-02-10 01:43:53 -0800386 err = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800387 ubd_dev->file = str;
388 ubd_dev->cow.file = backing_file;
389 ubd_dev->boot_openflags = flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800391 mutex_unlock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -0800392 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393}
394
395static int ubd_setup(char *str)
396{
Jeff Dikef28169d2007-02-10 01:43:53 -0800397 char *error;
398 int err;
399
400 err = ubd_setup_common(str, NULL, &error);
401 if(err)
402 printk(KERN_ERR "Failed to initialize device with \"%s\" : "
403 "%s\n", str, error);
404 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405}
406
407__setup("ubd", ubd_setup);
408__uml_help(ubd_setup,
409"ubd<n><flags>=<filename>[(:|,)<filename2>]\n"
410" This is used to associate a device with a file in the underlying\n"
411" filesystem. When specifying two filenames, the first one is the\n"
412" COW name and the second is the backing file name. As separator you can\n"
413" use either a ':' or a ',': the first one allows writing things like;\n"
414" ubd0=~/Uml/root_cow:~/Uml/root_backing_file\n"
415" while with a ',' the shell would not expand the 2nd '~'.\n"
Jeff Dikef28169d2007-02-10 01:43:53 -0800416" When using only one filename, UML will detect whether to treat it like\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417" a COW file or a backing file. To override this detection, add the 'd'\n"
418" flag:\n"
419" ubd0d=BackingFile\n"
420" Usually, there is a filesystem in the file, but \n"
421" that's not required. Swap devices containing swap files can be\n"
422" specified like this. Also, a file which doesn't contain a\n"
423" filesystem can have its contents read in the virtual \n"
424" machine by running 'dd' on the device. <n> must be in the range\n"
425" 0 to 7. Appending an 'r' to the number will cause that device\n"
426" to be mounted read-only. For example ubd1r=./ext_fs. Appending\n"
Jeff Dike20ede452008-02-04 22:30:37 -0800427" an 's' will cause data to be written to disk on the host immediately.\n"
428" 'c' will cause the device to be treated as being shared between multiple\n"
429" UMLs and file locking will be turned off - this is appropriate for a\n"
430" cluster filesystem and inappropriate at almost all other times.\n\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431);
432
Jeff Dike8299ca52008-02-04 22:30:48 -0800433static int udb_setup(char *str)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434{
435 printk("udb%s specified on command line is almost certainly a ubd -> "
436 "udb TYPO\n", str);
Jeff Dikedc764e52007-05-06 14:51:41 -0700437 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438}
439
440__setup("udb", udb_setup);
441__uml_help(udb_setup,
442"udb\n"
Jeff Dike0894e272005-05-28 15:51:55 -0700443" This option is here solely to catch ubd -> udb typos, which can be\n"
444" to impossible to catch visually unless you specifically look for\n"
445" them. The only result of any option starting with 'udb' is an error\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446" in the boot output.\n\n"
447);
448
Jens Axboe165125e2007-07-24 09:28:11 +0200449static void do_ubd_request(struct request_queue * q);
Jeff Dike91acb212005-10-10 23:10:32 -0400450
451/* Only changed by ubd_init, which is an initcall. */
WANG Cong5dc62b12008-04-28 02:13:58 -0700452static int thread_fd = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453
Kiyoshi Ueda4898b532007-12-11 17:42:53 -0500454static void ubd_end_request(struct request *req, int bytes, int error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455{
Kiyoshi Ueda4898b532007-12-11 17:42:53 -0500456 blk_end_request(req, error, bytes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457}
458
Paolo 'Blaisorblade' Giarrusso33f775e2006-10-30 22:07:08 -0800459/* Callable only from interrupt context - otherwise you need to do
460 * spin_lock_irq()/spin_lock_irqsave() */
Jeff Dikea0044bd2007-05-06 14:51:36 -0700461static inline void ubd_finish(struct request *req, int bytes)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462{
Jeff Dikea0044bd2007-05-06 14:51:36 -0700463 if(bytes < 0){
Kiyoshi Ueda4898b532007-12-11 17:42:53 -0500464 ubd_end_request(req, 0, -EIO);
Jeff Dikea0044bd2007-05-06 14:51:36 -0700465 return;
466 }
Kiyoshi Ueda4898b532007-12-11 17:42:53 -0500467 ubd_end_request(req, bytes, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468}
469
Jeff Dikea0044bd2007-05-06 14:51:36 -0700470static LIST_HEAD(restart);
471
Paolo 'Blaisorblade' Giarrusso2fe30a32006-10-30 22:07:09 -0800472/* XXX - move this inside ubd_intr. */
Jeff Dike62f96cb2007-02-10 01:44:16 -0800473/* Called without dev->lock held, and only in interrupt context. */
Jeff Dike91acb212005-10-10 23:10:32 -0400474static void ubd_handler(void)
475{
Jeff Dike2adcec22007-05-06 14:51:37 -0700476 struct io_thread_req *req;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800477 struct request *rq;
Jeff Dikea0044bd2007-05-06 14:51:36 -0700478 struct ubd *ubd;
479 struct list_head *list, *next_ele;
480 unsigned long flags;
Jeff Dike91acb212005-10-10 23:10:32 -0400481 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482
Jeff Dikea0044bd2007-05-06 14:51:36 -0700483 while(1){
Jeff Dikea6ea4cc2007-05-06 14:51:43 -0700484 n = os_read_file(thread_fd, &req,
485 sizeof(struct io_thread_req *));
Jeff Dikea0044bd2007-05-06 14:51:36 -0700486 if(n != sizeof(req)){
487 if(n == -EAGAIN)
488 break;
489 printk(KERN_ERR "spurious interrupt in ubd_handler, "
490 "err = %d\n", -n);
491 return;
492 }
493
Jeff Dike2adcec22007-05-06 14:51:37 -0700494 rq = req->req;
495 rq->nr_sectors -= req->length >> 9;
Jeff Dikea0044bd2007-05-06 14:51:36 -0700496 if(rq->nr_sectors == 0)
497 ubd_finish(rq, rq->hard_nr_sectors << 9);
Jeff Dike2adcec22007-05-06 14:51:37 -0700498 kfree(req);
Jeff Dike91acb212005-10-10 23:10:32 -0400499 }
Jeff Dike62f96cb2007-02-10 01:44:16 -0800500 reactivate_fd(thread_fd, UBD_IRQ);
Jeff Dikea0044bd2007-05-06 14:51:36 -0700501
502 list_for_each_safe(list, next_ele, &restart){
503 ubd = container_of(list, struct ubd, restart);
504 list_del_init(&ubd->restart);
505 spin_lock_irqsave(&ubd->lock, flags);
506 do_ubd_request(ubd->queue);
507 spin_unlock_irqrestore(&ubd->lock, flags);
508 }
Jeff Dike91acb212005-10-10 23:10:32 -0400509}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510
Al Viro7bea96f2006-10-08 22:49:34 +0100511static irqreturn_t ubd_intr(int irq, void *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512{
Jeff Dike91acb212005-10-10 23:10:32 -0400513 ubd_handler();
Jeff Dikedc764e52007-05-06 14:51:41 -0700514 return IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515}
516
Jeff Dike91acb212005-10-10 23:10:32 -0400517/* Only changed by ubd_init, which is an initcall. */
518static int io_pid = -1;
519
WANG Cong5dc62b12008-04-28 02:13:58 -0700520static void kill_io_thread(void)
Jeff Dike91acb212005-10-10 23:10:32 -0400521{
Jeff Dike6c29256c2006-03-27 01:14:37 -0800522 if(io_pid != -1)
Jeff Dike91acb212005-10-10 23:10:32 -0400523 os_kill_process(io_pid, 1);
524}
525
526__uml_exitcall(kill_io_thread);
527
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800528static inline int ubd_file_size(struct ubd *ubd_dev, __u64 *size_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529{
530 char *file;
531
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800532 file = ubd_dev->cow.file ? ubd_dev->cow.file : ubd_dev->file;
Jeff Dikedc764e52007-05-06 14:51:41 -0700533 return os_file_size(file, size_out);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534}
535
WANG Cong5dc62b12008-04-28 02:13:58 -0700536static int read_cow_bitmap(int fd, void *buf, int offset, int len)
537{
538 int err;
539
540 err = os_seek_file(fd, offset);
541 if (err < 0)
542 return err;
543
544 err = os_read_file(fd, buf, len);
545 if (err < 0)
546 return err;
547
548 return 0;
549}
550
551static int backing_file_mismatch(char *file, __u64 size, time_t mtime)
552{
553 unsigned long modtime;
554 unsigned long long actual;
555 int err;
556
557 err = os_file_modtime(file, &modtime);
558 if (err < 0) {
559 printk(KERN_ERR "Failed to get modification time of backing "
560 "file \"%s\", err = %d\n", file, -err);
561 return err;
562 }
563
564 err = os_file_size(file, &actual);
565 if (err < 0) {
566 printk(KERN_ERR "Failed to get size of backing file \"%s\", "
567 "err = %d\n", file, -err);
568 return err;
569 }
570
571 if (actual != size) {
572 /*__u64 can be a long on AMD64 and with %lu GCC complains; so
573 * the typecast.*/
574 printk(KERN_ERR "Size mismatch (%llu vs %llu) of COW header "
575 "vs backing file\n", (unsigned long long) size, actual);
576 return -EINVAL;
577 }
578 if (modtime != mtime) {
579 printk(KERN_ERR "mtime mismatch (%ld vs %ld) of COW header vs "
580 "backing file\n", mtime, modtime);
581 return -EINVAL;
582 }
583 return 0;
584}
585
586static int path_requires_switch(char *from_cmdline, char *from_cow, char *cow)
587{
588 struct uml_stat buf1, buf2;
589 int err;
590
591 if (from_cmdline == NULL)
592 return 0;
593 if (!strcmp(from_cmdline, from_cow))
594 return 0;
595
596 err = os_stat_file(from_cmdline, &buf1);
597 if (err < 0) {
598 printk(KERN_ERR "Couldn't stat '%s', err = %d\n", from_cmdline,
599 -err);
600 return 0;
601 }
602 err = os_stat_file(from_cow, &buf2);
603 if (err < 0) {
604 printk(KERN_ERR "Couldn't stat '%s', err = %d\n", from_cow,
605 -err);
606 return 1;
607 }
608 if ((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino))
609 return 0;
610
611 printk(KERN_ERR "Backing file mismatch - \"%s\" requested, "
612 "\"%s\" specified in COW header of \"%s\"\n",
613 from_cmdline, from_cow, cow);
614 return 1;
615}
616
617static int open_ubd_file(char *file, struct openflags *openflags, int shared,
618 char **backing_file_out, int *bitmap_offset_out,
619 unsigned long *bitmap_len_out, int *data_offset_out,
620 int *create_cow_out)
621{
622 time_t mtime;
623 unsigned long long size;
624 __u32 version, align;
625 char *backing_file;
626 int fd, err, sectorsize, asked_switch, mode = 0644;
627
628 fd = os_open_file(file, *openflags, mode);
629 if (fd < 0) {
630 if ((fd == -ENOENT) && (create_cow_out != NULL))
631 *create_cow_out = 1;
632 if (!openflags->w ||
633 ((fd != -EROFS) && (fd != -EACCES)))
634 return fd;
635 openflags->w = 0;
636 fd = os_open_file(file, *openflags, mode);
637 if (fd < 0)
638 return fd;
639 }
640
641 if (shared)
642 printk(KERN_INFO "Not locking \"%s\" on the host\n", file);
643 else {
644 err = os_lock_file(fd, openflags->w);
645 if (err < 0) {
646 printk(KERN_ERR "Failed to lock '%s', err = %d\n",
647 file, -err);
648 goto out_close;
649 }
650 }
651
652 /* Successful return case! */
653 if (backing_file_out == NULL)
654 return fd;
655
656 err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime,
657 &size, &sectorsize, &align, bitmap_offset_out);
658 if (err && (*backing_file_out != NULL)) {
659 printk(KERN_ERR "Failed to read COW header from COW file "
660 "\"%s\", errno = %d\n", file, -err);
661 goto out_close;
662 }
663 if (err)
664 return fd;
665
666 asked_switch = path_requires_switch(*backing_file_out, backing_file,
667 file);
668
669 /* Allow switching only if no mismatch. */
670 if (asked_switch && !backing_file_mismatch(*backing_file_out, size,
671 mtime)) {
672 printk(KERN_ERR "Switching backing file to '%s'\n",
673 *backing_file_out);
674 err = write_cow_header(file, fd, *backing_file_out,
675 sectorsize, align, &size);
676 if (err) {
677 printk(KERN_ERR "Switch failed, errno = %d\n", -err);
678 goto out_close;
679 }
680 } else {
681 *backing_file_out = backing_file;
682 err = backing_file_mismatch(*backing_file_out, size, mtime);
683 if (err)
684 goto out_close;
685 }
686
687 cow_sizes(version, size, sectorsize, align, *bitmap_offset_out,
688 bitmap_len_out, data_offset_out);
689
690 return fd;
691 out_close:
692 os_close_file(fd);
693 return err;
694}
695
696static int create_cow_file(char *cow_file, char *backing_file,
697 struct openflags flags,
698 int sectorsize, int alignment, int *bitmap_offset_out,
699 unsigned long *bitmap_len_out, int *data_offset_out)
700{
701 int err, fd;
702
703 flags.c = 1;
704 fd = open_ubd_file(cow_file, &flags, 0, NULL, NULL, NULL, NULL, NULL);
705 if (fd < 0) {
706 err = fd;
707 printk(KERN_ERR "Open of COW file '%s' failed, errno = %d\n",
708 cow_file, -err);
709 goto out;
710 }
711
712 err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment,
713 bitmap_offset_out, bitmap_len_out,
714 data_offset_out);
715 if (!err)
716 return fd;
717 os_close_file(fd);
718 out:
719 return err;
720}
721
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800722static void ubd_close_dev(struct ubd *ubd_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800724 os_close_file(ubd_dev->fd);
725 if(ubd_dev->cow.file == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 return;
727
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800728 os_close_file(ubd_dev->cow.fd);
729 vfree(ubd_dev->cow.bitmap);
730 ubd_dev->cow.bitmap = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731}
732
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800733static int ubd_open_dev(struct ubd *ubd_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734{
735 struct openflags flags;
736 char **back_ptr;
737 int err, create_cow, *create_ptr;
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800738 int fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800740 ubd_dev->openflags = ubd_dev->boot_openflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 create_cow = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800742 create_ptr = (ubd_dev->cow.file != NULL) ? &create_cow : NULL;
743 back_ptr = ubd_dev->no_cow ? NULL : &ubd_dev->cow.file;
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800744
745 fd = open_ubd_file(ubd_dev->file, &ubd_dev->openflags, ubd_dev->shared,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800746 back_ptr, &ubd_dev->cow.bitmap_offset,
747 &ubd_dev->cow.bitmap_len, &ubd_dev->cow.data_offset,
Jeff Dike6c29256c2006-03-27 01:14:37 -0800748 create_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800750 if((fd == -ENOENT) && create_cow){
751 fd = create_cow_file(ubd_dev->file, ubd_dev->cow.file,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800752 ubd_dev->openflags, 1 << 9, PAGE_SIZE,
753 &ubd_dev->cow.bitmap_offset,
754 &ubd_dev->cow.bitmap_len,
755 &ubd_dev->cow.data_offset);
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800756 if(fd >= 0){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 printk(KERN_INFO "Creating \"%s\" as COW file for "
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800758 "\"%s\"\n", ubd_dev->file, ubd_dev->cow.file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 }
760 }
761
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800762 if(fd < 0){
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800763 printk("Failed to open '%s', errno = %d\n", ubd_dev->file,
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800764 -fd);
765 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 }
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800767 ubd_dev->fd = fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800769 if(ubd_dev->cow.file != NULL){
Jeff Dikef4768ff2007-08-22 14:01:53 -0700770 blk_queue_max_sectors(ubd_dev->queue, 8 * sizeof(long));
771
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 err = -ENOMEM;
Jesper Juhlda2486b2007-10-16 01:27:19 -0700773 ubd_dev->cow.bitmap = vmalloc(ubd_dev->cow.bitmap_len);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800774 if(ubd_dev->cow.bitmap == NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 printk(KERN_ERR "Failed to vmalloc COW bitmap\n");
776 goto error;
777 }
778 flush_tlb_kernel_vm();
779
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800780 err = read_cow_bitmap(ubd_dev->fd, ubd_dev->cow.bitmap,
781 ubd_dev->cow.bitmap_offset,
782 ubd_dev->cow.bitmap_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 if(err < 0)
784 goto error;
785
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800786 flags = ubd_dev->openflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 flags.w = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800788 err = open_ubd_file(ubd_dev->cow.file, &flags, ubd_dev->shared, NULL,
Jeff Dike6c29256c2006-03-27 01:14:37 -0800789 NULL, NULL, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 if(err < 0) goto error;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800791 ubd_dev->cow.fd = err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 }
Jeff Dikedc764e52007-05-06 14:51:41 -0700793 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 error:
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800795 os_close_file(ubd_dev->fd);
Jeff Dikedc764e52007-05-06 14:51:41 -0700796 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797}
798
Jeff Dike2e3f5252007-05-06 14:51:29 -0700799static void ubd_device_release(struct device *dev)
800{
801 struct ubd *ubd_dev = dev->driver_data;
802
803 blk_cleanup_queue(ubd_dev->queue);
804 *ubd_dev = ((struct ubd) DEFAULT_UBD);
805}
806
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800807static int ubd_disk_register(int major, u64 size, int unit,
Jeff Dikeb8831a12007-02-10 01:44:17 -0800808 struct gendisk **disk_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809{
810 struct gendisk *disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811
812 disk = alloc_disk(1 << UBD_SHIFT);
813 if(disk == NULL)
Jeff Dikedc764e52007-05-06 14:51:41 -0700814 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815
816 disk->major = major;
817 disk->first_minor = unit << UBD_SHIFT;
818 disk->fops = &ubd_blops;
819 set_capacity(disk, size / 512);
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700820 if (major == UBD_MAJOR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 sprintf(disk->disk_name, "ubd%c", 'a' + unit);
Greg Kroah-Hartmance7b0f42005-06-20 21:15:16 -0700822 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 sprintf(disk->disk_name, "ubd_fake%d", unit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824
825 /* sysfs register (not for ide fake devices) */
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700826 if (major == UBD_MAJOR) {
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800827 ubd_devs[unit].pdev.id = unit;
828 ubd_devs[unit].pdev.name = DRIVER_NAME;
Jeff Dike2e3f5252007-05-06 14:51:29 -0700829 ubd_devs[unit].pdev.dev.release = ubd_device_release;
830 ubd_devs[unit].pdev.dev.driver_data = &ubd_devs[unit];
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800831 platform_device_register(&ubd_devs[unit].pdev);
832 disk->driverfs_dev = &ubd_devs[unit].pdev.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 }
834
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800835 disk->private_data = &ubd_devs[unit];
Jeff Dike62f96cb2007-02-10 01:44:16 -0800836 disk->queue = ubd_devs[unit].queue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 add_disk(disk);
838
839 *disk_out = disk;
840 return 0;
841}
842
843#define ROUND_BLOCK(n) ((n + ((1 << 9) - 1)) & (-1 << 9))
844
Jeff Dikef28169d2007-02-10 01:43:53 -0800845static int ubd_add(int n, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800847 struct ubd *ubd_dev = &ubd_devs[n];
Jeff Dikef28169d2007-02-10 01:43:53 -0800848 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800850 if(ubd_dev->file == NULL)
Jeff Dikeec7cf782005-09-03 15:57:29 -0700851 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800853 err = ubd_file_size(ubd_dev, &ubd_dev->size);
Jeff Dikef28169d2007-02-10 01:43:53 -0800854 if(err < 0){
855 *error_out = "Couldn't determine size of device's file";
Jeff Dike80c13742006-09-29 01:58:51 -0700856 goto out;
Jeff Dikef28169d2007-02-10 01:43:53 -0800857 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800859 ubd_dev->size = ROUND_BLOCK(ubd_dev->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860
Jeff Dikea0044bd2007-05-06 14:51:36 -0700861 INIT_LIST_HEAD(&ubd_dev->restart);
WANG Cong4f40c052007-11-05 14:50:59 -0800862 sg_init_table(ubd_dev->sg, MAX_SG);
Jeff Dikea0044bd2007-05-06 14:51:36 -0700863
Jeff Dike62f96cb2007-02-10 01:44:16 -0800864 err = -ENOMEM;
865 ubd_dev->queue = blk_init_queue(do_ubd_request, &ubd_dev->lock);
866 if (ubd_dev->queue == NULL) {
867 *error_out = "Failed to initialize device queue";
Jeff Dike80c13742006-09-29 01:58:51 -0700868 goto out;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800869 }
870 ubd_dev->queue->queuedata = ubd_dev;
871
Jeff Dikea0044bd2007-05-06 14:51:36 -0700872 blk_queue_max_hw_segments(ubd_dev->queue, MAX_SG);
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700873 err = ubd_disk_register(UBD_MAJOR, ubd_dev->size, n, &ubd_gendisk[n]);
Jeff Dike62f96cb2007-02-10 01:44:16 -0800874 if(err){
875 *error_out = "Failed to register device";
876 goto out_cleanup;
877 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800878
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700879 if (fake_major != UBD_MAJOR)
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800880 ubd_disk_register(fake_major, ubd_dev->size, n,
Jeff Dike62f96cb2007-02-10 01:44:16 -0800881 &fake_gendisk[n]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882
Jeff Dike83380cc2008-02-04 22:31:18 -0800883 /*
884 * Perhaps this should also be under the "if (fake_major)" above
885 * using the fake_disk->disk_name
886 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 if (fake_ide)
888 make_ide_entries(ubd_gendisk[n]->disk_name);
889
Jeff Dikeec7cf782005-09-03 15:57:29 -0700890 err = 0;
Jeff Dikeec7cf782005-09-03 15:57:29 -0700891out:
892 return err;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800893
894out_cleanup:
895 blk_cleanup_queue(ubd_dev->queue);
896 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897}
898
Jeff Dikef28169d2007-02-10 01:43:53 -0800899static int ubd_config(char *str, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900{
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800901 int n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902
Jeff Dikef28169d2007-02-10 01:43:53 -0800903 /* This string is possibly broken up and stored, so it's only
904 * freed if ubd_setup_common fails, or if only general options
905 * were set.
906 */
Jeff Dike970d6e32006-01-06 00:18:48 -0800907 str = kstrdup(str, GFP_KERNEL);
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800908 if (str == NULL) {
Jeff Dikef28169d2007-02-10 01:43:53 -0800909 *error_out = "Failed to allocate memory";
910 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 }
Jeff Dikef28169d2007-02-10 01:43:53 -0800912
913 ret = ubd_setup_common(str, &n, error_out);
914 if (ret)
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800915 goto err_free;
Jeff Dikef28169d2007-02-10 01:43:53 -0800916
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800917 if (n == -1) {
918 ret = 0;
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800919 goto err_free;
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800920 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921
Jeff Dikedc764e52007-05-06 14:51:41 -0700922 mutex_lock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -0800923 ret = ubd_add(n, error_out);
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800924 if (ret)
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800925 ubd_devs[n].file = NULL;
Jeff Dikedc764e52007-05-06 14:51:41 -0700926 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800928out:
Jeff Dikedc764e52007-05-06 14:51:41 -0700929 return ret;
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800930
931err_free:
932 kfree(str);
933 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934}
935
936static int ubd_get_config(char *name, char *str, int size, char **error_out)
937{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800938 struct ubd *ubd_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 int n, len = 0;
940
941 n = parse_unit(&name);
942 if((n >= MAX_DEV) || (n < 0)){
943 *error_out = "ubd_get_config : device number out of range";
Jeff Dikedc764e52007-05-06 14:51:41 -0700944 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 }
946
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800947 ubd_dev = &ubd_devs[n];
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800948 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800950 if(ubd_dev->file == NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 CONFIG_CHUNK(str, size, len, "", 1);
952 goto out;
953 }
954
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800955 CONFIG_CHUNK(str, size, len, ubd_dev->file, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800957 if(ubd_dev->cow.file != NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 CONFIG_CHUNK(str, size, len, ",", 0);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800959 CONFIG_CHUNK(str, size, len, ubd_dev->cow.file, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 }
961 else CONFIG_CHUNK(str, size, len, "", 1);
962
963 out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800964 mutex_unlock(&ubd_lock);
Jeff Dikedc764e52007-05-06 14:51:41 -0700965 return len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966}
967
Jeff Dike29d56cf2005-06-25 14:55:25 -0700968static int ubd_id(char **str, int *start_out, int *end_out)
969{
Jeff Dikedc764e52007-05-06 14:51:41 -0700970 int n;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700971
972 n = parse_unit(str);
Jeff Dikedc764e52007-05-06 14:51:41 -0700973 *start_out = 0;
974 *end_out = MAX_DEV - 1;
975 return n;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700976}
977
Jeff Dikef28169d2007-02-10 01:43:53 -0800978static int ubd_remove(int n, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979{
Jeff Dike2e3f5252007-05-06 14:51:29 -0700980 struct gendisk *disk = ubd_gendisk[n];
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800981 struct ubd *ubd_dev;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700982 int err = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800984 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800986 ubd_dev = &ubd_devs[n];
Jeff Dike29d56cf2005-06-25 14:55:25 -0700987
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800988 if(ubd_dev->file == NULL)
Jeff Dike29d56cf2005-06-25 14:55:25 -0700989 goto out;
990
991 /* you cannot remove a open disk */
992 err = -EBUSY;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800993 if(ubd_dev->count > 0)
Jeff Dike29d56cf2005-06-25 14:55:25 -0700994 goto out;
995
Jeff Dikedc764e52007-05-06 14:51:41 -0700996 ubd_gendisk[n] = NULL;
Jeff Dikeb47d2de2007-05-06 14:51:01 -0700997 if(disk != NULL){
998 del_gendisk(disk);
999 put_disk(disk);
1000 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001
1002 if(fake_gendisk[n] != NULL){
1003 del_gendisk(fake_gendisk[n]);
1004 put_disk(fake_gendisk[n]);
1005 fake_gendisk[n] = NULL;
1006 }
1007
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 err = 0;
Jeff Dike2e3f5252007-05-06 14:51:29 -07001009 platform_device_unregister(&ubd_dev->pdev);
Jeff Dike29d56cf2005-06-25 14:55:25 -07001010out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -08001011 mutex_unlock(&ubd_lock);
Jeff Dike29d56cf2005-06-25 14:55:25 -07001012 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013}
1014
Jeff Dikef28169d2007-02-10 01:43:53 -08001015/* All these are called by mconsole in process context and without
Jeff Dikeb8831a12007-02-10 01:44:17 -08001016 * ubd-specific locks. The structure itself is const except for .list.
Jeff Dikef28169d2007-02-10 01:43:53 -08001017 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018static struct mc_device ubd_mc = {
Jeff Dike84f48d42007-02-10 01:44:01 -08001019 .list = LIST_HEAD_INIT(ubd_mc.list),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 .name = "ubd",
1021 .config = ubd_config,
Jeff Dikedc764e52007-05-06 14:51:41 -07001022 .get_config = ubd_get_config,
Jeff Dike29d56cf2005-06-25 14:55:25 -07001023 .id = ubd_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 .remove = ubd_remove,
1025};
1026
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001027static int __init ubd_mc_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028{
1029 mconsole_register_dev(&ubd_mc);
1030 return 0;
1031}
1032
1033__initcall(ubd_mc_init);
1034
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001035static int __init ubd0_init(void)
1036{
1037 struct ubd *ubd_dev = &ubd_devs[0];
1038
Jeff Dikeb8831a12007-02-10 01:44:17 -08001039 mutex_lock(&ubd_lock);
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001040 if(ubd_dev->file == NULL)
1041 ubd_dev->file = "root_fs";
Jeff Dikeb8831a12007-02-10 01:44:17 -08001042 mutex_unlock(&ubd_lock);
1043
Jeff Dikedc764e52007-05-06 14:51:41 -07001044 return 0;
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001045}
1046
1047__initcall(ubd0_init);
1048
Jeff Dikeb8831a12007-02-10 01:44:17 -08001049/* Used in ubd_init, which is an initcall */
Russell King3ae5eae2005-11-09 22:32:44 +00001050static struct platform_driver ubd_driver = {
1051 .driver = {
1052 .name = DRIVER_NAME,
1053 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054};
1055
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001056static int __init ubd_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057{
Jeff Dikef28169d2007-02-10 01:43:53 -08001058 char *error;
1059 int i, err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060
Christoph Hellwig792dd4f2009-03-31 15:23:39 -07001061 if (register_blkdev(UBD_MAJOR, "ubd"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 return -1;
1063
Christoph Hellwig792dd4f2009-03-31 15:23:39 -07001064 if (fake_major != UBD_MAJOR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 char name[sizeof("ubd_nnn\0")];
1066
1067 snprintf(name, sizeof(name), "ubd_%d", fake_major);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 if (register_blkdev(fake_major, "ubd"))
1069 return -1;
1070 }
Russell King3ae5eae2005-11-09 22:32:44 +00001071 platform_driver_register(&ubd_driver);
Jeff Dikedc764e52007-05-06 14:51:41 -07001072 mutex_lock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -08001073 for (i = 0; i < MAX_DEV; i++){
1074 err = ubd_add(i, &error);
1075 if(err)
1076 printk(KERN_ERR "Failed to initialize ubd device %d :"
1077 "%s\n", i, error);
1078 }
Jeff Dikedc764e52007-05-06 14:51:41 -07001079 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 return 0;
1081}
1082
1083late_initcall(ubd_init);
1084
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001085static int __init ubd_driver_init(void){
Jeff Dike91acb212005-10-10 23:10:32 -04001086 unsigned long stack;
1087 int err;
1088
1089 /* Set by CONFIG_BLK_DEV_UBD_SYNC or ubd=sync.*/
1090 if(global_openflags.s){
1091 printk(KERN_INFO "ubd: Synchronous mode\n");
1092 /* Letting ubd=sync be like using ubd#s= instead of ubd#= is
1093 * enough. So use anyway the io thread. */
1094 }
1095 stack = alloc_stack(0, 0);
Jeff Dike6c29256c2006-03-27 01:14:37 -08001096 io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *),
Jeff Dike91acb212005-10-10 23:10:32 -04001097 &thread_fd);
1098 if(io_pid < 0){
Jeff Dike6c29256c2006-03-27 01:14:37 -08001099 printk(KERN_ERR
Jeff Dike91acb212005-10-10 23:10:32 -04001100 "ubd : Failed to start I/O thread (errno = %d) - "
1101 "falling back to synchronous I/O\n", -io_pid);
1102 io_pid = -1;
Jeff Dikedc764e52007-05-06 14:51:41 -07001103 return 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001104 }
Jeff Dike6c29256c2006-03-27 01:14:37 -08001105 err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001106 IRQF_DISABLED, "ubd", ubd_devs);
Jeff Dike91acb212005-10-10 23:10:32 -04001107 if(err != 0)
1108 printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err);
Jeff Dikef4c57a72006-03-31 02:30:10 -08001109 return 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001110}
1111
1112device_initcall(ubd_driver_init);
1113
Al Viroa625c992008-03-02 09:16:26 -05001114static int ubd_open(struct block_device *bdev, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115{
Al Viroa625c992008-03-02 09:16:26 -05001116 struct gendisk *disk = bdev->bd_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001117 struct ubd *ubd_dev = disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 int err = 0;
1119
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001120 if(ubd_dev->count == 0){
1121 err = ubd_open_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 if(err){
1123 printk(KERN_ERR "%s: Can't open \"%s\": errno = %d\n",
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001124 disk->disk_name, ubd_dev->file, -err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 goto out;
1126 }
1127 }
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001128 ubd_dev->count++;
1129 set_disk_ro(disk, !ubd_dev->openflags.w);
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -07001130
1131 /* This should no more be needed. And it didn't work anyway to exclude
1132 * read-write remounting of filesystems.*/
Al Viroa625c992008-03-02 09:16:26 -05001133 /*if((mode & FMODE_WRITE) && !ubd_dev->openflags.w){
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -08001134 if(--ubd_dev->count == 0) ubd_close_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 err = -EROFS;
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -07001136 }*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 out:
Jeff Dikedc764e52007-05-06 14:51:41 -07001138 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139}
1140
Al Viroa625c992008-03-02 09:16:26 -05001141static int ubd_release(struct gendisk *disk, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001143 struct ubd *ubd_dev = disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001145 if(--ubd_dev->count == 0)
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -08001146 ubd_close_dev(ubd_dev);
Jeff Dikedc764e52007-05-06 14:51:41 -07001147 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148}
1149
Jeff Dike91acb212005-10-10 23:10:32 -04001150static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask,
1151 __u64 *cow_offset, unsigned long *bitmap,
1152 __u64 bitmap_offset, unsigned long *bitmap_words,
1153 __u64 bitmap_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154{
Jeff Dike91acb212005-10-10 23:10:32 -04001155 __u64 sector = io_offset >> 9;
1156 int i, update_bitmap = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157
Jeff Dike91acb212005-10-10 23:10:32 -04001158 for(i = 0; i < length >> 9; i++){
1159 if(cow_mask != NULL)
1160 ubd_set_bit(i, (unsigned char *) cow_mask);
1161 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
1162 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163
Jeff Dike91acb212005-10-10 23:10:32 -04001164 update_bitmap = 1;
1165 ubd_set_bit(sector + i, (unsigned char *) bitmap);
1166 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167
Jeff Dike91acb212005-10-10 23:10:32 -04001168 if(!update_bitmap)
1169 return;
1170
1171 *cow_offset = sector / (sizeof(unsigned long) * 8);
1172
1173 /* This takes care of the case where we're exactly at the end of the
1174 * device, and *cow_offset + 1 is off the end. So, just back it up
1175 * by one word. Thanks to Lynn Kerby for the fix and James McMechan
1176 * for the original diagnosis.
1177 */
Jiri Olsa6d074242008-05-12 14:01:56 -07001178 if (*cow_offset == (DIV_ROUND_UP(bitmap_len,
1179 sizeof(unsigned long)) - 1))
Jeff Dike91acb212005-10-10 23:10:32 -04001180 (*cow_offset)--;
1181
1182 bitmap_words[0] = bitmap[*cow_offset];
1183 bitmap_words[1] = bitmap[*cow_offset + 1];
1184
1185 *cow_offset *= sizeof(unsigned long);
1186 *cow_offset += bitmap_offset;
1187}
1188
1189static void cowify_req(struct io_thread_req *req, unsigned long *bitmap,
1190 __u64 bitmap_offset, __u64 bitmap_len)
1191{
1192 __u64 sector = req->offset >> 9;
1193 int i;
1194
1195 if(req->length > (sizeof(req->sector_mask) * 8) << 9)
1196 panic("Operation too long");
1197
1198 if(req->op == UBD_READ) {
1199 for(i = 0; i < req->length >> 9; i++){
1200 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
Jeff Dike6c29256c2006-03-27 01:14:37 -08001201 ubd_set_bit(i, (unsigned char *)
Jeff Dike91acb212005-10-10 23:10:32 -04001202 &req->sector_mask);
Jeff Dikedc764e52007-05-06 14:51:41 -07001203 }
Jeff Dike91acb212005-10-10 23:10:32 -04001204 }
1205 else cowify_bitmap(req->offset, req->length, &req->sector_mask,
1206 &req->cow_offset, bitmap, bitmap_offset,
1207 req->bitmap_words, bitmap_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208}
1209
Jeff Dike62f96cb2007-02-10 01:44:16 -08001210/* Called with dev->lock held */
Jeff Dikea0044bd2007-05-06 14:51:36 -07001211static void prepare_request(struct request *req, struct io_thread_req *io_req,
1212 unsigned long long offset, int page_offset,
1213 int len, struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214{
1215 struct gendisk *disk = req->rq_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001216 struct ubd *ubd_dev = disk->private_data;
Jeff Dike91acb212005-10-10 23:10:32 -04001217
Jeff Dike62f96cb2007-02-10 01:44:16 -08001218 io_req->req = req;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001219 io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd :
1220 ubd_dev->fd;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001221 io_req->fds[1] = ubd_dev->fd;
Jeff Dike91acb212005-10-10 23:10:32 -04001222 io_req->cow_offset = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 io_req->offset = offset;
1224 io_req->length = len;
1225 io_req->error = 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001226 io_req->sector_mask = 0;
1227
1228 io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 io_req->offsets[0] = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001230 io_req->offsets[1] = ubd_dev->cow.data_offset;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001231 io_req->buffer = page_address(page) + page_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 io_req->sectorsize = 1 << 9;
1233
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001234 if(ubd_dev->cow.file != NULL)
Jeff Dikea0044bd2007-05-06 14:51:36 -07001235 cowify_req(io_req, ubd_dev->cow.bitmap,
1236 ubd_dev->cow.bitmap_offset, ubd_dev->cow.bitmap_len);
Jeff Dike91acb212005-10-10 23:10:32 -04001237
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238}
1239
Jeff Dike62f96cb2007-02-10 01:44:16 -08001240/* Called with dev->lock held */
Jens Axboe165125e2007-07-24 09:28:11 +02001241static void do_ubd_request(struct request_queue *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242{
Jeff Dike2adcec22007-05-06 14:51:37 -07001243 struct io_thread_req *io_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 struct request *req;
Jeff Dike0a6d3a22007-07-15 23:38:47 -07001245 int n, last_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246
Jeff Dikea0044bd2007-05-06 14:51:36 -07001247 while(1){
Jeff Dike2a9529a2007-03-29 01:20:27 -07001248 struct ubd *dev = q->queuedata;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001249 if(dev->end_sg == 0){
1250 struct request *req = elv_next_request(q);
1251 if(req == NULL)
1252 return;
1253
1254 dev->request = req;
1255 blkdev_dequeue_request(req);
1256 dev->start_sg = 0;
1257 dev->end_sg = blk_rq_map_sg(q, req, dev->sg);
Jeff Dike91acb212005-10-10 23:10:32 -04001258 }
Jeff Dikea0044bd2007-05-06 14:51:36 -07001259
1260 req = dev->request;
Jeff Dike0a6d3a22007-07-15 23:38:47 -07001261 last_sectors = 0;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001262 while(dev->start_sg < dev->end_sg){
1263 struct scatterlist *sg = &dev->sg[dev->start_sg];
1264
Jeff Dike0a6d3a22007-07-15 23:38:47 -07001265 req->sector += last_sectors;
Jeff Dike2adcec22007-05-06 14:51:37 -07001266 io_req = kmalloc(sizeof(struct io_thread_req),
Peter Zijlstra990c5582007-05-06 14:51:38 -07001267 GFP_ATOMIC);
Jeff Dike2adcec22007-05-06 14:51:37 -07001268 if(io_req == NULL){
1269 if(list_empty(&dev->restart))
1270 list_add(&dev->restart, &restart);
1271 return;
1272 }
1273 prepare_request(req, io_req,
Jeff Dikea0044bd2007-05-06 14:51:36 -07001274 (unsigned long long) req->sector << 9,
Jens Axboe45711f12007-10-22 21:19:53 +02001275 sg->offset, sg->length, sg_page(sg));
Jeff Dikea0044bd2007-05-06 14:51:36 -07001276
Jeff Dike0a6d3a22007-07-15 23:38:47 -07001277 last_sectors = sg->length >> 9;
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001278 n = os_write_file(thread_fd, &io_req,
1279 sizeof(struct io_thread_req *));
Jeff Dike2adcec22007-05-06 14:51:37 -07001280 if(n != sizeof(struct io_thread_req *)){
Jeff Dikea0044bd2007-05-06 14:51:36 -07001281 if(n != -EAGAIN)
1282 printk("write to io thread failed, "
1283 "errno = %d\n", -n);
1284 else if(list_empty(&dev->restart))
1285 list_add(&dev->restart, &restart);
Miklos Szeredi12429bf2007-11-28 16:21:52 -08001286 kfree(io_req);
Jeff Dikea0044bd2007-05-06 14:51:36 -07001287 return;
1288 }
1289
Jeff Dikea0044bd2007-05-06 14:51:36 -07001290 dev->start_sg++;
1291 }
1292 dev->end_sg = 0;
1293 dev->request = NULL;
Jeff Dike91acb212005-10-10 23:10:32 -04001294 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295}
1296
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001297static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
1298{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001299 struct ubd *ubd_dev = bdev->bd_disk->private_data;
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001300
1301 geo->heads = 128;
1302 geo->sectors = 32;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001303 geo->cylinders = ubd_dev->size / (128 * 32 * 512);
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001304 return 0;
1305}
1306
Al Viroa625c992008-03-02 09:16:26 -05001307static int ubd_ioctl(struct block_device *bdev, fmode_t mode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 unsigned int cmd, unsigned long arg)
1309{
Al Viroa625c992008-03-02 09:16:26 -05001310 struct ubd *ubd_dev = bdev->bd_disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 struct hd_driveid ubd_id = {
1312 .cyls = 0,
1313 .heads = 128,
1314 .sectors = 32,
1315 };
1316
1317 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 struct cdrom_volctrl volume;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 case HDIO_GET_IDENTITY:
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001320 ubd_id.cyls = ubd_dev->size / (128 * 32 * 512);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 if(copy_to_user((char __user *) arg, (char *) &ubd_id,
1322 sizeof(ubd_id)))
Jeff Dikedc764e52007-05-06 14:51:41 -07001323 return -EFAULT;
1324 return 0;
Jeff Dikeb8831a12007-02-10 01:44:17 -08001325
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 case CDROMVOLREAD:
1327 if(copy_from_user(&volume, (char __user *) arg, sizeof(volume)))
Jeff Dikedc764e52007-05-06 14:51:41 -07001328 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 volume.channel0 = 255;
1330 volume.channel1 = 255;
1331 volume.channel2 = 255;
1332 volume.channel3 = 255;
1333 if(copy_to_user((char __user *) arg, &volume, sizeof(volume)))
Jeff Dikedc764e52007-05-06 14:51:41 -07001334 return -EFAULT;
1335 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 }
Jeff Dikedc764e52007-05-06 14:51:41 -07001337 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338}
1339
Jeff Dike91acb212005-10-10 23:10:32 -04001340static int update_bitmap(struct io_thread_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341{
Jeff Dike91acb212005-10-10 23:10:32 -04001342 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343
Jeff Dike91acb212005-10-10 23:10:32 -04001344 if(req->cow_offset == -1)
Jeff Dikedc764e52007-05-06 14:51:41 -07001345 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346
Jeff Dike91acb212005-10-10 23:10:32 -04001347 n = os_seek_file(req->fds[1], req->cow_offset);
1348 if(n < 0){
1349 printk("do_io - bitmap lseek failed : err = %d\n", -n);
Jeff Dikedc764e52007-05-06 14:51:41 -07001350 return 1;
Jeff Dike91acb212005-10-10 23:10:32 -04001351 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001353 n = os_write_file(req->fds[1], &req->bitmap_words,
1354 sizeof(req->bitmap_words));
Jeff Dike91acb212005-10-10 23:10:32 -04001355 if(n != sizeof(req->bitmap_words)){
1356 printk("do_io - bitmap update failed, err = %d fd = %d\n", -n,
1357 req->fds[1]);
Jeff Dikedc764e52007-05-06 14:51:41 -07001358 return 1;
Jeff Dike91acb212005-10-10 23:10:32 -04001359 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360
Jeff Dikedc764e52007-05-06 14:51:41 -07001361 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362}
Jeff Dike91acb212005-10-10 23:10:32 -04001363
WANG Cong5dc62b12008-04-28 02:13:58 -07001364static void do_io(struct io_thread_req *req)
Jeff Dike91acb212005-10-10 23:10:32 -04001365{
1366 char *buf;
1367 unsigned long len;
1368 int n, nsectors, start, end, bit;
1369 int err;
1370 __u64 off;
1371
1372 nsectors = req->length / req->sectorsize;
1373 start = 0;
1374 do {
1375 bit = ubd_test_bit(start, (unsigned char *) &req->sector_mask);
1376 end = start;
1377 while((end < nsectors) &&
1378 (ubd_test_bit(end, (unsigned char *)
1379 &req->sector_mask) == bit))
1380 end++;
1381
1382 off = req->offset + req->offsets[bit] +
1383 start * req->sectorsize;
1384 len = (end - start) * req->sectorsize;
1385 buf = &req->buffer[start * req->sectorsize];
1386
1387 err = os_seek_file(req->fds[bit], off);
1388 if(err < 0){
1389 printk("do_io - lseek failed : err = %d\n", -err);
1390 req->error = 1;
1391 return;
1392 }
1393 if(req->op == UBD_READ){
1394 n = 0;
1395 do {
1396 buf = &buf[n];
1397 len -= n;
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001398 n = os_read_file(req->fds[bit], buf, len);
Jeff Dike91acb212005-10-10 23:10:32 -04001399 if (n < 0) {
1400 printk("do_io - read failed, err = %d "
1401 "fd = %d\n", -n, req->fds[bit]);
1402 req->error = 1;
1403 return;
1404 }
1405 } while((n < len) && (n != 0));
1406 if (n < len) memset(&buf[n], 0, len - n);
1407 } else {
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001408 n = os_write_file(req->fds[bit], buf, len);
Jeff Dike91acb212005-10-10 23:10:32 -04001409 if(n != len){
1410 printk("do_io - write failed err = %d "
1411 "fd = %d\n", -n, req->fds[bit]);
1412 req->error = 1;
1413 return;
1414 }
1415 }
1416
1417 start = end;
1418 } while(start < nsectors);
1419
1420 req->error = update_bitmap(req);
1421}
1422
1423/* Changed in start_io_thread, which is serialized by being called only
1424 * from ubd_init, which is an initcall.
1425 */
1426int kernel_fd = -1;
1427
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001428/* Only changed by the io thread. XXX: currently unused. */
1429static int io_count = 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001430
1431int io_thread(void *arg)
1432{
Jeff Dike2adcec22007-05-06 14:51:37 -07001433 struct io_thread_req *req;
Jeff Dike91acb212005-10-10 23:10:32 -04001434 int n;
1435
1436 ignore_sigwinch_sig();
1437 while(1){
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001438 n = os_read_file(kernel_fd, &req,
Jeff Dike2adcec22007-05-06 14:51:37 -07001439 sizeof(struct io_thread_req *));
1440 if(n != sizeof(struct io_thread_req *)){
Jeff Dike91acb212005-10-10 23:10:32 -04001441 if(n < 0)
1442 printk("io_thread - read failed, fd = %d, "
1443 "err = %d\n", kernel_fd, -n);
1444 else {
1445 printk("io_thread - short read, fd = %d, "
1446 "length = %d\n", kernel_fd, n);
1447 }
1448 continue;
1449 }
1450 io_count++;
Jeff Dike2adcec22007-05-06 14:51:37 -07001451 do_io(req);
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001452 n = os_write_file(kernel_fd, &req,
Jeff Dike2adcec22007-05-06 14:51:37 -07001453 sizeof(struct io_thread_req *));
1454 if(n != sizeof(struct io_thread_req *))
Jeff Dike91acb212005-10-10 23:10:32 -04001455 printk("io_thread - write failed, fd = %d, err = %d\n",
1456 kernel_fd, -n);
1457 }
Jeff Dike91acb212005-10-10 23:10:32 -04001458
Jeff Dike1b57e9c2006-01-06 00:18:49 -08001459 return 0;
1460}