blob: 620f5b70957d55c4001a31fc9b9682a2e4feb687 [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 Bergmann9a181c52010-09-11 18:38:03 +020036#include "linux/mutex.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);
Arnd Bergmann9a181c52010-09-11 18:38:03 +0200103static DEFINE_MUTEX(ubd_mutex); /* replaces BKL, might not be needed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104
Al Viroa625c992008-03-02 09:16:26 -0500105static int ubd_open(struct block_device *bdev, fmode_t mode);
106static int ubd_release(struct gendisk *disk, fmode_t mode);
107static int ubd_ioctl(struct block_device *bdev, fmode_t mode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 unsigned int cmd, unsigned long arg);
Christoph Hellwiga885c8c2006-01-08 01:02:50 -0800109static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110
Paolo 'Blaisorblade' Giarrusso97d88ac2006-10-30 22:07:03 -0800111#define MAX_DEV (16)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112
Alexey Dobriyan83d5cde2009-09-21 17:01:13 -0700113static const struct block_device_operations ubd_blops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114 .owner = THIS_MODULE,
Al Viroa625c992008-03-02 09:16:26 -0500115 .open = ubd_open,
116 .release = ubd_release,
117 .ioctl = ubd_ioctl,
Christoph Hellwiga885c8c2006-01-08 01:02:50 -0800118 .getgeo = ubd_getgeo,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119};
120
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121/* Protected by ubd_lock */
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700122static int fake_major = UBD_MAJOR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123static struct gendisk *ubd_gendisk[MAX_DEV];
124static struct gendisk *fake_gendisk[MAX_DEV];
Jeff Dike6c29256c2006-03-27 01:14:37 -0800125
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126#ifdef CONFIG_BLK_DEV_UBD_SYNC
127#define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 1, .c = 0, \
128 .cl = 1 })
129#else
130#define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 0, .c = 0, \
131 .cl = 1 })
132#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133static struct openflags global_openflags = OPEN_FLAGS;
134
135struct cow {
Paolo 'Blaisorblade' Giarrusso2a9d32f2006-10-30 22:07:04 -0800136 /* backing file name */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 char *file;
Paolo 'Blaisorblade' Giarrusso2a9d32f2006-10-30 22:07:04 -0800138 /* backing file fd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 int fd;
140 unsigned long *bitmap;
141 unsigned long bitmap_len;
142 int bitmap_offset;
Jeff Dikedc764e52007-05-06 14:51:41 -0700143 int data_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144};
145
Jeff Dikea0044bd2007-05-06 14:51:36 -0700146#define MAX_SG 64
147
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148struct ubd {
Jeff Dikea0044bd2007-05-06 14:51:36 -0700149 struct list_head restart;
Paolo 'Blaisorblade' Giarrusso2a9d32f2006-10-30 22:07:04 -0800150 /* name (and fd, below) of the file opened for writing, either the
151 * backing or the cow file. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 char *file;
153 int count;
154 int fd;
155 __u64 size;
156 struct openflags boot_openflags;
157 struct openflags openflags;
Paolo 'Blaisorblade' Giarrusso84e945e2006-10-30 22:07:10 -0800158 unsigned shared:1;
159 unsigned no_cow:1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 struct cow cow;
161 struct platform_device pdev;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800162 struct request_queue *queue;
163 spinlock_t lock;
Jeff Dikea0044bd2007-05-06 14:51:36 -0700164 struct scatterlist sg[MAX_SG];
165 struct request *request;
166 int start_sg, end_sg;
Tejun Heo47526902010-10-15 12:56:21 +0200167 sector_t rq_pos;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168};
169
170#define DEFAULT_COW { \
171 .file = NULL, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700172 .fd = -1, \
173 .bitmap = NULL, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 .bitmap_offset = 0, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700175 .data_offset = 0, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176}
177
178#define DEFAULT_UBD { \
179 .file = NULL, \
180 .count = 0, \
181 .fd = -1, \
182 .size = -1, \
183 .boot_openflags = OPEN_FLAGS, \
184 .openflags = OPEN_FLAGS, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700185 .no_cow = 0, \
Jeff Dike6c29256c2006-03-27 01:14:37 -0800186 .shared = 0, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700187 .cow = DEFAULT_COW, \
Thomas Gleixner22e65002011-01-23 15:21:25 +0100188 .lock = __SPIN_LOCK_UNLOCKED(ubd_devs.lock), \
Jeff Dikea0044bd2007-05-06 14:51:36 -0700189 .request = NULL, \
190 .start_sg = 0, \
191 .end_sg = 0, \
Tejun Heo47526902010-10-15 12:56:21 +0200192 .rq_pos = 0, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193}
194
Jeff Dikeb8831a12007-02-10 01:44:17 -0800195/* Protected by ubd_lock */
WANG Cong5dc62b12008-04-28 02:13:58 -0700196static struct ubd ubd_devs[MAX_DEV] = { [0 ... MAX_DEV - 1] = DEFAULT_UBD };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198/* Only changed by fake_ide_setup which is a setup */
199static int fake_ide = 0;
200static struct proc_dir_entry *proc_ide_root = NULL;
201static struct proc_dir_entry *proc_ide = NULL;
202
203static void make_proc_ide(void)
204{
205 proc_ide_root = proc_mkdir("ide", NULL);
206 proc_ide = proc_mkdir("ide0", proc_ide_root);
207}
208
Alexey Dobriyan6613c5e2009-12-14 18:00:11 -0800209static int fake_ide_media_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210{
Alexey Dobriyan6613c5e2009-12-14 18:00:11 -0800211 seq_puts(m, "disk\n");
212 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213}
214
Alexey Dobriyan6613c5e2009-12-14 18:00:11 -0800215static int fake_ide_media_proc_open(struct inode *inode, struct file *file)
216{
217 return single_open(file, fake_ide_media_proc_show, NULL);
218}
219
220static const struct file_operations fake_ide_media_proc_fops = {
221 .owner = THIS_MODULE,
222 .open = fake_ide_media_proc_open,
223 .read = seq_read,
224 .llseek = seq_lseek,
225 .release = single_release,
226};
227
WANG Congc0a92902008-02-04 22:30:41 -0800228static void make_ide_entries(const char *dev_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229{
230 struct proc_dir_entry *dir, *ent;
231 char name[64];
232
233 if(proc_ide_root == NULL) make_proc_ide();
234
235 dir = proc_mkdir(dev_name, proc_ide);
236 if(!dir) return;
237
Alexey Dobriyan6613c5e2009-12-14 18:00:11 -0800238 ent = proc_create("media", S_IRUGO, dir, &fake_ide_media_proc_fops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 if(!ent) return;
WANG Congc0a92902008-02-04 22:30:41 -0800240 snprintf(name, sizeof(name), "ide0/%s", dev_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 proc_symlink(dev_name, proc_ide_root, name);
242}
243
244static int fake_ide_setup(char *str)
245{
246 fake_ide = 1;
Jeff Dikedc764e52007-05-06 14:51:41 -0700247 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248}
249
250__setup("fake_ide", fake_ide_setup);
251
252__uml_help(fake_ide_setup,
253"fake_ide\n"
254" Create ide0 entries that map onto ubd devices.\n\n"
255);
256
257static int parse_unit(char **ptr)
258{
259 char *str = *ptr, *end;
260 int n = -1;
261
262 if(isdigit(*str)) {
263 n = simple_strtoul(str, &end, 0);
264 if(end == str)
Jeff Dikedc764e52007-05-06 14:51:41 -0700265 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 *ptr = end;
267 }
Paolo 'Blaisorblade' Giarrusso97d88ac2006-10-30 22:07:03 -0800268 else if (('a' <= *str) && (*str <= 'z')) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 n = *str - 'a';
270 str++;
271 *ptr = str;
272 }
Jeff Dikedc764e52007-05-06 14:51:41 -0700273 return n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274}
275
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800276/* If *index_out == -1 at exit, the passed option was a general one;
277 * otherwise, the str pointer is used (and owned) inside ubd_devs array, so it
278 * should not be freed on exit.
279 */
Jeff Dikef28169d2007-02-10 01:43:53 -0800280static int ubd_setup_common(char *str, int *index_out, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800282 struct ubd *ubd_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 struct openflags flags = global_openflags;
284 char *backing_file;
Jeff Dikeb8831a12007-02-10 01:44:17 -0800285 int n, err = 0, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286
287 if(index_out) *index_out = -1;
288 n = *str;
289 if(n == '='){
290 char *end;
291 int major;
292
293 str++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 if(!strcmp(str, "sync")){
295 global_openflags = of_sync(global_openflags);
Jeff Dikeb8831a12007-02-10 01:44:17 -0800296 goto out1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 }
298
Jeff Dikef28169d2007-02-10 01:43:53 -0800299 err = -EINVAL;
Jeff Dikeb8831a12007-02-10 01:44:17 -0800300 major = simple_strtoul(str, &end, 0);
301 if((*end != '\0') || (end == str)){
302 *error_out = "Didn't parse major number";
303 goto out1;
304 }
305
Jeff Dikef28169d2007-02-10 01:43:53 -0800306 mutex_lock(&ubd_lock);
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700307 if (fake_major != UBD_MAJOR) {
Jeff Dikef28169d2007-02-10 01:43:53 -0800308 *error_out = "Can't assign a fake major twice";
309 goto out1;
310 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800311
Jeff Dikef28169d2007-02-10 01:43:53 -0800312 fake_major = major;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313
314 printk(KERN_INFO "Setting extra ubd major number to %d\n",
315 major);
Jeff Dikef28169d2007-02-10 01:43:53 -0800316 err = 0;
317 out1:
318 mutex_unlock(&ubd_lock);
319 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 }
321
322 n = parse_unit(&str);
323 if(n < 0){
Jeff Dikef28169d2007-02-10 01:43:53 -0800324 *error_out = "Couldn't parse device number";
325 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 }
327 if(n >= MAX_DEV){
Jeff Dikef28169d2007-02-10 01:43:53 -0800328 *error_out = "Device number out of range";
329 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 }
331
Jeff Dikef28169d2007-02-10 01:43:53 -0800332 err = -EBUSY;
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800333 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800335 ubd_dev = &ubd_devs[n];
336 if(ubd_dev->file != NULL){
Jeff Dikef28169d2007-02-10 01:43:53 -0800337 *error_out = "Device is already configured";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 goto out;
339 }
340
341 if (index_out)
342 *index_out = n;
343
Jeff Dikef28169d2007-02-10 01:43:53 -0800344 err = -EINVAL;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800345 for (i = 0; i < sizeof("rscd="); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 switch (*str) {
347 case 'r':
348 flags.w = 0;
349 break;
350 case 's':
351 flags.s = 1;
352 break;
353 case 'd':
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800354 ubd_dev->no_cow = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 break;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800356 case 'c':
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800357 ubd_dev->shared = 1;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800358 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 case '=':
360 str++;
361 goto break_loop;
362 default:
Jeff Dikef28169d2007-02-10 01:43:53 -0800363 *error_out = "Expected '=' or flag letter "
364 "(r, s, c, or d)";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 goto out;
366 }
367 str++;
368 }
369
Jeff Dikef28169d2007-02-10 01:43:53 -0800370 if (*str == '=')
371 *error_out = "Too many flags specified";
372 else
373 *error_out = "Missing '='";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 goto out;
375
376break_loop:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 backing_file = strchr(str, ',');
378
Jeff Dikef28169d2007-02-10 01:43:53 -0800379 if (backing_file == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 backing_file = strchr(str, ':');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381
Jeff Dikef28169d2007-02-10 01:43:53 -0800382 if(backing_file != NULL){
383 if(ubd_dev->no_cow){
384 *error_out = "Can't specify both 'd' and a cow file";
385 goto out;
386 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 else {
388 *backing_file = '\0';
389 backing_file++;
390 }
391 }
Jeff Dikef28169d2007-02-10 01:43:53 -0800392 err = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800393 ubd_dev->file = str;
394 ubd_dev->cow.file = backing_file;
395 ubd_dev->boot_openflags = flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800397 mutex_unlock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -0800398 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399}
400
401static int ubd_setup(char *str)
402{
Jeff Dikef28169d2007-02-10 01:43:53 -0800403 char *error;
404 int err;
405
406 err = ubd_setup_common(str, NULL, &error);
407 if(err)
408 printk(KERN_ERR "Failed to initialize device with \"%s\" : "
409 "%s\n", str, error);
410 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411}
412
413__setup("ubd", ubd_setup);
414__uml_help(ubd_setup,
415"ubd<n><flags>=<filename>[(:|,)<filename2>]\n"
416" This is used to associate a device with a file in the underlying\n"
417" filesystem. When specifying two filenames, the first one is the\n"
418" COW name and the second is the backing file name. As separator you can\n"
419" use either a ':' or a ',': the first one allows writing things like;\n"
420" ubd0=~/Uml/root_cow:~/Uml/root_backing_file\n"
421" while with a ',' the shell would not expand the 2nd '~'.\n"
Jeff Dikef28169d2007-02-10 01:43:53 -0800422" When using only one filename, UML will detect whether to treat it like\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423" a COW file or a backing file. To override this detection, add the 'd'\n"
424" flag:\n"
425" ubd0d=BackingFile\n"
426" Usually, there is a filesystem in the file, but \n"
427" that's not required. Swap devices containing swap files can be\n"
428" specified like this. Also, a file which doesn't contain a\n"
429" filesystem can have its contents read in the virtual \n"
430" machine by running 'dd' on the device. <n> must be in the range\n"
431" 0 to 7. Appending an 'r' to the number will cause that device\n"
432" to be mounted read-only. For example ubd1r=./ext_fs. Appending\n"
Jeff Dike20ede452008-02-04 22:30:37 -0800433" an 's' will cause data to be written to disk on the host immediately.\n"
434" 'c' will cause the device to be treated as being shared between multiple\n"
435" UMLs and file locking will be turned off - this is appropriate for a\n"
436" cluster filesystem and inappropriate at almost all other times.\n\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437);
438
Jeff Dike8299ca52008-02-04 22:30:48 -0800439static int udb_setup(char *str)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440{
441 printk("udb%s specified on command line is almost certainly a ubd -> "
442 "udb TYPO\n", str);
Jeff Dikedc764e52007-05-06 14:51:41 -0700443 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444}
445
446__setup("udb", udb_setup);
447__uml_help(udb_setup,
448"udb\n"
Jeff Dike0894e272005-05-28 15:51:55 -0700449" This option is here solely to catch ubd -> udb typos, which can be\n"
450" to impossible to catch visually unless you specifically look for\n"
451" them. The only result of any option starting with 'udb' is an error\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452" in the boot output.\n\n"
453);
454
Jens Axboe165125e2007-07-24 09:28:11 +0200455static void do_ubd_request(struct request_queue * q);
Jeff Dike91acb212005-10-10 23:10:32 -0400456
457/* Only changed by ubd_init, which is an initcall. */
WANG Cong5dc62b12008-04-28 02:13:58 -0700458static int thread_fd = -1;
Jeff Dikea0044bd2007-05-06 14:51:36 -0700459static LIST_HEAD(restart);
460
Paolo 'Blaisorblade' Giarrusso2fe30a32006-10-30 22:07:09 -0800461/* XXX - move this inside ubd_intr. */
Jeff Dike62f96cb2007-02-10 01:44:16 -0800462/* Called without dev->lock held, and only in interrupt context. */
Jeff Dike91acb212005-10-10 23:10:32 -0400463static void ubd_handler(void)
464{
Jeff Dike2adcec22007-05-06 14:51:37 -0700465 struct io_thread_req *req;
Jeff Dikea0044bd2007-05-06 14:51:36 -0700466 struct ubd *ubd;
467 struct list_head *list, *next_ele;
468 unsigned long flags;
Jeff Dike91acb212005-10-10 23:10:32 -0400469 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470
Jeff Dikea0044bd2007-05-06 14:51:36 -0700471 while(1){
Jeff Dikea6ea4cc2007-05-06 14:51:43 -0700472 n = os_read_file(thread_fd, &req,
473 sizeof(struct io_thread_req *));
Jeff Dikea0044bd2007-05-06 14:51:36 -0700474 if(n != sizeof(req)){
475 if(n == -EAGAIN)
476 break;
477 printk(KERN_ERR "spurious interrupt in ubd_handler, "
478 "err = %d\n", -n);
479 return;
480 }
481
Tejun Heo4d6c84d2009-04-28 13:06:09 +0900482 blk_end_request(req->req, 0, req->length);
Jeff Dike2adcec22007-05-06 14:51:37 -0700483 kfree(req);
Jeff Dike91acb212005-10-10 23:10:32 -0400484 }
Jeff Dike62f96cb2007-02-10 01:44:16 -0800485 reactivate_fd(thread_fd, UBD_IRQ);
Jeff Dikea0044bd2007-05-06 14:51:36 -0700486
487 list_for_each_safe(list, next_ele, &restart){
488 ubd = container_of(list, struct ubd, restart);
489 list_del_init(&ubd->restart);
490 spin_lock_irqsave(&ubd->lock, flags);
491 do_ubd_request(ubd->queue);
492 spin_unlock_irqrestore(&ubd->lock, flags);
493 }
Jeff Dike91acb212005-10-10 23:10:32 -0400494}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495
Al Viro7bea96f2006-10-08 22:49:34 +0100496static irqreturn_t ubd_intr(int irq, void *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497{
Jeff Dike91acb212005-10-10 23:10:32 -0400498 ubd_handler();
Jeff Dikedc764e52007-05-06 14:51:41 -0700499 return IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500}
501
Jeff Dike91acb212005-10-10 23:10:32 -0400502/* Only changed by ubd_init, which is an initcall. */
503static int io_pid = -1;
504
WANG Cong5dc62b12008-04-28 02:13:58 -0700505static void kill_io_thread(void)
Jeff Dike91acb212005-10-10 23:10:32 -0400506{
Jeff Dike6c29256c2006-03-27 01:14:37 -0800507 if(io_pid != -1)
Jeff Dike91acb212005-10-10 23:10:32 -0400508 os_kill_process(io_pid, 1);
509}
510
511__uml_exitcall(kill_io_thread);
512
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800513static inline int ubd_file_size(struct ubd *ubd_dev, __u64 *size_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514{
515 char *file;
516
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800517 file = ubd_dev->cow.file ? ubd_dev->cow.file : ubd_dev->file;
Jeff Dikedc764e52007-05-06 14:51:41 -0700518 return os_file_size(file, size_out);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519}
520
WANG Cong5dc62b12008-04-28 02:13:58 -0700521static int read_cow_bitmap(int fd, void *buf, int offset, int len)
522{
523 int err;
524
525 err = os_seek_file(fd, offset);
526 if (err < 0)
527 return err;
528
529 err = os_read_file(fd, buf, len);
530 if (err < 0)
531 return err;
532
533 return 0;
534}
535
536static int backing_file_mismatch(char *file, __u64 size, time_t mtime)
537{
538 unsigned long modtime;
539 unsigned long long actual;
540 int err;
541
542 err = os_file_modtime(file, &modtime);
543 if (err < 0) {
544 printk(KERN_ERR "Failed to get modification time of backing "
545 "file \"%s\", err = %d\n", file, -err);
546 return err;
547 }
548
549 err = os_file_size(file, &actual);
550 if (err < 0) {
551 printk(KERN_ERR "Failed to get size of backing file \"%s\", "
552 "err = %d\n", file, -err);
553 return err;
554 }
555
556 if (actual != size) {
557 /*__u64 can be a long on AMD64 and with %lu GCC complains; so
558 * the typecast.*/
559 printk(KERN_ERR "Size mismatch (%llu vs %llu) of COW header "
560 "vs backing file\n", (unsigned long long) size, actual);
561 return -EINVAL;
562 }
563 if (modtime != mtime) {
564 printk(KERN_ERR "mtime mismatch (%ld vs %ld) of COW header vs "
565 "backing file\n", mtime, modtime);
566 return -EINVAL;
567 }
568 return 0;
569}
570
571static int path_requires_switch(char *from_cmdline, char *from_cow, char *cow)
572{
573 struct uml_stat buf1, buf2;
574 int err;
575
576 if (from_cmdline == NULL)
577 return 0;
578 if (!strcmp(from_cmdline, from_cow))
579 return 0;
580
581 err = os_stat_file(from_cmdline, &buf1);
582 if (err < 0) {
583 printk(KERN_ERR "Couldn't stat '%s', err = %d\n", from_cmdline,
584 -err);
585 return 0;
586 }
587 err = os_stat_file(from_cow, &buf2);
588 if (err < 0) {
589 printk(KERN_ERR "Couldn't stat '%s', err = %d\n", from_cow,
590 -err);
591 return 1;
592 }
593 if ((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino))
594 return 0;
595
596 printk(KERN_ERR "Backing file mismatch - \"%s\" requested, "
597 "\"%s\" specified in COW header of \"%s\"\n",
598 from_cmdline, from_cow, cow);
599 return 1;
600}
601
602static int open_ubd_file(char *file, struct openflags *openflags, int shared,
603 char **backing_file_out, int *bitmap_offset_out,
604 unsigned long *bitmap_len_out, int *data_offset_out,
605 int *create_cow_out)
606{
607 time_t mtime;
608 unsigned long long size;
609 __u32 version, align;
610 char *backing_file;
611 int fd, err, sectorsize, asked_switch, mode = 0644;
612
613 fd = os_open_file(file, *openflags, mode);
614 if (fd < 0) {
615 if ((fd == -ENOENT) && (create_cow_out != NULL))
616 *create_cow_out = 1;
617 if (!openflags->w ||
618 ((fd != -EROFS) && (fd != -EACCES)))
619 return fd;
620 openflags->w = 0;
621 fd = os_open_file(file, *openflags, mode);
622 if (fd < 0)
623 return fd;
624 }
625
626 if (shared)
627 printk(KERN_INFO "Not locking \"%s\" on the host\n", file);
628 else {
629 err = os_lock_file(fd, openflags->w);
630 if (err < 0) {
631 printk(KERN_ERR "Failed to lock '%s', err = %d\n",
632 file, -err);
633 goto out_close;
634 }
635 }
636
637 /* Successful return case! */
638 if (backing_file_out == NULL)
639 return fd;
640
641 err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime,
642 &size, &sectorsize, &align, bitmap_offset_out);
643 if (err && (*backing_file_out != NULL)) {
644 printk(KERN_ERR "Failed to read COW header from COW file "
645 "\"%s\", errno = %d\n", file, -err);
646 goto out_close;
647 }
648 if (err)
649 return fd;
650
651 asked_switch = path_requires_switch(*backing_file_out, backing_file,
652 file);
653
654 /* Allow switching only if no mismatch. */
655 if (asked_switch && !backing_file_mismatch(*backing_file_out, size,
656 mtime)) {
657 printk(KERN_ERR "Switching backing file to '%s'\n",
658 *backing_file_out);
659 err = write_cow_header(file, fd, *backing_file_out,
660 sectorsize, align, &size);
661 if (err) {
662 printk(KERN_ERR "Switch failed, errno = %d\n", -err);
663 goto out_close;
664 }
665 } else {
666 *backing_file_out = backing_file;
667 err = backing_file_mismatch(*backing_file_out, size, mtime);
668 if (err)
669 goto out_close;
670 }
671
672 cow_sizes(version, size, sectorsize, align, *bitmap_offset_out,
673 bitmap_len_out, data_offset_out);
674
675 return fd;
676 out_close:
677 os_close_file(fd);
678 return err;
679}
680
681static int create_cow_file(char *cow_file, char *backing_file,
682 struct openflags flags,
683 int sectorsize, int alignment, int *bitmap_offset_out,
684 unsigned long *bitmap_len_out, int *data_offset_out)
685{
686 int err, fd;
687
688 flags.c = 1;
689 fd = open_ubd_file(cow_file, &flags, 0, NULL, NULL, NULL, NULL, NULL);
690 if (fd < 0) {
691 err = fd;
692 printk(KERN_ERR "Open of COW file '%s' failed, errno = %d\n",
693 cow_file, -err);
694 goto out;
695 }
696
697 err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment,
698 bitmap_offset_out, bitmap_len_out,
699 data_offset_out);
700 if (!err)
701 return fd;
702 os_close_file(fd);
703 out:
704 return err;
705}
706
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800707static void ubd_close_dev(struct ubd *ubd_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800709 os_close_file(ubd_dev->fd);
710 if(ubd_dev->cow.file == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 return;
712
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800713 os_close_file(ubd_dev->cow.fd);
714 vfree(ubd_dev->cow.bitmap);
715 ubd_dev->cow.bitmap = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716}
717
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800718static int ubd_open_dev(struct ubd *ubd_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719{
720 struct openflags flags;
721 char **back_ptr;
722 int err, create_cow, *create_ptr;
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800723 int fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800725 ubd_dev->openflags = ubd_dev->boot_openflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 create_cow = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800727 create_ptr = (ubd_dev->cow.file != NULL) ? &create_cow : NULL;
728 back_ptr = ubd_dev->no_cow ? NULL : &ubd_dev->cow.file;
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800729
730 fd = open_ubd_file(ubd_dev->file, &ubd_dev->openflags, ubd_dev->shared,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800731 back_ptr, &ubd_dev->cow.bitmap_offset,
732 &ubd_dev->cow.bitmap_len, &ubd_dev->cow.data_offset,
Jeff Dike6c29256c2006-03-27 01:14:37 -0800733 create_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800735 if((fd == -ENOENT) && create_cow){
736 fd = create_cow_file(ubd_dev->file, ubd_dev->cow.file,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800737 ubd_dev->openflags, 1 << 9, PAGE_SIZE,
738 &ubd_dev->cow.bitmap_offset,
739 &ubd_dev->cow.bitmap_len,
740 &ubd_dev->cow.data_offset);
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800741 if(fd >= 0){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 printk(KERN_INFO "Creating \"%s\" as COW file for "
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800743 "\"%s\"\n", ubd_dev->file, ubd_dev->cow.file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 }
745 }
746
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800747 if(fd < 0){
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800748 printk("Failed to open '%s', errno = %d\n", ubd_dev->file,
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800749 -fd);
750 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 }
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800752 ubd_dev->fd = fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800754 if(ubd_dev->cow.file != NULL){
Martin K. Petersen086fa5f2010-02-26 00:20:38 -0500755 blk_queue_max_hw_sectors(ubd_dev->queue, 8 * sizeof(long));
Jeff Dikef4768ff2007-08-22 14:01:53 -0700756
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 err = -ENOMEM;
Jesper Juhlda2486b2007-10-16 01:27:19 -0700758 ubd_dev->cow.bitmap = vmalloc(ubd_dev->cow.bitmap_len);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800759 if(ubd_dev->cow.bitmap == NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 printk(KERN_ERR "Failed to vmalloc COW bitmap\n");
761 goto error;
762 }
763 flush_tlb_kernel_vm();
764
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800765 err = read_cow_bitmap(ubd_dev->fd, ubd_dev->cow.bitmap,
766 ubd_dev->cow.bitmap_offset,
767 ubd_dev->cow.bitmap_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 if(err < 0)
769 goto error;
770
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800771 flags = ubd_dev->openflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 flags.w = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800773 err = open_ubd_file(ubd_dev->cow.file, &flags, ubd_dev->shared, NULL,
Jeff Dike6c29256c2006-03-27 01:14:37 -0800774 NULL, NULL, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 if(err < 0) goto error;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800776 ubd_dev->cow.fd = err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 }
Jeff Dikedc764e52007-05-06 14:51:41 -0700778 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 error:
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800780 os_close_file(ubd_dev->fd);
Jeff Dikedc764e52007-05-06 14:51:41 -0700781 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782}
783
Jeff Dike2e3f5252007-05-06 14:51:29 -0700784static void ubd_device_release(struct device *dev)
785{
Greg Kroah-Hartman8691b972009-05-04 12:40:54 -0700786 struct ubd *ubd_dev = dev_get_drvdata(dev);
Jeff Dike2e3f5252007-05-06 14:51:29 -0700787
788 blk_cleanup_queue(ubd_dev->queue);
789 *ubd_dev = ((struct ubd) DEFAULT_UBD);
790}
791
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800792static int ubd_disk_register(int major, u64 size, int unit,
Jeff Dikeb8831a12007-02-10 01:44:17 -0800793 struct gendisk **disk_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794{
795 struct gendisk *disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796
797 disk = alloc_disk(1 << UBD_SHIFT);
798 if(disk == NULL)
Jeff Dikedc764e52007-05-06 14:51:41 -0700799 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800
801 disk->major = major;
802 disk->first_minor = unit << UBD_SHIFT;
803 disk->fops = &ubd_blops;
804 set_capacity(disk, size / 512);
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700805 if (major == UBD_MAJOR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 sprintf(disk->disk_name, "ubd%c", 'a' + unit);
Greg Kroah-Hartmance7b0f42005-06-20 21:15:16 -0700807 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 sprintf(disk->disk_name, "ubd_fake%d", unit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809
810 /* sysfs register (not for ide fake devices) */
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700811 if (major == UBD_MAJOR) {
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800812 ubd_devs[unit].pdev.id = unit;
813 ubd_devs[unit].pdev.name = DRIVER_NAME;
Jeff Dike2e3f5252007-05-06 14:51:29 -0700814 ubd_devs[unit].pdev.dev.release = ubd_device_release;
Greg Kroah-Hartman8691b972009-05-04 12:40:54 -0700815 dev_set_drvdata(&ubd_devs[unit].pdev.dev, &ubd_devs[unit]);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800816 platform_device_register(&ubd_devs[unit].pdev);
817 disk->driverfs_dev = &ubd_devs[unit].pdev.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 }
819
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800820 disk->private_data = &ubd_devs[unit];
Jeff Dike62f96cb2007-02-10 01:44:16 -0800821 disk->queue = ubd_devs[unit].queue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 add_disk(disk);
823
824 *disk_out = disk;
825 return 0;
826}
827
828#define ROUND_BLOCK(n) ((n + ((1 << 9) - 1)) & (-1 << 9))
829
Jeff Dikef28169d2007-02-10 01:43:53 -0800830static int ubd_add(int n, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800832 struct ubd *ubd_dev = &ubd_devs[n];
Jeff Dikef28169d2007-02-10 01:43:53 -0800833 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800835 if(ubd_dev->file == NULL)
Jeff Dikeec7cf782005-09-03 15:57:29 -0700836 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800838 err = ubd_file_size(ubd_dev, &ubd_dev->size);
Jeff Dikef28169d2007-02-10 01:43:53 -0800839 if(err < 0){
840 *error_out = "Couldn't determine size of device's file";
Jeff Dike80c13742006-09-29 01:58:51 -0700841 goto out;
Jeff Dikef28169d2007-02-10 01:43:53 -0800842 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800844 ubd_dev->size = ROUND_BLOCK(ubd_dev->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845
Jeff Dikea0044bd2007-05-06 14:51:36 -0700846 INIT_LIST_HEAD(&ubd_dev->restart);
WANG Cong4f40c052007-11-05 14:50:59 -0800847 sg_init_table(ubd_dev->sg, MAX_SG);
Jeff Dikea0044bd2007-05-06 14:51:36 -0700848
Jeff Dike62f96cb2007-02-10 01:44:16 -0800849 err = -ENOMEM;
850 ubd_dev->queue = blk_init_queue(do_ubd_request, &ubd_dev->lock);
851 if (ubd_dev->queue == NULL) {
852 *error_out = "Failed to initialize device queue";
Jeff Dike80c13742006-09-29 01:58:51 -0700853 goto out;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800854 }
855 ubd_dev->queue->queuedata = ubd_dev;
856
Martin K. Petersen8a783622010-02-26 00:20:39 -0500857 blk_queue_max_segments(ubd_dev->queue, MAX_SG);
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700858 err = ubd_disk_register(UBD_MAJOR, ubd_dev->size, n, &ubd_gendisk[n]);
Jeff Dike62f96cb2007-02-10 01:44:16 -0800859 if(err){
860 *error_out = "Failed to register device";
861 goto out_cleanup;
862 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800863
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700864 if (fake_major != UBD_MAJOR)
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800865 ubd_disk_register(fake_major, ubd_dev->size, n,
Jeff Dike62f96cb2007-02-10 01:44:16 -0800866 &fake_gendisk[n]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867
Jeff Dike83380cc2008-02-04 22:31:18 -0800868 /*
869 * Perhaps this should also be under the "if (fake_major)" above
870 * using the fake_disk->disk_name
871 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 if (fake_ide)
873 make_ide_entries(ubd_gendisk[n]->disk_name);
874
Jeff Dikeec7cf782005-09-03 15:57:29 -0700875 err = 0;
Jeff Dikeec7cf782005-09-03 15:57:29 -0700876out:
877 return err;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800878
879out_cleanup:
880 blk_cleanup_queue(ubd_dev->queue);
881 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882}
883
Jeff Dikef28169d2007-02-10 01:43:53 -0800884static int ubd_config(char *str, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885{
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800886 int n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887
Jeff Dikef28169d2007-02-10 01:43:53 -0800888 /* This string is possibly broken up and stored, so it's only
889 * freed if ubd_setup_common fails, or if only general options
890 * were set.
891 */
Jeff Dike970d6e32006-01-06 00:18:48 -0800892 str = kstrdup(str, GFP_KERNEL);
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800893 if (str == NULL) {
Jeff Dikef28169d2007-02-10 01:43:53 -0800894 *error_out = "Failed to allocate memory";
895 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 }
Jeff Dikef28169d2007-02-10 01:43:53 -0800897
898 ret = ubd_setup_common(str, &n, error_out);
899 if (ret)
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800900 goto err_free;
Jeff Dikef28169d2007-02-10 01:43:53 -0800901
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800902 if (n == -1) {
903 ret = 0;
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800904 goto err_free;
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800905 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906
Jeff Dikedc764e52007-05-06 14:51:41 -0700907 mutex_lock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -0800908 ret = ubd_add(n, error_out);
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800909 if (ret)
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800910 ubd_devs[n].file = NULL;
Jeff Dikedc764e52007-05-06 14:51:41 -0700911 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800913out:
Jeff Dikedc764e52007-05-06 14:51:41 -0700914 return ret;
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800915
916err_free:
917 kfree(str);
918 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919}
920
921static int ubd_get_config(char *name, char *str, int size, char **error_out)
922{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800923 struct ubd *ubd_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 int n, len = 0;
925
926 n = parse_unit(&name);
927 if((n >= MAX_DEV) || (n < 0)){
928 *error_out = "ubd_get_config : device number out of range";
Jeff Dikedc764e52007-05-06 14:51:41 -0700929 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 }
931
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800932 ubd_dev = &ubd_devs[n];
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800933 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800935 if(ubd_dev->file == NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 CONFIG_CHUNK(str, size, len, "", 1);
937 goto out;
938 }
939
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800940 CONFIG_CHUNK(str, size, len, ubd_dev->file, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800942 if(ubd_dev->cow.file != NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 CONFIG_CHUNK(str, size, len, ",", 0);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800944 CONFIG_CHUNK(str, size, len, ubd_dev->cow.file, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 }
946 else CONFIG_CHUNK(str, size, len, "", 1);
947
948 out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800949 mutex_unlock(&ubd_lock);
Jeff Dikedc764e52007-05-06 14:51:41 -0700950 return len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951}
952
Jeff Dike29d56cf2005-06-25 14:55:25 -0700953static int ubd_id(char **str, int *start_out, int *end_out)
954{
Jeff Dikedc764e52007-05-06 14:51:41 -0700955 int n;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700956
957 n = parse_unit(str);
Jeff Dikedc764e52007-05-06 14:51:41 -0700958 *start_out = 0;
959 *end_out = MAX_DEV - 1;
960 return n;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700961}
962
Jeff Dikef28169d2007-02-10 01:43:53 -0800963static int ubd_remove(int n, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964{
Jeff Dike2e3f5252007-05-06 14:51:29 -0700965 struct gendisk *disk = ubd_gendisk[n];
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800966 struct ubd *ubd_dev;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700967 int err = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800969 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800971 ubd_dev = &ubd_devs[n];
Jeff Dike29d56cf2005-06-25 14:55:25 -0700972
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800973 if(ubd_dev->file == NULL)
Jeff Dike29d56cf2005-06-25 14:55:25 -0700974 goto out;
975
976 /* you cannot remove a open disk */
977 err = -EBUSY;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800978 if(ubd_dev->count > 0)
Jeff Dike29d56cf2005-06-25 14:55:25 -0700979 goto out;
980
Jeff Dikedc764e52007-05-06 14:51:41 -0700981 ubd_gendisk[n] = NULL;
Jeff Dikeb47d2de2007-05-06 14:51:01 -0700982 if(disk != NULL){
983 del_gendisk(disk);
984 put_disk(disk);
985 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986
987 if(fake_gendisk[n] != NULL){
988 del_gendisk(fake_gendisk[n]);
989 put_disk(fake_gendisk[n]);
990 fake_gendisk[n] = NULL;
991 }
992
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 err = 0;
Jeff Dike2e3f5252007-05-06 14:51:29 -0700994 platform_device_unregister(&ubd_dev->pdev);
Jeff Dike29d56cf2005-06-25 14:55:25 -0700995out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800996 mutex_unlock(&ubd_lock);
Jeff Dike29d56cf2005-06-25 14:55:25 -0700997 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998}
999
Jeff Dikef28169d2007-02-10 01:43:53 -08001000/* All these are called by mconsole in process context and without
Jeff Dikeb8831a12007-02-10 01:44:17 -08001001 * ubd-specific locks. The structure itself is const except for .list.
Jeff Dikef28169d2007-02-10 01:43:53 -08001002 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003static struct mc_device ubd_mc = {
Jeff Dike84f48d42007-02-10 01:44:01 -08001004 .list = LIST_HEAD_INIT(ubd_mc.list),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 .name = "ubd",
1006 .config = ubd_config,
Jeff Dikedc764e52007-05-06 14:51:41 -07001007 .get_config = ubd_get_config,
Jeff Dike29d56cf2005-06-25 14:55:25 -07001008 .id = ubd_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 .remove = ubd_remove,
1010};
1011
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001012static int __init ubd_mc_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013{
1014 mconsole_register_dev(&ubd_mc);
1015 return 0;
1016}
1017
1018__initcall(ubd_mc_init);
1019
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001020static int __init ubd0_init(void)
1021{
1022 struct ubd *ubd_dev = &ubd_devs[0];
1023
Jeff Dikeb8831a12007-02-10 01:44:17 -08001024 mutex_lock(&ubd_lock);
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001025 if(ubd_dev->file == NULL)
1026 ubd_dev->file = "root_fs";
Jeff Dikeb8831a12007-02-10 01:44:17 -08001027 mutex_unlock(&ubd_lock);
1028
Jeff Dikedc764e52007-05-06 14:51:41 -07001029 return 0;
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001030}
1031
1032__initcall(ubd0_init);
1033
Jeff Dikeb8831a12007-02-10 01:44:17 -08001034/* Used in ubd_init, which is an initcall */
Russell King3ae5eae2005-11-09 22:32:44 +00001035static struct platform_driver ubd_driver = {
1036 .driver = {
1037 .name = DRIVER_NAME,
1038 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039};
1040
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001041static int __init ubd_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042{
Jeff Dikef28169d2007-02-10 01:43:53 -08001043 char *error;
1044 int i, err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045
Christoph Hellwig792dd4f2009-03-31 15:23:39 -07001046 if (register_blkdev(UBD_MAJOR, "ubd"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 return -1;
1048
Christoph Hellwig792dd4f2009-03-31 15:23:39 -07001049 if (fake_major != UBD_MAJOR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 char name[sizeof("ubd_nnn\0")];
1051
1052 snprintf(name, sizeof(name), "ubd_%d", fake_major);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 if (register_blkdev(fake_major, "ubd"))
1054 return -1;
1055 }
Russell King3ae5eae2005-11-09 22:32:44 +00001056 platform_driver_register(&ubd_driver);
Jeff Dikedc764e52007-05-06 14:51:41 -07001057 mutex_lock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -08001058 for (i = 0; i < MAX_DEV; i++){
1059 err = ubd_add(i, &error);
1060 if(err)
1061 printk(KERN_ERR "Failed to initialize ubd device %d :"
1062 "%s\n", i, error);
1063 }
Jeff Dikedc764e52007-05-06 14:51:41 -07001064 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 return 0;
1066}
1067
1068late_initcall(ubd_init);
1069
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001070static int __init ubd_driver_init(void){
Jeff Dike91acb212005-10-10 23:10:32 -04001071 unsigned long stack;
1072 int err;
1073
1074 /* Set by CONFIG_BLK_DEV_UBD_SYNC or ubd=sync.*/
1075 if(global_openflags.s){
1076 printk(KERN_INFO "ubd: Synchronous mode\n");
1077 /* Letting ubd=sync be like using ubd#s= instead of ubd#= is
1078 * enough. So use anyway the io thread. */
1079 }
1080 stack = alloc_stack(0, 0);
Jeff Dike6c29256c2006-03-27 01:14:37 -08001081 io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *),
Jeff Dike91acb212005-10-10 23:10:32 -04001082 &thread_fd);
1083 if(io_pid < 0){
Jeff Dike6c29256c2006-03-27 01:14:37 -08001084 printk(KERN_ERR
Jeff Dike91acb212005-10-10 23:10:32 -04001085 "ubd : Failed to start I/O thread (errno = %d) - "
1086 "falling back to synchronous I/O\n", -io_pid);
1087 io_pid = -1;
Jeff Dikedc764e52007-05-06 14:51:41 -07001088 return 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001089 }
Jeff Dike6c29256c2006-03-27 01:14:37 -08001090 err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001091 IRQF_DISABLED, "ubd", ubd_devs);
Jeff Dike91acb212005-10-10 23:10:32 -04001092 if(err != 0)
1093 printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err);
Jeff Dikef4c57a72006-03-31 02:30:10 -08001094 return 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001095}
1096
1097device_initcall(ubd_driver_init);
1098
Al Viroa625c992008-03-02 09:16:26 -05001099static int ubd_open(struct block_device *bdev, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100{
Al Viroa625c992008-03-02 09:16:26 -05001101 struct gendisk *disk = bdev->bd_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001102 struct ubd *ubd_dev = disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 int err = 0;
1104
Arnd Bergmann9a181c52010-09-11 18:38:03 +02001105 mutex_lock(&ubd_mutex);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001106 if(ubd_dev->count == 0){
1107 err = ubd_open_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 if(err){
1109 printk(KERN_ERR "%s: Can't open \"%s\": errno = %d\n",
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001110 disk->disk_name, ubd_dev->file, -err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 goto out;
1112 }
1113 }
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001114 ubd_dev->count++;
1115 set_disk_ro(disk, !ubd_dev->openflags.w);
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -07001116
1117 /* This should no more be needed. And it didn't work anyway to exclude
1118 * read-write remounting of filesystems.*/
Al Viroa625c992008-03-02 09:16:26 -05001119 /*if((mode & FMODE_WRITE) && !ubd_dev->openflags.w){
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -08001120 if(--ubd_dev->count == 0) ubd_close_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 err = -EROFS;
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -07001122 }*/
Arnd Bergmann6e9624b2010-08-07 18:25:34 +02001123out:
Arnd Bergmann9a181c52010-09-11 18:38:03 +02001124 mutex_unlock(&ubd_mutex);
Jeff Dikedc764e52007-05-06 14:51:41 -07001125 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126}
1127
Al Viroa625c992008-03-02 09:16:26 -05001128static int ubd_release(struct gendisk *disk, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001130 struct ubd *ubd_dev = disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131
Arnd Bergmann9a181c52010-09-11 18:38:03 +02001132 mutex_lock(&ubd_mutex);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001133 if(--ubd_dev->count == 0)
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -08001134 ubd_close_dev(ubd_dev);
Arnd Bergmann9a181c52010-09-11 18:38:03 +02001135 mutex_unlock(&ubd_mutex);
Jeff Dikedc764e52007-05-06 14:51:41 -07001136 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137}
1138
Jeff Dike91acb212005-10-10 23:10:32 -04001139static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask,
1140 __u64 *cow_offset, unsigned long *bitmap,
1141 __u64 bitmap_offset, unsigned long *bitmap_words,
1142 __u64 bitmap_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143{
Jeff Dike91acb212005-10-10 23:10:32 -04001144 __u64 sector = io_offset >> 9;
1145 int i, update_bitmap = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146
Jeff Dike91acb212005-10-10 23:10:32 -04001147 for(i = 0; i < length >> 9; i++){
1148 if(cow_mask != NULL)
1149 ubd_set_bit(i, (unsigned char *) cow_mask);
1150 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
1151 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152
Jeff Dike91acb212005-10-10 23:10:32 -04001153 update_bitmap = 1;
1154 ubd_set_bit(sector + i, (unsigned char *) bitmap);
1155 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156
Jeff Dike91acb212005-10-10 23:10:32 -04001157 if(!update_bitmap)
1158 return;
1159
1160 *cow_offset = sector / (sizeof(unsigned long) * 8);
1161
1162 /* This takes care of the case where we're exactly at the end of the
1163 * device, and *cow_offset + 1 is off the end. So, just back it up
1164 * by one word. Thanks to Lynn Kerby for the fix and James McMechan
1165 * for the original diagnosis.
1166 */
Jiri Olsa6d074242008-05-12 14:01:56 -07001167 if (*cow_offset == (DIV_ROUND_UP(bitmap_len,
1168 sizeof(unsigned long)) - 1))
Jeff Dike91acb212005-10-10 23:10:32 -04001169 (*cow_offset)--;
1170
1171 bitmap_words[0] = bitmap[*cow_offset];
1172 bitmap_words[1] = bitmap[*cow_offset + 1];
1173
1174 *cow_offset *= sizeof(unsigned long);
1175 *cow_offset += bitmap_offset;
1176}
1177
1178static void cowify_req(struct io_thread_req *req, unsigned long *bitmap,
1179 __u64 bitmap_offset, __u64 bitmap_len)
1180{
1181 __u64 sector = req->offset >> 9;
1182 int i;
1183
1184 if(req->length > (sizeof(req->sector_mask) * 8) << 9)
1185 panic("Operation too long");
1186
1187 if(req->op == UBD_READ) {
1188 for(i = 0; i < req->length >> 9; i++){
1189 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
Jeff Dike6c29256c2006-03-27 01:14:37 -08001190 ubd_set_bit(i, (unsigned char *)
Jeff Dike91acb212005-10-10 23:10:32 -04001191 &req->sector_mask);
Jeff Dikedc764e52007-05-06 14:51:41 -07001192 }
Jeff Dike91acb212005-10-10 23:10:32 -04001193 }
1194 else cowify_bitmap(req->offset, req->length, &req->sector_mask,
1195 &req->cow_offset, bitmap, bitmap_offset,
1196 req->bitmap_words, bitmap_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197}
1198
Jeff Dike62f96cb2007-02-10 01:44:16 -08001199/* Called with dev->lock held */
Jeff Dikea0044bd2007-05-06 14:51:36 -07001200static void prepare_request(struct request *req, struct io_thread_req *io_req,
1201 unsigned long long offset, int page_offset,
1202 int len, struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203{
1204 struct gendisk *disk = req->rq_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001205 struct ubd *ubd_dev = disk->private_data;
Jeff Dike91acb212005-10-10 23:10:32 -04001206
Jeff Dike62f96cb2007-02-10 01:44:16 -08001207 io_req->req = req;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001208 io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd :
1209 ubd_dev->fd;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001210 io_req->fds[1] = ubd_dev->fd;
Jeff Dike91acb212005-10-10 23:10:32 -04001211 io_req->cow_offset = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 io_req->offset = offset;
1213 io_req->length = len;
1214 io_req->error = 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001215 io_req->sector_mask = 0;
1216
1217 io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 io_req->offsets[0] = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001219 io_req->offsets[1] = ubd_dev->cow.data_offset;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001220 io_req->buffer = page_address(page) + page_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 io_req->sectorsize = 1 << 9;
1222
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001223 if(ubd_dev->cow.file != NULL)
Jeff Dikea0044bd2007-05-06 14:51:36 -07001224 cowify_req(io_req, ubd_dev->cow.bitmap,
1225 ubd_dev->cow.bitmap_offset, ubd_dev->cow.bitmap_len);
Jeff Dike91acb212005-10-10 23:10:32 -04001226
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227}
1228
Jeff Dike62f96cb2007-02-10 01:44:16 -08001229/* Called with dev->lock held */
Jens Axboe165125e2007-07-24 09:28:11 +02001230static void do_ubd_request(struct request_queue *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231{
Jeff Dike2adcec22007-05-06 14:51:37 -07001232 struct io_thread_req *io_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233 struct request *req;
Tejun Heof81f2f72009-04-28 13:06:10 +09001234 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235
Jeff Dikea0044bd2007-05-06 14:51:36 -07001236 while(1){
Jeff Dike2a9529a2007-03-29 01:20:27 -07001237 struct ubd *dev = q->queuedata;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001238 if(dev->end_sg == 0){
Tejun Heo9934c8c2009-05-08 11:54:16 +09001239 struct request *req = blk_fetch_request(q);
Jeff Dikea0044bd2007-05-06 14:51:36 -07001240 if(req == NULL)
1241 return;
1242
1243 dev->request = req;
Tejun Heo47526902010-10-15 12:56:21 +02001244 dev->rq_pos = blk_rq_pos(req);
Jeff Dikea0044bd2007-05-06 14:51:36 -07001245 dev->start_sg = 0;
1246 dev->end_sg = blk_rq_map_sg(q, req, dev->sg);
Jeff Dike91acb212005-10-10 23:10:32 -04001247 }
Jeff Dikea0044bd2007-05-06 14:51:36 -07001248
1249 req = dev->request;
1250 while(dev->start_sg < dev->end_sg){
1251 struct scatterlist *sg = &dev->sg[dev->start_sg];
1252
Jeff Dike2adcec22007-05-06 14:51:37 -07001253 io_req = kmalloc(sizeof(struct io_thread_req),
Peter Zijlstra990c5582007-05-06 14:51:38 -07001254 GFP_ATOMIC);
Jeff Dike2adcec22007-05-06 14:51:37 -07001255 if(io_req == NULL){
1256 if(list_empty(&dev->restart))
1257 list_add(&dev->restart, &restart);
1258 return;
1259 }
1260 prepare_request(req, io_req,
Tejun Heo47526902010-10-15 12:56:21 +02001261 (unsigned long long)dev->rq_pos << 9,
Jens Axboe45711f12007-10-22 21:19:53 +02001262 sg->offset, sg->length, sg_page(sg));
Jeff Dikea0044bd2007-05-06 14:51:36 -07001263
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001264 n = os_write_file(thread_fd, &io_req,
1265 sizeof(struct io_thread_req *));
Jeff Dike2adcec22007-05-06 14:51:37 -07001266 if(n != sizeof(struct io_thread_req *)){
Jeff Dikea0044bd2007-05-06 14:51:36 -07001267 if(n != -EAGAIN)
1268 printk("write to io thread failed, "
1269 "errno = %d\n", -n);
1270 else if(list_empty(&dev->restart))
1271 list_add(&dev->restart, &restart);
Miklos Szeredi12429bf2007-11-28 16:21:52 -08001272 kfree(io_req);
Jeff Dikea0044bd2007-05-06 14:51:36 -07001273 return;
1274 }
1275
Tejun Heo47526902010-10-15 12:56:21 +02001276 dev->rq_pos += sg->length >> 9;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001277 dev->start_sg++;
1278 }
1279 dev->end_sg = 0;
1280 dev->request = NULL;
Jeff Dike91acb212005-10-10 23:10:32 -04001281 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282}
1283
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001284static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
1285{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001286 struct ubd *ubd_dev = bdev->bd_disk->private_data;
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001287
1288 geo->heads = 128;
1289 geo->sectors = 32;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001290 geo->cylinders = ubd_dev->size / (128 * 32 * 512);
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001291 return 0;
1292}
1293
Al Viroa625c992008-03-02 09:16:26 -05001294static int ubd_ioctl(struct block_device *bdev, fmode_t mode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 unsigned int cmd, unsigned long arg)
1296{
Al Viroa625c992008-03-02 09:16:26 -05001297 struct ubd *ubd_dev = bdev->bd_disk->private_data;
Bartlomiej Zolnierkiewicz73855e12009-04-01 21:42:21 +02001298 u16 ubd_id[ATA_ID_WORDS];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299
1300 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 struct cdrom_volctrl volume;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 case HDIO_GET_IDENTITY:
Bartlomiej Zolnierkiewicz73855e12009-04-01 21:42:21 +02001303 memset(&ubd_id, 0, ATA_ID_WORDS * 2);
1304 ubd_id[ATA_ID_CYLS] = ubd_dev->size / (128 * 32 * 512);
1305 ubd_id[ATA_ID_HEADS] = 128;
1306 ubd_id[ATA_ID_SECTORS] = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 if(copy_to_user((char __user *) arg, (char *) &ubd_id,
1308 sizeof(ubd_id)))
Jeff Dikedc764e52007-05-06 14:51:41 -07001309 return -EFAULT;
1310 return 0;
Jeff Dikeb8831a12007-02-10 01:44:17 -08001311
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 case CDROMVOLREAD:
1313 if(copy_from_user(&volume, (char __user *) arg, sizeof(volume)))
Jeff Dikedc764e52007-05-06 14:51:41 -07001314 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 volume.channel0 = 255;
1316 volume.channel1 = 255;
1317 volume.channel2 = 255;
1318 volume.channel3 = 255;
1319 if(copy_to_user((char __user *) arg, &volume, sizeof(volume)))
Jeff Dikedc764e52007-05-06 14:51:41 -07001320 return -EFAULT;
1321 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 }
Jeff Dikedc764e52007-05-06 14:51:41 -07001323 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324}
1325
Jeff Dike91acb212005-10-10 23:10:32 -04001326static int update_bitmap(struct io_thread_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327{
Jeff Dike91acb212005-10-10 23:10:32 -04001328 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329
Jeff Dike91acb212005-10-10 23:10:32 -04001330 if(req->cow_offset == -1)
Jeff Dikedc764e52007-05-06 14:51:41 -07001331 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332
Jeff Dike91acb212005-10-10 23:10:32 -04001333 n = os_seek_file(req->fds[1], req->cow_offset);
1334 if(n < 0){
1335 printk("do_io - bitmap lseek failed : err = %d\n", -n);
Jeff Dikedc764e52007-05-06 14:51:41 -07001336 return 1;
Jeff Dike91acb212005-10-10 23:10:32 -04001337 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001339 n = os_write_file(req->fds[1], &req->bitmap_words,
1340 sizeof(req->bitmap_words));
Jeff Dike91acb212005-10-10 23:10:32 -04001341 if(n != sizeof(req->bitmap_words)){
1342 printk("do_io - bitmap update failed, err = %d fd = %d\n", -n,
1343 req->fds[1]);
Jeff Dikedc764e52007-05-06 14:51:41 -07001344 return 1;
Jeff Dike91acb212005-10-10 23:10:32 -04001345 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346
Jeff Dikedc764e52007-05-06 14:51:41 -07001347 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348}
Jeff Dike91acb212005-10-10 23:10:32 -04001349
WANG Cong5dc62b12008-04-28 02:13:58 -07001350static void do_io(struct io_thread_req *req)
Jeff Dike91acb212005-10-10 23:10:32 -04001351{
1352 char *buf;
1353 unsigned long len;
1354 int n, nsectors, start, end, bit;
1355 int err;
1356 __u64 off;
1357
1358 nsectors = req->length / req->sectorsize;
1359 start = 0;
1360 do {
1361 bit = ubd_test_bit(start, (unsigned char *) &req->sector_mask);
1362 end = start;
1363 while((end < nsectors) &&
1364 (ubd_test_bit(end, (unsigned char *)
1365 &req->sector_mask) == bit))
1366 end++;
1367
1368 off = req->offset + req->offsets[bit] +
1369 start * req->sectorsize;
1370 len = (end - start) * req->sectorsize;
1371 buf = &req->buffer[start * req->sectorsize];
1372
1373 err = os_seek_file(req->fds[bit], off);
1374 if(err < 0){
1375 printk("do_io - lseek failed : err = %d\n", -err);
1376 req->error = 1;
1377 return;
1378 }
1379 if(req->op == UBD_READ){
1380 n = 0;
1381 do {
1382 buf = &buf[n];
1383 len -= n;
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001384 n = os_read_file(req->fds[bit], buf, len);
Jeff Dike91acb212005-10-10 23:10:32 -04001385 if (n < 0) {
1386 printk("do_io - read failed, err = %d "
1387 "fd = %d\n", -n, req->fds[bit]);
1388 req->error = 1;
1389 return;
1390 }
1391 } while((n < len) && (n != 0));
1392 if (n < len) memset(&buf[n], 0, len - n);
1393 } else {
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001394 n = os_write_file(req->fds[bit], buf, len);
Jeff Dike91acb212005-10-10 23:10:32 -04001395 if(n != len){
1396 printk("do_io - write failed err = %d "
1397 "fd = %d\n", -n, req->fds[bit]);
1398 req->error = 1;
1399 return;
1400 }
1401 }
1402
1403 start = end;
1404 } while(start < nsectors);
1405
1406 req->error = update_bitmap(req);
1407}
1408
1409/* Changed in start_io_thread, which is serialized by being called only
1410 * from ubd_init, which is an initcall.
1411 */
1412int kernel_fd = -1;
1413
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001414/* Only changed by the io thread. XXX: currently unused. */
1415static int io_count = 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001416
1417int io_thread(void *arg)
1418{
Jeff Dike2adcec22007-05-06 14:51:37 -07001419 struct io_thread_req *req;
Jeff Dike91acb212005-10-10 23:10:32 -04001420 int n;
1421
1422 ignore_sigwinch_sig();
1423 while(1){
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001424 n = os_read_file(kernel_fd, &req,
Jeff Dike2adcec22007-05-06 14:51:37 -07001425 sizeof(struct io_thread_req *));
1426 if(n != sizeof(struct io_thread_req *)){
Jeff Dike91acb212005-10-10 23:10:32 -04001427 if(n < 0)
1428 printk("io_thread - read failed, fd = %d, "
1429 "err = %d\n", kernel_fd, -n);
1430 else {
1431 printk("io_thread - short read, fd = %d, "
1432 "length = %d\n", kernel_fd, n);
1433 }
1434 continue;
1435 }
1436 io_count++;
Jeff Dike2adcec22007-05-06 14:51:37 -07001437 do_io(req);
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001438 n = os_write_file(kernel_fd, &req,
Jeff Dike2adcec22007-05-06 14:51:37 -07001439 sizeof(struct io_thread_req *));
1440 if(n != sizeof(struct io_thread_req *))
Jeff Dike91acb212005-10-10 23:10:32 -04001441 printk("io_thread - write failed, fd = %d, err = %d\n",
1442 kernel_fd, -n);
1443 }
Jeff Dike91acb212005-10-10 23:10:32 -04001444
Jeff Dike1b57e9c2006-01-06 00:18:49 -08001445 return 0;
1446}