blob: 36ca9fa89d05df47b22e9447ecb10a9496b0d93b [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"
Bartlomiej Zolnierkiewicz73855e12009-04-01 21:42:21 +020025#include "linux/ata.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include "linux/hdreg.h"
27#include "linux/init.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include "linux/cdrom.h"
29#include "linux/proc_fs.h"
30#include "linux/ctype.h"
31#include "linux/capability.h"
32#include "linux/mm.h"
33#include "linux/vmalloc.h"
34#include "linux/blkpg.h"
35#include "linux/genhd.h"
36#include "linux/spinlock.h"
Russell Kingd052d1b2005-10-29 19:07:23 +010037#include "linux/platform_device.h"
WANG Cong23464ff2007-10-24 13:07:11 +020038#include "linux/scatterlist.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include "asm/segment.h"
40#include "asm/uaccess.h"
41#include "asm/irq.h"
42#include "asm/types.h"
43#include "asm/tlbflush.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#include "mem_user.h"
45#include "kern_util.h"
46#include "kern.h"
47#include "mconsole_kern.h"
48#include "init.h"
49#include "irq_user.h"
50#include "irq_kern.h"
51#include "ubd_user.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070052#include "os.h"
53#include "mem.h"
54#include "mem_kern.h"
55#include "cow.h"
56
Jeff Dike7b9014c2005-05-20 13:59:11 -070057enum ubd_req { UBD_READ, UBD_WRITE };
Linus Torvalds1da177e2005-04-16 15:20:36 -070058
59struct io_thread_req {
Jeff Dike62f96cb2007-02-10 01:44:16 -080060 struct request *req;
Jeff Dike91acb212005-10-10 23:10:32 -040061 enum ubd_req op;
Linus Torvalds1da177e2005-04-16 15:20:36 -070062 int fds[2];
63 unsigned long offsets[2];
64 unsigned long long offset;
65 unsigned long length;
66 char *buffer;
67 int sectorsize;
Jeff Dike91acb212005-10-10 23:10:32 -040068 unsigned long sector_mask;
69 unsigned long long cow_offset;
70 unsigned long bitmap_words[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -070071 int error;
72};
73
Jeff Dike91acb212005-10-10 23:10:32 -040074static inline int ubd_test_bit(__u64 bit, unsigned char *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -070075{
76 __u64 n;
77 int bits, off;
78
Jeff Dike91acb212005-10-10 23:10:32 -040079 bits = sizeof(data[0]) * 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -070080 n = bit / bits;
81 off = bit % bits;
Jeff Dikedc764e52007-05-06 14:51:41 -070082 return (data[n] & (1 << off)) != 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070083}
84
Jeff Dike91acb212005-10-10 23:10:32 -040085static inline void ubd_set_bit(__u64 bit, unsigned char *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -070086{
87 __u64 n;
88 int bits, off;
89
Jeff Dike91acb212005-10-10 23:10:32 -040090 bits = sizeof(data[0]) * 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -070091 n = bit / bits;
92 off = bit % bits;
Jeff Dike91acb212005-10-10 23:10:32 -040093 data[n] |= (1 << off);
Linus Torvalds1da177e2005-04-16 15:20:36 -070094}
95/*End stuff from ubd_user.h*/
96
97#define DRIVER_NAME "uml-blkdev"
98
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -080099static DEFINE_MUTEX(ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100
Al Viroa625c992008-03-02 09:16:26 -0500101static int ubd_open(struct block_device *bdev, fmode_t mode);
102static int ubd_release(struct gendisk *disk, fmode_t mode);
103static int ubd_ioctl(struct block_device *bdev, fmode_t mode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 unsigned int cmd, unsigned long arg);
Christoph Hellwiga885c8c2006-01-08 01:02:50 -0800105static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106
Paolo 'Blaisorblade' Giarrusso97d88ac2006-10-30 22:07:03 -0800107#define MAX_DEV (16)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109static struct block_device_operations ubd_blops = {
110 .owner = THIS_MODULE,
Al Viroa625c992008-03-02 09:16:26 -0500111 .open = ubd_open,
112 .release = ubd_release,
113 .ioctl = ubd_ioctl,
Christoph Hellwiga885c8c2006-01-08 01:02:50 -0800114 .getgeo = ubd_getgeo,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115};
116
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117/* Protected by ubd_lock */
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700118static int fake_major = UBD_MAJOR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119static struct gendisk *ubd_gendisk[MAX_DEV];
120static struct gendisk *fake_gendisk[MAX_DEV];
Jeff Dike6c29256c2006-03-27 01:14:37 -0800121
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122#ifdef CONFIG_BLK_DEV_UBD_SYNC
123#define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 1, .c = 0, \
124 .cl = 1 })
125#else
126#define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 0, .c = 0, \
127 .cl = 1 })
128#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129static struct openflags global_openflags = OPEN_FLAGS;
130
131struct cow {
Paolo 'Blaisorblade' Giarrusso2a9d32f2006-10-30 22:07:04 -0800132 /* backing file name */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133 char *file;
Paolo 'Blaisorblade' Giarrusso2a9d32f2006-10-30 22:07:04 -0800134 /* backing file fd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 int fd;
136 unsigned long *bitmap;
137 unsigned long bitmap_len;
138 int bitmap_offset;
Jeff Dikedc764e52007-05-06 14:51:41 -0700139 int data_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140};
141
Jeff Dikea0044bd2007-05-06 14:51:36 -0700142#define MAX_SG 64
143
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144struct ubd {
Jeff Dikea0044bd2007-05-06 14:51:36 -0700145 struct list_head restart;
Paolo 'Blaisorblade' Giarrusso2a9d32f2006-10-30 22:07:04 -0800146 /* name (and fd, below) of the file opened for writing, either the
147 * backing or the cow file. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 char *file;
149 int count;
150 int fd;
151 __u64 size;
152 struct openflags boot_openflags;
153 struct openflags openflags;
Paolo 'Blaisorblade' Giarrusso84e945e2006-10-30 22:07:10 -0800154 unsigned shared:1;
155 unsigned no_cow:1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 struct cow cow;
157 struct platform_device pdev;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800158 struct request_queue *queue;
159 spinlock_t lock;
Jeff Dikea0044bd2007-05-06 14:51:36 -0700160 struct scatterlist sg[MAX_SG];
161 struct request *request;
162 int start_sg, end_sg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163};
164
165#define DEFAULT_COW { \
166 .file = NULL, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700167 .fd = -1, \
168 .bitmap = NULL, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169 .bitmap_offset = 0, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700170 .data_offset = 0, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171}
172
173#define DEFAULT_UBD { \
174 .file = NULL, \
175 .count = 0, \
176 .fd = -1, \
177 .size = -1, \
178 .boot_openflags = OPEN_FLAGS, \
179 .openflags = OPEN_FLAGS, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700180 .no_cow = 0, \
Jeff Dike6c29256c2006-03-27 01:14:37 -0800181 .shared = 0, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700182 .cow = DEFAULT_COW, \
Jeff Dike62f96cb2007-02-10 01:44:16 -0800183 .lock = SPIN_LOCK_UNLOCKED, \
Jeff Dikea0044bd2007-05-06 14:51:36 -0700184 .request = NULL, \
185 .start_sg = 0, \
186 .end_sg = 0, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187}
188
Jeff Dikeb8831a12007-02-10 01:44:17 -0800189/* Protected by ubd_lock */
WANG Cong5dc62b12008-04-28 02:13:58 -0700190static struct ubd ubd_devs[MAX_DEV] = { [0 ... MAX_DEV - 1] = DEFAULT_UBD };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192/* Only changed by fake_ide_setup which is a setup */
193static int fake_ide = 0;
194static struct proc_dir_entry *proc_ide_root = NULL;
195static struct proc_dir_entry *proc_ide = NULL;
196
197static void make_proc_ide(void)
198{
199 proc_ide_root = proc_mkdir("ide", NULL);
200 proc_ide = proc_mkdir("ide0", proc_ide_root);
201}
202
203static int proc_ide_read_media(char *page, char **start, off_t off, int count,
204 int *eof, void *data)
205{
206 int len;
207
208 strcpy(page, "disk\n");
209 len = strlen("disk\n");
210 len -= off;
211 if (len < count){
212 *eof = 1;
213 if (len <= 0) return 0;
214 }
215 else len = count;
216 *start = page + off;
217 return len;
218}
219
WANG Congc0a92902008-02-04 22:30:41 -0800220static void make_ide_entries(const char *dev_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221{
222 struct proc_dir_entry *dir, *ent;
223 char name[64];
224
225 if(proc_ide_root == NULL) make_proc_ide();
226
227 dir = proc_mkdir(dev_name, proc_ide);
228 if(!dir) return;
229
230 ent = create_proc_entry("media", S_IFREG|S_IRUGO, dir);
231 if(!ent) return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 ent->data = NULL;
233 ent->read_proc = proc_ide_read_media;
234 ent->write_proc = NULL;
WANG Congc0a92902008-02-04 22:30:41 -0800235 snprintf(name, sizeof(name), "ide0/%s", dev_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 proc_symlink(dev_name, proc_ide_root, name);
237}
238
239static int fake_ide_setup(char *str)
240{
241 fake_ide = 1;
Jeff Dikedc764e52007-05-06 14:51:41 -0700242 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243}
244
245__setup("fake_ide", fake_ide_setup);
246
247__uml_help(fake_ide_setup,
248"fake_ide\n"
249" Create ide0 entries that map onto ubd devices.\n\n"
250);
251
252static int parse_unit(char **ptr)
253{
254 char *str = *ptr, *end;
255 int n = -1;
256
257 if(isdigit(*str)) {
258 n = simple_strtoul(str, &end, 0);
259 if(end == str)
Jeff Dikedc764e52007-05-06 14:51:41 -0700260 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 *ptr = end;
262 }
Paolo 'Blaisorblade' Giarrusso97d88ac2006-10-30 22:07:03 -0800263 else if (('a' <= *str) && (*str <= 'z')) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 n = *str - 'a';
265 str++;
266 *ptr = str;
267 }
Jeff Dikedc764e52007-05-06 14:51:41 -0700268 return n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269}
270
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800271/* If *index_out == -1 at exit, the passed option was a general one;
272 * otherwise, the str pointer is used (and owned) inside ubd_devs array, so it
273 * should not be freed on exit.
274 */
Jeff Dikef28169d2007-02-10 01:43:53 -0800275static int ubd_setup_common(char *str, int *index_out, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800277 struct ubd *ubd_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 struct openflags flags = global_openflags;
279 char *backing_file;
Jeff Dikeb8831a12007-02-10 01:44:17 -0800280 int n, err = 0, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281
282 if(index_out) *index_out = -1;
283 n = *str;
284 if(n == '='){
285 char *end;
286 int major;
287
288 str++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 if(!strcmp(str, "sync")){
290 global_openflags = of_sync(global_openflags);
Jeff Dikeb8831a12007-02-10 01:44:17 -0800291 goto out1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 }
293
Jeff Dikef28169d2007-02-10 01:43:53 -0800294 err = -EINVAL;
Jeff Dikeb8831a12007-02-10 01:44:17 -0800295 major = simple_strtoul(str, &end, 0);
296 if((*end != '\0') || (end == str)){
297 *error_out = "Didn't parse major number";
298 goto out1;
299 }
300
Jeff Dikef28169d2007-02-10 01:43:53 -0800301 mutex_lock(&ubd_lock);
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700302 if (fake_major != UBD_MAJOR) {
Jeff Dikef28169d2007-02-10 01:43:53 -0800303 *error_out = "Can't assign a fake major twice";
304 goto out1;
305 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800306
Jeff Dikef28169d2007-02-10 01:43:53 -0800307 fake_major = major;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308
309 printk(KERN_INFO "Setting extra ubd major number to %d\n",
310 major);
Jeff Dikef28169d2007-02-10 01:43:53 -0800311 err = 0;
312 out1:
313 mutex_unlock(&ubd_lock);
314 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 }
316
317 n = parse_unit(&str);
318 if(n < 0){
Jeff Dikef28169d2007-02-10 01:43:53 -0800319 *error_out = "Couldn't parse device number";
320 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 }
322 if(n >= MAX_DEV){
Jeff Dikef28169d2007-02-10 01:43:53 -0800323 *error_out = "Device number out of range";
324 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 }
326
Jeff Dikef28169d2007-02-10 01:43:53 -0800327 err = -EBUSY;
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800328 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800330 ubd_dev = &ubd_devs[n];
331 if(ubd_dev->file != NULL){
Jeff Dikef28169d2007-02-10 01:43:53 -0800332 *error_out = "Device is already configured";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 goto out;
334 }
335
336 if (index_out)
337 *index_out = n;
338
Jeff Dikef28169d2007-02-10 01:43:53 -0800339 err = -EINVAL;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800340 for (i = 0; i < sizeof("rscd="); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 switch (*str) {
342 case 'r':
343 flags.w = 0;
344 break;
345 case 's':
346 flags.s = 1;
347 break;
348 case 'd':
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800349 ubd_dev->no_cow = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 break;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800351 case 'c':
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800352 ubd_dev->shared = 1;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800353 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 case '=':
355 str++;
356 goto break_loop;
357 default:
Jeff Dikef28169d2007-02-10 01:43:53 -0800358 *error_out = "Expected '=' or flag letter "
359 "(r, s, c, or d)";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 goto out;
361 }
362 str++;
363 }
364
Jeff Dikef28169d2007-02-10 01:43:53 -0800365 if (*str == '=')
366 *error_out = "Too many flags specified";
367 else
368 *error_out = "Missing '='";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 goto out;
370
371break_loop:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 backing_file = strchr(str, ',');
373
Jeff Dikef28169d2007-02-10 01:43:53 -0800374 if (backing_file == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 backing_file = strchr(str, ':');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376
Jeff Dikef28169d2007-02-10 01:43:53 -0800377 if(backing_file != NULL){
378 if(ubd_dev->no_cow){
379 *error_out = "Can't specify both 'd' and a cow file";
380 goto out;
381 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 else {
383 *backing_file = '\0';
384 backing_file++;
385 }
386 }
Jeff Dikef28169d2007-02-10 01:43:53 -0800387 err = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800388 ubd_dev->file = str;
389 ubd_dev->cow.file = backing_file;
390 ubd_dev->boot_openflags = flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800392 mutex_unlock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -0800393 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394}
395
396static int ubd_setup(char *str)
397{
Jeff Dikef28169d2007-02-10 01:43:53 -0800398 char *error;
399 int err;
400
401 err = ubd_setup_common(str, NULL, &error);
402 if(err)
403 printk(KERN_ERR "Failed to initialize device with \"%s\" : "
404 "%s\n", str, error);
405 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406}
407
408__setup("ubd", ubd_setup);
409__uml_help(ubd_setup,
410"ubd<n><flags>=<filename>[(:|,)<filename2>]\n"
411" This is used to associate a device with a file in the underlying\n"
412" filesystem. When specifying two filenames, the first one is the\n"
413" COW name and the second is the backing file name. As separator you can\n"
414" use either a ':' or a ',': the first one allows writing things like;\n"
415" ubd0=~/Uml/root_cow:~/Uml/root_backing_file\n"
416" while with a ',' the shell would not expand the 2nd '~'.\n"
Jeff Dikef28169d2007-02-10 01:43:53 -0800417" When using only one filename, UML will detect whether to treat it like\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418" a COW file or a backing file. To override this detection, add the 'd'\n"
419" flag:\n"
420" ubd0d=BackingFile\n"
421" Usually, there is a filesystem in the file, but \n"
422" that's not required. Swap devices containing swap files can be\n"
423" specified like this. Also, a file which doesn't contain a\n"
424" filesystem can have its contents read in the virtual \n"
425" machine by running 'dd' on the device. <n> must be in the range\n"
426" 0 to 7. Appending an 'r' to the number will cause that device\n"
427" to be mounted read-only. For example ubd1r=./ext_fs. Appending\n"
Jeff Dike20ede452008-02-04 22:30:37 -0800428" an 's' will cause data to be written to disk on the host immediately.\n"
429" 'c' will cause the device to be treated as being shared between multiple\n"
430" UMLs and file locking will be turned off - this is appropriate for a\n"
431" cluster filesystem and inappropriate at almost all other times.\n\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432);
433
Jeff Dike8299ca52008-02-04 22:30:48 -0800434static int udb_setup(char *str)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435{
436 printk("udb%s specified on command line is almost certainly a ubd -> "
437 "udb TYPO\n", str);
Jeff Dikedc764e52007-05-06 14:51:41 -0700438 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439}
440
441__setup("udb", udb_setup);
442__uml_help(udb_setup,
443"udb\n"
Jeff Dike0894e272005-05-28 15:51:55 -0700444" This option is here solely to catch ubd -> udb typos, which can be\n"
445" to impossible to catch visually unless you specifically look for\n"
446" them. The only result of any option starting with 'udb' is an error\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447" in the boot output.\n\n"
448);
449
Jens Axboe165125e2007-07-24 09:28:11 +0200450static void do_ubd_request(struct request_queue * q);
Jeff Dike91acb212005-10-10 23:10:32 -0400451
452/* Only changed by ubd_init, which is an initcall. */
WANG Cong5dc62b12008-04-28 02:13:58 -0700453static int thread_fd = -1;
Jeff Dikea0044bd2007-05-06 14:51:36 -0700454static LIST_HEAD(restart);
455
Paolo 'Blaisorblade' Giarrusso2fe30a32006-10-30 22:07:09 -0800456/* XXX - move this inside ubd_intr. */
Jeff Dike62f96cb2007-02-10 01:44:16 -0800457/* Called without dev->lock held, and only in interrupt context. */
Jeff Dike91acb212005-10-10 23:10:32 -0400458static void ubd_handler(void)
459{
Jeff Dike2adcec22007-05-06 14:51:37 -0700460 struct io_thread_req *req;
Jeff Dikea0044bd2007-05-06 14:51:36 -0700461 struct ubd *ubd;
462 struct list_head *list, *next_ele;
463 unsigned long flags;
Jeff Dike91acb212005-10-10 23:10:32 -0400464 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465
Jeff Dikea0044bd2007-05-06 14:51:36 -0700466 while(1){
Jeff Dikea6ea4cc2007-05-06 14:51:43 -0700467 n = os_read_file(thread_fd, &req,
468 sizeof(struct io_thread_req *));
Jeff Dikea0044bd2007-05-06 14:51:36 -0700469 if(n != sizeof(req)){
470 if(n == -EAGAIN)
471 break;
472 printk(KERN_ERR "spurious interrupt in ubd_handler, "
473 "err = %d\n", -n);
474 return;
475 }
476
Tejun Heo4d6c84d2009-04-28 13:06:09 +0900477 blk_end_request(req->req, 0, req->length);
Jeff Dike2adcec22007-05-06 14:51:37 -0700478 kfree(req);
Jeff Dike91acb212005-10-10 23:10:32 -0400479 }
Jeff Dike62f96cb2007-02-10 01:44:16 -0800480 reactivate_fd(thread_fd, UBD_IRQ);
Jeff Dikea0044bd2007-05-06 14:51:36 -0700481
482 list_for_each_safe(list, next_ele, &restart){
483 ubd = container_of(list, struct ubd, restart);
484 list_del_init(&ubd->restart);
485 spin_lock_irqsave(&ubd->lock, flags);
486 do_ubd_request(ubd->queue);
487 spin_unlock_irqrestore(&ubd->lock, flags);
488 }
Jeff Dike91acb212005-10-10 23:10:32 -0400489}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490
Al Viro7bea96f2006-10-08 22:49:34 +0100491static irqreturn_t ubd_intr(int irq, void *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492{
Jeff Dike91acb212005-10-10 23:10:32 -0400493 ubd_handler();
Jeff Dikedc764e52007-05-06 14:51:41 -0700494 return IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495}
496
Jeff Dike91acb212005-10-10 23:10:32 -0400497/* Only changed by ubd_init, which is an initcall. */
498static int io_pid = -1;
499
WANG Cong5dc62b12008-04-28 02:13:58 -0700500static void kill_io_thread(void)
Jeff Dike91acb212005-10-10 23:10:32 -0400501{
Jeff Dike6c29256c2006-03-27 01:14:37 -0800502 if(io_pid != -1)
Jeff Dike91acb212005-10-10 23:10:32 -0400503 os_kill_process(io_pid, 1);
504}
505
506__uml_exitcall(kill_io_thread);
507
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800508static inline int ubd_file_size(struct ubd *ubd_dev, __u64 *size_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509{
510 char *file;
511
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800512 file = ubd_dev->cow.file ? ubd_dev->cow.file : ubd_dev->file;
Jeff Dikedc764e52007-05-06 14:51:41 -0700513 return os_file_size(file, size_out);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514}
515
WANG Cong5dc62b12008-04-28 02:13:58 -0700516static int read_cow_bitmap(int fd, void *buf, int offset, int len)
517{
518 int err;
519
520 err = os_seek_file(fd, offset);
521 if (err < 0)
522 return err;
523
524 err = os_read_file(fd, buf, len);
525 if (err < 0)
526 return err;
527
528 return 0;
529}
530
531static int backing_file_mismatch(char *file, __u64 size, time_t mtime)
532{
533 unsigned long modtime;
534 unsigned long long actual;
535 int err;
536
537 err = os_file_modtime(file, &modtime);
538 if (err < 0) {
539 printk(KERN_ERR "Failed to get modification time of backing "
540 "file \"%s\", err = %d\n", file, -err);
541 return err;
542 }
543
544 err = os_file_size(file, &actual);
545 if (err < 0) {
546 printk(KERN_ERR "Failed to get size of backing file \"%s\", "
547 "err = %d\n", file, -err);
548 return err;
549 }
550
551 if (actual != size) {
552 /*__u64 can be a long on AMD64 and with %lu GCC complains; so
553 * the typecast.*/
554 printk(KERN_ERR "Size mismatch (%llu vs %llu) of COW header "
555 "vs backing file\n", (unsigned long long) size, actual);
556 return -EINVAL;
557 }
558 if (modtime != mtime) {
559 printk(KERN_ERR "mtime mismatch (%ld vs %ld) of COW header vs "
560 "backing file\n", mtime, modtime);
561 return -EINVAL;
562 }
563 return 0;
564}
565
566static int path_requires_switch(char *from_cmdline, char *from_cow, char *cow)
567{
568 struct uml_stat buf1, buf2;
569 int err;
570
571 if (from_cmdline == NULL)
572 return 0;
573 if (!strcmp(from_cmdline, from_cow))
574 return 0;
575
576 err = os_stat_file(from_cmdline, &buf1);
577 if (err < 0) {
578 printk(KERN_ERR "Couldn't stat '%s', err = %d\n", from_cmdline,
579 -err);
580 return 0;
581 }
582 err = os_stat_file(from_cow, &buf2);
583 if (err < 0) {
584 printk(KERN_ERR "Couldn't stat '%s', err = %d\n", from_cow,
585 -err);
586 return 1;
587 }
588 if ((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino))
589 return 0;
590
591 printk(KERN_ERR "Backing file mismatch - \"%s\" requested, "
592 "\"%s\" specified in COW header of \"%s\"\n",
593 from_cmdline, from_cow, cow);
594 return 1;
595}
596
597static int open_ubd_file(char *file, struct openflags *openflags, int shared,
598 char **backing_file_out, int *bitmap_offset_out,
599 unsigned long *bitmap_len_out, int *data_offset_out,
600 int *create_cow_out)
601{
602 time_t mtime;
603 unsigned long long size;
604 __u32 version, align;
605 char *backing_file;
606 int fd, err, sectorsize, asked_switch, mode = 0644;
607
608 fd = os_open_file(file, *openflags, mode);
609 if (fd < 0) {
610 if ((fd == -ENOENT) && (create_cow_out != NULL))
611 *create_cow_out = 1;
612 if (!openflags->w ||
613 ((fd != -EROFS) && (fd != -EACCES)))
614 return fd;
615 openflags->w = 0;
616 fd = os_open_file(file, *openflags, mode);
617 if (fd < 0)
618 return fd;
619 }
620
621 if (shared)
622 printk(KERN_INFO "Not locking \"%s\" on the host\n", file);
623 else {
624 err = os_lock_file(fd, openflags->w);
625 if (err < 0) {
626 printk(KERN_ERR "Failed to lock '%s', err = %d\n",
627 file, -err);
628 goto out_close;
629 }
630 }
631
632 /* Successful return case! */
633 if (backing_file_out == NULL)
634 return fd;
635
636 err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime,
637 &size, &sectorsize, &align, bitmap_offset_out);
638 if (err && (*backing_file_out != NULL)) {
639 printk(KERN_ERR "Failed to read COW header from COW file "
640 "\"%s\", errno = %d\n", file, -err);
641 goto out_close;
642 }
643 if (err)
644 return fd;
645
646 asked_switch = path_requires_switch(*backing_file_out, backing_file,
647 file);
648
649 /* Allow switching only if no mismatch. */
650 if (asked_switch && !backing_file_mismatch(*backing_file_out, size,
651 mtime)) {
652 printk(KERN_ERR "Switching backing file to '%s'\n",
653 *backing_file_out);
654 err = write_cow_header(file, fd, *backing_file_out,
655 sectorsize, align, &size);
656 if (err) {
657 printk(KERN_ERR "Switch failed, errno = %d\n", -err);
658 goto out_close;
659 }
660 } else {
661 *backing_file_out = backing_file;
662 err = backing_file_mismatch(*backing_file_out, size, mtime);
663 if (err)
664 goto out_close;
665 }
666
667 cow_sizes(version, size, sectorsize, align, *bitmap_offset_out,
668 bitmap_len_out, data_offset_out);
669
670 return fd;
671 out_close:
672 os_close_file(fd);
673 return err;
674}
675
676static int create_cow_file(char *cow_file, char *backing_file,
677 struct openflags flags,
678 int sectorsize, int alignment, int *bitmap_offset_out,
679 unsigned long *bitmap_len_out, int *data_offset_out)
680{
681 int err, fd;
682
683 flags.c = 1;
684 fd = open_ubd_file(cow_file, &flags, 0, NULL, NULL, NULL, NULL, NULL);
685 if (fd < 0) {
686 err = fd;
687 printk(KERN_ERR "Open of COW file '%s' failed, errno = %d\n",
688 cow_file, -err);
689 goto out;
690 }
691
692 err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment,
693 bitmap_offset_out, bitmap_len_out,
694 data_offset_out);
695 if (!err)
696 return fd;
697 os_close_file(fd);
698 out:
699 return err;
700}
701
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800702static void ubd_close_dev(struct ubd *ubd_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800704 os_close_file(ubd_dev->fd);
705 if(ubd_dev->cow.file == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 return;
707
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800708 os_close_file(ubd_dev->cow.fd);
709 vfree(ubd_dev->cow.bitmap);
710 ubd_dev->cow.bitmap = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711}
712
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800713static int ubd_open_dev(struct ubd *ubd_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714{
715 struct openflags flags;
716 char **back_ptr;
717 int err, create_cow, *create_ptr;
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800718 int fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800720 ubd_dev->openflags = ubd_dev->boot_openflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 create_cow = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800722 create_ptr = (ubd_dev->cow.file != NULL) ? &create_cow : NULL;
723 back_ptr = ubd_dev->no_cow ? NULL : &ubd_dev->cow.file;
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800724
725 fd = open_ubd_file(ubd_dev->file, &ubd_dev->openflags, ubd_dev->shared,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800726 back_ptr, &ubd_dev->cow.bitmap_offset,
727 &ubd_dev->cow.bitmap_len, &ubd_dev->cow.data_offset,
Jeff Dike6c29256c2006-03-27 01:14:37 -0800728 create_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800730 if((fd == -ENOENT) && create_cow){
731 fd = create_cow_file(ubd_dev->file, ubd_dev->cow.file,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800732 ubd_dev->openflags, 1 << 9, PAGE_SIZE,
733 &ubd_dev->cow.bitmap_offset,
734 &ubd_dev->cow.bitmap_len,
735 &ubd_dev->cow.data_offset);
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800736 if(fd >= 0){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 printk(KERN_INFO "Creating \"%s\" as COW file for "
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800738 "\"%s\"\n", ubd_dev->file, ubd_dev->cow.file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 }
740 }
741
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800742 if(fd < 0){
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800743 printk("Failed to open '%s', errno = %d\n", ubd_dev->file,
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800744 -fd);
745 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 }
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800747 ubd_dev->fd = fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800749 if(ubd_dev->cow.file != NULL){
Jeff Dikef4768ff2007-08-22 14:01:53 -0700750 blk_queue_max_sectors(ubd_dev->queue, 8 * sizeof(long));
751
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 err = -ENOMEM;
Jesper Juhlda2486b2007-10-16 01:27:19 -0700753 ubd_dev->cow.bitmap = vmalloc(ubd_dev->cow.bitmap_len);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800754 if(ubd_dev->cow.bitmap == NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 printk(KERN_ERR "Failed to vmalloc COW bitmap\n");
756 goto error;
757 }
758 flush_tlb_kernel_vm();
759
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800760 err = read_cow_bitmap(ubd_dev->fd, ubd_dev->cow.bitmap,
761 ubd_dev->cow.bitmap_offset,
762 ubd_dev->cow.bitmap_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 if(err < 0)
764 goto error;
765
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800766 flags = ubd_dev->openflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 flags.w = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800768 err = open_ubd_file(ubd_dev->cow.file, &flags, ubd_dev->shared, NULL,
Jeff Dike6c29256c2006-03-27 01:14:37 -0800769 NULL, NULL, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 if(err < 0) goto error;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800771 ubd_dev->cow.fd = err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 }
Jeff Dikedc764e52007-05-06 14:51:41 -0700773 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 error:
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800775 os_close_file(ubd_dev->fd);
Jeff Dikedc764e52007-05-06 14:51:41 -0700776 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777}
778
Jeff Dike2e3f5252007-05-06 14:51:29 -0700779static void ubd_device_release(struct device *dev)
780{
781 struct ubd *ubd_dev = dev->driver_data;
782
783 blk_cleanup_queue(ubd_dev->queue);
784 *ubd_dev = ((struct ubd) DEFAULT_UBD);
785}
786
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800787static int ubd_disk_register(int major, u64 size, int unit,
Jeff Dikeb8831a12007-02-10 01:44:17 -0800788 struct gendisk **disk_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789{
790 struct gendisk *disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791
792 disk = alloc_disk(1 << UBD_SHIFT);
793 if(disk == NULL)
Jeff Dikedc764e52007-05-06 14:51:41 -0700794 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795
796 disk->major = major;
797 disk->first_minor = unit << UBD_SHIFT;
798 disk->fops = &ubd_blops;
799 set_capacity(disk, size / 512);
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700800 if (major == UBD_MAJOR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 sprintf(disk->disk_name, "ubd%c", 'a' + unit);
Greg Kroah-Hartmance7b0f42005-06-20 21:15:16 -0700802 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 sprintf(disk->disk_name, "ubd_fake%d", unit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804
805 /* sysfs register (not for ide fake devices) */
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700806 if (major == UBD_MAJOR) {
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800807 ubd_devs[unit].pdev.id = unit;
808 ubd_devs[unit].pdev.name = DRIVER_NAME;
Jeff Dike2e3f5252007-05-06 14:51:29 -0700809 ubd_devs[unit].pdev.dev.release = ubd_device_release;
810 ubd_devs[unit].pdev.dev.driver_data = &ubd_devs[unit];
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800811 platform_device_register(&ubd_devs[unit].pdev);
812 disk->driverfs_dev = &ubd_devs[unit].pdev.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 }
814
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800815 disk->private_data = &ubd_devs[unit];
Jeff Dike62f96cb2007-02-10 01:44:16 -0800816 disk->queue = ubd_devs[unit].queue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 add_disk(disk);
818
819 *disk_out = disk;
820 return 0;
821}
822
823#define ROUND_BLOCK(n) ((n + ((1 << 9) - 1)) & (-1 << 9))
824
Jeff Dikef28169d2007-02-10 01:43:53 -0800825static int ubd_add(int n, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800827 struct ubd *ubd_dev = &ubd_devs[n];
Jeff Dikef28169d2007-02-10 01:43:53 -0800828 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800830 if(ubd_dev->file == NULL)
Jeff Dikeec7cf782005-09-03 15:57:29 -0700831 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800833 err = ubd_file_size(ubd_dev, &ubd_dev->size);
Jeff Dikef28169d2007-02-10 01:43:53 -0800834 if(err < 0){
835 *error_out = "Couldn't determine size of device's file";
Jeff Dike80c13742006-09-29 01:58:51 -0700836 goto out;
Jeff Dikef28169d2007-02-10 01:43:53 -0800837 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800839 ubd_dev->size = ROUND_BLOCK(ubd_dev->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840
Jeff Dikea0044bd2007-05-06 14:51:36 -0700841 INIT_LIST_HEAD(&ubd_dev->restart);
WANG Cong4f40c052007-11-05 14:50:59 -0800842 sg_init_table(ubd_dev->sg, MAX_SG);
Jeff Dikea0044bd2007-05-06 14:51:36 -0700843
Jeff Dike62f96cb2007-02-10 01:44:16 -0800844 err = -ENOMEM;
845 ubd_dev->queue = blk_init_queue(do_ubd_request, &ubd_dev->lock);
846 if (ubd_dev->queue == NULL) {
847 *error_out = "Failed to initialize device queue";
Jeff Dike80c13742006-09-29 01:58:51 -0700848 goto out;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800849 }
850 ubd_dev->queue->queuedata = ubd_dev;
851
Jeff Dikea0044bd2007-05-06 14:51:36 -0700852 blk_queue_max_hw_segments(ubd_dev->queue, MAX_SG);
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700853 err = ubd_disk_register(UBD_MAJOR, ubd_dev->size, n, &ubd_gendisk[n]);
Jeff Dike62f96cb2007-02-10 01:44:16 -0800854 if(err){
855 *error_out = "Failed to register device";
856 goto out_cleanup;
857 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800858
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700859 if (fake_major != UBD_MAJOR)
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800860 ubd_disk_register(fake_major, ubd_dev->size, n,
Jeff Dike62f96cb2007-02-10 01:44:16 -0800861 &fake_gendisk[n]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862
Jeff Dike83380cc2008-02-04 22:31:18 -0800863 /*
864 * Perhaps this should also be under the "if (fake_major)" above
865 * using the fake_disk->disk_name
866 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 if (fake_ide)
868 make_ide_entries(ubd_gendisk[n]->disk_name);
869
Jeff Dikeec7cf782005-09-03 15:57:29 -0700870 err = 0;
Jeff Dikeec7cf782005-09-03 15:57:29 -0700871out:
872 return err;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800873
874out_cleanup:
875 blk_cleanup_queue(ubd_dev->queue);
876 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877}
878
Jeff Dikef28169d2007-02-10 01:43:53 -0800879static int ubd_config(char *str, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880{
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800881 int n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882
Jeff Dikef28169d2007-02-10 01:43:53 -0800883 /* This string is possibly broken up and stored, so it's only
884 * freed if ubd_setup_common fails, or if only general options
885 * were set.
886 */
Jeff Dike970d6e32006-01-06 00:18:48 -0800887 str = kstrdup(str, GFP_KERNEL);
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800888 if (str == NULL) {
Jeff Dikef28169d2007-02-10 01:43:53 -0800889 *error_out = "Failed to allocate memory";
890 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 }
Jeff Dikef28169d2007-02-10 01:43:53 -0800892
893 ret = ubd_setup_common(str, &n, error_out);
894 if (ret)
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800895 goto err_free;
Jeff Dikef28169d2007-02-10 01:43:53 -0800896
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800897 if (n == -1) {
898 ret = 0;
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800899 goto err_free;
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800900 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901
Jeff Dikedc764e52007-05-06 14:51:41 -0700902 mutex_lock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -0800903 ret = ubd_add(n, error_out);
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800904 if (ret)
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800905 ubd_devs[n].file = NULL;
Jeff Dikedc764e52007-05-06 14:51:41 -0700906 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800908out:
Jeff Dikedc764e52007-05-06 14:51:41 -0700909 return ret;
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800910
911err_free:
912 kfree(str);
913 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914}
915
916static int ubd_get_config(char *name, char *str, int size, char **error_out)
917{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800918 struct ubd *ubd_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 int n, len = 0;
920
921 n = parse_unit(&name);
922 if((n >= MAX_DEV) || (n < 0)){
923 *error_out = "ubd_get_config : device number out of range";
Jeff Dikedc764e52007-05-06 14:51:41 -0700924 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 }
926
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800927 ubd_dev = &ubd_devs[n];
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800928 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800930 if(ubd_dev->file == NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 CONFIG_CHUNK(str, size, len, "", 1);
932 goto out;
933 }
934
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800935 CONFIG_CHUNK(str, size, len, ubd_dev->file, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800937 if(ubd_dev->cow.file != NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 CONFIG_CHUNK(str, size, len, ",", 0);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800939 CONFIG_CHUNK(str, size, len, ubd_dev->cow.file, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 }
941 else CONFIG_CHUNK(str, size, len, "", 1);
942
943 out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800944 mutex_unlock(&ubd_lock);
Jeff Dikedc764e52007-05-06 14:51:41 -0700945 return len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946}
947
Jeff Dike29d56cf2005-06-25 14:55:25 -0700948static int ubd_id(char **str, int *start_out, int *end_out)
949{
Jeff Dikedc764e52007-05-06 14:51:41 -0700950 int n;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700951
952 n = parse_unit(str);
Jeff Dikedc764e52007-05-06 14:51:41 -0700953 *start_out = 0;
954 *end_out = MAX_DEV - 1;
955 return n;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700956}
957
Jeff Dikef28169d2007-02-10 01:43:53 -0800958static int ubd_remove(int n, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959{
Jeff Dike2e3f5252007-05-06 14:51:29 -0700960 struct gendisk *disk = ubd_gendisk[n];
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800961 struct ubd *ubd_dev;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700962 int err = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800964 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800966 ubd_dev = &ubd_devs[n];
Jeff Dike29d56cf2005-06-25 14:55:25 -0700967
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800968 if(ubd_dev->file == NULL)
Jeff Dike29d56cf2005-06-25 14:55:25 -0700969 goto out;
970
971 /* you cannot remove a open disk */
972 err = -EBUSY;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800973 if(ubd_dev->count > 0)
Jeff Dike29d56cf2005-06-25 14:55:25 -0700974 goto out;
975
Jeff Dikedc764e52007-05-06 14:51:41 -0700976 ubd_gendisk[n] = NULL;
Jeff Dikeb47d2de2007-05-06 14:51:01 -0700977 if(disk != NULL){
978 del_gendisk(disk);
979 put_disk(disk);
980 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981
982 if(fake_gendisk[n] != NULL){
983 del_gendisk(fake_gendisk[n]);
984 put_disk(fake_gendisk[n]);
985 fake_gendisk[n] = NULL;
986 }
987
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 err = 0;
Jeff Dike2e3f5252007-05-06 14:51:29 -0700989 platform_device_unregister(&ubd_dev->pdev);
Jeff Dike29d56cf2005-06-25 14:55:25 -0700990out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800991 mutex_unlock(&ubd_lock);
Jeff Dike29d56cf2005-06-25 14:55:25 -0700992 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993}
994
Jeff Dikef28169d2007-02-10 01:43:53 -0800995/* All these are called by mconsole in process context and without
Jeff Dikeb8831a12007-02-10 01:44:17 -0800996 * ubd-specific locks. The structure itself is const except for .list.
Jeff Dikef28169d2007-02-10 01:43:53 -0800997 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998static struct mc_device ubd_mc = {
Jeff Dike84f48d42007-02-10 01:44:01 -0800999 .list = LIST_HEAD_INIT(ubd_mc.list),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 .name = "ubd",
1001 .config = ubd_config,
Jeff Dikedc764e52007-05-06 14:51:41 -07001002 .get_config = ubd_get_config,
Jeff Dike29d56cf2005-06-25 14:55:25 -07001003 .id = ubd_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 .remove = ubd_remove,
1005};
1006
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001007static int __init ubd_mc_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008{
1009 mconsole_register_dev(&ubd_mc);
1010 return 0;
1011}
1012
1013__initcall(ubd_mc_init);
1014
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001015static int __init ubd0_init(void)
1016{
1017 struct ubd *ubd_dev = &ubd_devs[0];
1018
Jeff Dikeb8831a12007-02-10 01:44:17 -08001019 mutex_lock(&ubd_lock);
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001020 if(ubd_dev->file == NULL)
1021 ubd_dev->file = "root_fs";
Jeff Dikeb8831a12007-02-10 01:44:17 -08001022 mutex_unlock(&ubd_lock);
1023
Jeff Dikedc764e52007-05-06 14:51:41 -07001024 return 0;
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001025}
1026
1027__initcall(ubd0_init);
1028
Jeff Dikeb8831a12007-02-10 01:44:17 -08001029/* Used in ubd_init, which is an initcall */
Russell King3ae5eae2005-11-09 22:32:44 +00001030static struct platform_driver ubd_driver = {
1031 .driver = {
1032 .name = DRIVER_NAME,
1033 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034};
1035
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001036static int __init ubd_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037{
Jeff Dikef28169d2007-02-10 01:43:53 -08001038 char *error;
1039 int i, err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040
Christoph Hellwig792dd4f2009-03-31 15:23:39 -07001041 if (register_blkdev(UBD_MAJOR, "ubd"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 return -1;
1043
Christoph Hellwig792dd4f2009-03-31 15:23:39 -07001044 if (fake_major != UBD_MAJOR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 char name[sizeof("ubd_nnn\0")];
1046
1047 snprintf(name, sizeof(name), "ubd_%d", fake_major);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 if (register_blkdev(fake_major, "ubd"))
1049 return -1;
1050 }
Russell King3ae5eae2005-11-09 22:32:44 +00001051 platform_driver_register(&ubd_driver);
Jeff Dikedc764e52007-05-06 14:51:41 -07001052 mutex_lock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -08001053 for (i = 0; i < MAX_DEV; i++){
1054 err = ubd_add(i, &error);
1055 if(err)
1056 printk(KERN_ERR "Failed to initialize ubd device %d :"
1057 "%s\n", i, error);
1058 }
Jeff Dikedc764e52007-05-06 14:51:41 -07001059 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 return 0;
1061}
1062
1063late_initcall(ubd_init);
1064
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001065static int __init ubd_driver_init(void){
Jeff Dike91acb212005-10-10 23:10:32 -04001066 unsigned long stack;
1067 int err;
1068
1069 /* Set by CONFIG_BLK_DEV_UBD_SYNC or ubd=sync.*/
1070 if(global_openflags.s){
1071 printk(KERN_INFO "ubd: Synchronous mode\n");
1072 /* Letting ubd=sync be like using ubd#s= instead of ubd#= is
1073 * enough. So use anyway the io thread. */
1074 }
1075 stack = alloc_stack(0, 0);
Jeff Dike6c29256c2006-03-27 01:14:37 -08001076 io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *),
Jeff Dike91acb212005-10-10 23:10:32 -04001077 &thread_fd);
1078 if(io_pid < 0){
Jeff Dike6c29256c2006-03-27 01:14:37 -08001079 printk(KERN_ERR
Jeff Dike91acb212005-10-10 23:10:32 -04001080 "ubd : Failed to start I/O thread (errno = %d) - "
1081 "falling back to synchronous I/O\n", -io_pid);
1082 io_pid = -1;
Jeff Dikedc764e52007-05-06 14:51:41 -07001083 return 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001084 }
Jeff Dike6c29256c2006-03-27 01:14:37 -08001085 err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001086 IRQF_DISABLED, "ubd", ubd_devs);
Jeff Dike91acb212005-10-10 23:10:32 -04001087 if(err != 0)
1088 printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err);
Jeff Dikef4c57a72006-03-31 02:30:10 -08001089 return 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001090}
1091
1092device_initcall(ubd_driver_init);
1093
Al Viroa625c992008-03-02 09:16:26 -05001094static int ubd_open(struct block_device *bdev, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095{
Al Viroa625c992008-03-02 09:16:26 -05001096 struct gendisk *disk = bdev->bd_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001097 struct ubd *ubd_dev = disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 int err = 0;
1099
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001100 if(ubd_dev->count == 0){
1101 err = ubd_open_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 if(err){
1103 printk(KERN_ERR "%s: Can't open \"%s\": errno = %d\n",
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001104 disk->disk_name, ubd_dev->file, -err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 goto out;
1106 }
1107 }
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001108 ubd_dev->count++;
1109 set_disk_ro(disk, !ubd_dev->openflags.w);
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -07001110
1111 /* This should no more be needed. And it didn't work anyway to exclude
1112 * read-write remounting of filesystems.*/
Al Viroa625c992008-03-02 09:16:26 -05001113 /*if((mode & FMODE_WRITE) && !ubd_dev->openflags.w){
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -08001114 if(--ubd_dev->count == 0) ubd_close_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 err = -EROFS;
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -07001116 }*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 out:
Jeff Dikedc764e52007-05-06 14:51:41 -07001118 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119}
1120
Al Viroa625c992008-03-02 09:16:26 -05001121static int ubd_release(struct gendisk *disk, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001123 struct ubd *ubd_dev = disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001125 if(--ubd_dev->count == 0)
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -08001126 ubd_close_dev(ubd_dev);
Jeff Dikedc764e52007-05-06 14:51:41 -07001127 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128}
1129
Jeff Dike91acb212005-10-10 23:10:32 -04001130static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask,
1131 __u64 *cow_offset, unsigned long *bitmap,
1132 __u64 bitmap_offset, unsigned long *bitmap_words,
1133 __u64 bitmap_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134{
Jeff Dike91acb212005-10-10 23:10:32 -04001135 __u64 sector = io_offset >> 9;
1136 int i, update_bitmap = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137
Jeff Dike91acb212005-10-10 23:10:32 -04001138 for(i = 0; i < length >> 9; i++){
1139 if(cow_mask != NULL)
1140 ubd_set_bit(i, (unsigned char *) cow_mask);
1141 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
1142 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143
Jeff Dike91acb212005-10-10 23:10:32 -04001144 update_bitmap = 1;
1145 ubd_set_bit(sector + i, (unsigned char *) bitmap);
1146 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147
Jeff Dike91acb212005-10-10 23:10:32 -04001148 if(!update_bitmap)
1149 return;
1150
1151 *cow_offset = sector / (sizeof(unsigned long) * 8);
1152
1153 /* This takes care of the case where we're exactly at the end of the
1154 * device, and *cow_offset + 1 is off the end. So, just back it up
1155 * by one word. Thanks to Lynn Kerby for the fix and James McMechan
1156 * for the original diagnosis.
1157 */
Jiri Olsa6d074242008-05-12 14:01:56 -07001158 if (*cow_offset == (DIV_ROUND_UP(bitmap_len,
1159 sizeof(unsigned long)) - 1))
Jeff Dike91acb212005-10-10 23:10:32 -04001160 (*cow_offset)--;
1161
1162 bitmap_words[0] = bitmap[*cow_offset];
1163 bitmap_words[1] = bitmap[*cow_offset + 1];
1164
1165 *cow_offset *= sizeof(unsigned long);
1166 *cow_offset += bitmap_offset;
1167}
1168
1169static void cowify_req(struct io_thread_req *req, unsigned long *bitmap,
1170 __u64 bitmap_offset, __u64 bitmap_len)
1171{
1172 __u64 sector = req->offset >> 9;
1173 int i;
1174
1175 if(req->length > (sizeof(req->sector_mask) * 8) << 9)
1176 panic("Operation too long");
1177
1178 if(req->op == UBD_READ) {
1179 for(i = 0; i < req->length >> 9; i++){
1180 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
Jeff Dike6c29256c2006-03-27 01:14:37 -08001181 ubd_set_bit(i, (unsigned char *)
Jeff Dike91acb212005-10-10 23:10:32 -04001182 &req->sector_mask);
Jeff Dikedc764e52007-05-06 14:51:41 -07001183 }
Jeff Dike91acb212005-10-10 23:10:32 -04001184 }
1185 else cowify_bitmap(req->offset, req->length, &req->sector_mask,
1186 &req->cow_offset, bitmap, bitmap_offset,
1187 req->bitmap_words, bitmap_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188}
1189
Jeff Dike62f96cb2007-02-10 01:44:16 -08001190/* Called with dev->lock held */
Jeff Dikea0044bd2007-05-06 14:51:36 -07001191static void prepare_request(struct request *req, struct io_thread_req *io_req,
1192 unsigned long long offset, int page_offset,
1193 int len, struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194{
1195 struct gendisk *disk = req->rq_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001196 struct ubd *ubd_dev = disk->private_data;
Jeff Dike91acb212005-10-10 23:10:32 -04001197
Jeff Dike62f96cb2007-02-10 01:44:16 -08001198 io_req->req = req;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001199 io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd :
1200 ubd_dev->fd;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001201 io_req->fds[1] = ubd_dev->fd;
Jeff Dike91acb212005-10-10 23:10:32 -04001202 io_req->cow_offset = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 io_req->offset = offset;
1204 io_req->length = len;
1205 io_req->error = 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001206 io_req->sector_mask = 0;
1207
1208 io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209 io_req->offsets[0] = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001210 io_req->offsets[1] = ubd_dev->cow.data_offset;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001211 io_req->buffer = page_address(page) + page_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 io_req->sectorsize = 1 << 9;
1213
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001214 if(ubd_dev->cow.file != NULL)
Jeff Dikea0044bd2007-05-06 14:51:36 -07001215 cowify_req(io_req, ubd_dev->cow.bitmap,
1216 ubd_dev->cow.bitmap_offset, ubd_dev->cow.bitmap_len);
Jeff Dike91acb212005-10-10 23:10:32 -04001217
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218}
1219
Jeff Dike62f96cb2007-02-10 01:44:16 -08001220/* Called with dev->lock held */
Jens Axboe165125e2007-07-24 09:28:11 +02001221static void do_ubd_request(struct request_queue *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222{
Jeff Dike2adcec22007-05-06 14:51:37 -07001223 struct io_thread_req *io_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 struct request *req;
Jeff Dike0a6d3a22007-07-15 23:38:47 -07001225 int n, last_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226
Jeff Dikea0044bd2007-05-06 14:51:36 -07001227 while(1){
Jeff Dike2a9529a2007-03-29 01:20:27 -07001228 struct ubd *dev = q->queuedata;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001229 if(dev->end_sg == 0){
1230 struct request *req = elv_next_request(q);
1231 if(req == NULL)
1232 return;
1233
1234 dev->request = req;
1235 blkdev_dequeue_request(req);
1236 dev->start_sg = 0;
1237 dev->end_sg = blk_rq_map_sg(q, req, dev->sg);
Jeff Dike91acb212005-10-10 23:10:32 -04001238 }
Jeff Dikea0044bd2007-05-06 14:51:36 -07001239
1240 req = dev->request;
Jeff Dike0a6d3a22007-07-15 23:38:47 -07001241 last_sectors = 0;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001242 while(dev->start_sg < dev->end_sg){
1243 struct scatterlist *sg = &dev->sg[dev->start_sg];
1244
Jeff Dike0a6d3a22007-07-15 23:38:47 -07001245 req->sector += last_sectors;
Jeff Dike2adcec22007-05-06 14:51:37 -07001246 io_req = kmalloc(sizeof(struct io_thread_req),
Peter Zijlstra990c5582007-05-06 14:51:38 -07001247 GFP_ATOMIC);
Jeff Dike2adcec22007-05-06 14:51:37 -07001248 if(io_req == NULL){
1249 if(list_empty(&dev->restart))
1250 list_add(&dev->restart, &restart);
1251 return;
1252 }
1253 prepare_request(req, io_req,
Jeff Dikea0044bd2007-05-06 14:51:36 -07001254 (unsigned long long) req->sector << 9,
Jens Axboe45711f12007-10-22 21:19:53 +02001255 sg->offset, sg->length, sg_page(sg));
Jeff Dikea0044bd2007-05-06 14:51:36 -07001256
Jeff Dike0a6d3a22007-07-15 23:38:47 -07001257 last_sectors = sg->length >> 9;
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001258 n = os_write_file(thread_fd, &io_req,
1259 sizeof(struct io_thread_req *));
Jeff Dike2adcec22007-05-06 14:51:37 -07001260 if(n != sizeof(struct io_thread_req *)){
Jeff Dikea0044bd2007-05-06 14:51:36 -07001261 if(n != -EAGAIN)
1262 printk("write to io thread failed, "
1263 "errno = %d\n", -n);
1264 else if(list_empty(&dev->restart))
1265 list_add(&dev->restart, &restart);
Miklos Szeredi12429bf2007-11-28 16:21:52 -08001266 kfree(io_req);
Jeff Dikea0044bd2007-05-06 14:51:36 -07001267 return;
1268 }
1269
Jeff Dikea0044bd2007-05-06 14:51:36 -07001270 dev->start_sg++;
1271 }
1272 dev->end_sg = 0;
1273 dev->request = NULL;
Jeff Dike91acb212005-10-10 23:10:32 -04001274 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275}
1276
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001277static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
1278{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001279 struct ubd *ubd_dev = bdev->bd_disk->private_data;
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001280
1281 geo->heads = 128;
1282 geo->sectors = 32;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001283 geo->cylinders = ubd_dev->size / (128 * 32 * 512);
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001284 return 0;
1285}
1286
Al Viroa625c992008-03-02 09:16:26 -05001287static int ubd_ioctl(struct block_device *bdev, fmode_t mode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 unsigned int cmd, unsigned long arg)
1289{
Al Viroa625c992008-03-02 09:16:26 -05001290 struct ubd *ubd_dev = bdev->bd_disk->private_data;
Bartlomiej Zolnierkiewicz73855e12009-04-01 21:42:21 +02001291 u16 ubd_id[ATA_ID_WORDS];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292
1293 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 struct cdrom_volctrl volume;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 case HDIO_GET_IDENTITY:
Bartlomiej Zolnierkiewicz73855e12009-04-01 21:42:21 +02001296 memset(&ubd_id, 0, ATA_ID_WORDS * 2);
1297 ubd_id[ATA_ID_CYLS] = ubd_dev->size / (128 * 32 * 512);
1298 ubd_id[ATA_ID_HEADS] = 128;
1299 ubd_id[ATA_ID_SECTORS] = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 if(copy_to_user((char __user *) arg, (char *) &ubd_id,
1301 sizeof(ubd_id)))
Jeff Dikedc764e52007-05-06 14:51:41 -07001302 return -EFAULT;
1303 return 0;
Jeff Dikeb8831a12007-02-10 01:44:17 -08001304
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 case CDROMVOLREAD:
1306 if(copy_from_user(&volume, (char __user *) arg, sizeof(volume)))
Jeff Dikedc764e52007-05-06 14:51:41 -07001307 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 volume.channel0 = 255;
1309 volume.channel1 = 255;
1310 volume.channel2 = 255;
1311 volume.channel3 = 255;
1312 if(copy_to_user((char __user *) arg, &volume, sizeof(volume)))
Jeff Dikedc764e52007-05-06 14:51:41 -07001313 return -EFAULT;
1314 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 }
Jeff Dikedc764e52007-05-06 14:51:41 -07001316 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317}
1318
Jeff Dike91acb212005-10-10 23:10:32 -04001319static int update_bitmap(struct io_thread_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320{
Jeff Dike91acb212005-10-10 23:10:32 -04001321 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322
Jeff Dike91acb212005-10-10 23:10:32 -04001323 if(req->cow_offset == -1)
Jeff Dikedc764e52007-05-06 14:51:41 -07001324 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325
Jeff Dike91acb212005-10-10 23:10:32 -04001326 n = os_seek_file(req->fds[1], req->cow_offset);
1327 if(n < 0){
1328 printk("do_io - bitmap lseek failed : err = %d\n", -n);
Jeff Dikedc764e52007-05-06 14:51:41 -07001329 return 1;
Jeff Dike91acb212005-10-10 23:10:32 -04001330 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001332 n = os_write_file(req->fds[1], &req->bitmap_words,
1333 sizeof(req->bitmap_words));
Jeff Dike91acb212005-10-10 23:10:32 -04001334 if(n != sizeof(req->bitmap_words)){
1335 printk("do_io - bitmap update failed, err = %d fd = %d\n", -n,
1336 req->fds[1]);
Jeff Dikedc764e52007-05-06 14:51:41 -07001337 return 1;
Jeff Dike91acb212005-10-10 23:10:32 -04001338 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339
Jeff Dikedc764e52007-05-06 14:51:41 -07001340 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341}
Jeff Dike91acb212005-10-10 23:10:32 -04001342
WANG Cong5dc62b12008-04-28 02:13:58 -07001343static void do_io(struct io_thread_req *req)
Jeff Dike91acb212005-10-10 23:10:32 -04001344{
1345 char *buf;
1346 unsigned long len;
1347 int n, nsectors, start, end, bit;
1348 int err;
1349 __u64 off;
1350
1351 nsectors = req->length / req->sectorsize;
1352 start = 0;
1353 do {
1354 bit = ubd_test_bit(start, (unsigned char *) &req->sector_mask);
1355 end = start;
1356 while((end < nsectors) &&
1357 (ubd_test_bit(end, (unsigned char *)
1358 &req->sector_mask) == bit))
1359 end++;
1360
1361 off = req->offset + req->offsets[bit] +
1362 start * req->sectorsize;
1363 len = (end - start) * req->sectorsize;
1364 buf = &req->buffer[start * req->sectorsize];
1365
1366 err = os_seek_file(req->fds[bit], off);
1367 if(err < 0){
1368 printk("do_io - lseek failed : err = %d\n", -err);
1369 req->error = 1;
1370 return;
1371 }
1372 if(req->op == UBD_READ){
1373 n = 0;
1374 do {
1375 buf = &buf[n];
1376 len -= n;
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001377 n = os_read_file(req->fds[bit], buf, len);
Jeff Dike91acb212005-10-10 23:10:32 -04001378 if (n < 0) {
1379 printk("do_io - read failed, err = %d "
1380 "fd = %d\n", -n, req->fds[bit]);
1381 req->error = 1;
1382 return;
1383 }
1384 } while((n < len) && (n != 0));
1385 if (n < len) memset(&buf[n], 0, len - n);
1386 } else {
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001387 n = os_write_file(req->fds[bit], buf, len);
Jeff Dike91acb212005-10-10 23:10:32 -04001388 if(n != len){
1389 printk("do_io - write failed err = %d "
1390 "fd = %d\n", -n, req->fds[bit]);
1391 req->error = 1;
1392 return;
1393 }
1394 }
1395
1396 start = end;
1397 } while(start < nsectors);
1398
1399 req->error = update_bitmap(req);
1400}
1401
1402/* Changed in start_io_thread, which is serialized by being called only
1403 * from ubd_init, which is an initcall.
1404 */
1405int kernel_fd = -1;
1406
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001407/* Only changed by the io thread. XXX: currently unused. */
1408static int io_count = 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001409
1410int io_thread(void *arg)
1411{
Jeff Dike2adcec22007-05-06 14:51:37 -07001412 struct io_thread_req *req;
Jeff Dike91acb212005-10-10 23:10:32 -04001413 int n;
1414
1415 ignore_sigwinch_sig();
1416 while(1){
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001417 n = os_read_file(kernel_fd, &req,
Jeff Dike2adcec22007-05-06 14:51:37 -07001418 sizeof(struct io_thread_req *));
1419 if(n != sizeof(struct io_thread_req *)){
Jeff Dike91acb212005-10-10 23:10:32 -04001420 if(n < 0)
1421 printk("io_thread - read failed, fd = %d, "
1422 "err = %d\n", kernel_fd, -n);
1423 else {
1424 printk("io_thread - short read, fd = %d, "
1425 "length = %d\n", kernel_fd, n);
1426 }
1427 continue;
1428 }
1429 io_count++;
Jeff Dike2adcec22007-05-06 14:51:37 -07001430 do_io(req);
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001431 n = os_write_file(kernel_fd, &req,
Jeff Dike2adcec22007-05-06 14:51:37 -07001432 sizeof(struct io_thread_req *));
1433 if(n != sizeof(struct io_thread_req *))
Jeff Dike91acb212005-10-10 23:10:32 -04001434 printk("io_thread - write failed, fd = %d, err = %d\n",
1435 kernel_fd, -n);
1436 }
Jeff Dike91acb212005-10-10 23:10:32 -04001437
Jeff Dike1b57e9c2006-01-06 00:18:49 -08001438 return 0;
1439}