blob: 9734994cba1e86c53f60dead72952f7feb3ab02d [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"
Alexey Dobriyan6613c5e2009-12-14 18:00:11 -080030#include "linux/seq_file.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include "linux/ctype.h"
32#include "linux/capability.h"
33#include "linux/mm.h"
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090034#include "linux/slab.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include "linux/vmalloc.h"
Arnd Bergmann6e9624b2010-08-07 18:25:34 +020036#include "linux/smp_lock.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#include "linux/blkpg.h"
38#include "linux/genhd.h"
39#include "linux/spinlock.h"
Russell Kingd052d1b2005-10-29 19:07:23 +010040#include "linux/platform_device.h"
WANG Cong23464ff2007-10-24 13:07:11 +020041#include "linux/scatterlist.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include "asm/segment.h"
43#include "asm/uaccess.h"
44#include "asm/irq.h"
45#include "asm/types.h"
46#include "asm/tlbflush.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070047#include "mem_user.h"
48#include "kern_util.h"
49#include "kern.h"
50#include "mconsole_kern.h"
51#include "init.h"
52#include "irq_user.h"
53#include "irq_kern.h"
54#include "ubd_user.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070055#include "os.h"
56#include "mem.h"
57#include "mem_kern.h"
58#include "cow.h"
59
Jeff Dike7b9014c2005-05-20 13:59:11 -070060enum ubd_req { UBD_READ, UBD_WRITE };
Linus Torvalds1da177e2005-04-16 15:20:36 -070061
62struct io_thread_req {
Jeff Dike62f96cb2007-02-10 01:44:16 -080063 struct request *req;
Jeff Dike91acb212005-10-10 23:10:32 -040064 enum ubd_req op;
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 int fds[2];
66 unsigned long offsets[2];
67 unsigned long long offset;
68 unsigned long length;
69 char *buffer;
70 int sectorsize;
Jeff Dike91acb212005-10-10 23:10:32 -040071 unsigned long sector_mask;
72 unsigned long long cow_offset;
73 unsigned long bitmap_words[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -070074 int error;
75};
76
Jeff Dike91acb212005-10-10 23:10:32 -040077static inline int ubd_test_bit(__u64 bit, unsigned char *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -070078{
79 __u64 n;
80 int bits, off;
81
Jeff Dike91acb212005-10-10 23:10:32 -040082 bits = sizeof(data[0]) * 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -070083 n = bit / bits;
84 off = bit % bits;
Jeff Dikedc764e52007-05-06 14:51:41 -070085 return (data[n] & (1 << off)) != 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070086}
87
Jeff Dike91acb212005-10-10 23:10:32 -040088static inline void ubd_set_bit(__u64 bit, unsigned char *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -070089{
90 __u64 n;
91 int bits, off;
92
Jeff Dike91acb212005-10-10 23:10:32 -040093 bits = sizeof(data[0]) * 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -070094 n = bit / bits;
95 off = bit % bits;
Jeff Dike91acb212005-10-10 23:10:32 -040096 data[n] |= (1 << off);
Linus Torvalds1da177e2005-04-16 15:20:36 -070097}
98/*End stuff from ubd_user.h*/
99
100#define DRIVER_NAME "uml-blkdev"
101
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800102static DEFINE_MUTEX(ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103
Al Viroa625c992008-03-02 09:16:26 -0500104static int ubd_open(struct block_device *bdev, fmode_t mode);
105static int ubd_release(struct gendisk *disk, fmode_t mode);
106static int ubd_ioctl(struct block_device *bdev, fmode_t mode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 unsigned int cmd, unsigned long arg);
Christoph Hellwiga885c8c2006-01-08 01:02:50 -0800108static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109
Paolo 'Blaisorblade' Giarrusso97d88ac2006-10-30 22:07:03 -0800110#define MAX_DEV (16)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111
Alexey Dobriyan83d5cde2009-09-21 17:01:13 -0700112static const struct block_device_operations ubd_blops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 .owner = THIS_MODULE,
Al Viroa625c992008-03-02 09:16:26 -0500114 .open = ubd_open,
115 .release = ubd_release,
116 .ioctl = ubd_ioctl,
Christoph Hellwiga885c8c2006-01-08 01:02:50 -0800117 .getgeo = ubd_getgeo,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118};
119
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120/* Protected by ubd_lock */
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700121static int fake_major = UBD_MAJOR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122static struct gendisk *ubd_gendisk[MAX_DEV];
123static struct gendisk *fake_gendisk[MAX_DEV];
Jeff Dike6c29256c2006-03-27 01:14:37 -0800124
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125#ifdef CONFIG_BLK_DEV_UBD_SYNC
126#define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 1, .c = 0, \
127 .cl = 1 })
128#else
129#define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 0, .c = 0, \
130 .cl = 1 })
131#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132static struct openflags global_openflags = OPEN_FLAGS;
133
134struct cow {
Paolo 'Blaisorblade' Giarrusso2a9d32f2006-10-30 22:07:04 -0800135 /* backing file name */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 char *file;
Paolo 'Blaisorblade' Giarrusso2a9d32f2006-10-30 22:07:04 -0800137 /* backing file fd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138 int fd;
139 unsigned long *bitmap;
140 unsigned long bitmap_len;
141 int bitmap_offset;
Jeff Dikedc764e52007-05-06 14:51:41 -0700142 int data_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143};
144
Jeff Dikea0044bd2007-05-06 14:51:36 -0700145#define MAX_SG 64
146
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147struct ubd {
Jeff Dikea0044bd2007-05-06 14:51:36 -0700148 struct list_head restart;
Paolo 'Blaisorblade' Giarrusso2a9d32f2006-10-30 22:07:04 -0800149 /* name (and fd, below) of the file opened for writing, either the
150 * backing or the cow file. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 char *file;
152 int count;
153 int fd;
154 __u64 size;
155 struct openflags boot_openflags;
156 struct openflags openflags;
Paolo 'Blaisorblade' Giarrusso84e945e2006-10-30 22:07:10 -0800157 unsigned shared:1;
158 unsigned no_cow:1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 struct cow cow;
160 struct platform_device pdev;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800161 struct request_queue *queue;
162 spinlock_t lock;
Jeff Dikea0044bd2007-05-06 14:51:36 -0700163 struct scatterlist sg[MAX_SG];
164 struct request *request;
165 int start_sg, end_sg;
Tejun Heo47526902010-10-15 12:56:21 +0200166 sector_t rq_pos;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167};
168
169#define DEFAULT_COW { \
170 .file = NULL, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700171 .fd = -1, \
172 .bitmap = NULL, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 .bitmap_offset = 0, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700174 .data_offset = 0, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175}
176
177#define DEFAULT_UBD { \
178 .file = NULL, \
179 .count = 0, \
180 .fd = -1, \
181 .size = -1, \
182 .boot_openflags = OPEN_FLAGS, \
183 .openflags = OPEN_FLAGS, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700184 .no_cow = 0, \
Jeff Dike6c29256c2006-03-27 01:14:37 -0800185 .shared = 0, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700186 .cow = DEFAULT_COW, \
Jeff Dike62f96cb2007-02-10 01:44:16 -0800187 .lock = SPIN_LOCK_UNLOCKED, \
Jeff Dikea0044bd2007-05-06 14:51:36 -0700188 .request = NULL, \
189 .start_sg = 0, \
190 .end_sg = 0, \
Tejun Heo47526902010-10-15 12:56:21 +0200191 .rq_pos = 0, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192}
193
Jeff Dikeb8831a12007-02-10 01:44:17 -0800194/* Protected by ubd_lock */
WANG Cong5dc62b12008-04-28 02:13:58 -0700195static struct ubd ubd_devs[MAX_DEV] = { [0 ... MAX_DEV - 1] = DEFAULT_UBD };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197/* Only changed by fake_ide_setup which is a setup */
198static int fake_ide = 0;
199static struct proc_dir_entry *proc_ide_root = NULL;
200static struct proc_dir_entry *proc_ide = NULL;
201
202static void make_proc_ide(void)
203{
204 proc_ide_root = proc_mkdir("ide", NULL);
205 proc_ide = proc_mkdir("ide0", proc_ide_root);
206}
207
Alexey Dobriyan6613c5e2009-12-14 18:00:11 -0800208static int fake_ide_media_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209{
Alexey Dobriyan6613c5e2009-12-14 18:00:11 -0800210 seq_puts(m, "disk\n");
211 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212}
213
Alexey Dobriyan6613c5e2009-12-14 18:00:11 -0800214static int fake_ide_media_proc_open(struct inode *inode, struct file *file)
215{
216 return single_open(file, fake_ide_media_proc_show, NULL);
217}
218
219static const struct file_operations fake_ide_media_proc_fops = {
220 .owner = THIS_MODULE,
221 .open = fake_ide_media_proc_open,
222 .read = seq_read,
223 .llseek = seq_lseek,
224 .release = single_release,
225};
226
WANG Congc0a92902008-02-04 22:30:41 -0800227static void make_ide_entries(const char *dev_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228{
229 struct proc_dir_entry *dir, *ent;
230 char name[64];
231
232 if(proc_ide_root == NULL) make_proc_ide();
233
234 dir = proc_mkdir(dev_name, proc_ide);
235 if(!dir) return;
236
Alexey Dobriyan6613c5e2009-12-14 18:00:11 -0800237 ent = proc_create("media", S_IRUGO, dir, &fake_ide_media_proc_fops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 if(!ent) return;
WANG Congc0a92902008-02-04 22:30:41 -0800239 snprintf(name, sizeof(name), "ide0/%s", dev_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 proc_symlink(dev_name, proc_ide_root, name);
241}
242
243static int fake_ide_setup(char *str)
244{
245 fake_ide = 1;
Jeff Dikedc764e52007-05-06 14:51:41 -0700246 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247}
248
249__setup("fake_ide", fake_ide_setup);
250
251__uml_help(fake_ide_setup,
252"fake_ide\n"
253" Create ide0 entries that map onto ubd devices.\n\n"
254);
255
256static int parse_unit(char **ptr)
257{
258 char *str = *ptr, *end;
259 int n = -1;
260
261 if(isdigit(*str)) {
262 n = simple_strtoul(str, &end, 0);
263 if(end == str)
Jeff Dikedc764e52007-05-06 14:51:41 -0700264 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 *ptr = end;
266 }
Paolo 'Blaisorblade' Giarrusso97d88ac2006-10-30 22:07:03 -0800267 else if (('a' <= *str) && (*str <= 'z')) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 n = *str - 'a';
269 str++;
270 *ptr = str;
271 }
Jeff Dikedc764e52007-05-06 14:51:41 -0700272 return n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273}
274
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800275/* If *index_out == -1 at exit, the passed option was a general one;
276 * otherwise, the str pointer is used (and owned) inside ubd_devs array, so it
277 * should not be freed on exit.
278 */
Jeff Dikef28169d2007-02-10 01:43:53 -0800279static int ubd_setup_common(char *str, int *index_out, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800281 struct ubd *ubd_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 struct openflags flags = global_openflags;
283 char *backing_file;
Jeff Dikeb8831a12007-02-10 01:44:17 -0800284 int n, err = 0, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285
286 if(index_out) *index_out = -1;
287 n = *str;
288 if(n == '='){
289 char *end;
290 int major;
291
292 str++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 if(!strcmp(str, "sync")){
294 global_openflags = of_sync(global_openflags);
Jeff Dikeb8831a12007-02-10 01:44:17 -0800295 goto out1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 }
297
Jeff Dikef28169d2007-02-10 01:43:53 -0800298 err = -EINVAL;
Jeff Dikeb8831a12007-02-10 01:44:17 -0800299 major = simple_strtoul(str, &end, 0);
300 if((*end != '\0') || (end == str)){
301 *error_out = "Didn't parse major number";
302 goto out1;
303 }
304
Jeff Dikef28169d2007-02-10 01:43:53 -0800305 mutex_lock(&ubd_lock);
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700306 if (fake_major != UBD_MAJOR) {
Jeff Dikef28169d2007-02-10 01:43:53 -0800307 *error_out = "Can't assign a fake major twice";
308 goto out1;
309 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800310
Jeff Dikef28169d2007-02-10 01:43:53 -0800311 fake_major = major;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
313 printk(KERN_INFO "Setting extra ubd major number to %d\n",
314 major);
Jeff Dikef28169d2007-02-10 01:43:53 -0800315 err = 0;
316 out1:
317 mutex_unlock(&ubd_lock);
318 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 }
320
321 n = parse_unit(&str);
322 if(n < 0){
Jeff Dikef28169d2007-02-10 01:43:53 -0800323 *error_out = "Couldn't parse device number";
324 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 }
326 if(n >= MAX_DEV){
Jeff Dikef28169d2007-02-10 01:43:53 -0800327 *error_out = "Device number out of range";
328 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 }
330
Jeff Dikef28169d2007-02-10 01:43:53 -0800331 err = -EBUSY;
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800332 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800334 ubd_dev = &ubd_devs[n];
335 if(ubd_dev->file != NULL){
Jeff Dikef28169d2007-02-10 01:43:53 -0800336 *error_out = "Device is already configured";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 goto out;
338 }
339
340 if (index_out)
341 *index_out = n;
342
Jeff Dikef28169d2007-02-10 01:43:53 -0800343 err = -EINVAL;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800344 for (i = 0; i < sizeof("rscd="); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 switch (*str) {
346 case 'r':
347 flags.w = 0;
348 break;
349 case 's':
350 flags.s = 1;
351 break;
352 case 'd':
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800353 ubd_dev->no_cow = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 break;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800355 case 'c':
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800356 ubd_dev->shared = 1;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800357 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 case '=':
359 str++;
360 goto break_loop;
361 default:
Jeff Dikef28169d2007-02-10 01:43:53 -0800362 *error_out = "Expected '=' or flag letter "
363 "(r, s, c, or d)";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 goto out;
365 }
366 str++;
367 }
368
Jeff Dikef28169d2007-02-10 01:43:53 -0800369 if (*str == '=')
370 *error_out = "Too many flags specified";
371 else
372 *error_out = "Missing '='";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 goto out;
374
375break_loop:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 backing_file = strchr(str, ',');
377
Jeff Dikef28169d2007-02-10 01:43:53 -0800378 if (backing_file == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 backing_file = strchr(str, ':');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380
Jeff Dikef28169d2007-02-10 01:43:53 -0800381 if(backing_file != NULL){
382 if(ubd_dev->no_cow){
383 *error_out = "Can't specify both 'd' and a cow file";
384 goto out;
385 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 else {
387 *backing_file = '\0';
388 backing_file++;
389 }
390 }
Jeff Dikef28169d2007-02-10 01:43:53 -0800391 err = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800392 ubd_dev->file = str;
393 ubd_dev->cow.file = backing_file;
394 ubd_dev->boot_openflags = flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800396 mutex_unlock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -0800397 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398}
399
400static int ubd_setup(char *str)
401{
Jeff Dikef28169d2007-02-10 01:43:53 -0800402 char *error;
403 int err;
404
405 err = ubd_setup_common(str, NULL, &error);
406 if(err)
407 printk(KERN_ERR "Failed to initialize device with \"%s\" : "
408 "%s\n", str, error);
409 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410}
411
412__setup("ubd", ubd_setup);
413__uml_help(ubd_setup,
414"ubd<n><flags>=<filename>[(:|,)<filename2>]\n"
415" This is used to associate a device with a file in the underlying\n"
416" filesystem. When specifying two filenames, the first one is the\n"
417" COW name and the second is the backing file name. As separator you can\n"
418" use either a ':' or a ',': the first one allows writing things like;\n"
419" ubd0=~/Uml/root_cow:~/Uml/root_backing_file\n"
420" while with a ',' the shell would not expand the 2nd '~'.\n"
Jeff Dikef28169d2007-02-10 01:43:53 -0800421" When using only one filename, UML will detect whether to treat it like\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422" a COW file or a backing file. To override this detection, add the 'd'\n"
423" flag:\n"
424" ubd0d=BackingFile\n"
425" Usually, there is a filesystem in the file, but \n"
426" that's not required. Swap devices containing swap files can be\n"
427" specified like this. Also, a file which doesn't contain a\n"
428" filesystem can have its contents read in the virtual \n"
429" machine by running 'dd' on the device. <n> must be in the range\n"
430" 0 to 7. Appending an 'r' to the number will cause that device\n"
431" to be mounted read-only. For example ubd1r=./ext_fs. Appending\n"
Jeff Dike20ede452008-02-04 22:30:37 -0800432" an 's' will cause data to be written to disk on the host immediately.\n"
433" 'c' will cause the device to be treated as being shared between multiple\n"
434" UMLs and file locking will be turned off - this is appropriate for a\n"
435" cluster filesystem and inappropriate at almost all other times.\n\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436);
437
Jeff Dike8299ca52008-02-04 22:30:48 -0800438static int udb_setup(char *str)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439{
440 printk("udb%s specified on command line is almost certainly a ubd -> "
441 "udb TYPO\n", str);
Jeff Dikedc764e52007-05-06 14:51:41 -0700442 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443}
444
445__setup("udb", udb_setup);
446__uml_help(udb_setup,
447"udb\n"
Jeff Dike0894e272005-05-28 15:51:55 -0700448" This option is here solely to catch ubd -> udb typos, which can be\n"
449" to impossible to catch visually unless you specifically look for\n"
450" them. The only result of any option starting with 'udb' is an error\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451" in the boot output.\n\n"
452);
453
Jens Axboe165125e2007-07-24 09:28:11 +0200454static void do_ubd_request(struct request_queue * q);
Jeff Dike91acb212005-10-10 23:10:32 -0400455
456/* Only changed by ubd_init, which is an initcall. */
WANG Cong5dc62b12008-04-28 02:13:58 -0700457static int thread_fd = -1;
Jeff Dikea0044bd2007-05-06 14:51:36 -0700458static LIST_HEAD(restart);
459
Paolo 'Blaisorblade' Giarrusso2fe30a32006-10-30 22:07:09 -0800460/* XXX - move this inside ubd_intr. */
Jeff Dike62f96cb2007-02-10 01:44:16 -0800461/* Called without dev->lock held, and only in interrupt context. */
Jeff Dike91acb212005-10-10 23:10:32 -0400462static void ubd_handler(void)
463{
Jeff Dike2adcec22007-05-06 14:51:37 -0700464 struct io_thread_req *req;
Jeff Dikea0044bd2007-05-06 14:51:36 -0700465 struct ubd *ubd;
466 struct list_head *list, *next_ele;
467 unsigned long flags;
Jeff Dike91acb212005-10-10 23:10:32 -0400468 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469
Jeff Dikea0044bd2007-05-06 14:51:36 -0700470 while(1){
Jeff Dikea6ea4cc2007-05-06 14:51:43 -0700471 n = os_read_file(thread_fd, &req,
472 sizeof(struct io_thread_req *));
Jeff Dikea0044bd2007-05-06 14:51:36 -0700473 if(n != sizeof(req)){
474 if(n == -EAGAIN)
475 break;
476 printk(KERN_ERR "spurious interrupt in ubd_handler, "
477 "err = %d\n", -n);
478 return;
479 }
480
Tejun Heo4d6c84d2009-04-28 13:06:09 +0900481 blk_end_request(req->req, 0, req->length);
Jeff Dike2adcec22007-05-06 14:51:37 -0700482 kfree(req);
Jeff Dike91acb212005-10-10 23:10:32 -0400483 }
Jeff Dike62f96cb2007-02-10 01:44:16 -0800484 reactivate_fd(thread_fd, UBD_IRQ);
Jeff Dikea0044bd2007-05-06 14:51:36 -0700485
486 list_for_each_safe(list, next_ele, &restart){
487 ubd = container_of(list, struct ubd, restart);
488 list_del_init(&ubd->restart);
489 spin_lock_irqsave(&ubd->lock, flags);
490 do_ubd_request(ubd->queue);
491 spin_unlock_irqrestore(&ubd->lock, flags);
492 }
Jeff Dike91acb212005-10-10 23:10:32 -0400493}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494
Al Viro7bea96f2006-10-08 22:49:34 +0100495static irqreturn_t ubd_intr(int irq, void *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496{
Jeff Dike91acb212005-10-10 23:10:32 -0400497 ubd_handler();
Jeff Dikedc764e52007-05-06 14:51:41 -0700498 return IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499}
500
Jeff Dike91acb212005-10-10 23:10:32 -0400501/* Only changed by ubd_init, which is an initcall. */
502static int io_pid = -1;
503
WANG Cong5dc62b12008-04-28 02:13:58 -0700504static void kill_io_thread(void)
Jeff Dike91acb212005-10-10 23:10:32 -0400505{
Jeff Dike6c29256c2006-03-27 01:14:37 -0800506 if(io_pid != -1)
Jeff Dike91acb212005-10-10 23:10:32 -0400507 os_kill_process(io_pid, 1);
508}
509
510__uml_exitcall(kill_io_thread);
511
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800512static inline int ubd_file_size(struct ubd *ubd_dev, __u64 *size_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513{
514 char *file;
515
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800516 file = ubd_dev->cow.file ? ubd_dev->cow.file : ubd_dev->file;
Jeff Dikedc764e52007-05-06 14:51:41 -0700517 return os_file_size(file, size_out);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518}
519
WANG Cong5dc62b12008-04-28 02:13:58 -0700520static int read_cow_bitmap(int fd, void *buf, int offset, int len)
521{
522 int err;
523
524 err = os_seek_file(fd, offset);
525 if (err < 0)
526 return err;
527
528 err = os_read_file(fd, buf, len);
529 if (err < 0)
530 return err;
531
532 return 0;
533}
534
535static int backing_file_mismatch(char *file, __u64 size, time_t mtime)
536{
537 unsigned long modtime;
538 unsigned long long actual;
539 int err;
540
541 err = os_file_modtime(file, &modtime);
542 if (err < 0) {
543 printk(KERN_ERR "Failed to get modification time of backing "
544 "file \"%s\", err = %d\n", file, -err);
545 return err;
546 }
547
548 err = os_file_size(file, &actual);
549 if (err < 0) {
550 printk(KERN_ERR "Failed to get size of backing file \"%s\", "
551 "err = %d\n", file, -err);
552 return err;
553 }
554
555 if (actual != size) {
556 /*__u64 can be a long on AMD64 and with %lu GCC complains; so
557 * the typecast.*/
558 printk(KERN_ERR "Size mismatch (%llu vs %llu) of COW header "
559 "vs backing file\n", (unsigned long long) size, actual);
560 return -EINVAL;
561 }
562 if (modtime != mtime) {
563 printk(KERN_ERR "mtime mismatch (%ld vs %ld) of COW header vs "
564 "backing file\n", mtime, modtime);
565 return -EINVAL;
566 }
567 return 0;
568}
569
570static int path_requires_switch(char *from_cmdline, char *from_cow, char *cow)
571{
572 struct uml_stat buf1, buf2;
573 int err;
574
575 if (from_cmdline == NULL)
576 return 0;
577 if (!strcmp(from_cmdline, from_cow))
578 return 0;
579
580 err = os_stat_file(from_cmdline, &buf1);
581 if (err < 0) {
582 printk(KERN_ERR "Couldn't stat '%s', err = %d\n", from_cmdline,
583 -err);
584 return 0;
585 }
586 err = os_stat_file(from_cow, &buf2);
587 if (err < 0) {
588 printk(KERN_ERR "Couldn't stat '%s', err = %d\n", from_cow,
589 -err);
590 return 1;
591 }
592 if ((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino))
593 return 0;
594
595 printk(KERN_ERR "Backing file mismatch - \"%s\" requested, "
596 "\"%s\" specified in COW header of \"%s\"\n",
597 from_cmdline, from_cow, cow);
598 return 1;
599}
600
601static int open_ubd_file(char *file, struct openflags *openflags, int shared,
602 char **backing_file_out, int *bitmap_offset_out,
603 unsigned long *bitmap_len_out, int *data_offset_out,
604 int *create_cow_out)
605{
606 time_t mtime;
607 unsigned long long size;
608 __u32 version, align;
609 char *backing_file;
610 int fd, err, sectorsize, asked_switch, mode = 0644;
611
612 fd = os_open_file(file, *openflags, mode);
613 if (fd < 0) {
614 if ((fd == -ENOENT) && (create_cow_out != NULL))
615 *create_cow_out = 1;
616 if (!openflags->w ||
617 ((fd != -EROFS) && (fd != -EACCES)))
618 return fd;
619 openflags->w = 0;
620 fd = os_open_file(file, *openflags, mode);
621 if (fd < 0)
622 return fd;
623 }
624
625 if (shared)
626 printk(KERN_INFO "Not locking \"%s\" on the host\n", file);
627 else {
628 err = os_lock_file(fd, openflags->w);
629 if (err < 0) {
630 printk(KERN_ERR "Failed to lock '%s', err = %d\n",
631 file, -err);
632 goto out_close;
633 }
634 }
635
636 /* Successful return case! */
637 if (backing_file_out == NULL)
638 return fd;
639
640 err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime,
641 &size, &sectorsize, &align, bitmap_offset_out);
642 if (err && (*backing_file_out != NULL)) {
643 printk(KERN_ERR "Failed to read COW header from COW file "
644 "\"%s\", errno = %d\n", file, -err);
645 goto out_close;
646 }
647 if (err)
648 return fd;
649
650 asked_switch = path_requires_switch(*backing_file_out, backing_file,
651 file);
652
653 /* Allow switching only if no mismatch. */
654 if (asked_switch && !backing_file_mismatch(*backing_file_out, size,
655 mtime)) {
656 printk(KERN_ERR "Switching backing file to '%s'\n",
657 *backing_file_out);
658 err = write_cow_header(file, fd, *backing_file_out,
659 sectorsize, align, &size);
660 if (err) {
661 printk(KERN_ERR "Switch failed, errno = %d\n", -err);
662 goto out_close;
663 }
664 } else {
665 *backing_file_out = backing_file;
666 err = backing_file_mismatch(*backing_file_out, size, mtime);
667 if (err)
668 goto out_close;
669 }
670
671 cow_sizes(version, size, sectorsize, align, *bitmap_offset_out,
672 bitmap_len_out, data_offset_out);
673
674 return fd;
675 out_close:
676 os_close_file(fd);
677 return err;
678}
679
680static int create_cow_file(char *cow_file, char *backing_file,
681 struct openflags flags,
682 int sectorsize, int alignment, int *bitmap_offset_out,
683 unsigned long *bitmap_len_out, int *data_offset_out)
684{
685 int err, fd;
686
687 flags.c = 1;
688 fd = open_ubd_file(cow_file, &flags, 0, NULL, NULL, NULL, NULL, NULL);
689 if (fd < 0) {
690 err = fd;
691 printk(KERN_ERR "Open of COW file '%s' failed, errno = %d\n",
692 cow_file, -err);
693 goto out;
694 }
695
696 err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment,
697 bitmap_offset_out, bitmap_len_out,
698 data_offset_out);
699 if (!err)
700 return fd;
701 os_close_file(fd);
702 out:
703 return err;
704}
705
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800706static void ubd_close_dev(struct ubd *ubd_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800708 os_close_file(ubd_dev->fd);
709 if(ubd_dev->cow.file == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 return;
711
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800712 os_close_file(ubd_dev->cow.fd);
713 vfree(ubd_dev->cow.bitmap);
714 ubd_dev->cow.bitmap = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715}
716
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800717static int ubd_open_dev(struct ubd *ubd_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718{
719 struct openflags flags;
720 char **back_ptr;
721 int err, create_cow, *create_ptr;
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800722 int fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800724 ubd_dev->openflags = ubd_dev->boot_openflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 create_cow = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800726 create_ptr = (ubd_dev->cow.file != NULL) ? &create_cow : NULL;
727 back_ptr = ubd_dev->no_cow ? NULL : &ubd_dev->cow.file;
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800728
729 fd = open_ubd_file(ubd_dev->file, &ubd_dev->openflags, ubd_dev->shared,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800730 back_ptr, &ubd_dev->cow.bitmap_offset,
731 &ubd_dev->cow.bitmap_len, &ubd_dev->cow.data_offset,
Jeff Dike6c29256c2006-03-27 01:14:37 -0800732 create_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800734 if((fd == -ENOENT) && create_cow){
735 fd = create_cow_file(ubd_dev->file, ubd_dev->cow.file,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800736 ubd_dev->openflags, 1 << 9, PAGE_SIZE,
737 &ubd_dev->cow.bitmap_offset,
738 &ubd_dev->cow.bitmap_len,
739 &ubd_dev->cow.data_offset);
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800740 if(fd >= 0){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 printk(KERN_INFO "Creating \"%s\" as COW file for "
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800742 "\"%s\"\n", ubd_dev->file, ubd_dev->cow.file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 }
744 }
745
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800746 if(fd < 0){
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800747 printk("Failed to open '%s', errno = %d\n", ubd_dev->file,
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800748 -fd);
749 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 }
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800751 ubd_dev->fd = fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800753 if(ubd_dev->cow.file != NULL){
Martin K. Petersen086fa5f2010-02-26 00:20:38 -0500754 blk_queue_max_hw_sectors(ubd_dev->queue, 8 * sizeof(long));
Jeff Dikef4768ff2007-08-22 14:01:53 -0700755
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 err = -ENOMEM;
Jesper Juhlda2486b2007-10-16 01:27:19 -0700757 ubd_dev->cow.bitmap = vmalloc(ubd_dev->cow.bitmap_len);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800758 if(ubd_dev->cow.bitmap == NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 printk(KERN_ERR "Failed to vmalloc COW bitmap\n");
760 goto error;
761 }
762 flush_tlb_kernel_vm();
763
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800764 err = read_cow_bitmap(ubd_dev->fd, ubd_dev->cow.bitmap,
765 ubd_dev->cow.bitmap_offset,
766 ubd_dev->cow.bitmap_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 if(err < 0)
768 goto error;
769
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800770 flags = ubd_dev->openflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 flags.w = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800772 err = open_ubd_file(ubd_dev->cow.file, &flags, ubd_dev->shared, NULL,
Jeff Dike6c29256c2006-03-27 01:14:37 -0800773 NULL, NULL, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 if(err < 0) goto error;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800775 ubd_dev->cow.fd = err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 }
Jeff Dikedc764e52007-05-06 14:51:41 -0700777 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 error:
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800779 os_close_file(ubd_dev->fd);
Jeff Dikedc764e52007-05-06 14:51:41 -0700780 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781}
782
Jeff Dike2e3f5252007-05-06 14:51:29 -0700783static void ubd_device_release(struct device *dev)
784{
Greg Kroah-Hartman8691b972009-05-04 12:40:54 -0700785 struct ubd *ubd_dev = dev_get_drvdata(dev);
Jeff Dike2e3f5252007-05-06 14:51:29 -0700786
787 blk_cleanup_queue(ubd_dev->queue);
788 *ubd_dev = ((struct ubd) DEFAULT_UBD);
789}
790
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800791static int ubd_disk_register(int major, u64 size, int unit,
Jeff Dikeb8831a12007-02-10 01:44:17 -0800792 struct gendisk **disk_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793{
794 struct gendisk *disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795
796 disk = alloc_disk(1 << UBD_SHIFT);
797 if(disk == NULL)
Jeff Dikedc764e52007-05-06 14:51:41 -0700798 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799
800 disk->major = major;
801 disk->first_minor = unit << UBD_SHIFT;
802 disk->fops = &ubd_blops;
803 set_capacity(disk, size / 512);
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700804 if (major == UBD_MAJOR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 sprintf(disk->disk_name, "ubd%c", 'a' + unit);
Greg Kroah-Hartmance7b0f42005-06-20 21:15:16 -0700806 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 sprintf(disk->disk_name, "ubd_fake%d", unit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808
809 /* sysfs register (not for ide fake devices) */
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700810 if (major == UBD_MAJOR) {
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800811 ubd_devs[unit].pdev.id = unit;
812 ubd_devs[unit].pdev.name = DRIVER_NAME;
Jeff Dike2e3f5252007-05-06 14:51:29 -0700813 ubd_devs[unit].pdev.dev.release = ubd_device_release;
Greg Kroah-Hartman8691b972009-05-04 12:40:54 -0700814 dev_set_drvdata(&ubd_devs[unit].pdev.dev, &ubd_devs[unit]);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800815 platform_device_register(&ubd_devs[unit].pdev);
816 disk->driverfs_dev = &ubd_devs[unit].pdev.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 }
818
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800819 disk->private_data = &ubd_devs[unit];
Jeff Dike62f96cb2007-02-10 01:44:16 -0800820 disk->queue = ubd_devs[unit].queue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 add_disk(disk);
822
823 *disk_out = disk;
824 return 0;
825}
826
827#define ROUND_BLOCK(n) ((n + ((1 << 9) - 1)) & (-1 << 9))
828
Jeff Dikef28169d2007-02-10 01:43:53 -0800829static int ubd_add(int n, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800831 struct ubd *ubd_dev = &ubd_devs[n];
Jeff Dikef28169d2007-02-10 01:43:53 -0800832 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800834 if(ubd_dev->file == NULL)
Jeff Dikeec7cf782005-09-03 15:57:29 -0700835 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800837 err = ubd_file_size(ubd_dev, &ubd_dev->size);
Jeff Dikef28169d2007-02-10 01:43:53 -0800838 if(err < 0){
839 *error_out = "Couldn't determine size of device's file";
Jeff Dike80c13742006-09-29 01:58:51 -0700840 goto out;
Jeff Dikef28169d2007-02-10 01:43:53 -0800841 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800843 ubd_dev->size = ROUND_BLOCK(ubd_dev->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844
Jeff Dikea0044bd2007-05-06 14:51:36 -0700845 INIT_LIST_HEAD(&ubd_dev->restart);
WANG Cong4f40c052007-11-05 14:50:59 -0800846 sg_init_table(ubd_dev->sg, MAX_SG);
Jeff Dikea0044bd2007-05-06 14:51:36 -0700847
Jeff Dike62f96cb2007-02-10 01:44:16 -0800848 err = -ENOMEM;
849 ubd_dev->queue = blk_init_queue(do_ubd_request, &ubd_dev->lock);
850 if (ubd_dev->queue == NULL) {
851 *error_out = "Failed to initialize device queue";
Jeff Dike80c13742006-09-29 01:58:51 -0700852 goto out;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800853 }
854 ubd_dev->queue->queuedata = ubd_dev;
855
Martin K. Petersen8a783622010-02-26 00:20:39 -0500856 blk_queue_max_segments(ubd_dev->queue, MAX_SG);
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700857 err = ubd_disk_register(UBD_MAJOR, ubd_dev->size, n, &ubd_gendisk[n]);
Jeff Dike62f96cb2007-02-10 01:44:16 -0800858 if(err){
859 *error_out = "Failed to register device";
860 goto out_cleanup;
861 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800862
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700863 if (fake_major != UBD_MAJOR)
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800864 ubd_disk_register(fake_major, ubd_dev->size, n,
Jeff Dike62f96cb2007-02-10 01:44:16 -0800865 &fake_gendisk[n]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866
Jeff Dike83380cc2008-02-04 22:31:18 -0800867 /*
868 * Perhaps this should also be under the "if (fake_major)" above
869 * using the fake_disk->disk_name
870 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 if (fake_ide)
872 make_ide_entries(ubd_gendisk[n]->disk_name);
873
Jeff Dikeec7cf782005-09-03 15:57:29 -0700874 err = 0;
Jeff Dikeec7cf782005-09-03 15:57:29 -0700875out:
876 return err;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800877
878out_cleanup:
879 blk_cleanup_queue(ubd_dev->queue);
880 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881}
882
Jeff Dikef28169d2007-02-10 01:43:53 -0800883static int ubd_config(char *str, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884{
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800885 int n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886
Jeff Dikef28169d2007-02-10 01:43:53 -0800887 /* This string is possibly broken up and stored, so it's only
888 * freed if ubd_setup_common fails, or if only general options
889 * were set.
890 */
Jeff Dike970d6e32006-01-06 00:18:48 -0800891 str = kstrdup(str, GFP_KERNEL);
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800892 if (str == NULL) {
Jeff Dikef28169d2007-02-10 01:43:53 -0800893 *error_out = "Failed to allocate memory";
894 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 }
Jeff Dikef28169d2007-02-10 01:43:53 -0800896
897 ret = ubd_setup_common(str, &n, error_out);
898 if (ret)
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800899 goto err_free;
Jeff Dikef28169d2007-02-10 01:43:53 -0800900
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800901 if (n == -1) {
902 ret = 0;
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800903 goto err_free;
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800904 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905
Jeff Dikedc764e52007-05-06 14:51:41 -0700906 mutex_lock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -0800907 ret = ubd_add(n, error_out);
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800908 if (ret)
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800909 ubd_devs[n].file = NULL;
Jeff Dikedc764e52007-05-06 14:51:41 -0700910 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800912out:
Jeff Dikedc764e52007-05-06 14:51:41 -0700913 return ret;
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800914
915err_free:
916 kfree(str);
917 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918}
919
920static int ubd_get_config(char *name, char *str, int size, char **error_out)
921{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800922 struct ubd *ubd_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 int n, len = 0;
924
925 n = parse_unit(&name);
926 if((n >= MAX_DEV) || (n < 0)){
927 *error_out = "ubd_get_config : device number out of range";
Jeff Dikedc764e52007-05-06 14:51:41 -0700928 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 }
930
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800931 ubd_dev = &ubd_devs[n];
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800932 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800934 if(ubd_dev->file == NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 CONFIG_CHUNK(str, size, len, "", 1);
936 goto out;
937 }
938
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800939 CONFIG_CHUNK(str, size, len, ubd_dev->file, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800941 if(ubd_dev->cow.file != NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 CONFIG_CHUNK(str, size, len, ",", 0);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800943 CONFIG_CHUNK(str, size, len, ubd_dev->cow.file, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 }
945 else CONFIG_CHUNK(str, size, len, "", 1);
946
947 out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800948 mutex_unlock(&ubd_lock);
Jeff Dikedc764e52007-05-06 14:51:41 -0700949 return len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950}
951
Jeff Dike29d56cf2005-06-25 14:55:25 -0700952static int ubd_id(char **str, int *start_out, int *end_out)
953{
Jeff Dikedc764e52007-05-06 14:51:41 -0700954 int n;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700955
956 n = parse_unit(str);
Jeff Dikedc764e52007-05-06 14:51:41 -0700957 *start_out = 0;
958 *end_out = MAX_DEV - 1;
959 return n;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700960}
961
Jeff Dikef28169d2007-02-10 01:43:53 -0800962static int ubd_remove(int n, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963{
Jeff Dike2e3f5252007-05-06 14:51:29 -0700964 struct gendisk *disk = ubd_gendisk[n];
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800965 struct ubd *ubd_dev;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700966 int err = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800968 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800970 ubd_dev = &ubd_devs[n];
Jeff Dike29d56cf2005-06-25 14:55:25 -0700971
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800972 if(ubd_dev->file == NULL)
Jeff Dike29d56cf2005-06-25 14:55:25 -0700973 goto out;
974
975 /* you cannot remove a open disk */
976 err = -EBUSY;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800977 if(ubd_dev->count > 0)
Jeff Dike29d56cf2005-06-25 14:55:25 -0700978 goto out;
979
Jeff Dikedc764e52007-05-06 14:51:41 -0700980 ubd_gendisk[n] = NULL;
Jeff Dikeb47d2de2007-05-06 14:51:01 -0700981 if(disk != NULL){
982 del_gendisk(disk);
983 put_disk(disk);
984 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985
986 if(fake_gendisk[n] != NULL){
987 del_gendisk(fake_gendisk[n]);
988 put_disk(fake_gendisk[n]);
989 fake_gendisk[n] = NULL;
990 }
991
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 err = 0;
Jeff Dike2e3f5252007-05-06 14:51:29 -0700993 platform_device_unregister(&ubd_dev->pdev);
Jeff Dike29d56cf2005-06-25 14:55:25 -0700994out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800995 mutex_unlock(&ubd_lock);
Jeff Dike29d56cf2005-06-25 14:55:25 -0700996 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997}
998
Jeff Dikef28169d2007-02-10 01:43:53 -0800999/* All these are called by mconsole in process context and without
Jeff Dikeb8831a12007-02-10 01:44:17 -08001000 * ubd-specific locks. The structure itself is const except for .list.
Jeff Dikef28169d2007-02-10 01:43:53 -08001001 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002static struct mc_device ubd_mc = {
Jeff Dike84f48d42007-02-10 01:44:01 -08001003 .list = LIST_HEAD_INIT(ubd_mc.list),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 .name = "ubd",
1005 .config = ubd_config,
Jeff Dikedc764e52007-05-06 14:51:41 -07001006 .get_config = ubd_get_config,
Jeff Dike29d56cf2005-06-25 14:55:25 -07001007 .id = ubd_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 .remove = ubd_remove,
1009};
1010
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001011static int __init ubd_mc_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012{
1013 mconsole_register_dev(&ubd_mc);
1014 return 0;
1015}
1016
1017__initcall(ubd_mc_init);
1018
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001019static int __init ubd0_init(void)
1020{
1021 struct ubd *ubd_dev = &ubd_devs[0];
1022
Jeff Dikeb8831a12007-02-10 01:44:17 -08001023 mutex_lock(&ubd_lock);
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001024 if(ubd_dev->file == NULL)
1025 ubd_dev->file = "root_fs";
Jeff Dikeb8831a12007-02-10 01:44:17 -08001026 mutex_unlock(&ubd_lock);
1027
Jeff Dikedc764e52007-05-06 14:51:41 -07001028 return 0;
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001029}
1030
1031__initcall(ubd0_init);
1032
Jeff Dikeb8831a12007-02-10 01:44:17 -08001033/* Used in ubd_init, which is an initcall */
Russell King3ae5eae2005-11-09 22:32:44 +00001034static struct platform_driver ubd_driver = {
1035 .driver = {
1036 .name = DRIVER_NAME,
1037 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038};
1039
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001040static int __init ubd_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041{
Jeff Dikef28169d2007-02-10 01:43:53 -08001042 char *error;
1043 int i, err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044
Christoph Hellwig792dd4f2009-03-31 15:23:39 -07001045 if (register_blkdev(UBD_MAJOR, "ubd"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 return -1;
1047
Christoph Hellwig792dd4f2009-03-31 15:23:39 -07001048 if (fake_major != UBD_MAJOR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 char name[sizeof("ubd_nnn\0")];
1050
1051 snprintf(name, sizeof(name), "ubd_%d", fake_major);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 if (register_blkdev(fake_major, "ubd"))
1053 return -1;
1054 }
Russell King3ae5eae2005-11-09 22:32:44 +00001055 platform_driver_register(&ubd_driver);
Jeff Dikedc764e52007-05-06 14:51:41 -07001056 mutex_lock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -08001057 for (i = 0; i < MAX_DEV; i++){
1058 err = ubd_add(i, &error);
1059 if(err)
1060 printk(KERN_ERR "Failed to initialize ubd device %d :"
1061 "%s\n", i, error);
1062 }
Jeff Dikedc764e52007-05-06 14:51:41 -07001063 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 return 0;
1065}
1066
1067late_initcall(ubd_init);
1068
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001069static int __init ubd_driver_init(void){
Jeff Dike91acb212005-10-10 23:10:32 -04001070 unsigned long stack;
1071 int err;
1072
1073 /* Set by CONFIG_BLK_DEV_UBD_SYNC or ubd=sync.*/
1074 if(global_openflags.s){
1075 printk(KERN_INFO "ubd: Synchronous mode\n");
1076 /* Letting ubd=sync be like using ubd#s= instead of ubd#= is
1077 * enough. So use anyway the io thread. */
1078 }
1079 stack = alloc_stack(0, 0);
Jeff Dike6c29256c2006-03-27 01:14:37 -08001080 io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *),
Jeff Dike91acb212005-10-10 23:10:32 -04001081 &thread_fd);
1082 if(io_pid < 0){
Jeff Dike6c29256c2006-03-27 01:14:37 -08001083 printk(KERN_ERR
Jeff Dike91acb212005-10-10 23:10:32 -04001084 "ubd : Failed to start I/O thread (errno = %d) - "
1085 "falling back to synchronous I/O\n", -io_pid);
1086 io_pid = -1;
Jeff Dikedc764e52007-05-06 14:51:41 -07001087 return 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001088 }
Jeff Dike6c29256c2006-03-27 01:14:37 -08001089 err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001090 IRQF_DISABLED, "ubd", ubd_devs);
Jeff Dike91acb212005-10-10 23:10:32 -04001091 if(err != 0)
1092 printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err);
Jeff Dikef4c57a72006-03-31 02:30:10 -08001093 return 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001094}
1095
1096device_initcall(ubd_driver_init);
1097
Al Viroa625c992008-03-02 09:16:26 -05001098static int ubd_open(struct block_device *bdev, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099{
Al Viroa625c992008-03-02 09:16:26 -05001100 struct gendisk *disk = bdev->bd_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001101 struct ubd *ubd_dev = disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 int err = 0;
1103
Arnd Bergmann6e9624b2010-08-07 18:25:34 +02001104 lock_kernel();
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001105 if(ubd_dev->count == 0){
1106 err = ubd_open_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 if(err){
1108 printk(KERN_ERR "%s: Can't open \"%s\": errno = %d\n",
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001109 disk->disk_name, ubd_dev->file, -err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 goto out;
1111 }
1112 }
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001113 ubd_dev->count++;
1114 set_disk_ro(disk, !ubd_dev->openflags.w);
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -07001115
1116 /* This should no more be needed. And it didn't work anyway to exclude
1117 * read-write remounting of filesystems.*/
Al Viroa625c992008-03-02 09:16:26 -05001118 /*if((mode & FMODE_WRITE) && !ubd_dev->openflags.w){
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -08001119 if(--ubd_dev->count == 0) ubd_close_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 err = -EROFS;
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -07001121 }*/
Arnd Bergmann6e9624b2010-08-07 18:25:34 +02001122out:
1123 unlock_kernel();
Jeff Dikedc764e52007-05-06 14:51:41 -07001124 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125}
1126
Al Viroa625c992008-03-02 09:16:26 -05001127static int ubd_release(struct gendisk *disk, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001129 struct ubd *ubd_dev = disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130
Arnd Bergmann6e9624b2010-08-07 18:25:34 +02001131 lock_kernel();
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001132 if(--ubd_dev->count == 0)
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -08001133 ubd_close_dev(ubd_dev);
Arnd Bergmann6e9624b2010-08-07 18:25:34 +02001134 unlock_kernel();
Jeff Dikedc764e52007-05-06 14:51:41 -07001135 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136}
1137
Jeff Dike91acb212005-10-10 23:10:32 -04001138static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask,
1139 __u64 *cow_offset, unsigned long *bitmap,
1140 __u64 bitmap_offset, unsigned long *bitmap_words,
1141 __u64 bitmap_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142{
Jeff Dike91acb212005-10-10 23:10:32 -04001143 __u64 sector = io_offset >> 9;
1144 int i, update_bitmap = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145
Jeff Dike91acb212005-10-10 23:10:32 -04001146 for(i = 0; i < length >> 9; i++){
1147 if(cow_mask != NULL)
1148 ubd_set_bit(i, (unsigned char *) cow_mask);
1149 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
1150 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151
Jeff Dike91acb212005-10-10 23:10:32 -04001152 update_bitmap = 1;
1153 ubd_set_bit(sector + i, (unsigned char *) bitmap);
1154 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155
Jeff Dike91acb212005-10-10 23:10:32 -04001156 if(!update_bitmap)
1157 return;
1158
1159 *cow_offset = sector / (sizeof(unsigned long) * 8);
1160
1161 /* This takes care of the case where we're exactly at the end of the
1162 * device, and *cow_offset + 1 is off the end. So, just back it up
1163 * by one word. Thanks to Lynn Kerby for the fix and James McMechan
1164 * for the original diagnosis.
1165 */
Jiri Olsa6d074242008-05-12 14:01:56 -07001166 if (*cow_offset == (DIV_ROUND_UP(bitmap_len,
1167 sizeof(unsigned long)) - 1))
Jeff Dike91acb212005-10-10 23:10:32 -04001168 (*cow_offset)--;
1169
1170 bitmap_words[0] = bitmap[*cow_offset];
1171 bitmap_words[1] = bitmap[*cow_offset + 1];
1172
1173 *cow_offset *= sizeof(unsigned long);
1174 *cow_offset += bitmap_offset;
1175}
1176
1177static void cowify_req(struct io_thread_req *req, unsigned long *bitmap,
1178 __u64 bitmap_offset, __u64 bitmap_len)
1179{
1180 __u64 sector = req->offset >> 9;
1181 int i;
1182
1183 if(req->length > (sizeof(req->sector_mask) * 8) << 9)
1184 panic("Operation too long");
1185
1186 if(req->op == UBD_READ) {
1187 for(i = 0; i < req->length >> 9; i++){
1188 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
Jeff Dike6c29256c2006-03-27 01:14:37 -08001189 ubd_set_bit(i, (unsigned char *)
Jeff Dike91acb212005-10-10 23:10:32 -04001190 &req->sector_mask);
Jeff Dikedc764e52007-05-06 14:51:41 -07001191 }
Jeff Dike91acb212005-10-10 23:10:32 -04001192 }
1193 else cowify_bitmap(req->offset, req->length, &req->sector_mask,
1194 &req->cow_offset, bitmap, bitmap_offset,
1195 req->bitmap_words, bitmap_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196}
1197
Jeff Dike62f96cb2007-02-10 01:44:16 -08001198/* Called with dev->lock held */
Jeff Dikea0044bd2007-05-06 14:51:36 -07001199static void prepare_request(struct request *req, struct io_thread_req *io_req,
1200 unsigned long long offset, int page_offset,
1201 int len, struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202{
1203 struct gendisk *disk = req->rq_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001204 struct ubd *ubd_dev = disk->private_data;
Jeff Dike91acb212005-10-10 23:10:32 -04001205
Jeff Dike62f96cb2007-02-10 01:44:16 -08001206 io_req->req = req;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001207 io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd :
1208 ubd_dev->fd;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001209 io_req->fds[1] = ubd_dev->fd;
Jeff Dike91acb212005-10-10 23:10:32 -04001210 io_req->cow_offset = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 io_req->offset = offset;
1212 io_req->length = len;
1213 io_req->error = 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001214 io_req->sector_mask = 0;
1215
1216 io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 io_req->offsets[0] = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001218 io_req->offsets[1] = ubd_dev->cow.data_offset;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001219 io_req->buffer = page_address(page) + page_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 io_req->sectorsize = 1 << 9;
1221
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001222 if(ubd_dev->cow.file != NULL)
Jeff Dikea0044bd2007-05-06 14:51:36 -07001223 cowify_req(io_req, ubd_dev->cow.bitmap,
1224 ubd_dev->cow.bitmap_offset, ubd_dev->cow.bitmap_len);
Jeff Dike91acb212005-10-10 23:10:32 -04001225
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226}
1227
Jeff Dike62f96cb2007-02-10 01:44:16 -08001228/* Called with dev->lock held */
Jens Axboe165125e2007-07-24 09:28:11 +02001229static void do_ubd_request(struct request_queue *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230{
Jeff Dike2adcec22007-05-06 14:51:37 -07001231 struct io_thread_req *io_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 struct request *req;
Tejun Heof81f2f72009-04-28 13:06:10 +09001233 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234
Jeff Dikea0044bd2007-05-06 14:51:36 -07001235 while(1){
Jeff Dike2a9529a2007-03-29 01:20:27 -07001236 struct ubd *dev = q->queuedata;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001237 if(dev->end_sg == 0){
Tejun Heo9934c8c2009-05-08 11:54:16 +09001238 struct request *req = blk_fetch_request(q);
Jeff Dikea0044bd2007-05-06 14:51:36 -07001239 if(req == NULL)
1240 return;
1241
1242 dev->request = req;
Tejun Heo47526902010-10-15 12:56:21 +02001243 dev->rq_pos = blk_rq_pos(req);
Jeff Dikea0044bd2007-05-06 14:51:36 -07001244 dev->start_sg = 0;
1245 dev->end_sg = blk_rq_map_sg(q, req, dev->sg);
Jeff Dike91acb212005-10-10 23:10:32 -04001246 }
Jeff Dikea0044bd2007-05-06 14:51:36 -07001247
1248 req = dev->request;
1249 while(dev->start_sg < dev->end_sg){
1250 struct scatterlist *sg = &dev->sg[dev->start_sg];
1251
Jeff Dike2adcec22007-05-06 14:51:37 -07001252 io_req = kmalloc(sizeof(struct io_thread_req),
Peter Zijlstra990c5582007-05-06 14:51:38 -07001253 GFP_ATOMIC);
Jeff Dike2adcec22007-05-06 14:51:37 -07001254 if(io_req == NULL){
1255 if(list_empty(&dev->restart))
1256 list_add(&dev->restart, &restart);
1257 return;
1258 }
1259 prepare_request(req, io_req,
Tejun Heo47526902010-10-15 12:56:21 +02001260 (unsigned long long)dev->rq_pos << 9,
Jens Axboe45711f12007-10-22 21:19:53 +02001261 sg->offset, sg->length, sg_page(sg));
Jeff Dikea0044bd2007-05-06 14:51:36 -07001262
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001263 n = os_write_file(thread_fd, &io_req,
1264 sizeof(struct io_thread_req *));
Jeff Dike2adcec22007-05-06 14:51:37 -07001265 if(n != sizeof(struct io_thread_req *)){
Jeff Dikea0044bd2007-05-06 14:51:36 -07001266 if(n != -EAGAIN)
1267 printk("write to io thread failed, "
1268 "errno = %d\n", -n);
1269 else if(list_empty(&dev->restart))
1270 list_add(&dev->restart, &restart);
Miklos Szeredi12429bf2007-11-28 16:21:52 -08001271 kfree(io_req);
Jeff Dikea0044bd2007-05-06 14:51:36 -07001272 return;
1273 }
1274
Tejun Heo47526902010-10-15 12:56:21 +02001275 dev->rq_pos += sg->length >> 9;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001276 dev->start_sg++;
1277 }
1278 dev->end_sg = 0;
1279 dev->request = NULL;
Jeff Dike91acb212005-10-10 23:10:32 -04001280 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281}
1282
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001283static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
1284{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001285 struct ubd *ubd_dev = bdev->bd_disk->private_data;
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001286
1287 geo->heads = 128;
1288 geo->sectors = 32;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001289 geo->cylinders = ubd_dev->size / (128 * 32 * 512);
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001290 return 0;
1291}
1292
Al Viroa625c992008-03-02 09:16:26 -05001293static int ubd_ioctl(struct block_device *bdev, fmode_t mode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 unsigned int cmd, unsigned long arg)
1295{
Al Viroa625c992008-03-02 09:16:26 -05001296 struct ubd *ubd_dev = bdev->bd_disk->private_data;
Bartlomiej Zolnierkiewicz73855e12009-04-01 21:42:21 +02001297 u16 ubd_id[ATA_ID_WORDS];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298
1299 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 struct cdrom_volctrl volume;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 case HDIO_GET_IDENTITY:
Bartlomiej Zolnierkiewicz73855e12009-04-01 21:42:21 +02001302 memset(&ubd_id, 0, ATA_ID_WORDS * 2);
1303 ubd_id[ATA_ID_CYLS] = ubd_dev->size / (128 * 32 * 512);
1304 ubd_id[ATA_ID_HEADS] = 128;
1305 ubd_id[ATA_ID_SECTORS] = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 if(copy_to_user((char __user *) arg, (char *) &ubd_id,
1307 sizeof(ubd_id)))
Jeff Dikedc764e52007-05-06 14:51:41 -07001308 return -EFAULT;
1309 return 0;
Jeff Dikeb8831a12007-02-10 01:44:17 -08001310
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 case CDROMVOLREAD:
1312 if(copy_from_user(&volume, (char __user *) arg, sizeof(volume)))
Jeff Dikedc764e52007-05-06 14:51:41 -07001313 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 volume.channel0 = 255;
1315 volume.channel1 = 255;
1316 volume.channel2 = 255;
1317 volume.channel3 = 255;
1318 if(copy_to_user((char __user *) arg, &volume, sizeof(volume)))
Jeff Dikedc764e52007-05-06 14:51:41 -07001319 return -EFAULT;
1320 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 }
Jeff Dikedc764e52007-05-06 14:51:41 -07001322 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323}
1324
Jeff Dike91acb212005-10-10 23:10:32 -04001325static int update_bitmap(struct io_thread_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326{
Jeff Dike91acb212005-10-10 23:10:32 -04001327 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328
Jeff Dike91acb212005-10-10 23:10:32 -04001329 if(req->cow_offset == -1)
Jeff Dikedc764e52007-05-06 14:51:41 -07001330 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331
Jeff Dike91acb212005-10-10 23:10:32 -04001332 n = os_seek_file(req->fds[1], req->cow_offset);
1333 if(n < 0){
1334 printk("do_io - bitmap lseek failed : err = %d\n", -n);
Jeff Dikedc764e52007-05-06 14:51:41 -07001335 return 1;
Jeff Dike91acb212005-10-10 23:10:32 -04001336 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001338 n = os_write_file(req->fds[1], &req->bitmap_words,
1339 sizeof(req->bitmap_words));
Jeff Dike91acb212005-10-10 23:10:32 -04001340 if(n != sizeof(req->bitmap_words)){
1341 printk("do_io - bitmap update failed, err = %d fd = %d\n", -n,
1342 req->fds[1]);
Jeff Dikedc764e52007-05-06 14:51:41 -07001343 return 1;
Jeff Dike91acb212005-10-10 23:10:32 -04001344 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345
Jeff Dikedc764e52007-05-06 14:51:41 -07001346 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347}
Jeff Dike91acb212005-10-10 23:10:32 -04001348
WANG Cong5dc62b12008-04-28 02:13:58 -07001349static void do_io(struct io_thread_req *req)
Jeff Dike91acb212005-10-10 23:10:32 -04001350{
1351 char *buf;
1352 unsigned long len;
1353 int n, nsectors, start, end, bit;
1354 int err;
1355 __u64 off;
1356
1357 nsectors = req->length / req->sectorsize;
1358 start = 0;
1359 do {
1360 bit = ubd_test_bit(start, (unsigned char *) &req->sector_mask);
1361 end = start;
1362 while((end < nsectors) &&
1363 (ubd_test_bit(end, (unsigned char *)
1364 &req->sector_mask) == bit))
1365 end++;
1366
1367 off = req->offset + req->offsets[bit] +
1368 start * req->sectorsize;
1369 len = (end - start) * req->sectorsize;
1370 buf = &req->buffer[start * req->sectorsize];
1371
1372 err = os_seek_file(req->fds[bit], off);
1373 if(err < 0){
1374 printk("do_io - lseek failed : err = %d\n", -err);
1375 req->error = 1;
1376 return;
1377 }
1378 if(req->op == UBD_READ){
1379 n = 0;
1380 do {
1381 buf = &buf[n];
1382 len -= n;
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001383 n = os_read_file(req->fds[bit], buf, len);
Jeff Dike91acb212005-10-10 23:10:32 -04001384 if (n < 0) {
1385 printk("do_io - read failed, err = %d "
1386 "fd = %d\n", -n, req->fds[bit]);
1387 req->error = 1;
1388 return;
1389 }
1390 } while((n < len) && (n != 0));
1391 if (n < len) memset(&buf[n], 0, len - n);
1392 } else {
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001393 n = os_write_file(req->fds[bit], buf, len);
Jeff Dike91acb212005-10-10 23:10:32 -04001394 if(n != len){
1395 printk("do_io - write failed err = %d "
1396 "fd = %d\n", -n, req->fds[bit]);
1397 req->error = 1;
1398 return;
1399 }
1400 }
1401
1402 start = end;
1403 } while(start < nsectors);
1404
1405 req->error = update_bitmap(req);
1406}
1407
1408/* Changed in start_io_thread, which is serialized by being called only
1409 * from ubd_init, which is an initcall.
1410 */
1411int kernel_fd = -1;
1412
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001413/* Only changed by the io thread. XXX: currently unused. */
1414static int io_count = 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001415
1416int io_thread(void *arg)
1417{
Jeff Dike2adcec22007-05-06 14:51:37 -07001418 struct io_thread_req *req;
Jeff Dike91acb212005-10-10 23:10:32 -04001419 int n;
1420
1421 ignore_sigwinch_sig();
1422 while(1){
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001423 n = os_read_file(kernel_fd, &req,
Jeff Dike2adcec22007-05-06 14:51:37 -07001424 sizeof(struct io_thread_req *));
1425 if(n != sizeof(struct io_thread_req *)){
Jeff Dike91acb212005-10-10 23:10:32 -04001426 if(n < 0)
1427 printk("io_thread - read failed, fd = %d, "
1428 "err = %d\n", kernel_fd, -n);
1429 else {
1430 printk("io_thread - short read, fd = %d, "
1431 "length = %d\n", kernel_fd, n);
1432 }
1433 continue;
1434 }
1435 io_count++;
Jeff Dike2adcec22007-05-06 14:51:37 -07001436 do_io(req);
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001437 n = os_write_file(kernel_fd, &req,
Jeff Dike2adcec22007-05-06 14:51:37 -07001438 sizeof(struct io_thread_req *));
1439 if(n != sizeof(struct io_thread_req *))
Jeff Dike91acb212005-10-10 23:10:32 -04001440 printk("io_thread - write failed, fd = %d, err = %d\n",
1441 kernel_fd, -n);
1442 }
Jeff Dike91acb212005-10-10 23:10:32 -04001443
Jeff Dike1b57e9c2006-01-06 00:18:49 -08001444 return 0;
1445}