blob: 1bcd208c459f609ab3634f951e1c11b3b2e50038 [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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166};
167
168#define DEFAULT_COW { \
169 .file = NULL, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700170 .fd = -1, \
171 .bitmap = NULL, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 .bitmap_offset = 0, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700173 .data_offset = 0, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174}
175
176#define DEFAULT_UBD { \
177 .file = NULL, \
178 .count = 0, \
179 .fd = -1, \
180 .size = -1, \
181 .boot_openflags = OPEN_FLAGS, \
182 .openflags = OPEN_FLAGS, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700183 .no_cow = 0, \
Jeff Dike6c29256c2006-03-27 01:14:37 -0800184 .shared = 0, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700185 .cow = DEFAULT_COW, \
Jeff Dike62f96cb2007-02-10 01:44:16 -0800186 .lock = SPIN_LOCK_UNLOCKED, \
Jeff Dikea0044bd2007-05-06 14:51:36 -0700187 .request = NULL, \
188 .start_sg = 0, \
189 .end_sg = 0, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190}
191
Jeff Dikeb8831a12007-02-10 01:44:17 -0800192/* Protected by ubd_lock */
WANG Cong5dc62b12008-04-28 02:13:58 -0700193static struct ubd ubd_devs[MAX_DEV] = { [0 ... MAX_DEV - 1] = DEFAULT_UBD };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195/* Only changed by fake_ide_setup which is a setup */
196static int fake_ide = 0;
197static struct proc_dir_entry *proc_ide_root = NULL;
198static struct proc_dir_entry *proc_ide = NULL;
199
200static void make_proc_ide(void)
201{
202 proc_ide_root = proc_mkdir("ide", NULL);
203 proc_ide = proc_mkdir("ide0", proc_ide_root);
204}
205
Alexey Dobriyan6613c5e2009-12-14 18:00:11 -0800206static int fake_ide_media_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207{
Alexey Dobriyan6613c5e2009-12-14 18:00:11 -0800208 seq_puts(m, "disk\n");
209 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210}
211
Alexey Dobriyan6613c5e2009-12-14 18:00:11 -0800212static int fake_ide_media_proc_open(struct inode *inode, struct file *file)
213{
214 return single_open(file, fake_ide_media_proc_show, NULL);
215}
216
217static const struct file_operations fake_ide_media_proc_fops = {
218 .owner = THIS_MODULE,
219 .open = fake_ide_media_proc_open,
220 .read = seq_read,
221 .llseek = seq_lseek,
222 .release = single_release,
223};
224
WANG Congc0a92902008-02-04 22:30:41 -0800225static void make_ide_entries(const char *dev_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226{
227 struct proc_dir_entry *dir, *ent;
228 char name[64];
229
230 if(proc_ide_root == NULL) make_proc_ide();
231
232 dir = proc_mkdir(dev_name, proc_ide);
233 if(!dir) return;
234
Alexey Dobriyan6613c5e2009-12-14 18:00:11 -0800235 ent = proc_create("media", S_IRUGO, dir, &fake_ide_media_proc_fops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 if(!ent) return;
WANG Congc0a92902008-02-04 22:30:41 -0800237 snprintf(name, sizeof(name), "ide0/%s", dev_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 proc_symlink(dev_name, proc_ide_root, name);
239}
240
241static int fake_ide_setup(char *str)
242{
243 fake_ide = 1;
Jeff Dikedc764e52007-05-06 14:51:41 -0700244 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245}
246
247__setup("fake_ide", fake_ide_setup);
248
249__uml_help(fake_ide_setup,
250"fake_ide\n"
251" Create ide0 entries that map onto ubd devices.\n\n"
252);
253
254static int parse_unit(char **ptr)
255{
256 char *str = *ptr, *end;
257 int n = -1;
258
259 if(isdigit(*str)) {
260 n = simple_strtoul(str, &end, 0);
261 if(end == str)
Jeff Dikedc764e52007-05-06 14:51:41 -0700262 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 *ptr = end;
264 }
Paolo 'Blaisorblade' Giarrusso97d88ac2006-10-30 22:07:03 -0800265 else if (('a' <= *str) && (*str <= 'z')) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 n = *str - 'a';
267 str++;
268 *ptr = str;
269 }
Jeff Dikedc764e52007-05-06 14:51:41 -0700270 return n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271}
272
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800273/* If *index_out == -1 at exit, the passed option was a general one;
274 * otherwise, the str pointer is used (and owned) inside ubd_devs array, so it
275 * should not be freed on exit.
276 */
Jeff Dikef28169d2007-02-10 01:43:53 -0800277static int ubd_setup_common(char *str, int *index_out, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800279 struct ubd *ubd_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 struct openflags flags = global_openflags;
281 char *backing_file;
Jeff Dikeb8831a12007-02-10 01:44:17 -0800282 int n, err = 0, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283
284 if(index_out) *index_out = -1;
285 n = *str;
286 if(n == '='){
287 char *end;
288 int major;
289
290 str++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 if(!strcmp(str, "sync")){
292 global_openflags = of_sync(global_openflags);
Jeff Dikeb8831a12007-02-10 01:44:17 -0800293 goto out1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 }
295
Jeff Dikef28169d2007-02-10 01:43:53 -0800296 err = -EINVAL;
Jeff Dikeb8831a12007-02-10 01:44:17 -0800297 major = simple_strtoul(str, &end, 0);
298 if((*end != '\0') || (end == str)){
299 *error_out = "Didn't parse major number";
300 goto out1;
301 }
302
Jeff Dikef28169d2007-02-10 01:43:53 -0800303 mutex_lock(&ubd_lock);
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700304 if (fake_major != UBD_MAJOR) {
Jeff Dikef28169d2007-02-10 01:43:53 -0800305 *error_out = "Can't assign a fake major twice";
306 goto out1;
307 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800308
Jeff Dikef28169d2007-02-10 01:43:53 -0800309 fake_major = major;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310
311 printk(KERN_INFO "Setting extra ubd major number to %d\n",
312 major);
Jeff Dikef28169d2007-02-10 01:43:53 -0800313 err = 0;
314 out1:
315 mutex_unlock(&ubd_lock);
316 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 }
318
319 n = parse_unit(&str);
320 if(n < 0){
Jeff Dikef28169d2007-02-10 01:43:53 -0800321 *error_out = "Couldn't parse device number";
322 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 }
324 if(n >= MAX_DEV){
Jeff Dikef28169d2007-02-10 01:43:53 -0800325 *error_out = "Device number out of range";
326 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 }
328
Jeff Dikef28169d2007-02-10 01:43:53 -0800329 err = -EBUSY;
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800330 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800332 ubd_dev = &ubd_devs[n];
333 if(ubd_dev->file != NULL){
Jeff Dikef28169d2007-02-10 01:43:53 -0800334 *error_out = "Device is already configured";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 goto out;
336 }
337
338 if (index_out)
339 *index_out = n;
340
Jeff Dikef28169d2007-02-10 01:43:53 -0800341 err = -EINVAL;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800342 for (i = 0; i < sizeof("rscd="); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 switch (*str) {
344 case 'r':
345 flags.w = 0;
346 break;
347 case 's':
348 flags.s = 1;
349 break;
350 case 'd':
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800351 ubd_dev->no_cow = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 break;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800353 case 'c':
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800354 ubd_dev->shared = 1;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800355 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 case '=':
357 str++;
358 goto break_loop;
359 default:
Jeff Dikef28169d2007-02-10 01:43:53 -0800360 *error_out = "Expected '=' or flag letter "
361 "(r, s, c, or d)";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 goto out;
363 }
364 str++;
365 }
366
Jeff Dikef28169d2007-02-10 01:43:53 -0800367 if (*str == '=')
368 *error_out = "Too many flags specified";
369 else
370 *error_out = "Missing '='";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 goto out;
372
373break_loop:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 backing_file = strchr(str, ',');
375
Jeff Dikef28169d2007-02-10 01:43:53 -0800376 if (backing_file == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 backing_file = strchr(str, ':');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378
Jeff Dikef28169d2007-02-10 01:43:53 -0800379 if(backing_file != NULL){
380 if(ubd_dev->no_cow){
381 *error_out = "Can't specify both 'd' and a cow file";
382 goto out;
383 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 else {
385 *backing_file = '\0';
386 backing_file++;
387 }
388 }
Jeff Dikef28169d2007-02-10 01:43:53 -0800389 err = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800390 ubd_dev->file = str;
391 ubd_dev->cow.file = backing_file;
392 ubd_dev->boot_openflags = flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800394 mutex_unlock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -0800395 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396}
397
398static int ubd_setup(char *str)
399{
Jeff Dikef28169d2007-02-10 01:43:53 -0800400 char *error;
401 int err;
402
403 err = ubd_setup_common(str, NULL, &error);
404 if(err)
405 printk(KERN_ERR "Failed to initialize device with \"%s\" : "
406 "%s\n", str, error);
407 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408}
409
410__setup("ubd", ubd_setup);
411__uml_help(ubd_setup,
412"ubd<n><flags>=<filename>[(:|,)<filename2>]\n"
413" This is used to associate a device with a file in the underlying\n"
414" filesystem. When specifying two filenames, the first one is the\n"
415" COW name and the second is the backing file name. As separator you can\n"
416" use either a ':' or a ',': the first one allows writing things like;\n"
417" ubd0=~/Uml/root_cow:~/Uml/root_backing_file\n"
418" while with a ',' the shell would not expand the 2nd '~'.\n"
Jeff Dikef28169d2007-02-10 01:43:53 -0800419" When using only one filename, UML will detect whether to treat it like\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420" a COW file or a backing file. To override this detection, add the 'd'\n"
421" flag:\n"
422" ubd0d=BackingFile\n"
423" Usually, there is a filesystem in the file, but \n"
424" that's not required. Swap devices containing swap files can be\n"
425" specified like this. Also, a file which doesn't contain a\n"
426" filesystem can have its contents read in the virtual \n"
427" machine by running 'dd' on the device. <n> must be in the range\n"
428" 0 to 7. Appending an 'r' to the number will cause that device\n"
429" to be mounted read-only. For example ubd1r=./ext_fs. Appending\n"
Jeff Dike20ede452008-02-04 22:30:37 -0800430" an 's' will cause data to be written to disk on the host immediately.\n"
431" 'c' will cause the device to be treated as being shared between multiple\n"
432" UMLs and file locking will be turned off - this is appropriate for a\n"
433" cluster filesystem and inappropriate at almost all other times.\n\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434);
435
Jeff Dike8299ca52008-02-04 22:30:48 -0800436static int udb_setup(char *str)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437{
438 printk("udb%s specified on command line is almost certainly a ubd -> "
439 "udb TYPO\n", str);
Jeff Dikedc764e52007-05-06 14:51:41 -0700440 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441}
442
443__setup("udb", udb_setup);
444__uml_help(udb_setup,
445"udb\n"
Jeff Dike0894e272005-05-28 15:51:55 -0700446" This option is here solely to catch ubd -> udb typos, which can be\n"
447" to impossible to catch visually unless you specifically look for\n"
448" them. The only result of any option starting with 'udb' is an error\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449" in the boot output.\n\n"
450);
451
Jens Axboe165125e2007-07-24 09:28:11 +0200452static void do_ubd_request(struct request_queue * q);
Jeff Dike91acb212005-10-10 23:10:32 -0400453
454/* Only changed by ubd_init, which is an initcall. */
WANG Cong5dc62b12008-04-28 02:13:58 -0700455static int thread_fd = -1;
Jeff Dikea0044bd2007-05-06 14:51:36 -0700456static LIST_HEAD(restart);
457
Paolo 'Blaisorblade' Giarrusso2fe30a32006-10-30 22:07:09 -0800458/* XXX - move this inside ubd_intr. */
Jeff Dike62f96cb2007-02-10 01:44:16 -0800459/* Called without dev->lock held, and only in interrupt context. */
Jeff Dike91acb212005-10-10 23:10:32 -0400460static void ubd_handler(void)
461{
Jeff Dike2adcec22007-05-06 14:51:37 -0700462 struct io_thread_req *req;
Jeff Dikea0044bd2007-05-06 14:51:36 -0700463 struct ubd *ubd;
464 struct list_head *list, *next_ele;
465 unsigned long flags;
Jeff Dike91acb212005-10-10 23:10:32 -0400466 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467
Jeff Dikea0044bd2007-05-06 14:51:36 -0700468 while(1){
Jeff Dikea6ea4cc2007-05-06 14:51:43 -0700469 n = os_read_file(thread_fd, &req,
470 sizeof(struct io_thread_req *));
Jeff Dikea0044bd2007-05-06 14:51:36 -0700471 if(n != sizeof(req)){
472 if(n == -EAGAIN)
473 break;
474 printk(KERN_ERR "spurious interrupt in ubd_handler, "
475 "err = %d\n", -n);
476 return;
477 }
478
Tejun Heo4d6c84d2009-04-28 13:06:09 +0900479 blk_end_request(req->req, 0, req->length);
Jeff Dike2adcec22007-05-06 14:51:37 -0700480 kfree(req);
Jeff Dike91acb212005-10-10 23:10:32 -0400481 }
Jeff Dike62f96cb2007-02-10 01:44:16 -0800482 reactivate_fd(thread_fd, UBD_IRQ);
Jeff Dikea0044bd2007-05-06 14:51:36 -0700483
484 list_for_each_safe(list, next_ele, &restart){
485 ubd = container_of(list, struct ubd, restart);
486 list_del_init(&ubd->restart);
487 spin_lock_irqsave(&ubd->lock, flags);
488 do_ubd_request(ubd->queue);
489 spin_unlock_irqrestore(&ubd->lock, flags);
490 }
Jeff Dike91acb212005-10-10 23:10:32 -0400491}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492
Al Viro7bea96f2006-10-08 22:49:34 +0100493static irqreturn_t ubd_intr(int irq, void *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494{
Jeff Dike91acb212005-10-10 23:10:32 -0400495 ubd_handler();
Jeff Dikedc764e52007-05-06 14:51:41 -0700496 return IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497}
498
Jeff Dike91acb212005-10-10 23:10:32 -0400499/* Only changed by ubd_init, which is an initcall. */
500static int io_pid = -1;
501
WANG Cong5dc62b12008-04-28 02:13:58 -0700502static void kill_io_thread(void)
Jeff Dike91acb212005-10-10 23:10:32 -0400503{
Jeff Dike6c29256c2006-03-27 01:14:37 -0800504 if(io_pid != -1)
Jeff Dike91acb212005-10-10 23:10:32 -0400505 os_kill_process(io_pid, 1);
506}
507
508__uml_exitcall(kill_io_thread);
509
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800510static inline int ubd_file_size(struct ubd *ubd_dev, __u64 *size_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511{
512 char *file;
513
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800514 file = ubd_dev->cow.file ? ubd_dev->cow.file : ubd_dev->file;
Jeff Dikedc764e52007-05-06 14:51:41 -0700515 return os_file_size(file, size_out);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516}
517
WANG Cong5dc62b12008-04-28 02:13:58 -0700518static int read_cow_bitmap(int fd, void *buf, int offset, int len)
519{
520 int err;
521
522 err = os_seek_file(fd, offset);
523 if (err < 0)
524 return err;
525
526 err = os_read_file(fd, buf, len);
527 if (err < 0)
528 return err;
529
530 return 0;
531}
532
533static int backing_file_mismatch(char *file, __u64 size, time_t mtime)
534{
535 unsigned long modtime;
536 unsigned long long actual;
537 int err;
538
539 err = os_file_modtime(file, &modtime);
540 if (err < 0) {
541 printk(KERN_ERR "Failed to get modification time of backing "
542 "file \"%s\", err = %d\n", file, -err);
543 return err;
544 }
545
546 err = os_file_size(file, &actual);
547 if (err < 0) {
548 printk(KERN_ERR "Failed to get size of backing file \"%s\", "
549 "err = %d\n", file, -err);
550 return err;
551 }
552
553 if (actual != size) {
554 /*__u64 can be a long on AMD64 and with %lu GCC complains; so
555 * the typecast.*/
556 printk(KERN_ERR "Size mismatch (%llu vs %llu) of COW header "
557 "vs backing file\n", (unsigned long long) size, actual);
558 return -EINVAL;
559 }
560 if (modtime != mtime) {
561 printk(KERN_ERR "mtime mismatch (%ld vs %ld) of COW header vs "
562 "backing file\n", mtime, modtime);
563 return -EINVAL;
564 }
565 return 0;
566}
567
568static int path_requires_switch(char *from_cmdline, char *from_cow, char *cow)
569{
570 struct uml_stat buf1, buf2;
571 int err;
572
573 if (from_cmdline == NULL)
574 return 0;
575 if (!strcmp(from_cmdline, from_cow))
576 return 0;
577
578 err = os_stat_file(from_cmdline, &buf1);
579 if (err < 0) {
580 printk(KERN_ERR "Couldn't stat '%s', err = %d\n", from_cmdline,
581 -err);
582 return 0;
583 }
584 err = os_stat_file(from_cow, &buf2);
585 if (err < 0) {
586 printk(KERN_ERR "Couldn't stat '%s', err = %d\n", from_cow,
587 -err);
588 return 1;
589 }
590 if ((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino))
591 return 0;
592
593 printk(KERN_ERR "Backing file mismatch - \"%s\" requested, "
594 "\"%s\" specified in COW header of \"%s\"\n",
595 from_cmdline, from_cow, cow);
596 return 1;
597}
598
599static int open_ubd_file(char *file, struct openflags *openflags, int shared,
600 char **backing_file_out, int *bitmap_offset_out,
601 unsigned long *bitmap_len_out, int *data_offset_out,
602 int *create_cow_out)
603{
604 time_t mtime;
605 unsigned long long size;
606 __u32 version, align;
607 char *backing_file;
608 int fd, err, sectorsize, asked_switch, mode = 0644;
609
610 fd = os_open_file(file, *openflags, mode);
611 if (fd < 0) {
612 if ((fd == -ENOENT) && (create_cow_out != NULL))
613 *create_cow_out = 1;
614 if (!openflags->w ||
615 ((fd != -EROFS) && (fd != -EACCES)))
616 return fd;
617 openflags->w = 0;
618 fd = os_open_file(file, *openflags, mode);
619 if (fd < 0)
620 return fd;
621 }
622
623 if (shared)
624 printk(KERN_INFO "Not locking \"%s\" on the host\n", file);
625 else {
626 err = os_lock_file(fd, openflags->w);
627 if (err < 0) {
628 printk(KERN_ERR "Failed to lock '%s', err = %d\n",
629 file, -err);
630 goto out_close;
631 }
632 }
633
634 /* Successful return case! */
635 if (backing_file_out == NULL)
636 return fd;
637
638 err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime,
639 &size, &sectorsize, &align, bitmap_offset_out);
640 if (err && (*backing_file_out != NULL)) {
641 printk(KERN_ERR "Failed to read COW header from COW file "
642 "\"%s\", errno = %d\n", file, -err);
643 goto out_close;
644 }
645 if (err)
646 return fd;
647
648 asked_switch = path_requires_switch(*backing_file_out, backing_file,
649 file);
650
651 /* Allow switching only if no mismatch. */
652 if (asked_switch && !backing_file_mismatch(*backing_file_out, size,
653 mtime)) {
654 printk(KERN_ERR "Switching backing file to '%s'\n",
655 *backing_file_out);
656 err = write_cow_header(file, fd, *backing_file_out,
657 sectorsize, align, &size);
658 if (err) {
659 printk(KERN_ERR "Switch failed, errno = %d\n", -err);
660 goto out_close;
661 }
662 } else {
663 *backing_file_out = backing_file;
664 err = backing_file_mismatch(*backing_file_out, size, mtime);
665 if (err)
666 goto out_close;
667 }
668
669 cow_sizes(version, size, sectorsize, align, *bitmap_offset_out,
670 bitmap_len_out, data_offset_out);
671
672 return fd;
673 out_close:
674 os_close_file(fd);
675 return err;
676}
677
678static int create_cow_file(char *cow_file, char *backing_file,
679 struct openflags flags,
680 int sectorsize, int alignment, int *bitmap_offset_out,
681 unsigned long *bitmap_len_out, int *data_offset_out)
682{
683 int err, fd;
684
685 flags.c = 1;
686 fd = open_ubd_file(cow_file, &flags, 0, NULL, NULL, NULL, NULL, NULL);
687 if (fd < 0) {
688 err = fd;
689 printk(KERN_ERR "Open of COW file '%s' failed, errno = %d\n",
690 cow_file, -err);
691 goto out;
692 }
693
694 err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment,
695 bitmap_offset_out, bitmap_len_out,
696 data_offset_out);
697 if (!err)
698 return fd;
699 os_close_file(fd);
700 out:
701 return err;
702}
703
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800704static void ubd_close_dev(struct ubd *ubd_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800706 os_close_file(ubd_dev->fd);
707 if(ubd_dev->cow.file == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 return;
709
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800710 os_close_file(ubd_dev->cow.fd);
711 vfree(ubd_dev->cow.bitmap);
712 ubd_dev->cow.bitmap = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713}
714
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800715static int ubd_open_dev(struct ubd *ubd_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716{
717 struct openflags flags;
718 char **back_ptr;
719 int err, create_cow, *create_ptr;
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800720 int fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800722 ubd_dev->openflags = ubd_dev->boot_openflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 create_cow = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800724 create_ptr = (ubd_dev->cow.file != NULL) ? &create_cow : NULL;
725 back_ptr = ubd_dev->no_cow ? NULL : &ubd_dev->cow.file;
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800726
727 fd = open_ubd_file(ubd_dev->file, &ubd_dev->openflags, ubd_dev->shared,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800728 back_ptr, &ubd_dev->cow.bitmap_offset,
729 &ubd_dev->cow.bitmap_len, &ubd_dev->cow.data_offset,
Jeff Dike6c29256c2006-03-27 01:14:37 -0800730 create_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800732 if((fd == -ENOENT) && create_cow){
733 fd = create_cow_file(ubd_dev->file, ubd_dev->cow.file,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800734 ubd_dev->openflags, 1 << 9, PAGE_SIZE,
735 &ubd_dev->cow.bitmap_offset,
736 &ubd_dev->cow.bitmap_len,
737 &ubd_dev->cow.data_offset);
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800738 if(fd >= 0){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 printk(KERN_INFO "Creating \"%s\" as COW file for "
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800740 "\"%s\"\n", ubd_dev->file, ubd_dev->cow.file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 }
742 }
743
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800744 if(fd < 0){
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800745 printk("Failed to open '%s', errno = %d\n", ubd_dev->file,
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800746 -fd);
747 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 }
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800749 ubd_dev->fd = fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800751 if(ubd_dev->cow.file != NULL){
Martin K. Petersen086fa5f2010-02-26 00:20:38 -0500752 blk_queue_max_hw_sectors(ubd_dev->queue, 8 * sizeof(long));
Jeff Dikef4768ff2007-08-22 14:01:53 -0700753
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 err = -ENOMEM;
Jesper Juhlda2486b2007-10-16 01:27:19 -0700755 ubd_dev->cow.bitmap = vmalloc(ubd_dev->cow.bitmap_len);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800756 if(ubd_dev->cow.bitmap == NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 printk(KERN_ERR "Failed to vmalloc COW bitmap\n");
758 goto error;
759 }
760 flush_tlb_kernel_vm();
761
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800762 err = read_cow_bitmap(ubd_dev->fd, ubd_dev->cow.bitmap,
763 ubd_dev->cow.bitmap_offset,
764 ubd_dev->cow.bitmap_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 if(err < 0)
766 goto error;
767
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800768 flags = ubd_dev->openflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 flags.w = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800770 err = open_ubd_file(ubd_dev->cow.file, &flags, ubd_dev->shared, NULL,
Jeff Dike6c29256c2006-03-27 01:14:37 -0800771 NULL, NULL, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 if(err < 0) goto error;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800773 ubd_dev->cow.fd = err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 }
Jeff Dikedc764e52007-05-06 14:51:41 -0700775 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 error:
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800777 os_close_file(ubd_dev->fd);
Jeff Dikedc764e52007-05-06 14:51:41 -0700778 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779}
780
Jeff Dike2e3f5252007-05-06 14:51:29 -0700781static void ubd_device_release(struct device *dev)
782{
Greg Kroah-Hartman8691b972009-05-04 12:40:54 -0700783 struct ubd *ubd_dev = dev_get_drvdata(dev);
Jeff Dike2e3f5252007-05-06 14:51:29 -0700784
785 blk_cleanup_queue(ubd_dev->queue);
786 *ubd_dev = ((struct ubd) DEFAULT_UBD);
787}
788
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800789static int ubd_disk_register(int major, u64 size, int unit,
Jeff Dikeb8831a12007-02-10 01:44:17 -0800790 struct gendisk **disk_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791{
792 struct gendisk *disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793
794 disk = alloc_disk(1 << UBD_SHIFT);
795 if(disk == NULL)
Jeff Dikedc764e52007-05-06 14:51:41 -0700796 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797
798 disk->major = major;
799 disk->first_minor = unit << UBD_SHIFT;
800 disk->fops = &ubd_blops;
801 set_capacity(disk, size / 512);
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700802 if (major == UBD_MAJOR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 sprintf(disk->disk_name, "ubd%c", 'a' + unit);
Greg Kroah-Hartmance7b0f42005-06-20 21:15:16 -0700804 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 sprintf(disk->disk_name, "ubd_fake%d", unit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806
807 /* sysfs register (not for ide fake devices) */
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700808 if (major == UBD_MAJOR) {
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800809 ubd_devs[unit].pdev.id = unit;
810 ubd_devs[unit].pdev.name = DRIVER_NAME;
Jeff Dike2e3f5252007-05-06 14:51:29 -0700811 ubd_devs[unit].pdev.dev.release = ubd_device_release;
Greg Kroah-Hartman8691b972009-05-04 12:40:54 -0700812 dev_set_drvdata(&ubd_devs[unit].pdev.dev, &ubd_devs[unit]);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800813 platform_device_register(&ubd_devs[unit].pdev);
814 disk->driverfs_dev = &ubd_devs[unit].pdev.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 }
816
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800817 disk->private_data = &ubd_devs[unit];
Jeff Dike62f96cb2007-02-10 01:44:16 -0800818 disk->queue = ubd_devs[unit].queue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 add_disk(disk);
820
821 *disk_out = disk;
822 return 0;
823}
824
825#define ROUND_BLOCK(n) ((n + ((1 << 9) - 1)) & (-1 << 9))
826
Jeff Dikef28169d2007-02-10 01:43:53 -0800827static int ubd_add(int n, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800829 struct ubd *ubd_dev = &ubd_devs[n];
Jeff Dikef28169d2007-02-10 01:43:53 -0800830 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800832 if(ubd_dev->file == NULL)
Jeff Dikeec7cf782005-09-03 15:57:29 -0700833 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800835 err = ubd_file_size(ubd_dev, &ubd_dev->size);
Jeff Dikef28169d2007-02-10 01:43:53 -0800836 if(err < 0){
837 *error_out = "Couldn't determine size of device's file";
Jeff Dike80c13742006-09-29 01:58:51 -0700838 goto out;
Jeff Dikef28169d2007-02-10 01:43:53 -0800839 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800841 ubd_dev->size = ROUND_BLOCK(ubd_dev->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842
Jeff Dikea0044bd2007-05-06 14:51:36 -0700843 INIT_LIST_HEAD(&ubd_dev->restart);
WANG Cong4f40c052007-11-05 14:50:59 -0800844 sg_init_table(ubd_dev->sg, MAX_SG);
Jeff Dikea0044bd2007-05-06 14:51:36 -0700845
Jeff Dike62f96cb2007-02-10 01:44:16 -0800846 err = -ENOMEM;
847 ubd_dev->queue = blk_init_queue(do_ubd_request, &ubd_dev->lock);
848 if (ubd_dev->queue == NULL) {
849 *error_out = "Failed to initialize device queue";
Jeff Dike80c13742006-09-29 01:58:51 -0700850 goto out;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800851 }
852 ubd_dev->queue->queuedata = ubd_dev;
853
Martin K. Petersen8a783622010-02-26 00:20:39 -0500854 blk_queue_max_segments(ubd_dev->queue, MAX_SG);
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700855 err = ubd_disk_register(UBD_MAJOR, ubd_dev->size, n, &ubd_gendisk[n]);
Jeff Dike62f96cb2007-02-10 01:44:16 -0800856 if(err){
857 *error_out = "Failed to register device";
858 goto out_cleanup;
859 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800860
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700861 if (fake_major != UBD_MAJOR)
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800862 ubd_disk_register(fake_major, ubd_dev->size, n,
Jeff Dike62f96cb2007-02-10 01:44:16 -0800863 &fake_gendisk[n]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864
Jeff Dike83380cc2008-02-04 22:31:18 -0800865 /*
866 * Perhaps this should also be under the "if (fake_major)" above
867 * using the fake_disk->disk_name
868 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 if (fake_ide)
870 make_ide_entries(ubd_gendisk[n]->disk_name);
871
Jeff Dikeec7cf782005-09-03 15:57:29 -0700872 err = 0;
Jeff Dikeec7cf782005-09-03 15:57:29 -0700873out:
874 return err;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800875
876out_cleanup:
877 blk_cleanup_queue(ubd_dev->queue);
878 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879}
880
Jeff Dikef28169d2007-02-10 01:43:53 -0800881static int ubd_config(char *str, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882{
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800883 int n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884
Jeff Dikef28169d2007-02-10 01:43:53 -0800885 /* This string is possibly broken up and stored, so it's only
886 * freed if ubd_setup_common fails, or if only general options
887 * were set.
888 */
Jeff Dike970d6e32006-01-06 00:18:48 -0800889 str = kstrdup(str, GFP_KERNEL);
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800890 if (str == NULL) {
Jeff Dikef28169d2007-02-10 01:43:53 -0800891 *error_out = "Failed to allocate memory";
892 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 }
Jeff Dikef28169d2007-02-10 01:43:53 -0800894
895 ret = ubd_setup_common(str, &n, error_out);
896 if (ret)
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800897 goto err_free;
Jeff Dikef28169d2007-02-10 01:43:53 -0800898
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800899 if (n == -1) {
900 ret = 0;
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800901 goto err_free;
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800902 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903
Jeff Dikedc764e52007-05-06 14:51:41 -0700904 mutex_lock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -0800905 ret = ubd_add(n, error_out);
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800906 if (ret)
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800907 ubd_devs[n].file = NULL;
Jeff Dikedc764e52007-05-06 14:51:41 -0700908 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800910out:
Jeff Dikedc764e52007-05-06 14:51:41 -0700911 return ret;
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800912
913err_free:
914 kfree(str);
915 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916}
917
918static int ubd_get_config(char *name, char *str, int size, char **error_out)
919{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800920 struct ubd *ubd_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 int n, len = 0;
922
923 n = parse_unit(&name);
924 if((n >= MAX_DEV) || (n < 0)){
925 *error_out = "ubd_get_config : device number out of range";
Jeff Dikedc764e52007-05-06 14:51:41 -0700926 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 }
928
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800929 ubd_dev = &ubd_devs[n];
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800930 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800932 if(ubd_dev->file == NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 CONFIG_CHUNK(str, size, len, "", 1);
934 goto out;
935 }
936
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800937 CONFIG_CHUNK(str, size, len, ubd_dev->file, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800939 if(ubd_dev->cow.file != NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 CONFIG_CHUNK(str, size, len, ",", 0);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800941 CONFIG_CHUNK(str, size, len, ubd_dev->cow.file, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 }
943 else CONFIG_CHUNK(str, size, len, "", 1);
944
945 out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800946 mutex_unlock(&ubd_lock);
Jeff Dikedc764e52007-05-06 14:51:41 -0700947 return len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948}
949
Jeff Dike29d56cf2005-06-25 14:55:25 -0700950static int ubd_id(char **str, int *start_out, int *end_out)
951{
Jeff Dikedc764e52007-05-06 14:51:41 -0700952 int n;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700953
954 n = parse_unit(str);
Jeff Dikedc764e52007-05-06 14:51:41 -0700955 *start_out = 0;
956 *end_out = MAX_DEV - 1;
957 return n;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700958}
959
Jeff Dikef28169d2007-02-10 01:43:53 -0800960static int ubd_remove(int n, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961{
Jeff Dike2e3f5252007-05-06 14:51:29 -0700962 struct gendisk *disk = ubd_gendisk[n];
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800963 struct ubd *ubd_dev;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700964 int err = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800966 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800968 ubd_dev = &ubd_devs[n];
Jeff Dike29d56cf2005-06-25 14:55:25 -0700969
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800970 if(ubd_dev->file == NULL)
Jeff Dike29d56cf2005-06-25 14:55:25 -0700971 goto out;
972
973 /* you cannot remove a open disk */
974 err = -EBUSY;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800975 if(ubd_dev->count > 0)
Jeff Dike29d56cf2005-06-25 14:55:25 -0700976 goto out;
977
Jeff Dikedc764e52007-05-06 14:51:41 -0700978 ubd_gendisk[n] = NULL;
Jeff Dikeb47d2de2007-05-06 14:51:01 -0700979 if(disk != NULL){
980 del_gendisk(disk);
981 put_disk(disk);
982 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983
984 if(fake_gendisk[n] != NULL){
985 del_gendisk(fake_gendisk[n]);
986 put_disk(fake_gendisk[n]);
987 fake_gendisk[n] = NULL;
988 }
989
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 err = 0;
Jeff Dike2e3f5252007-05-06 14:51:29 -0700991 platform_device_unregister(&ubd_dev->pdev);
Jeff Dike29d56cf2005-06-25 14:55:25 -0700992out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800993 mutex_unlock(&ubd_lock);
Jeff Dike29d56cf2005-06-25 14:55:25 -0700994 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995}
996
Jeff Dikef28169d2007-02-10 01:43:53 -0800997/* All these are called by mconsole in process context and without
Jeff Dikeb8831a12007-02-10 01:44:17 -0800998 * ubd-specific locks. The structure itself is const except for .list.
Jeff Dikef28169d2007-02-10 01:43:53 -0800999 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000static struct mc_device ubd_mc = {
Jeff Dike84f48d42007-02-10 01:44:01 -08001001 .list = LIST_HEAD_INIT(ubd_mc.list),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 .name = "ubd",
1003 .config = ubd_config,
Jeff Dikedc764e52007-05-06 14:51:41 -07001004 .get_config = ubd_get_config,
Jeff Dike29d56cf2005-06-25 14:55:25 -07001005 .id = ubd_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 .remove = ubd_remove,
1007};
1008
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001009static int __init ubd_mc_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010{
1011 mconsole_register_dev(&ubd_mc);
1012 return 0;
1013}
1014
1015__initcall(ubd_mc_init);
1016
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001017static int __init ubd0_init(void)
1018{
1019 struct ubd *ubd_dev = &ubd_devs[0];
1020
Jeff Dikeb8831a12007-02-10 01:44:17 -08001021 mutex_lock(&ubd_lock);
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001022 if(ubd_dev->file == NULL)
1023 ubd_dev->file = "root_fs";
Jeff Dikeb8831a12007-02-10 01:44:17 -08001024 mutex_unlock(&ubd_lock);
1025
Jeff Dikedc764e52007-05-06 14:51:41 -07001026 return 0;
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001027}
1028
1029__initcall(ubd0_init);
1030
Jeff Dikeb8831a12007-02-10 01:44:17 -08001031/* Used in ubd_init, which is an initcall */
Russell King3ae5eae2005-11-09 22:32:44 +00001032static struct platform_driver ubd_driver = {
1033 .driver = {
1034 .name = DRIVER_NAME,
1035 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036};
1037
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001038static int __init ubd_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039{
Jeff Dikef28169d2007-02-10 01:43:53 -08001040 char *error;
1041 int i, err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042
Christoph Hellwig792dd4f2009-03-31 15:23:39 -07001043 if (register_blkdev(UBD_MAJOR, "ubd"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 return -1;
1045
Christoph Hellwig792dd4f2009-03-31 15:23:39 -07001046 if (fake_major != UBD_MAJOR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 char name[sizeof("ubd_nnn\0")];
1048
1049 snprintf(name, sizeof(name), "ubd_%d", fake_major);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 if (register_blkdev(fake_major, "ubd"))
1051 return -1;
1052 }
Russell King3ae5eae2005-11-09 22:32:44 +00001053 platform_driver_register(&ubd_driver);
Jeff Dikedc764e52007-05-06 14:51:41 -07001054 mutex_lock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -08001055 for (i = 0; i < MAX_DEV; i++){
1056 err = ubd_add(i, &error);
1057 if(err)
1058 printk(KERN_ERR "Failed to initialize ubd device %d :"
1059 "%s\n", i, error);
1060 }
Jeff Dikedc764e52007-05-06 14:51:41 -07001061 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 return 0;
1063}
1064
1065late_initcall(ubd_init);
1066
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001067static int __init ubd_driver_init(void){
Jeff Dike91acb212005-10-10 23:10:32 -04001068 unsigned long stack;
1069 int err;
1070
1071 /* Set by CONFIG_BLK_DEV_UBD_SYNC or ubd=sync.*/
1072 if(global_openflags.s){
1073 printk(KERN_INFO "ubd: Synchronous mode\n");
1074 /* Letting ubd=sync be like using ubd#s= instead of ubd#= is
1075 * enough. So use anyway the io thread. */
1076 }
1077 stack = alloc_stack(0, 0);
Jeff Dike6c29256c2006-03-27 01:14:37 -08001078 io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *),
Jeff Dike91acb212005-10-10 23:10:32 -04001079 &thread_fd);
1080 if(io_pid < 0){
Jeff Dike6c29256c2006-03-27 01:14:37 -08001081 printk(KERN_ERR
Jeff Dike91acb212005-10-10 23:10:32 -04001082 "ubd : Failed to start I/O thread (errno = %d) - "
1083 "falling back to synchronous I/O\n", -io_pid);
1084 io_pid = -1;
Jeff Dikedc764e52007-05-06 14:51:41 -07001085 return 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001086 }
Jeff Dike6c29256c2006-03-27 01:14:37 -08001087 err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001088 IRQF_DISABLED, "ubd", ubd_devs);
Jeff Dike91acb212005-10-10 23:10:32 -04001089 if(err != 0)
1090 printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err);
Jeff Dikef4c57a72006-03-31 02:30:10 -08001091 return 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001092}
1093
1094device_initcall(ubd_driver_init);
1095
Al Viroa625c992008-03-02 09:16:26 -05001096static int ubd_open(struct block_device *bdev, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097{
Al Viroa625c992008-03-02 09:16:26 -05001098 struct gendisk *disk = bdev->bd_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001099 struct ubd *ubd_dev = disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 int err = 0;
1101
Arnd Bergmann6e9624b2010-08-07 18:25:34 +02001102 lock_kernel();
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001103 if(ubd_dev->count == 0){
1104 err = ubd_open_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 if(err){
1106 printk(KERN_ERR "%s: Can't open \"%s\": errno = %d\n",
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001107 disk->disk_name, ubd_dev->file, -err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 goto out;
1109 }
1110 }
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001111 ubd_dev->count++;
1112 set_disk_ro(disk, !ubd_dev->openflags.w);
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -07001113
1114 /* This should no more be needed. And it didn't work anyway to exclude
1115 * read-write remounting of filesystems.*/
Al Viroa625c992008-03-02 09:16:26 -05001116 /*if((mode & FMODE_WRITE) && !ubd_dev->openflags.w){
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -08001117 if(--ubd_dev->count == 0) ubd_close_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 err = -EROFS;
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -07001119 }*/
Arnd Bergmann6e9624b2010-08-07 18:25:34 +02001120out:
1121 unlock_kernel();
Jeff Dikedc764e52007-05-06 14:51:41 -07001122 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123}
1124
Al Viroa625c992008-03-02 09:16:26 -05001125static int ubd_release(struct gendisk *disk, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001127 struct ubd *ubd_dev = disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128
Arnd Bergmann6e9624b2010-08-07 18:25:34 +02001129 lock_kernel();
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001130 if(--ubd_dev->count == 0)
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -08001131 ubd_close_dev(ubd_dev);
Arnd Bergmann6e9624b2010-08-07 18:25:34 +02001132 unlock_kernel();
Jeff Dikedc764e52007-05-06 14:51:41 -07001133 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134}
1135
Jeff Dike91acb212005-10-10 23:10:32 -04001136static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask,
1137 __u64 *cow_offset, unsigned long *bitmap,
1138 __u64 bitmap_offset, unsigned long *bitmap_words,
1139 __u64 bitmap_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140{
Jeff Dike91acb212005-10-10 23:10:32 -04001141 __u64 sector = io_offset >> 9;
1142 int i, update_bitmap = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143
Jeff Dike91acb212005-10-10 23:10:32 -04001144 for(i = 0; i < length >> 9; i++){
1145 if(cow_mask != NULL)
1146 ubd_set_bit(i, (unsigned char *) cow_mask);
1147 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
1148 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149
Jeff Dike91acb212005-10-10 23:10:32 -04001150 update_bitmap = 1;
1151 ubd_set_bit(sector + i, (unsigned char *) bitmap);
1152 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153
Jeff Dike91acb212005-10-10 23:10:32 -04001154 if(!update_bitmap)
1155 return;
1156
1157 *cow_offset = sector / (sizeof(unsigned long) * 8);
1158
1159 /* This takes care of the case where we're exactly at the end of the
1160 * device, and *cow_offset + 1 is off the end. So, just back it up
1161 * by one word. Thanks to Lynn Kerby for the fix and James McMechan
1162 * for the original diagnosis.
1163 */
Jiri Olsa6d074242008-05-12 14:01:56 -07001164 if (*cow_offset == (DIV_ROUND_UP(bitmap_len,
1165 sizeof(unsigned long)) - 1))
Jeff Dike91acb212005-10-10 23:10:32 -04001166 (*cow_offset)--;
1167
1168 bitmap_words[0] = bitmap[*cow_offset];
1169 bitmap_words[1] = bitmap[*cow_offset + 1];
1170
1171 *cow_offset *= sizeof(unsigned long);
1172 *cow_offset += bitmap_offset;
1173}
1174
1175static void cowify_req(struct io_thread_req *req, unsigned long *bitmap,
1176 __u64 bitmap_offset, __u64 bitmap_len)
1177{
1178 __u64 sector = req->offset >> 9;
1179 int i;
1180
1181 if(req->length > (sizeof(req->sector_mask) * 8) << 9)
1182 panic("Operation too long");
1183
1184 if(req->op == UBD_READ) {
1185 for(i = 0; i < req->length >> 9; i++){
1186 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
Jeff Dike6c29256c2006-03-27 01:14:37 -08001187 ubd_set_bit(i, (unsigned char *)
Jeff Dike91acb212005-10-10 23:10:32 -04001188 &req->sector_mask);
Jeff Dikedc764e52007-05-06 14:51:41 -07001189 }
Jeff Dike91acb212005-10-10 23:10:32 -04001190 }
1191 else cowify_bitmap(req->offset, req->length, &req->sector_mask,
1192 &req->cow_offset, bitmap, bitmap_offset,
1193 req->bitmap_words, bitmap_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194}
1195
Jeff Dike62f96cb2007-02-10 01:44:16 -08001196/* Called with dev->lock held */
Jeff Dikea0044bd2007-05-06 14:51:36 -07001197static void prepare_request(struct request *req, struct io_thread_req *io_req,
1198 unsigned long long offset, int page_offset,
1199 int len, struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200{
1201 struct gendisk *disk = req->rq_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001202 struct ubd *ubd_dev = disk->private_data;
Jeff Dike91acb212005-10-10 23:10:32 -04001203
Jeff Dike62f96cb2007-02-10 01:44:16 -08001204 io_req->req = req;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001205 io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd :
1206 ubd_dev->fd;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001207 io_req->fds[1] = ubd_dev->fd;
Jeff Dike91acb212005-10-10 23:10:32 -04001208 io_req->cow_offset = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209 io_req->offset = offset;
1210 io_req->length = len;
1211 io_req->error = 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001212 io_req->sector_mask = 0;
1213
1214 io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215 io_req->offsets[0] = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001216 io_req->offsets[1] = ubd_dev->cow.data_offset;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001217 io_req->buffer = page_address(page) + page_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 io_req->sectorsize = 1 << 9;
1219
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001220 if(ubd_dev->cow.file != NULL)
Jeff Dikea0044bd2007-05-06 14:51:36 -07001221 cowify_req(io_req, ubd_dev->cow.bitmap,
1222 ubd_dev->cow.bitmap_offset, ubd_dev->cow.bitmap_len);
Jeff Dike91acb212005-10-10 23:10:32 -04001223
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224}
1225
Jeff Dike62f96cb2007-02-10 01:44:16 -08001226/* Called with dev->lock held */
Jens Axboe165125e2007-07-24 09:28:11 +02001227static void do_ubd_request(struct request_queue *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228{
Jeff Dike2adcec22007-05-06 14:51:37 -07001229 struct io_thread_req *io_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 struct request *req;
Tejun Heof81f2f72009-04-28 13:06:10 +09001231 sector_t sector;
1232 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233
Jeff Dikea0044bd2007-05-06 14:51:36 -07001234 while(1){
Jeff Dike2a9529a2007-03-29 01:20:27 -07001235 struct ubd *dev = q->queuedata;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001236 if(dev->end_sg == 0){
Tejun Heo9934c8c2009-05-08 11:54:16 +09001237 struct request *req = blk_fetch_request(q);
Jeff Dikea0044bd2007-05-06 14:51:36 -07001238 if(req == NULL)
1239 return;
1240
1241 dev->request = req;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001242 dev->start_sg = 0;
1243 dev->end_sg = blk_rq_map_sg(q, req, dev->sg);
Jeff Dike91acb212005-10-10 23:10:32 -04001244 }
Jeff Dikea0044bd2007-05-06 14:51:36 -07001245
1246 req = dev->request;
Tejun Heo83096eb2009-05-07 22:24:39 +09001247 sector = blk_rq_pos(req);
Jeff Dikea0044bd2007-05-06 14:51:36 -07001248 while(dev->start_sg < dev->end_sg){
1249 struct scatterlist *sg = &dev->sg[dev->start_sg];
1250
Jeff Dike2adcec22007-05-06 14:51:37 -07001251 io_req = kmalloc(sizeof(struct io_thread_req),
Peter Zijlstra990c5582007-05-06 14:51:38 -07001252 GFP_ATOMIC);
Jeff Dike2adcec22007-05-06 14:51:37 -07001253 if(io_req == NULL){
1254 if(list_empty(&dev->restart))
1255 list_add(&dev->restart, &restart);
1256 return;
1257 }
1258 prepare_request(req, io_req,
Tejun Heof81f2f72009-04-28 13:06:10 +09001259 (unsigned long long)sector << 9,
Jens Axboe45711f12007-10-22 21:19:53 +02001260 sg->offset, sg->length, sg_page(sg));
Jeff Dikea0044bd2007-05-06 14:51:36 -07001261
Tejun Heof81f2f72009-04-28 13:06:10 +09001262 sector += sg->length >> 9;
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
Jeff Dikea0044bd2007-05-06 14:51:36 -07001275 dev->start_sg++;
1276 }
1277 dev->end_sg = 0;
1278 dev->request = NULL;
Jeff Dike91acb212005-10-10 23:10:32 -04001279 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280}
1281
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001282static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
1283{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001284 struct ubd *ubd_dev = bdev->bd_disk->private_data;
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001285
1286 geo->heads = 128;
1287 geo->sectors = 32;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001288 geo->cylinders = ubd_dev->size / (128 * 32 * 512);
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001289 return 0;
1290}
1291
Al Viroa625c992008-03-02 09:16:26 -05001292static int ubd_ioctl(struct block_device *bdev, fmode_t mode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293 unsigned int cmd, unsigned long arg)
1294{
Al Viroa625c992008-03-02 09:16:26 -05001295 struct ubd *ubd_dev = bdev->bd_disk->private_data;
Bartlomiej Zolnierkiewicz73855e12009-04-01 21:42:21 +02001296 u16 ubd_id[ATA_ID_WORDS];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297
1298 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299 struct cdrom_volctrl volume;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 case HDIO_GET_IDENTITY:
Bartlomiej Zolnierkiewicz73855e12009-04-01 21:42:21 +02001301 memset(&ubd_id, 0, ATA_ID_WORDS * 2);
1302 ubd_id[ATA_ID_CYLS] = ubd_dev->size / (128 * 32 * 512);
1303 ubd_id[ATA_ID_HEADS] = 128;
1304 ubd_id[ATA_ID_SECTORS] = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 if(copy_to_user((char __user *) arg, (char *) &ubd_id,
1306 sizeof(ubd_id)))
Jeff Dikedc764e52007-05-06 14:51:41 -07001307 return -EFAULT;
1308 return 0;
Jeff Dikeb8831a12007-02-10 01:44:17 -08001309
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310 case CDROMVOLREAD:
1311 if(copy_from_user(&volume, (char __user *) arg, sizeof(volume)))
Jeff Dikedc764e52007-05-06 14:51:41 -07001312 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 volume.channel0 = 255;
1314 volume.channel1 = 255;
1315 volume.channel2 = 255;
1316 volume.channel3 = 255;
1317 if(copy_to_user((char __user *) arg, &volume, sizeof(volume)))
Jeff Dikedc764e52007-05-06 14:51:41 -07001318 return -EFAULT;
1319 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 }
Jeff Dikedc764e52007-05-06 14:51:41 -07001321 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322}
1323
Jeff Dike91acb212005-10-10 23:10:32 -04001324static int update_bitmap(struct io_thread_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325{
Jeff Dike91acb212005-10-10 23:10:32 -04001326 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327
Jeff Dike91acb212005-10-10 23:10:32 -04001328 if(req->cow_offset == -1)
Jeff Dikedc764e52007-05-06 14:51:41 -07001329 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330
Jeff Dike91acb212005-10-10 23:10:32 -04001331 n = os_seek_file(req->fds[1], req->cow_offset);
1332 if(n < 0){
1333 printk("do_io - bitmap lseek failed : err = %d\n", -n);
Jeff Dikedc764e52007-05-06 14:51:41 -07001334 return 1;
Jeff Dike91acb212005-10-10 23:10:32 -04001335 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001337 n = os_write_file(req->fds[1], &req->bitmap_words,
1338 sizeof(req->bitmap_words));
Jeff Dike91acb212005-10-10 23:10:32 -04001339 if(n != sizeof(req->bitmap_words)){
1340 printk("do_io - bitmap update failed, err = %d fd = %d\n", -n,
1341 req->fds[1]);
Jeff Dikedc764e52007-05-06 14:51:41 -07001342 return 1;
Jeff Dike91acb212005-10-10 23:10:32 -04001343 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344
Jeff Dikedc764e52007-05-06 14:51:41 -07001345 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346}
Jeff Dike91acb212005-10-10 23:10:32 -04001347
WANG Cong5dc62b12008-04-28 02:13:58 -07001348static void do_io(struct io_thread_req *req)
Jeff Dike91acb212005-10-10 23:10:32 -04001349{
1350 char *buf;
1351 unsigned long len;
1352 int n, nsectors, start, end, bit;
1353 int err;
1354 __u64 off;
1355
1356 nsectors = req->length / req->sectorsize;
1357 start = 0;
1358 do {
1359 bit = ubd_test_bit(start, (unsigned char *) &req->sector_mask);
1360 end = start;
1361 while((end < nsectors) &&
1362 (ubd_test_bit(end, (unsigned char *)
1363 &req->sector_mask) == bit))
1364 end++;
1365
1366 off = req->offset + req->offsets[bit] +
1367 start * req->sectorsize;
1368 len = (end - start) * req->sectorsize;
1369 buf = &req->buffer[start * req->sectorsize];
1370
1371 err = os_seek_file(req->fds[bit], off);
1372 if(err < 0){
1373 printk("do_io - lseek failed : err = %d\n", -err);
1374 req->error = 1;
1375 return;
1376 }
1377 if(req->op == UBD_READ){
1378 n = 0;
1379 do {
1380 buf = &buf[n];
1381 len -= n;
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001382 n = os_read_file(req->fds[bit], buf, len);
Jeff Dike91acb212005-10-10 23:10:32 -04001383 if (n < 0) {
1384 printk("do_io - read failed, err = %d "
1385 "fd = %d\n", -n, req->fds[bit]);
1386 req->error = 1;
1387 return;
1388 }
1389 } while((n < len) && (n != 0));
1390 if (n < len) memset(&buf[n], 0, len - n);
1391 } else {
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001392 n = os_write_file(req->fds[bit], buf, len);
Jeff Dike91acb212005-10-10 23:10:32 -04001393 if(n != len){
1394 printk("do_io - write failed err = %d "
1395 "fd = %d\n", -n, req->fds[bit]);
1396 req->error = 1;
1397 return;
1398 }
1399 }
1400
1401 start = end;
1402 } while(start < nsectors);
1403
1404 req->error = update_bitmap(req);
1405}
1406
1407/* Changed in start_io_thread, which is serialized by being called only
1408 * from ubd_init, which is an initcall.
1409 */
1410int kernel_fd = -1;
1411
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001412/* Only changed by the io thread. XXX: currently unused. */
1413static int io_count = 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001414
1415int io_thread(void *arg)
1416{
Jeff Dike2adcec22007-05-06 14:51:37 -07001417 struct io_thread_req *req;
Jeff Dike91acb212005-10-10 23:10:32 -04001418 int n;
1419
1420 ignore_sigwinch_sig();
1421 while(1){
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001422 n = os_read_file(kernel_fd, &req,
Jeff Dike2adcec22007-05-06 14:51:37 -07001423 sizeof(struct io_thread_req *));
1424 if(n != sizeof(struct io_thread_req *)){
Jeff Dike91acb212005-10-10 23:10:32 -04001425 if(n < 0)
1426 printk("io_thread - read failed, fd = %d, "
1427 "err = %d\n", kernel_fd, -n);
1428 else {
1429 printk("io_thread - short read, fd = %d, "
1430 "length = %d\n", kernel_fd, n);
1431 }
1432 continue;
1433 }
1434 io_count++;
Jeff Dike2adcec22007-05-06 14:51:37 -07001435 do_io(req);
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001436 n = os_write_file(kernel_fd, &req,
Jeff Dike2adcec22007-05-06 14:51:37 -07001437 sizeof(struct io_thread_req *));
1438 if(n != sizeof(struct io_thread_req *))
Jeff Dike91acb212005-10-10 23:10:32 -04001439 printk("io_thread - write failed, fd = %d, err = %d\n",
1440 kernel_fd, -n);
1441 }
Jeff Dike91acb212005-10-10 23:10:32 -04001442
Jeff Dike1b57e9c2006-01-06 00:18:49 -08001443 return 0;
1444}