blob: 0c053607ce98b63362f6ac75b7e1e9df9d11f189 [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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167};
168
169#define DEFAULT_COW { \
170 .file = NULL, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700171 .fd = -1, \
172 .bitmap = NULL, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 .bitmap_offset = 0, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700174 .data_offset = 0, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175}
176
177#define DEFAULT_UBD { \
178 .file = NULL, \
179 .count = 0, \
180 .fd = -1, \
181 .size = -1, \
182 .boot_openflags = OPEN_FLAGS, \
183 .openflags = OPEN_FLAGS, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700184 .no_cow = 0, \
Jeff Dike6c29256c2006-03-27 01:14:37 -0800185 .shared = 0, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700186 .cow = DEFAULT_COW, \
Jeff Dike62f96cb2007-02-10 01:44:16 -0800187 .lock = SPIN_LOCK_UNLOCKED, \
Jeff Dikea0044bd2007-05-06 14:51:36 -0700188 .request = NULL, \
189 .start_sg = 0, \
190 .end_sg = 0, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191}
192
Jeff Dikeb8831a12007-02-10 01:44:17 -0800193/* Protected by ubd_lock */
WANG Cong5dc62b12008-04-28 02:13:58 -0700194static struct ubd ubd_devs[MAX_DEV] = { [0 ... MAX_DEV - 1] = DEFAULT_UBD };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196/* Only changed by fake_ide_setup which is a setup */
197static int fake_ide = 0;
198static struct proc_dir_entry *proc_ide_root = NULL;
199static struct proc_dir_entry *proc_ide = NULL;
200
201static void make_proc_ide(void)
202{
203 proc_ide_root = proc_mkdir("ide", NULL);
204 proc_ide = proc_mkdir("ide0", proc_ide_root);
205}
206
Alexey Dobriyan6613c5e2009-12-14 18:00:11 -0800207static int fake_ide_media_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208{
Alexey Dobriyan6613c5e2009-12-14 18:00:11 -0800209 seq_puts(m, "disk\n");
210 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211}
212
Alexey Dobriyan6613c5e2009-12-14 18:00:11 -0800213static int fake_ide_media_proc_open(struct inode *inode, struct file *file)
214{
215 return single_open(file, fake_ide_media_proc_show, NULL);
216}
217
218static const struct file_operations fake_ide_media_proc_fops = {
219 .owner = THIS_MODULE,
220 .open = fake_ide_media_proc_open,
221 .read = seq_read,
222 .llseek = seq_lseek,
223 .release = single_release,
224};
225
WANG Congc0a92902008-02-04 22:30:41 -0800226static void make_ide_entries(const char *dev_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227{
228 struct proc_dir_entry *dir, *ent;
229 char name[64];
230
231 if(proc_ide_root == NULL) make_proc_ide();
232
233 dir = proc_mkdir(dev_name, proc_ide);
234 if(!dir) return;
235
Alexey Dobriyan6613c5e2009-12-14 18:00:11 -0800236 ent = proc_create("media", S_IRUGO, dir, &fake_ide_media_proc_fops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 if(!ent) return;
WANG Congc0a92902008-02-04 22:30:41 -0800238 snprintf(name, sizeof(name), "ide0/%s", dev_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 proc_symlink(dev_name, proc_ide_root, name);
240}
241
242static int fake_ide_setup(char *str)
243{
244 fake_ide = 1;
Jeff Dikedc764e52007-05-06 14:51:41 -0700245 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246}
247
248__setup("fake_ide", fake_ide_setup);
249
250__uml_help(fake_ide_setup,
251"fake_ide\n"
252" Create ide0 entries that map onto ubd devices.\n\n"
253);
254
255static int parse_unit(char **ptr)
256{
257 char *str = *ptr, *end;
258 int n = -1;
259
260 if(isdigit(*str)) {
261 n = simple_strtoul(str, &end, 0);
262 if(end == str)
Jeff Dikedc764e52007-05-06 14:51:41 -0700263 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 *ptr = end;
265 }
Paolo 'Blaisorblade' Giarrusso97d88ac2006-10-30 22:07:03 -0800266 else if (('a' <= *str) && (*str <= 'z')) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 n = *str - 'a';
268 str++;
269 *ptr = str;
270 }
Jeff Dikedc764e52007-05-06 14:51:41 -0700271 return n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272}
273
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800274/* If *index_out == -1 at exit, the passed option was a general one;
275 * otherwise, the str pointer is used (and owned) inside ubd_devs array, so it
276 * should not be freed on exit.
277 */
Jeff Dikef28169d2007-02-10 01:43:53 -0800278static int ubd_setup_common(char *str, int *index_out, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800280 struct ubd *ubd_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 struct openflags flags = global_openflags;
282 char *backing_file;
Jeff Dikeb8831a12007-02-10 01:44:17 -0800283 int n, err = 0, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284
285 if(index_out) *index_out = -1;
286 n = *str;
287 if(n == '='){
288 char *end;
289 int major;
290
291 str++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 if(!strcmp(str, "sync")){
293 global_openflags = of_sync(global_openflags);
Jeff Dikeb8831a12007-02-10 01:44:17 -0800294 goto out1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 }
296
Jeff Dikef28169d2007-02-10 01:43:53 -0800297 err = -EINVAL;
Jeff Dikeb8831a12007-02-10 01:44:17 -0800298 major = simple_strtoul(str, &end, 0);
299 if((*end != '\0') || (end == str)){
300 *error_out = "Didn't parse major number";
301 goto out1;
302 }
303
Jeff Dikef28169d2007-02-10 01:43:53 -0800304 mutex_lock(&ubd_lock);
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700305 if (fake_major != UBD_MAJOR) {
Jeff Dikef28169d2007-02-10 01:43:53 -0800306 *error_out = "Can't assign a fake major twice";
307 goto out1;
308 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800309
Jeff Dikef28169d2007-02-10 01:43:53 -0800310 fake_major = major;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
312 printk(KERN_INFO "Setting extra ubd major number to %d\n",
313 major);
Jeff Dikef28169d2007-02-10 01:43:53 -0800314 err = 0;
315 out1:
316 mutex_unlock(&ubd_lock);
317 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 }
319
320 n = parse_unit(&str);
321 if(n < 0){
Jeff Dikef28169d2007-02-10 01:43:53 -0800322 *error_out = "Couldn't parse device number";
323 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 }
325 if(n >= MAX_DEV){
Jeff Dikef28169d2007-02-10 01:43:53 -0800326 *error_out = "Device number out of range";
327 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 }
329
Jeff Dikef28169d2007-02-10 01:43:53 -0800330 err = -EBUSY;
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800331 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800333 ubd_dev = &ubd_devs[n];
334 if(ubd_dev->file != NULL){
Jeff Dikef28169d2007-02-10 01:43:53 -0800335 *error_out = "Device is already configured";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 goto out;
337 }
338
339 if (index_out)
340 *index_out = n;
341
Jeff Dikef28169d2007-02-10 01:43:53 -0800342 err = -EINVAL;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800343 for (i = 0; i < sizeof("rscd="); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 switch (*str) {
345 case 'r':
346 flags.w = 0;
347 break;
348 case 's':
349 flags.s = 1;
350 break;
351 case 'd':
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800352 ubd_dev->no_cow = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 break;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800354 case 'c':
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800355 ubd_dev->shared = 1;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800356 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 case '=':
358 str++;
359 goto break_loop;
360 default:
Jeff Dikef28169d2007-02-10 01:43:53 -0800361 *error_out = "Expected '=' or flag letter "
362 "(r, s, c, or d)";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 goto out;
364 }
365 str++;
366 }
367
Jeff Dikef28169d2007-02-10 01:43:53 -0800368 if (*str == '=')
369 *error_out = "Too many flags specified";
370 else
371 *error_out = "Missing '='";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 goto out;
373
374break_loop:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 backing_file = strchr(str, ',');
376
Jeff Dikef28169d2007-02-10 01:43:53 -0800377 if (backing_file == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 backing_file = strchr(str, ':');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379
Jeff Dikef28169d2007-02-10 01:43:53 -0800380 if(backing_file != NULL){
381 if(ubd_dev->no_cow){
382 *error_out = "Can't specify both 'd' and a cow file";
383 goto out;
384 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 else {
386 *backing_file = '\0';
387 backing_file++;
388 }
389 }
Jeff Dikef28169d2007-02-10 01:43:53 -0800390 err = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800391 ubd_dev->file = str;
392 ubd_dev->cow.file = backing_file;
393 ubd_dev->boot_openflags = flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800395 mutex_unlock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -0800396 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397}
398
399static int ubd_setup(char *str)
400{
Jeff Dikef28169d2007-02-10 01:43:53 -0800401 char *error;
402 int err;
403
404 err = ubd_setup_common(str, NULL, &error);
405 if(err)
406 printk(KERN_ERR "Failed to initialize device with \"%s\" : "
407 "%s\n", str, error);
408 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409}
410
411__setup("ubd", ubd_setup);
412__uml_help(ubd_setup,
413"ubd<n><flags>=<filename>[(:|,)<filename2>]\n"
414" This is used to associate a device with a file in the underlying\n"
415" filesystem. When specifying two filenames, the first one is the\n"
416" COW name and the second is the backing file name. As separator you can\n"
417" use either a ':' or a ',': the first one allows writing things like;\n"
418" ubd0=~/Uml/root_cow:~/Uml/root_backing_file\n"
419" while with a ',' the shell would not expand the 2nd '~'.\n"
Jeff Dikef28169d2007-02-10 01:43:53 -0800420" When using only one filename, UML will detect whether to treat it like\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421" a COW file or a backing file. To override this detection, add the 'd'\n"
422" flag:\n"
423" ubd0d=BackingFile\n"
424" Usually, there is a filesystem in the file, but \n"
425" that's not required. Swap devices containing swap files can be\n"
426" specified like this. Also, a file which doesn't contain a\n"
427" filesystem can have its contents read in the virtual \n"
428" machine by running 'dd' on the device. <n> must be in the range\n"
429" 0 to 7. Appending an 'r' to the number will cause that device\n"
430" to be mounted read-only. For example ubd1r=./ext_fs. Appending\n"
Jeff Dike20ede452008-02-04 22:30:37 -0800431" an 's' will cause data to be written to disk on the host immediately.\n"
432" 'c' will cause the device to be treated as being shared between multiple\n"
433" UMLs and file locking will be turned off - this is appropriate for a\n"
434" cluster filesystem and inappropriate at almost all other times.\n\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435);
436
Jeff Dike8299ca52008-02-04 22:30:48 -0800437static int udb_setup(char *str)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438{
439 printk("udb%s specified on command line is almost certainly a ubd -> "
440 "udb TYPO\n", str);
Jeff Dikedc764e52007-05-06 14:51:41 -0700441 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442}
443
444__setup("udb", udb_setup);
445__uml_help(udb_setup,
446"udb\n"
Jeff Dike0894e272005-05-28 15:51:55 -0700447" This option is here solely to catch ubd -> udb typos, which can be\n"
448" to impossible to catch visually unless you specifically look for\n"
449" them. The only result of any option starting with 'udb' is an error\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450" in the boot output.\n\n"
451);
452
Jens Axboe165125e2007-07-24 09:28:11 +0200453static void do_ubd_request(struct request_queue * q);
Jeff Dike91acb212005-10-10 23:10:32 -0400454
455/* Only changed by ubd_init, which is an initcall. */
WANG Cong5dc62b12008-04-28 02:13:58 -0700456static int thread_fd = -1;
Jeff Dikea0044bd2007-05-06 14:51:36 -0700457static LIST_HEAD(restart);
458
Paolo 'Blaisorblade' Giarrusso2fe30a32006-10-30 22:07:09 -0800459/* XXX - move this inside ubd_intr. */
Jeff Dike62f96cb2007-02-10 01:44:16 -0800460/* Called without dev->lock held, and only in interrupt context. */
Jeff Dike91acb212005-10-10 23:10:32 -0400461static void ubd_handler(void)
462{
Jeff Dike2adcec22007-05-06 14:51:37 -0700463 struct io_thread_req *req;
Jeff Dikea0044bd2007-05-06 14:51:36 -0700464 struct ubd *ubd;
465 struct list_head *list, *next_ele;
466 unsigned long flags;
Jeff Dike91acb212005-10-10 23:10:32 -0400467 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468
Jeff Dikea0044bd2007-05-06 14:51:36 -0700469 while(1){
Jeff Dikea6ea4cc2007-05-06 14:51:43 -0700470 n = os_read_file(thread_fd, &req,
471 sizeof(struct io_thread_req *));
Jeff Dikea0044bd2007-05-06 14:51:36 -0700472 if(n != sizeof(req)){
473 if(n == -EAGAIN)
474 break;
475 printk(KERN_ERR "spurious interrupt in ubd_handler, "
476 "err = %d\n", -n);
477 return;
478 }
479
Tejun Heo4d6c84d2009-04-28 13:06:09 +0900480 blk_end_request(req->req, 0, req->length);
Jeff Dike2adcec22007-05-06 14:51:37 -0700481 kfree(req);
Jeff Dike91acb212005-10-10 23:10:32 -0400482 }
Jeff Dike62f96cb2007-02-10 01:44:16 -0800483 reactivate_fd(thread_fd, UBD_IRQ);
Jeff Dikea0044bd2007-05-06 14:51:36 -0700484
485 list_for_each_safe(list, next_ele, &restart){
486 ubd = container_of(list, struct ubd, restart);
487 list_del_init(&ubd->restart);
488 spin_lock_irqsave(&ubd->lock, flags);
489 do_ubd_request(ubd->queue);
490 spin_unlock_irqrestore(&ubd->lock, flags);
491 }
Jeff Dike91acb212005-10-10 23:10:32 -0400492}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493
Al Viro7bea96f2006-10-08 22:49:34 +0100494static irqreturn_t ubd_intr(int irq, void *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495{
Jeff Dike91acb212005-10-10 23:10:32 -0400496 ubd_handler();
Jeff Dikedc764e52007-05-06 14:51:41 -0700497 return IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498}
499
Jeff Dike91acb212005-10-10 23:10:32 -0400500/* Only changed by ubd_init, which is an initcall. */
501static int io_pid = -1;
502
WANG Cong5dc62b12008-04-28 02:13:58 -0700503static void kill_io_thread(void)
Jeff Dike91acb212005-10-10 23:10:32 -0400504{
Jeff Dike6c29256c2006-03-27 01:14:37 -0800505 if(io_pid != -1)
Jeff Dike91acb212005-10-10 23:10:32 -0400506 os_kill_process(io_pid, 1);
507}
508
509__uml_exitcall(kill_io_thread);
510
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800511static inline int ubd_file_size(struct ubd *ubd_dev, __u64 *size_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512{
513 char *file;
514
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800515 file = ubd_dev->cow.file ? ubd_dev->cow.file : ubd_dev->file;
Jeff Dikedc764e52007-05-06 14:51:41 -0700516 return os_file_size(file, size_out);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517}
518
WANG Cong5dc62b12008-04-28 02:13:58 -0700519static int read_cow_bitmap(int fd, void *buf, int offset, int len)
520{
521 int err;
522
523 err = os_seek_file(fd, offset);
524 if (err < 0)
525 return err;
526
527 err = os_read_file(fd, buf, len);
528 if (err < 0)
529 return err;
530
531 return 0;
532}
533
534static int backing_file_mismatch(char *file, __u64 size, time_t mtime)
535{
536 unsigned long modtime;
537 unsigned long long actual;
538 int err;
539
540 err = os_file_modtime(file, &modtime);
541 if (err < 0) {
542 printk(KERN_ERR "Failed to get modification time of backing "
543 "file \"%s\", err = %d\n", file, -err);
544 return err;
545 }
546
547 err = os_file_size(file, &actual);
548 if (err < 0) {
549 printk(KERN_ERR "Failed to get size of backing file \"%s\", "
550 "err = %d\n", file, -err);
551 return err;
552 }
553
554 if (actual != size) {
555 /*__u64 can be a long on AMD64 and with %lu GCC complains; so
556 * the typecast.*/
557 printk(KERN_ERR "Size mismatch (%llu vs %llu) of COW header "
558 "vs backing file\n", (unsigned long long) size, actual);
559 return -EINVAL;
560 }
561 if (modtime != mtime) {
562 printk(KERN_ERR "mtime mismatch (%ld vs %ld) of COW header vs "
563 "backing file\n", mtime, modtime);
564 return -EINVAL;
565 }
566 return 0;
567}
568
569static int path_requires_switch(char *from_cmdline, char *from_cow, char *cow)
570{
571 struct uml_stat buf1, buf2;
572 int err;
573
574 if (from_cmdline == NULL)
575 return 0;
576 if (!strcmp(from_cmdline, from_cow))
577 return 0;
578
579 err = os_stat_file(from_cmdline, &buf1);
580 if (err < 0) {
581 printk(KERN_ERR "Couldn't stat '%s', err = %d\n", from_cmdline,
582 -err);
583 return 0;
584 }
585 err = os_stat_file(from_cow, &buf2);
586 if (err < 0) {
587 printk(KERN_ERR "Couldn't stat '%s', err = %d\n", from_cow,
588 -err);
589 return 1;
590 }
591 if ((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino))
592 return 0;
593
594 printk(KERN_ERR "Backing file mismatch - \"%s\" requested, "
595 "\"%s\" specified in COW header of \"%s\"\n",
596 from_cmdline, from_cow, cow);
597 return 1;
598}
599
600static int open_ubd_file(char *file, struct openflags *openflags, int shared,
601 char **backing_file_out, int *bitmap_offset_out,
602 unsigned long *bitmap_len_out, int *data_offset_out,
603 int *create_cow_out)
604{
605 time_t mtime;
606 unsigned long long size;
607 __u32 version, align;
608 char *backing_file;
609 int fd, err, sectorsize, asked_switch, mode = 0644;
610
611 fd = os_open_file(file, *openflags, mode);
612 if (fd < 0) {
613 if ((fd == -ENOENT) && (create_cow_out != NULL))
614 *create_cow_out = 1;
615 if (!openflags->w ||
616 ((fd != -EROFS) && (fd != -EACCES)))
617 return fd;
618 openflags->w = 0;
619 fd = os_open_file(file, *openflags, mode);
620 if (fd < 0)
621 return fd;
622 }
623
624 if (shared)
625 printk(KERN_INFO "Not locking \"%s\" on the host\n", file);
626 else {
627 err = os_lock_file(fd, openflags->w);
628 if (err < 0) {
629 printk(KERN_ERR "Failed to lock '%s', err = %d\n",
630 file, -err);
631 goto out_close;
632 }
633 }
634
635 /* Successful return case! */
636 if (backing_file_out == NULL)
637 return fd;
638
639 err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime,
640 &size, &sectorsize, &align, bitmap_offset_out);
641 if (err && (*backing_file_out != NULL)) {
642 printk(KERN_ERR "Failed to read COW header from COW file "
643 "\"%s\", errno = %d\n", file, -err);
644 goto out_close;
645 }
646 if (err)
647 return fd;
648
649 asked_switch = path_requires_switch(*backing_file_out, backing_file,
650 file);
651
652 /* Allow switching only if no mismatch. */
653 if (asked_switch && !backing_file_mismatch(*backing_file_out, size,
654 mtime)) {
655 printk(KERN_ERR "Switching backing file to '%s'\n",
656 *backing_file_out);
657 err = write_cow_header(file, fd, *backing_file_out,
658 sectorsize, align, &size);
659 if (err) {
660 printk(KERN_ERR "Switch failed, errno = %d\n", -err);
661 goto out_close;
662 }
663 } else {
664 *backing_file_out = backing_file;
665 err = backing_file_mismatch(*backing_file_out, size, mtime);
666 if (err)
667 goto out_close;
668 }
669
670 cow_sizes(version, size, sectorsize, align, *bitmap_offset_out,
671 bitmap_len_out, data_offset_out);
672
673 return fd;
674 out_close:
675 os_close_file(fd);
676 return err;
677}
678
679static int create_cow_file(char *cow_file, char *backing_file,
680 struct openflags flags,
681 int sectorsize, int alignment, int *bitmap_offset_out,
682 unsigned long *bitmap_len_out, int *data_offset_out)
683{
684 int err, fd;
685
686 flags.c = 1;
687 fd = open_ubd_file(cow_file, &flags, 0, NULL, NULL, NULL, NULL, NULL);
688 if (fd < 0) {
689 err = fd;
690 printk(KERN_ERR "Open of COW file '%s' failed, errno = %d\n",
691 cow_file, -err);
692 goto out;
693 }
694
695 err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment,
696 bitmap_offset_out, bitmap_len_out,
697 data_offset_out);
698 if (!err)
699 return fd;
700 os_close_file(fd);
701 out:
702 return err;
703}
704
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800705static void ubd_close_dev(struct ubd *ubd_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800707 os_close_file(ubd_dev->fd);
708 if(ubd_dev->cow.file == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 return;
710
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800711 os_close_file(ubd_dev->cow.fd);
712 vfree(ubd_dev->cow.bitmap);
713 ubd_dev->cow.bitmap = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714}
715
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800716static int ubd_open_dev(struct ubd *ubd_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717{
718 struct openflags flags;
719 char **back_ptr;
720 int err, create_cow, *create_ptr;
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800721 int fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800723 ubd_dev->openflags = ubd_dev->boot_openflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 create_cow = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800725 create_ptr = (ubd_dev->cow.file != NULL) ? &create_cow : NULL;
726 back_ptr = ubd_dev->no_cow ? NULL : &ubd_dev->cow.file;
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800727
728 fd = open_ubd_file(ubd_dev->file, &ubd_dev->openflags, ubd_dev->shared,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800729 back_ptr, &ubd_dev->cow.bitmap_offset,
730 &ubd_dev->cow.bitmap_len, &ubd_dev->cow.data_offset,
Jeff Dike6c29256c2006-03-27 01:14:37 -0800731 create_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800733 if((fd == -ENOENT) && create_cow){
734 fd = create_cow_file(ubd_dev->file, ubd_dev->cow.file,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800735 ubd_dev->openflags, 1 << 9, PAGE_SIZE,
736 &ubd_dev->cow.bitmap_offset,
737 &ubd_dev->cow.bitmap_len,
738 &ubd_dev->cow.data_offset);
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800739 if(fd >= 0){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 printk(KERN_INFO "Creating \"%s\" as COW file for "
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800741 "\"%s\"\n", ubd_dev->file, ubd_dev->cow.file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 }
743 }
744
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800745 if(fd < 0){
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800746 printk("Failed to open '%s', errno = %d\n", ubd_dev->file,
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800747 -fd);
748 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 }
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800750 ubd_dev->fd = fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800752 if(ubd_dev->cow.file != NULL){
Martin K. Petersen086fa5f2010-02-26 00:20:38 -0500753 blk_queue_max_hw_sectors(ubd_dev->queue, 8 * sizeof(long));
Jeff Dikef4768ff2007-08-22 14:01:53 -0700754
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 err = -ENOMEM;
Jesper Juhlda2486b2007-10-16 01:27:19 -0700756 ubd_dev->cow.bitmap = vmalloc(ubd_dev->cow.bitmap_len);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800757 if(ubd_dev->cow.bitmap == NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 printk(KERN_ERR "Failed to vmalloc COW bitmap\n");
759 goto error;
760 }
761 flush_tlb_kernel_vm();
762
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800763 err = read_cow_bitmap(ubd_dev->fd, ubd_dev->cow.bitmap,
764 ubd_dev->cow.bitmap_offset,
765 ubd_dev->cow.bitmap_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 if(err < 0)
767 goto error;
768
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800769 flags = ubd_dev->openflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 flags.w = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800771 err = open_ubd_file(ubd_dev->cow.file, &flags, ubd_dev->shared, NULL,
Jeff Dike6c29256c2006-03-27 01:14:37 -0800772 NULL, NULL, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 if(err < 0) goto error;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800774 ubd_dev->cow.fd = err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 }
Jeff Dikedc764e52007-05-06 14:51:41 -0700776 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 error:
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800778 os_close_file(ubd_dev->fd);
Jeff Dikedc764e52007-05-06 14:51:41 -0700779 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780}
781
Jeff Dike2e3f5252007-05-06 14:51:29 -0700782static void ubd_device_release(struct device *dev)
783{
Greg Kroah-Hartman8691b972009-05-04 12:40:54 -0700784 struct ubd *ubd_dev = dev_get_drvdata(dev);
Jeff Dike2e3f5252007-05-06 14:51:29 -0700785
786 blk_cleanup_queue(ubd_dev->queue);
787 *ubd_dev = ((struct ubd) DEFAULT_UBD);
788}
789
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800790static int ubd_disk_register(int major, u64 size, int unit,
Jeff Dikeb8831a12007-02-10 01:44:17 -0800791 struct gendisk **disk_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792{
793 struct gendisk *disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794
795 disk = alloc_disk(1 << UBD_SHIFT);
796 if(disk == NULL)
Jeff Dikedc764e52007-05-06 14:51:41 -0700797 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798
799 disk->major = major;
800 disk->first_minor = unit << UBD_SHIFT;
801 disk->fops = &ubd_blops;
802 set_capacity(disk, size / 512);
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700803 if (major == UBD_MAJOR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 sprintf(disk->disk_name, "ubd%c", 'a' + unit);
Greg Kroah-Hartmance7b0f42005-06-20 21:15:16 -0700805 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 sprintf(disk->disk_name, "ubd_fake%d", unit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807
808 /* sysfs register (not for ide fake devices) */
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700809 if (major == UBD_MAJOR) {
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800810 ubd_devs[unit].pdev.id = unit;
811 ubd_devs[unit].pdev.name = DRIVER_NAME;
Jeff Dike2e3f5252007-05-06 14:51:29 -0700812 ubd_devs[unit].pdev.dev.release = ubd_device_release;
Greg Kroah-Hartman8691b972009-05-04 12:40:54 -0700813 dev_set_drvdata(&ubd_devs[unit].pdev.dev, &ubd_devs[unit]);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800814 platform_device_register(&ubd_devs[unit].pdev);
815 disk->driverfs_dev = &ubd_devs[unit].pdev.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 }
817
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800818 disk->private_data = &ubd_devs[unit];
Jeff Dike62f96cb2007-02-10 01:44:16 -0800819 disk->queue = ubd_devs[unit].queue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 add_disk(disk);
821
822 *disk_out = disk;
823 return 0;
824}
825
826#define ROUND_BLOCK(n) ((n + ((1 << 9) - 1)) & (-1 << 9))
827
Jeff Dikef28169d2007-02-10 01:43:53 -0800828static int ubd_add(int n, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800830 struct ubd *ubd_dev = &ubd_devs[n];
Jeff Dikef28169d2007-02-10 01:43:53 -0800831 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800833 if(ubd_dev->file == NULL)
Jeff Dikeec7cf782005-09-03 15:57:29 -0700834 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800836 err = ubd_file_size(ubd_dev, &ubd_dev->size);
Jeff Dikef28169d2007-02-10 01:43:53 -0800837 if(err < 0){
838 *error_out = "Couldn't determine size of device's file";
Jeff Dike80c13742006-09-29 01:58:51 -0700839 goto out;
Jeff Dikef28169d2007-02-10 01:43:53 -0800840 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800842 ubd_dev->size = ROUND_BLOCK(ubd_dev->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843
Jeff Dikea0044bd2007-05-06 14:51:36 -0700844 INIT_LIST_HEAD(&ubd_dev->restart);
WANG Cong4f40c052007-11-05 14:50:59 -0800845 sg_init_table(ubd_dev->sg, MAX_SG);
Jeff Dikea0044bd2007-05-06 14:51:36 -0700846
Jeff Dike62f96cb2007-02-10 01:44:16 -0800847 err = -ENOMEM;
848 ubd_dev->queue = blk_init_queue(do_ubd_request, &ubd_dev->lock);
849 if (ubd_dev->queue == NULL) {
850 *error_out = "Failed to initialize device queue";
Jeff Dike80c13742006-09-29 01:58:51 -0700851 goto out;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800852 }
853 ubd_dev->queue->queuedata = ubd_dev;
854
Martin K. Petersen8a783622010-02-26 00:20:39 -0500855 blk_queue_max_segments(ubd_dev->queue, MAX_SG);
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700856 err = ubd_disk_register(UBD_MAJOR, ubd_dev->size, n, &ubd_gendisk[n]);
Jeff Dike62f96cb2007-02-10 01:44:16 -0800857 if(err){
858 *error_out = "Failed to register device";
859 goto out_cleanup;
860 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800861
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700862 if (fake_major != UBD_MAJOR)
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800863 ubd_disk_register(fake_major, ubd_dev->size, n,
Jeff Dike62f96cb2007-02-10 01:44:16 -0800864 &fake_gendisk[n]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865
Jeff Dike83380cc2008-02-04 22:31:18 -0800866 /*
867 * Perhaps this should also be under the "if (fake_major)" above
868 * using the fake_disk->disk_name
869 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 if (fake_ide)
871 make_ide_entries(ubd_gendisk[n]->disk_name);
872
Jeff Dikeec7cf782005-09-03 15:57:29 -0700873 err = 0;
Jeff Dikeec7cf782005-09-03 15:57:29 -0700874out:
875 return err;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800876
877out_cleanup:
878 blk_cleanup_queue(ubd_dev->queue);
879 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880}
881
Jeff Dikef28169d2007-02-10 01:43:53 -0800882static int ubd_config(char *str, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883{
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800884 int n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885
Jeff Dikef28169d2007-02-10 01:43:53 -0800886 /* This string is possibly broken up and stored, so it's only
887 * freed if ubd_setup_common fails, or if only general options
888 * were set.
889 */
Jeff Dike970d6e32006-01-06 00:18:48 -0800890 str = kstrdup(str, GFP_KERNEL);
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800891 if (str == NULL) {
Jeff Dikef28169d2007-02-10 01:43:53 -0800892 *error_out = "Failed to allocate memory";
893 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 }
Jeff Dikef28169d2007-02-10 01:43:53 -0800895
896 ret = ubd_setup_common(str, &n, error_out);
897 if (ret)
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800898 goto err_free;
Jeff Dikef28169d2007-02-10 01:43:53 -0800899
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800900 if (n == -1) {
901 ret = 0;
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800902 goto err_free;
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800903 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904
Jeff Dikedc764e52007-05-06 14:51:41 -0700905 mutex_lock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -0800906 ret = ubd_add(n, error_out);
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800907 if (ret)
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800908 ubd_devs[n].file = NULL;
Jeff Dikedc764e52007-05-06 14:51:41 -0700909 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800911out:
Jeff Dikedc764e52007-05-06 14:51:41 -0700912 return ret;
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800913
914err_free:
915 kfree(str);
916 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917}
918
919static int ubd_get_config(char *name, char *str, int size, char **error_out)
920{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800921 struct ubd *ubd_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 int n, len = 0;
923
924 n = parse_unit(&name);
925 if((n >= MAX_DEV) || (n < 0)){
926 *error_out = "ubd_get_config : device number out of range";
Jeff Dikedc764e52007-05-06 14:51:41 -0700927 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 }
929
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800930 ubd_dev = &ubd_devs[n];
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800931 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800933 if(ubd_dev->file == NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 CONFIG_CHUNK(str, size, len, "", 1);
935 goto out;
936 }
937
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800938 CONFIG_CHUNK(str, size, len, ubd_dev->file, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800940 if(ubd_dev->cow.file != NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 CONFIG_CHUNK(str, size, len, ",", 0);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800942 CONFIG_CHUNK(str, size, len, ubd_dev->cow.file, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 }
944 else CONFIG_CHUNK(str, size, len, "", 1);
945
946 out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800947 mutex_unlock(&ubd_lock);
Jeff Dikedc764e52007-05-06 14:51:41 -0700948 return len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949}
950
Jeff Dike29d56cf2005-06-25 14:55:25 -0700951static int ubd_id(char **str, int *start_out, int *end_out)
952{
Jeff Dikedc764e52007-05-06 14:51:41 -0700953 int n;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700954
955 n = parse_unit(str);
Jeff Dikedc764e52007-05-06 14:51:41 -0700956 *start_out = 0;
957 *end_out = MAX_DEV - 1;
958 return n;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700959}
960
Jeff Dikef28169d2007-02-10 01:43:53 -0800961static int ubd_remove(int n, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962{
Jeff Dike2e3f5252007-05-06 14:51:29 -0700963 struct gendisk *disk = ubd_gendisk[n];
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800964 struct ubd *ubd_dev;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700965 int err = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800967 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800969 ubd_dev = &ubd_devs[n];
Jeff Dike29d56cf2005-06-25 14:55:25 -0700970
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800971 if(ubd_dev->file == NULL)
Jeff Dike29d56cf2005-06-25 14:55:25 -0700972 goto out;
973
974 /* you cannot remove a open disk */
975 err = -EBUSY;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800976 if(ubd_dev->count > 0)
Jeff Dike29d56cf2005-06-25 14:55:25 -0700977 goto out;
978
Jeff Dikedc764e52007-05-06 14:51:41 -0700979 ubd_gendisk[n] = NULL;
Jeff Dikeb47d2de2007-05-06 14:51:01 -0700980 if(disk != NULL){
981 del_gendisk(disk);
982 put_disk(disk);
983 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984
985 if(fake_gendisk[n] != NULL){
986 del_gendisk(fake_gendisk[n]);
987 put_disk(fake_gendisk[n]);
988 fake_gendisk[n] = NULL;
989 }
990
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 err = 0;
Jeff Dike2e3f5252007-05-06 14:51:29 -0700992 platform_device_unregister(&ubd_dev->pdev);
Jeff Dike29d56cf2005-06-25 14:55:25 -0700993out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800994 mutex_unlock(&ubd_lock);
Jeff Dike29d56cf2005-06-25 14:55:25 -0700995 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996}
997
Jeff Dikef28169d2007-02-10 01:43:53 -0800998/* All these are called by mconsole in process context and without
Jeff Dikeb8831a12007-02-10 01:44:17 -0800999 * ubd-specific locks. The structure itself is const except for .list.
Jeff Dikef28169d2007-02-10 01:43:53 -08001000 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001static struct mc_device ubd_mc = {
Jeff Dike84f48d42007-02-10 01:44:01 -08001002 .list = LIST_HEAD_INIT(ubd_mc.list),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 .name = "ubd",
1004 .config = ubd_config,
Jeff Dikedc764e52007-05-06 14:51:41 -07001005 .get_config = ubd_get_config,
Jeff Dike29d56cf2005-06-25 14:55:25 -07001006 .id = ubd_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 .remove = ubd_remove,
1008};
1009
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001010static int __init ubd_mc_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011{
1012 mconsole_register_dev(&ubd_mc);
1013 return 0;
1014}
1015
1016__initcall(ubd_mc_init);
1017
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001018static int __init ubd0_init(void)
1019{
1020 struct ubd *ubd_dev = &ubd_devs[0];
1021
Jeff Dikeb8831a12007-02-10 01:44:17 -08001022 mutex_lock(&ubd_lock);
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001023 if(ubd_dev->file == NULL)
1024 ubd_dev->file = "root_fs";
Jeff Dikeb8831a12007-02-10 01:44:17 -08001025 mutex_unlock(&ubd_lock);
1026
Jeff Dikedc764e52007-05-06 14:51:41 -07001027 return 0;
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001028}
1029
1030__initcall(ubd0_init);
1031
Jeff Dikeb8831a12007-02-10 01:44:17 -08001032/* Used in ubd_init, which is an initcall */
Russell King3ae5eae2005-11-09 22:32:44 +00001033static struct platform_driver ubd_driver = {
1034 .driver = {
1035 .name = DRIVER_NAME,
1036 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037};
1038
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001039static int __init ubd_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040{
Jeff Dikef28169d2007-02-10 01:43:53 -08001041 char *error;
1042 int i, err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043
Christoph Hellwig792dd4f2009-03-31 15:23:39 -07001044 if (register_blkdev(UBD_MAJOR, "ubd"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 return -1;
1046
Christoph Hellwig792dd4f2009-03-31 15:23:39 -07001047 if (fake_major != UBD_MAJOR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 char name[sizeof("ubd_nnn\0")];
1049
1050 snprintf(name, sizeof(name), "ubd_%d", fake_major);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 if (register_blkdev(fake_major, "ubd"))
1052 return -1;
1053 }
Russell King3ae5eae2005-11-09 22:32:44 +00001054 platform_driver_register(&ubd_driver);
Jeff Dikedc764e52007-05-06 14:51:41 -07001055 mutex_lock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -08001056 for (i = 0; i < MAX_DEV; i++){
1057 err = ubd_add(i, &error);
1058 if(err)
1059 printk(KERN_ERR "Failed to initialize ubd device %d :"
1060 "%s\n", i, error);
1061 }
Jeff Dikedc764e52007-05-06 14:51:41 -07001062 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 return 0;
1064}
1065
1066late_initcall(ubd_init);
1067
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001068static int __init ubd_driver_init(void){
Jeff Dike91acb212005-10-10 23:10:32 -04001069 unsigned long stack;
1070 int err;
1071
1072 /* Set by CONFIG_BLK_DEV_UBD_SYNC or ubd=sync.*/
1073 if(global_openflags.s){
1074 printk(KERN_INFO "ubd: Synchronous mode\n");
1075 /* Letting ubd=sync be like using ubd#s= instead of ubd#= is
1076 * enough. So use anyway the io thread. */
1077 }
1078 stack = alloc_stack(0, 0);
Jeff Dike6c29256c2006-03-27 01:14:37 -08001079 io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *),
Jeff Dike91acb212005-10-10 23:10:32 -04001080 &thread_fd);
1081 if(io_pid < 0){
Jeff Dike6c29256c2006-03-27 01:14:37 -08001082 printk(KERN_ERR
Jeff Dike91acb212005-10-10 23:10:32 -04001083 "ubd : Failed to start I/O thread (errno = %d) - "
1084 "falling back to synchronous I/O\n", -io_pid);
1085 io_pid = -1;
Jeff Dikedc764e52007-05-06 14:51:41 -07001086 return 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001087 }
Jeff Dike6c29256c2006-03-27 01:14:37 -08001088 err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001089 IRQF_DISABLED, "ubd", ubd_devs);
Jeff Dike91acb212005-10-10 23:10:32 -04001090 if(err != 0)
1091 printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err);
Jeff Dikef4c57a72006-03-31 02:30:10 -08001092 return 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001093}
1094
1095device_initcall(ubd_driver_init);
1096
Al Viroa625c992008-03-02 09:16:26 -05001097static int ubd_open(struct block_device *bdev, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098{
Al Viroa625c992008-03-02 09:16:26 -05001099 struct gendisk *disk = bdev->bd_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001100 struct ubd *ubd_dev = disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 int err = 0;
1102
Arnd Bergmann9a181c52010-09-11 18:38:03 +02001103 mutex_lock(&ubd_mutex);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001104 if(ubd_dev->count == 0){
1105 err = ubd_open_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 if(err){
1107 printk(KERN_ERR "%s: Can't open \"%s\": errno = %d\n",
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001108 disk->disk_name, ubd_dev->file, -err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 goto out;
1110 }
1111 }
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001112 ubd_dev->count++;
1113 set_disk_ro(disk, !ubd_dev->openflags.w);
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -07001114
1115 /* This should no more be needed. And it didn't work anyway to exclude
1116 * read-write remounting of filesystems.*/
Al Viroa625c992008-03-02 09:16:26 -05001117 /*if((mode & FMODE_WRITE) && !ubd_dev->openflags.w){
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -08001118 if(--ubd_dev->count == 0) ubd_close_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 err = -EROFS;
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -07001120 }*/
Arnd Bergmann6e9624b2010-08-07 18:25:34 +02001121out:
Arnd Bergmann9a181c52010-09-11 18:38:03 +02001122 mutex_unlock(&ubd_mutex);
Jeff Dikedc764e52007-05-06 14:51:41 -07001123 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124}
1125
Al Viroa625c992008-03-02 09:16:26 -05001126static int ubd_release(struct gendisk *disk, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001128 struct ubd *ubd_dev = disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129
Arnd Bergmann9a181c52010-09-11 18:38:03 +02001130 mutex_lock(&ubd_mutex);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001131 if(--ubd_dev->count == 0)
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -08001132 ubd_close_dev(ubd_dev);
Arnd Bergmann9a181c52010-09-11 18:38:03 +02001133 mutex_unlock(&ubd_mutex);
Jeff Dikedc764e52007-05-06 14:51:41 -07001134 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135}
1136
Jeff Dike91acb212005-10-10 23:10:32 -04001137static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask,
1138 __u64 *cow_offset, unsigned long *bitmap,
1139 __u64 bitmap_offset, unsigned long *bitmap_words,
1140 __u64 bitmap_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141{
Jeff Dike91acb212005-10-10 23:10:32 -04001142 __u64 sector = io_offset >> 9;
1143 int i, update_bitmap = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144
Jeff Dike91acb212005-10-10 23:10:32 -04001145 for(i = 0; i < length >> 9; i++){
1146 if(cow_mask != NULL)
1147 ubd_set_bit(i, (unsigned char *) cow_mask);
1148 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
1149 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150
Jeff Dike91acb212005-10-10 23:10:32 -04001151 update_bitmap = 1;
1152 ubd_set_bit(sector + i, (unsigned char *) bitmap);
1153 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154
Jeff Dike91acb212005-10-10 23:10:32 -04001155 if(!update_bitmap)
1156 return;
1157
1158 *cow_offset = sector / (sizeof(unsigned long) * 8);
1159
1160 /* This takes care of the case where we're exactly at the end of the
1161 * device, and *cow_offset + 1 is off the end. So, just back it up
1162 * by one word. Thanks to Lynn Kerby for the fix and James McMechan
1163 * for the original diagnosis.
1164 */
Jiri Olsa6d074242008-05-12 14:01:56 -07001165 if (*cow_offset == (DIV_ROUND_UP(bitmap_len,
1166 sizeof(unsigned long)) - 1))
Jeff Dike91acb212005-10-10 23:10:32 -04001167 (*cow_offset)--;
1168
1169 bitmap_words[0] = bitmap[*cow_offset];
1170 bitmap_words[1] = bitmap[*cow_offset + 1];
1171
1172 *cow_offset *= sizeof(unsigned long);
1173 *cow_offset += bitmap_offset;
1174}
1175
1176static void cowify_req(struct io_thread_req *req, unsigned long *bitmap,
1177 __u64 bitmap_offset, __u64 bitmap_len)
1178{
1179 __u64 sector = req->offset >> 9;
1180 int i;
1181
1182 if(req->length > (sizeof(req->sector_mask) * 8) << 9)
1183 panic("Operation too long");
1184
1185 if(req->op == UBD_READ) {
1186 for(i = 0; i < req->length >> 9; i++){
1187 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
Jeff Dike6c29256c2006-03-27 01:14:37 -08001188 ubd_set_bit(i, (unsigned char *)
Jeff Dike91acb212005-10-10 23:10:32 -04001189 &req->sector_mask);
Jeff Dikedc764e52007-05-06 14:51:41 -07001190 }
Jeff Dike91acb212005-10-10 23:10:32 -04001191 }
1192 else cowify_bitmap(req->offset, req->length, &req->sector_mask,
1193 &req->cow_offset, bitmap, bitmap_offset,
1194 req->bitmap_words, bitmap_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195}
1196
Jeff Dike62f96cb2007-02-10 01:44:16 -08001197/* Called with dev->lock held */
Jeff Dikea0044bd2007-05-06 14:51:36 -07001198static void prepare_request(struct request *req, struct io_thread_req *io_req,
1199 unsigned long long offset, int page_offset,
1200 int len, struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201{
1202 struct gendisk *disk = req->rq_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001203 struct ubd *ubd_dev = disk->private_data;
Jeff Dike91acb212005-10-10 23:10:32 -04001204
Jeff Dike62f96cb2007-02-10 01:44:16 -08001205 io_req->req = req;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001206 io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd :
1207 ubd_dev->fd;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001208 io_req->fds[1] = ubd_dev->fd;
Jeff Dike91acb212005-10-10 23:10:32 -04001209 io_req->cow_offset = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 io_req->offset = offset;
1211 io_req->length = len;
1212 io_req->error = 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001213 io_req->sector_mask = 0;
1214
1215 io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 io_req->offsets[0] = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001217 io_req->offsets[1] = ubd_dev->cow.data_offset;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001218 io_req->buffer = page_address(page) + page_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 io_req->sectorsize = 1 << 9;
1220
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001221 if(ubd_dev->cow.file != NULL)
Jeff Dikea0044bd2007-05-06 14:51:36 -07001222 cowify_req(io_req, ubd_dev->cow.bitmap,
1223 ubd_dev->cow.bitmap_offset, ubd_dev->cow.bitmap_len);
Jeff Dike91acb212005-10-10 23:10:32 -04001224
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225}
1226
Jeff Dike62f96cb2007-02-10 01:44:16 -08001227/* Called with dev->lock held */
Jens Axboe165125e2007-07-24 09:28:11 +02001228static void do_ubd_request(struct request_queue *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229{
Jeff Dike2adcec22007-05-06 14:51:37 -07001230 struct io_thread_req *io_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 struct request *req;
Tejun Heof81f2f72009-04-28 13:06:10 +09001232 sector_t sector;
1233 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234
Jeff Dikea0044bd2007-05-06 14:51:36 -07001235 while(1){
Jeff Dike2a9529a2007-03-29 01:20:27 -07001236 struct ubd *dev = q->queuedata;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001237 if(dev->end_sg == 0){
Tejun Heo9934c8c2009-05-08 11:54:16 +09001238 struct request *req = blk_fetch_request(q);
Jeff Dikea0044bd2007-05-06 14:51:36 -07001239 if(req == NULL)
1240 return;
1241
1242 dev->request = req;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001243 dev->start_sg = 0;
1244 dev->end_sg = blk_rq_map_sg(q, req, dev->sg);
Jeff Dike91acb212005-10-10 23:10:32 -04001245 }
Jeff Dikea0044bd2007-05-06 14:51:36 -07001246
1247 req = dev->request;
Tejun Heo83096eb2009-05-07 22:24:39 +09001248 sector = blk_rq_pos(req);
Jeff Dikea0044bd2007-05-06 14:51:36 -07001249 while(dev->start_sg < dev->end_sg){
1250 struct scatterlist *sg = &dev->sg[dev->start_sg];
1251
Jeff Dike2adcec22007-05-06 14:51:37 -07001252 io_req = kmalloc(sizeof(struct io_thread_req),
Peter Zijlstra990c5582007-05-06 14:51:38 -07001253 GFP_ATOMIC);
Jeff Dike2adcec22007-05-06 14:51:37 -07001254 if(io_req == NULL){
1255 if(list_empty(&dev->restart))
1256 list_add(&dev->restart, &restart);
1257 return;
1258 }
1259 prepare_request(req, io_req,
Tejun Heof81f2f72009-04-28 13:06:10 +09001260 (unsigned long long)sector << 9,
Jens Axboe45711f12007-10-22 21:19:53 +02001261 sg->offset, sg->length, sg_page(sg));
Jeff Dikea0044bd2007-05-06 14:51:36 -07001262
Tejun Heof81f2f72009-04-28 13:06:10 +09001263 sector += sg->length >> 9;
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
Jeff Dikea0044bd2007-05-06 14:51:36 -07001276 dev->start_sg++;
1277 }
1278 dev->end_sg = 0;
1279 dev->request = NULL;
Jeff Dike91acb212005-10-10 23:10:32 -04001280 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281}
1282
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001283static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
1284{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001285 struct ubd *ubd_dev = bdev->bd_disk->private_data;
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001286
1287 geo->heads = 128;
1288 geo->sectors = 32;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001289 geo->cylinders = ubd_dev->size / (128 * 32 * 512);
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001290 return 0;
1291}
1292
Al Viroa625c992008-03-02 09:16:26 -05001293static int ubd_ioctl(struct block_device *bdev, fmode_t mode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 unsigned int cmd, unsigned long arg)
1295{
Al Viroa625c992008-03-02 09:16:26 -05001296 struct ubd *ubd_dev = bdev->bd_disk->private_data;
Bartlomiej Zolnierkiewicz73855e12009-04-01 21:42:21 +02001297 u16 ubd_id[ATA_ID_WORDS];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298
1299 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 struct cdrom_volctrl volume;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 case HDIO_GET_IDENTITY:
Bartlomiej Zolnierkiewicz73855e12009-04-01 21:42:21 +02001302 memset(&ubd_id, 0, ATA_ID_WORDS * 2);
1303 ubd_id[ATA_ID_CYLS] = ubd_dev->size / (128 * 32 * 512);
1304 ubd_id[ATA_ID_HEADS] = 128;
1305 ubd_id[ATA_ID_SECTORS] = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 if(copy_to_user((char __user *) arg, (char *) &ubd_id,
1307 sizeof(ubd_id)))
Jeff Dikedc764e52007-05-06 14:51:41 -07001308 return -EFAULT;
1309 return 0;
Jeff Dikeb8831a12007-02-10 01:44:17 -08001310
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 case CDROMVOLREAD:
1312 if(copy_from_user(&volume, (char __user *) arg, sizeof(volume)))
Jeff Dikedc764e52007-05-06 14:51:41 -07001313 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 volume.channel0 = 255;
1315 volume.channel1 = 255;
1316 volume.channel2 = 255;
1317 volume.channel3 = 255;
1318 if(copy_to_user((char __user *) arg, &volume, sizeof(volume)))
Jeff Dikedc764e52007-05-06 14:51:41 -07001319 return -EFAULT;
1320 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 }
Jeff Dikedc764e52007-05-06 14:51:41 -07001322 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323}
1324
Jeff Dike91acb212005-10-10 23:10:32 -04001325static int update_bitmap(struct io_thread_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326{
Jeff Dike91acb212005-10-10 23:10:32 -04001327 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328
Jeff Dike91acb212005-10-10 23:10:32 -04001329 if(req->cow_offset == -1)
Jeff Dikedc764e52007-05-06 14:51:41 -07001330 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331
Jeff Dike91acb212005-10-10 23:10:32 -04001332 n = os_seek_file(req->fds[1], req->cow_offset);
1333 if(n < 0){
1334 printk("do_io - bitmap lseek failed : err = %d\n", -n);
Jeff Dikedc764e52007-05-06 14:51:41 -07001335 return 1;
Jeff Dike91acb212005-10-10 23:10:32 -04001336 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001338 n = os_write_file(req->fds[1], &req->bitmap_words,
1339 sizeof(req->bitmap_words));
Jeff Dike91acb212005-10-10 23:10:32 -04001340 if(n != sizeof(req->bitmap_words)){
1341 printk("do_io - bitmap update failed, err = %d fd = %d\n", -n,
1342 req->fds[1]);
Jeff Dikedc764e52007-05-06 14:51:41 -07001343 return 1;
Jeff Dike91acb212005-10-10 23:10:32 -04001344 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345
Jeff Dikedc764e52007-05-06 14:51:41 -07001346 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347}
Jeff Dike91acb212005-10-10 23:10:32 -04001348
WANG Cong5dc62b12008-04-28 02:13:58 -07001349static void do_io(struct io_thread_req *req)
Jeff Dike91acb212005-10-10 23:10:32 -04001350{
1351 char *buf;
1352 unsigned long len;
1353 int n, nsectors, start, end, bit;
1354 int err;
1355 __u64 off;
1356
1357 nsectors = req->length / req->sectorsize;
1358 start = 0;
1359 do {
1360 bit = ubd_test_bit(start, (unsigned char *) &req->sector_mask);
1361 end = start;
1362 while((end < nsectors) &&
1363 (ubd_test_bit(end, (unsigned char *)
1364 &req->sector_mask) == bit))
1365 end++;
1366
1367 off = req->offset + req->offsets[bit] +
1368 start * req->sectorsize;
1369 len = (end - start) * req->sectorsize;
1370 buf = &req->buffer[start * req->sectorsize];
1371
1372 err = os_seek_file(req->fds[bit], off);
1373 if(err < 0){
1374 printk("do_io - lseek failed : err = %d\n", -err);
1375 req->error = 1;
1376 return;
1377 }
1378 if(req->op == UBD_READ){
1379 n = 0;
1380 do {
1381 buf = &buf[n];
1382 len -= n;
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001383 n = os_read_file(req->fds[bit], buf, len);
Jeff Dike91acb212005-10-10 23:10:32 -04001384 if (n < 0) {
1385 printk("do_io - read failed, err = %d "
1386 "fd = %d\n", -n, req->fds[bit]);
1387 req->error = 1;
1388 return;
1389 }
1390 } while((n < len) && (n != 0));
1391 if (n < len) memset(&buf[n], 0, len - n);
1392 } else {
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001393 n = os_write_file(req->fds[bit], buf, len);
Jeff Dike91acb212005-10-10 23:10:32 -04001394 if(n != len){
1395 printk("do_io - write failed err = %d "
1396 "fd = %d\n", -n, req->fds[bit]);
1397 req->error = 1;
1398 return;
1399 }
1400 }
1401
1402 start = end;
1403 } while(start < nsectors);
1404
1405 req->error = update_bitmap(req);
1406}
1407
1408/* Changed in start_io_thread, which is serialized by being called only
1409 * from ubd_init, which is an initcall.
1410 */
1411int kernel_fd = -1;
1412
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001413/* Only changed by the io thread. XXX: currently unused. */
1414static int io_count = 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001415
1416int io_thread(void *arg)
1417{
Jeff Dike2adcec22007-05-06 14:51:37 -07001418 struct io_thread_req *req;
Jeff Dike91acb212005-10-10 23:10:32 -04001419 int n;
1420
1421 ignore_sigwinch_sig();
1422 while(1){
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001423 n = os_read_file(kernel_fd, &req,
Jeff Dike2adcec22007-05-06 14:51:37 -07001424 sizeof(struct io_thread_req *));
1425 if(n != sizeof(struct io_thread_req *)){
Jeff Dike91acb212005-10-10 23:10:32 -04001426 if(n < 0)
1427 printk("io_thread - read failed, fd = %d, "
1428 "err = %d\n", kernel_fd, -n);
1429 else {
1430 printk("io_thread - short read, fd = %d, "
1431 "length = %d\n", kernel_fd, n);
1432 }
1433 continue;
1434 }
1435 io_count++;
Jeff Dike2adcec22007-05-06 14:51:37 -07001436 do_io(req);
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001437 n = os_write_file(kernel_fd, &req,
Jeff Dike2adcec22007-05-06 14:51:37 -07001438 sizeof(struct io_thread_req *));
1439 if(n != sizeof(struct io_thread_req *))
Jeff Dike91acb212005-10-10 23:10:32 -04001440 printk("io_thread - write failed, fd = %d, err = %d\n",
1441 kernel_fd, -n);
1442 }
Jeff Dike91acb212005-10-10 23:10:32 -04001443
Jeff Dike1b57e9c2006-01-06 00:18:49 -08001444 return 0;
1445}