blob: 944453a3ec9972f136060054893f7e7aaa3ea568 [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"
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include "mconsole_kern.h"
50#include "init.h"
51#include "irq_user.h"
52#include "irq_kern.h"
53#include "ubd_user.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070054#include "os.h"
55#include "mem.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070056#include "cow.h"
57
Jeff Dike7b9014c2005-05-20 13:59:11 -070058enum ubd_req { UBD_READ, UBD_WRITE };
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
60struct io_thread_req {
Jeff Dike62f96cb2007-02-10 01:44:16 -080061 struct request *req;
Jeff Dike91acb212005-10-10 23:10:32 -040062 enum ubd_req op;
Linus Torvalds1da177e2005-04-16 15:20:36 -070063 int fds[2];
64 unsigned long offsets[2];
65 unsigned long long offset;
66 unsigned long length;
67 char *buffer;
68 int sectorsize;
Jeff Dike91acb212005-10-10 23:10:32 -040069 unsigned long sector_mask;
70 unsigned long long cow_offset;
71 unsigned long bitmap_words[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -070072 int error;
73};
74
Jeff Dike91acb212005-10-10 23:10:32 -040075static inline int ubd_test_bit(__u64 bit, unsigned char *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -070076{
77 __u64 n;
78 int bits, off;
79
Jeff Dike91acb212005-10-10 23:10:32 -040080 bits = sizeof(data[0]) * 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -070081 n = bit / bits;
82 off = bit % bits;
Jeff Dikedc764e52007-05-06 14:51:41 -070083 return (data[n] & (1 << off)) != 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070084}
85
Jeff Dike91acb212005-10-10 23:10:32 -040086static inline void ubd_set_bit(__u64 bit, unsigned char *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -070087{
88 __u64 n;
89 int bits, off;
90
Jeff Dike91acb212005-10-10 23:10:32 -040091 bits = sizeof(data[0]) * 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -070092 n = bit / bits;
93 off = bit % bits;
Jeff Dike91acb212005-10-10 23:10:32 -040094 data[n] |= (1 << off);
Linus Torvalds1da177e2005-04-16 15:20:36 -070095}
96/*End stuff from ubd_user.h*/
97
98#define DRIVER_NAME "uml-blkdev"
99
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800100static DEFINE_MUTEX(ubd_lock);
Arnd Bergmann9a181c52010-09-11 18:38:03 +0200101static DEFINE_MUTEX(ubd_mutex); /* replaces BKL, might not be needed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102
Al Viroa625c992008-03-02 09:16:26 -0500103static int ubd_open(struct block_device *bdev, fmode_t mode);
104static int ubd_release(struct gendisk *disk, fmode_t mode);
105static int ubd_ioctl(struct block_device *bdev, fmode_t mode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 unsigned int cmd, unsigned long arg);
Christoph Hellwiga885c8c2006-01-08 01:02:50 -0800107static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108
Paolo 'Blaisorblade' Giarrusso97d88ac2006-10-30 22:07:03 -0800109#define MAX_DEV (16)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110
Alexey Dobriyan83d5cde2009-09-21 17:01:13 -0700111static const struct block_device_operations ubd_blops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 .owner = THIS_MODULE,
Al Viroa625c992008-03-02 09:16:26 -0500113 .open = ubd_open,
114 .release = ubd_release,
115 .ioctl = ubd_ioctl,
Christoph Hellwiga885c8c2006-01-08 01:02:50 -0800116 .getgeo = ubd_getgeo,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117};
118
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119/* Protected by ubd_lock */
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700120static int fake_major = UBD_MAJOR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121static struct gendisk *ubd_gendisk[MAX_DEV];
122static struct gendisk *fake_gendisk[MAX_DEV];
Jeff Dike6c29256c2006-03-27 01:14:37 -0800123
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124#ifdef CONFIG_BLK_DEV_UBD_SYNC
125#define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 1, .c = 0, \
126 .cl = 1 })
127#else
128#define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 0, .c = 0, \
129 .cl = 1 })
130#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131static struct openflags global_openflags = OPEN_FLAGS;
132
133struct cow {
Paolo 'Blaisorblade' Giarrusso2a9d32f2006-10-30 22:07:04 -0800134 /* backing file name */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 char *file;
Paolo 'Blaisorblade' Giarrusso2a9d32f2006-10-30 22:07:04 -0800136 /* backing file fd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 int fd;
138 unsigned long *bitmap;
139 unsigned long bitmap_len;
140 int bitmap_offset;
Jeff Dikedc764e52007-05-06 14:51:41 -0700141 int data_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142};
143
Jeff Dikea0044bd2007-05-06 14:51:36 -0700144#define MAX_SG 64
145
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146struct ubd {
Jeff Dikea0044bd2007-05-06 14:51:36 -0700147 struct list_head restart;
Paolo 'Blaisorblade' Giarrusso2a9d32f2006-10-30 22:07:04 -0800148 /* name (and fd, below) of the file opened for writing, either the
149 * backing or the cow file. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 char *file;
151 int count;
152 int fd;
153 __u64 size;
154 struct openflags boot_openflags;
155 struct openflags openflags;
Paolo 'Blaisorblade' Giarrusso84e945e2006-10-30 22:07:10 -0800156 unsigned shared:1;
157 unsigned no_cow:1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 struct cow cow;
159 struct platform_device pdev;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800160 struct request_queue *queue;
161 spinlock_t lock;
Jeff Dikea0044bd2007-05-06 14:51:36 -0700162 struct scatterlist sg[MAX_SG];
163 struct request *request;
164 int start_sg, end_sg;
Tejun Heo47526902010-10-15 12:56:21 +0200165 sector_t rq_pos;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166};
167
168#define DEFAULT_COW { \
169 .file = NULL, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700170 .fd = -1, \
171 .bitmap = NULL, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 .bitmap_offset = 0, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700173 .data_offset = 0, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174}
175
176#define DEFAULT_UBD { \
177 .file = NULL, \
178 .count = 0, \
179 .fd = -1, \
180 .size = -1, \
181 .boot_openflags = OPEN_FLAGS, \
182 .openflags = OPEN_FLAGS, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700183 .no_cow = 0, \
Jeff Dike6c29256c2006-03-27 01:14:37 -0800184 .shared = 0, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700185 .cow = DEFAULT_COW, \
Thomas Gleixner22e65002011-01-23 15:21:25 +0100186 .lock = __SPIN_LOCK_UNLOCKED(ubd_devs.lock), \
Jeff Dikea0044bd2007-05-06 14:51:36 -0700187 .request = NULL, \
188 .start_sg = 0, \
189 .end_sg = 0, \
Tejun Heo47526902010-10-15 12:56:21 +0200190 .rq_pos = 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;
Richard Weinberger85356392011-11-02 13:17:27 +0100514 int fd;
515 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516
Richard Weinberger85356392011-11-02 13:17:27 +0100517 __u32 version;
518 __u32 align;
519 char *backing_file;
520 time_t mtime;
521 unsigned long long size;
522 int sector_size;
523 int bitmap_offset;
524
525 if (ubd_dev->file && ubd_dev->cow.file) {
526 file = ubd_dev->cow.file;
527
528 goto out;
529 }
530
531 fd = os_open_file(ubd_dev->file, global_openflags, 0);
532 if (fd < 0)
533 return fd;
534
535 err = read_cow_header(file_reader, &fd, &version, &backing_file, \
536 &mtime, &size, &sector_size, &align, &bitmap_offset);
537 os_close_file(fd);
538
539 if(err == -EINVAL)
540 file = ubd_dev->file;
541 else
542 file = backing_file;
543
544out:
Jeff Dikedc764e52007-05-06 14:51:41 -0700545 return os_file_size(file, size_out);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546}
547
WANG Cong5dc62b12008-04-28 02:13:58 -0700548static int read_cow_bitmap(int fd, void *buf, int offset, int len)
549{
550 int err;
551
552 err = os_seek_file(fd, offset);
553 if (err < 0)
554 return err;
555
556 err = os_read_file(fd, buf, len);
557 if (err < 0)
558 return err;
559
560 return 0;
561}
562
563static int backing_file_mismatch(char *file, __u64 size, time_t mtime)
564{
565 unsigned long modtime;
566 unsigned long long actual;
567 int err;
568
569 err = os_file_modtime(file, &modtime);
570 if (err < 0) {
571 printk(KERN_ERR "Failed to get modification time of backing "
572 "file \"%s\", err = %d\n", file, -err);
573 return err;
574 }
575
576 err = os_file_size(file, &actual);
577 if (err < 0) {
578 printk(KERN_ERR "Failed to get size of backing file \"%s\", "
579 "err = %d\n", file, -err);
580 return err;
581 }
582
583 if (actual != size) {
584 /*__u64 can be a long on AMD64 and with %lu GCC complains; so
585 * the typecast.*/
586 printk(KERN_ERR "Size mismatch (%llu vs %llu) of COW header "
587 "vs backing file\n", (unsigned long long) size, actual);
588 return -EINVAL;
589 }
590 if (modtime != mtime) {
591 printk(KERN_ERR "mtime mismatch (%ld vs %ld) of COW header vs "
592 "backing file\n", mtime, modtime);
593 return -EINVAL;
594 }
595 return 0;
596}
597
598static int path_requires_switch(char *from_cmdline, char *from_cow, char *cow)
599{
600 struct uml_stat buf1, buf2;
601 int err;
602
603 if (from_cmdline == NULL)
604 return 0;
605 if (!strcmp(from_cmdline, from_cow))
606 return 0;
607
608 err = os_stat_file(from_cmdline, &buf1);
609 if (err < 0) {
610 printk(KERN_ERR "Couldn't stat '%s', err = %d\n", from_cmdline,
611 -err);
612 return 0;
613 }
614 err = os_stat_file(from_cow, &buf2);
615 if (err < 0) {
616 printk(KERN_ERR "Couldn't stat '%s', err = %d\n", from_cow,
617 -err);
618 return 1;
619 }
620 if ((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino))
621 return 0;
622
623 printk(KERN_ERR "Backing file mismatch - \"%s\" requested, "
624 "\"%s\" specified in COW header of \"%s\"\n",
625 from_cmdline, from_cow, cow);
626 return 1;
627}
628
629static int open_ubd_file(char *file, struct openflags *openflags, int shared,
630 char **backing_file_out, int *bitmap_offset_out,
631 unsigned long *bitmap_len_out, int *data_offset_out,
632 int *create_cow_out)
633{
634 time_t mtime;
635 unsigned long long size;
636 __u32 version, align;
637 char *backing_file;
638 int fd, err, sectorsize, asked_switch, mode = 0644;
639
640 fd = os_open_file(file, *openflags, mode);
641 if (fd < 0) {
642 if ((fd == -ENOENT) && (create_cow_out != NULL))
643 *create_cow_out = 1;
644 if (!openflags->w ||
645 ((fd != -EROFS) && (fd != -EACCES)))
646 return fd;
647 openflags->w = 0;
648 fd = os_open_file(file, *openflags, mode);
649 if (fd < 0)
650 return fd;
651 }
652
653 if (shared)
654 printk(KERN_INFO "Not locking \"%s\" on the host\n", file);
655 else {
656 err = os_lock_file(fd, openflags->w);
657 if (err < 0) {
658 printk(KERN_ERR "Failed to lock '%s', err = %d\n",
659 file, -err);
660 goto out_close;
661 }
662 }
663
664 /* Successful return case! */
665 if (backing_file_out == NULL)
666 return fd;
667
668 err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime,
669 &size, &sectorsize, &align, bitmap_offset_out);
670 if (err && (*backing_file_out != NULL)) {
671 printk(KERN_ERR "Failed to read COW header from COW file "
672 "\"%s\", errno = %d\n", file, -err);
673 goto out_close;
674 }
675 if (err)
676 return fd;
677
678 asked_switch = path_requires_switch(*backing_file_out, backing_file,
679 file);
680
681 /* Allow switching only if no mismatch. */
682 if (asked_switch && !backing_file_mismatch(*backing_file_out, size,
683 mtime)) {
684 printk(KERN_ERR "Switching backing file to '%s'\n",
685 *backing_file_out);
686 err = write_cow_header(file, fd, *backing_file_out,
687 sectorsize, align, &size);
688 if (err) {
689 printk(KERN_ERR "Switch failed, errno = %d\n", -err);
690 goto out_close;
691 }
692 } else {
693 *backing_file_out = backing_file;
694 err = backing_file_mismatch(*backing_file_out, size, mtime);
695 if (err)
696 goto out_close;
697 }
698
699 cow_sizes(version, size, sectorsize, align, *bitmap_offset_out,
700 bitmap_len_out, data_offset_out);
701
702 return fd;
703 out_close:
704 os_close_file(fd);
705 return err;
706}
707
708static int create_cow_file(char *cow_file, char *backing_file,
709 struct openflags flags,
710 int sectorsize, int alignment, int *bitmap_offset_out,
711 unsigned long *bitmap_len_out, int *data_offset_out)
712{
713 int err, fd;
714
715 flags.c = 1;
716 fd = open_ubd_file(cow_file, &flags, 0, NULL, NULL, NULL, NULL, NULL);
717 if (fd < 0) {
718 err = fd;
719 printk(KERN_ERR "Open of COW file '%s' failed, errno = %d\n",
720 cow_file, -err);
721 goto out;
722 }
723
724 err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment,
725 bitmap_offset_out, bitmap_len_out,
726 data_offset_out);
727 if (!err)
728 return fd;
729 os_close_file(fd);
730 out:
731 return err;
732}
733
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800734static void ubd_close_dev(struct ubd *ubd_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800736 os_close_file(ubd_dev->fd);
737 if(ubd_dev->cow.file == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 return;
739
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800740 os_close_file(ubd_dev->cow.fd);
741 vfree(ubd_dev->cow.bitmap);
742 ubd_dev->cow.bitmap = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743}
744
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800745static int ubd_open_dev(struct ubd *ubd_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746{
747 struct openflags flags;
748 char **back_ptr;
749 int err, create_cow, *create_ptr;
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800750 int fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800752 ubd_dev->openflags = ubd_dev->boot_openflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 create_cow = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800754 create_ptr = (ubd_dev->cow.file != NULL) ? &create_cow : NULL;
755 back_ptr = ubd_dev->no_cow ? NULL : &ubd_dev->cow.file;
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800756
757 fd = open_ubd_file(ubd_dev->file, &ubd_dev->openflags, ubd_dev->shared,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800758 back_ptr, &ubd_dev->cow.bitmap_offset,
759 &ubd_dev->cow.bitmap_len, &ubd_dev->cow.data_offset,
Jeff Dike6c29256c2006-03-27 01:14:37 -0800760 create_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800762 if((fd == -ENOENT) && create_cow){
763 fd = create_cow_file(ubd_dev->file, ubd_dev->cow.file,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800764 ubd_dev->openflags, 1 << 9, PAGE_SIZE,
765 &ubd_dev->cow.bitmap_offset,
766 &ubd_dev->cow.bitmap_len,
767 &ubd_dev->cow.data_offset);
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800768 if(fd >= 0){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 printk(KERN_INFO "Creating \"%s\" as COW file for "
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800770 "\"%s\"\n", ubd_dev->file, ubd_dev->cow.file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 }
772 }
773
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800774 if(fd < 0){
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800775 printk("Failed to open '%s', errno = %d\n", ubd_dev->file,
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800776 -fd);
777 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 }
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800779 ubd_dev->fd = fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800781 if(ubd_dev->cow.file != NULL){
Martin K. Petersen086fa5f2010-02-26 00:20:38 -0500782 blk_queue_max_hw_sectors(ubd_dev->queue, 8 * sizeof(long));
Jeff Dikef4768ff2007-08-22 14:01:53 -0700783
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 err = -ENOMEM;
Jesper Juhlda2486b2007-10-16 01:27:19 -0700785 ubd_dev->cow.bitmap = vmalloc(ubd_dev->cow.bitmap_len);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800786 if(ubd_dev->cow.bitmap == NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 printk(KERN_ERR "Failed to vmalloc COW bitmap\n");
788 goto error;
789 }
790 flush_tlb_kernel_vm();
791
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800792 err = read_cow_bitmap(ubd_dev->fd, ubd_dev->cow.bitmap,
793 ubd_dev->cow.bitmap_offset,
794 ubd_dev->cow.bitmap_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 if(err < 0)
796 goto error;
797
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800798 flags = ubd_dev->openflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 flags.w = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800800 err = open_ubd_file(ubd_dev->cow.file, &flags, ubd_dev->shared, NULL,
Jeff Dike6c29256c2006-03-27 01:14:37 -0800801 NULL, NULL, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 if(err < 0) goto error;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800803 ubd_dev->cow.fd = err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 }
Jeff Dikedc764e52007-05-06 14:51:41 -0700805 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 error:
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800807 os_close_file(ubd_dev->fd);
Jeff Dikedc764e52007-05-06 14:51:41 -0700808 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809}
810
Jeff Dike2e3f5252007-05-06 14:51:29 -0700811static void ubd_device_release(struct device *dev)
812{
Greg Kroah-Hartman8691b972009-05-04 12:40:54 -0700813 struct ubd *ubd_dev = dev_get_drvdata(dev);
Jeff Dike2e3f5252007-05-06 14:51:29 -0700814
815 blk_cleanup_queue(ubd_dev->queue);
816 *ubd_dev = ((struct ubd) DEFAULT_UBD);
817}
818
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800819static int ubd_disk_register(int major, u64 size, int unit,
Jeff Dikeb8831a12007-02-10 01:44:17 -0800820 struct gendisk **disk_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821{
822 struct gendisk *disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823
824 disk = alloc_disk(1 << UBD_SHIFT);
825 if(disk == NULL)
Jeff Dikedc764e52007-05-06 14:51:41 -0700826 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827
828 disk->major = major;
829 disk->first_minor = unit << UBD_SHIFT;
830 disk->fops = &ubd_blops;
831 set_capacity(disk, size / 512);
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700832 if (major == UBD_MAJOR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 sprintf(disk->disk_name, "ubd%c", 'a' + unit);
Greg Kroah-Hartmance7b0f42005-06-20 21:15:16 -0700834 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 sprintf(disk->disk_name, "ubd_fake%d", unit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836
837 /* sysfs register (not for ide fake devices) */
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700838 if (major == UBD_MAJOR) {
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800839 ubd_devs[unit].pdev.id = unit;
840 ubd_devs[unit].pdev.name = DRIVER_NAME;
Jeff Dike2e3f5252007-05-06 14:51:29 -0700841 ubd_devs[unit].pdev.dev.release = ubd_device_release;
Greg Kroah-Hartman8691b972009-05-04 12:40:54 -0700842 dev_set_drvdata(&ubd_devs[unit].pdev.dev, &ubd_devs[unit]);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800843 platform_device_register(&ubd_devs[unit].pdev);
844 disk->driverfs_dev = &ubd_devs[unit].pdev.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 }
846
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800847 disk->private_data = &ubd_devs[unit];
Jeff Dike62f96cb2007-02-10 01:44:16 -0800848 disk->queue = ubd_devs[unit].queue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 add_disk(disk);
850
851 *disk_out = disk;
852 return 0;
853}
854
855#define ROUND_BLOCK(n) ((n + ((1 << 9) - 1)) & (-1 << 9))
856
Jeff Dikef28169d2007-02-10 01:43:53 -0800857static int ubd_add(int n, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800859 struct ubd *ubd_dev = &ubd_devs[n];
Jeff Dikef28169d2007-02-10 01:43:53 -0800860 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800862 if(ubd_dev->file == NULL)
Jeff Dikeec7cf782005-09-03 15:57:29 -0700863 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800865 err = ubd_file_size(ubd_dev, &ubd_dev->size);
Jeff Dikef28169d2007-02-10 01:43:53 -0800866 if(err < 0){
867 *error_out = "Couldn't determine size of device's file";
Jeff Dike80c13742006-09-29 01:58:51 -0700868 goto out;
Jeff Dikef28169d2007-02-10 01:43:53 -0800869 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800871 ubd_dev->size = ROUND_BLOCK(ubd_dev->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872
Jeff Dikea0044bd2007-05-06 14:51:36 -0700873 INIT_LIST_HEAD(&ubd_dev->restart);
WANG Cong4f40c052007-11-05 14:50:59 -0800874 sg_init_table(ubd_dev->sg, MAX_SG);
Jeff Dikea0044bd2007-05-06 14:51:36 -0700875
Jeff Dike62f96cb2007-02-10 01:44:16 -0800876 err = -ENOMEM;
877 ubd_dev->queue = blk_init_queue(do_ubd_request, &ubd_dev->lock);
878 if (ubd_dev->queue == NULL) {
879 *error_out = "Failed to initialize device queue";
Jeff Dike80c13742006-09-29 01:58:51 -0700880 goto out;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800881 }
882 ubd_dev->queue->queuedata = ubd_dev;
883
Martin K. Petersen8a783622010-02-26 00:20:39 -0500884 blk_queue_max_segments(ubd_dev->queue, MAX_SG);
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700885 err = ubd_disk_register(UBD_MAJOR, ubd_dev->size, n, &ubd_gendisk[n]);
Jeff Dike62f96cb2007-02-10 01:44:16 -0800886 if(err){
887 *error_out = "Failed to register device";
888 goto out_cleanup;
889 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800890
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700891 if (fake_major != UBD_MAJOR)
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800892 ubd_disk_register(fake_major, ubd_dev->size, n,
Jeff Dike62f96cb2007-02-10 01:44:16 -0800893 &fake_gendisk[n]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894
Jeff Dike83380cc2008-02-04 22:31:18 -0800895 /*
896 * Perhaps this should also be under the "if (fake_major)" above
897 * using the fake_disk->disk_name
898 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 if (fake_ide)
900 make_ide_entries(ubd_gendisk[n]->disk_name);
901
Jeff Dikeec7cf782005-09-03 15:57:29 -0700902 err = 0;
Jeff Dikeec7cf782005-09-03 15:57:29 -0700903out:
904 return err;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800905
906out_cleanup:
907 blk_cleanup_queue(ubd_dev->queue);
908 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909}
910
Jeff Dikef28169d2007-02-10 01:43:53 -0800911static int ubd_config(char *str, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912{
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800913 int n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914
Jeff Dikef28169d2007-02-10 01:43:53 -0800915 /* This string is possibly broken up and stored, so it's only
916 * freed if ubd_setup_common fails, or if only general options
917 * were set.
918 */
Jeff Dike970d6e32006-01-06 00:18:48 -0800919 str = kstrdup(str, GFP_KERNEL);
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800920 if (str == NULL) {
Jeff Dikef28169d2007-02-10 01:43:53 -0800921 *error_out = "Failed to allocate memory";
922 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 }
Jeff Dikef28169d2007-02-10 01:43:53 -0800924
925 ret = ubd_setup_common(str, &n, error_out);
926 if (ret)
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800927 goto err_free;
Jeff Dikef28169d2007-02-10 01:43:53 -0800928
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800929 if (n == -1) {
930 ret = 0;
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800931 goto err_free;
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800932 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933
Jeff Dikedc764e52007-05-06 14:51:41 -0700934 mutex_lock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -0800935 ret = ubd_add(n, error_out);
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800936 if (ret)
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800937 ubd_devs[n].file = NULL;
Jeff Dikedc764e52007-05-06 14:51:41 -0700938 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800940out:
Jeff Dikedc764e52007-05-06 14:51:41 -0700941 return ret;
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800942
943err_free:
944 kfree(str);
945 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946}
947
948static int ubd_get_config(char *name, char *str, int size, char **error_out)
949{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800950 struct ubd *ubd_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 int n, len = 0;
952
953 n = parse_unit(&name);
954 if((n >= MAX_DEV) || (n < 0)){
955 *error_out = "ubd_get_config : device number out of range";
Jeff Dikedc764e52007-05-06 14:51:41 -0700956 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 }
958
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800959 ubd_dev = &ubd_devs[n];
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800960 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800962 if(ubd_dev->file == NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 CONFIG_CHUNK(str, size, len, "", 1);
964 goto out;
965 }
966
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800967 CONFIG_CHUNK(str, size, len, ubd_dev->file, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800969 if(ubd_dev->cow.file != NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 CONFIG_CHUNK(str, size, len, ",", 0);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800971 CONFIG_CHUNK(str, size, len, ubd_dev->cow.file, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 }
973 else CONFIG_CHUNK(str, size, len, "", 1);
974
975 out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800976 mutex_unlock(&ubd_lock);
Jeff Dikedc764e52007-05-06 14:51:41 -0700977 return len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978}
979
Jeff Dike29d56cf2005-06-25 14:55:25 -0700980static int ubd_id(char **str, int *start_out, int *end_out)
981{
Jeff Dikedc764e52007-05-06 14:51:41 -0700982 int n;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700983
984 n = parse_unit(str);
Jeff Dikedc764e52007-05-06 14:51:41 -0700985 *start_out = 0;
986 *end_out = MAX_DEV - 1;
987 return n;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700988}
989
Jeff Dikef28169d2007-02-10 01:43:53 -0800990static int ubd_remove(int n, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991{
Jeff Dike2e3f5252007-05-06 14:51:29 -0700992 struct gendisk *disk = ubd_gendisk[n];
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800993 struct ubd *ubd_dev;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700994 int err = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800996 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800998 ubd_dev = &ubd_devs[n];
Jeff Dike29d56cf2005-06-25 14:55:25 -0700999
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001000 if(ubd_dev->file == NULL)
Jeff Dike29d56cf2005-06-25 14:55:25 -07001001 goto out;
1002
1003 /* you cannot remove a open disk */
1004 err = -EBUSY;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001005 if(ubd_dev->count > 0)
Jeff Dike29d56cf2005-06-25 14:55:25 -07001006 goto out;
1007
Jeff Dikedc764e52007-05-06 14:51:41 -07001008 ubd_gendisk[n] = NULL;
Jeff Dikeb47d2de2007-05-06 14:51:01 -07001009 if(disk != NULL){
1010 del_gendisk(disk);
1011 put_disk(disk);
1012 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013
1014 if(fake_gendisk[n] != NULL){
1015 del_gendisk(fake_gendisk[n]);
1016 put_disk(fake_gendisk[n]);
1017 fake_gendisk[n] = NULL;
1018 }
1019
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 err = 0;
Jeff Dike2e3f5252007-05-06 14:51:29 -07001021 platform_device_unregister(&ubd_dev->pdev);
Jeff Dike29d56cf2005-06-25 14:55:25 -07001022out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -08001023 mutex_unlock(&ubd_lock);
Jeff Dike29d56cf2005-06-25 14:55:25 -07001024 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025}
1026
Jeff Dikef28169d2007-02-10 01:43:53 -08001027/* All these are called by mconsole in process context and without
Jeff Dikeb8831a12007-02-10 01:44:17 -08001028 * ubd-specific locks. The structure itself is const except for .list.
Jeff Dikef28169d2007-02-10 01:43:53 -08001029 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030static struct mc_device ubd_mc = {
Jeff Dike84f48d42007-02-10 01:44:01 -08001031 .list = LIST_HEAD_INIT(ubd_mc.list),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 .name = "ubd",
1033 .config = ubd_config,
Jeff Dikedc764e52007-05-06 14:51:41 -07001034 .get_config = ubd_get_config,
Jeff Dike29d56cf2005-06-25 14:55:25 -07001035 .id = ubd_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 .remove = ubd_remove,
1037};
1038
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001039static int __init ubd_mc_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040{
1041 mconsole_register_dev(&ubd_mc);
1042 return 0;
1043}
1044
1045__initcall(ubd_mc_init);
1046
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001047static int __init ubd0_init(void)
1048{
1049 struct ubd *ubd_dev = &ubd_devs[0];
1050
Jeff Dikeb8831a12007-02-10 01:44:17 -08001051 mutex_lock(&ubd_lock);
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001052 if(ubd_dev->file == NULL)
1053 ubd_dev->file = "root_fs";
Jeff Dikeb8831a12007-02-10 01:44:17 -08001054 mutex_unlock(&ubd_lock);
1055
Jeff Dikedc764e52007-05-06 14:51:41 -07001056 return 0;
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001057}
1058
1059__initcall(ubd0_init);
1060
Jeff Dikeb8831a12007-02-10 01:44:17 -08001061/* Used in ubd_init, which is an initcall */
Russell King3ae5eae2005-11-09 22:32:44 +00001062static struct platform_driver ubd_driver = {
1063 .driver = {
1064 .name = DRIVER_NAME,
1065 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066};
1067
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001068static int __init ubd_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069{
Jeff Dikef28169d2007-02-10 01:43:53 -08001070 char *error;
1071 int i, err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072
Christoph Hellwig792dd4f2009-03-31 15:23:39 -07001073 if (register_blkdev(UBD_MAJOR, "ubd"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 return -1;
1075
Christoph Hellwig792dd4f2009-03-31 15:23:39 -07001076 if (fake_major != UBD_MAJOR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 char name[sizeof("ubd_nnn\0")];
1078
1079 snprintf(name, sizeof(name), "ubd_%d", fake_major);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 if (register_blkdev(fake_major, "ubd"))
1081 return -1;
1082 }
Russell King3ae5eae2005-11-09 22:32:44 +00001083 platform_driver_register(&ubd_driver);
Jeff Dikedc764e52007-05-06 14:51:41 -07001084 mutex_lock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -08001085 for (i = 0; i < MAX_DEV; i++){
1086 err = ubd_add(i, &error);
1087 if(err)
1088 printk(KERN_ERR "Failed to initialize ubd device %d :"
1089 "%s\n", i, error);
1090 }
Jeff Dikedc764e52007-05-06 14:51:41 -07001091 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 return 0;
1093}
1094
1095late_initcall(ubd_init);
1096
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001097static int __init ubd_driver_init(void){
Jeff Dike91acb212005-10-10 23:10:32 -04001098 unsigned long stack;
1099 int err;
1100
1101 /* Set by CONFIG_BLK_DEV_UBD_SYNC or ubd=sync.*/
1102 if(global_openflags.s){
1103 printk(KERN_INFO "ubd: Synchronous mode\n");
1104 /* Letting ubd=sync be like using ubd#s= instead of ubd#= is
1105 * enough. So use anyway the io thread. */
1106 }
1107 stack = alloc_stack(0, 0);
Jeff Dike6c29256c2006-03-27 01:14:37 -08001108 io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *),
Jeff Dike91acb212005-10-10 23:10:32 -04001109 &thread_fd);
1110 if(io_pid < 0){
Jeff Dike6c29256c2006-03-27 01:14:37 -08001111 printk(KERN_ERR
Jeff Dike91acb212005-10-10 23:10:32 -04001112 "ubd : Failed to start I/O thread (errno = %d) - "
1113 "falling back to synchronous I/O\n", -io_pid);
1114 io_pid = -1;
Jeff Dikedc764e52007-05-06 14:51:41 -07001115 return 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001116 }
Jeff Dike6c29256c2006-03-27 01:14:37 -08001117 err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001118 IRQF_DISABLED, "ubd", ubd_devs);
Jeff Dike91acb212005-10-10 23:10:32 -04001119 if(err != 0)
1120 printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err);
Jeff Dikef4c57a72006-03-31 02:30:10 -08001121 return 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001122}
1123
1124device_initcall(ubd_driver_init);
1125
Al Viroa625c992008-03-02 09:16:26 -05001126static int ubd_open(struct block_device *bdev, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127{
Al Viroa625c992008-03-02 09:16:26 -05001128 struct gendisk *disk = bdev->bd_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001129 struct ubd *ubd_dev = disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 int err = 0;
1131
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){
1134 err = ubd_open_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 if(err){
1136 printk(KERN_ERR "%s: Can't open \"%s\": errno = %d\n",
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001137 disk->disk_name, ubd_dev->file, -err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 goto out;
1139 }
1140 }
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001141 ubd_dev->count++;
1142 set_disk_ro(disk, !ubd_dev->openflags.w);
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -07001143
1144 /* This should no more be needed. And it didn't work anyway to exclude
1145 * read-write remounting of filesystems.*/
Al Viroa625c992008-03-02 09:16:26 -05001146 /*if((mode & FMODE_WRITE) && !ubd_dev->openflags.w){
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -08001147 if(--ubd_dev->count == 0) ubd_close_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 err = -EROFS;
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -07001149 }*/
Arnd Bergmann6e9624b2010-08-07 18:25:34 +02001150out:
Arnd Bergmann9a181c52010-09-11 18:38:03 +02001151 mutex_unlock(&ubd_mutex);
Jeff Dikedc764e52007-05-06 14:51:41 -07001152 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153}
1154
Al Viroa625c992008-03-02 09:16:26 -05001155static int ubd_release(struct gendisk *disk, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001157 struct ubd *ubd_dev = disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158
Arnd Bergmann9a181c52010-09-11 18:38:03 +02001159 mutex_lock(&ubd_mutex);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001160 if(--ubd_dev->count == 0)
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -08001161 ubd_close_dev(ubd_dev);
Arnd Bergmann9a181c52010-09-11 18:38:03 +02001162 mutex_unlock(&ubd_mutex);
Jeff Dikedc764e52007-05-06 14:51:41 -07001163 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164}
1165
Jeff Dike91acb212005-10-10 23:10:32 -04001166static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask,
1167 __u64 *cow_offset, unsigned long *bitmap,
1168 __u64 bitmap_offset, unsigned long *bitmap_words,
1169 __u64 bitmap_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170{
Jeff Dike91acb212005-10-10 23:10:32 -04001171 __u64 sector = io_offset >> 9;
1172 int i, update_bitmap = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173
Jeff Dike91acb212005-10-10 23:10:32 -04001174 for(i = 0; i < length >> 9; i++){
1175 if(cow_mask != NULL)
1176 ubd_set_bit(i, (unsigned char *) cow_mask);
1177 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
1178 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179
Jeff Dike91acb212005-10-10 23:10:32 -04001180 update_bitmap = 1;
1181 ubd_set_bit(sector + i, (unsigned char *) bitmap);
1182 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183
Jeff Dike91acb212005-10-10 23:10:32 -04001184 if(!update_bitmap)
1185 return;
1186
1187 *cow_offset = sector / (sizeof(unsigned long) * 8);
1188
1189 /* This takes care of the case where we're exactly at the end of the
1190 * device, and *cow_offset + 1 is off the end. So, just back it up
1191 * by one word. Thanks to Lynn Kerby for the fix and James McMechan
1192 * for the original diagnosis.
1193 */
Jiri Olsa6d074242008-05-12 14:01:56 -07001194 if (*cow_offset == (DIV_ROUND_UP(bitmap_len,
1195 sizeof(unsigned long)) - 1))
Jeff Dike91acb212005-10-10 23:10:32 -04001196 (*cow_offset)--;
1197
1198 bitmap_words[0] = bitmap[*cow_offset];
1199 bitmap_words[1] = bitmap[*cow_offset + 1];
1200
1201 *cow_offset *= sizeof(unsigned long);
1202 *cow_offset += bitmap_offset;
1203}
1204
1205static void cowify_req(struct io_thread_req *req, unsigned long *bitmap,
1206 __u64 bitmap_offset, __u64 bitmap_len)
1207{
1208 __u64 sector = req->offset >> 9;
1209 int i;
1210
1211 if(req->length > (sizeof(req->sector_mask) * 8) << 9)
1212 panic("Operation too long");
1213
1214 if(req->op == UBD_READ) {
1215 for(i = 0; i < req->length >> 9; i++){
1216 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
Jeff Dike6c29256c2006-03-27 01:14:37 -08001217 ubd_set_bit(i, (unsigned char *)
Jeff Dike91acb212005-10-10 23:10:32 -04001218 &req->sector_mask);
Jeff Dikedc764e52007-05-06 14:51:41 -07001219 }
Jeff Dike91acb212005-10-10 23:10:32 -04001220 }
1221 else cowify_bitmap(req->offset, req->length, &req->sector_mask,
1222 &req->cow_offset, bitmap, bitmap_offset,
1223 req->bitmap_words, bitmap_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224}
1225
Jeff Dike62f96cb2007-02-10 01:44:16 -08001226/* Called with dev->lock held */
Jeff Dikea0044bd2007-05-06 14:51:36 -07001227static void prepare_request(struct request *req, struct io_thread_req *io_req,
1228 unsigned long long offset, int page_offset,
1229 int len, struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230{
1231 struct gendisk *disk = req->rq_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001232 struct ubd *ubd_dev = disk->private_data;
Jeff Dike91acb212005-10-10 23:10:32 -04001233
Jeff Dike62f96cb2007-02-10 01:44:16 -08001234 io_req->req = req;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001235 io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd :
1236 ubd_dev->fd;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001237 io_req->fds[1] = ubd_dev->fd;
Jeff Dike91acb212005-10-10 23:10:32 -04001238 io_req->cow_offset = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 io_req->offset = offset;
1240 io_req->length = len;
1241 io_req->error = 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001242 io_req->sector_mask = 0;
1243
1244 io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 io_req->offsets[0] = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001246 io_req->offsets[1] = ubd_dev->cow.data_offset;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001247 io_req->buffer = page_address(page) + page_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248 io_req->sectorsize = 1 << 9;
1249
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001250 if(ubd_dev->cow.file != NULL)
Jeff Dikea0044bd2007-05-06 14:51:36 -07001251 cowify_req(io_req, ubd_dev->cow.bitmap,
1252 ubd_dev->cow.bitmap_offset, ubd_dev->cow.bitmap_len);
Jeff Dike91acb212005-10-10 23:10:32 -04001253
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254}
1255
Jeff Dike62f96cb2007-02-10 01:44:16 -08001256/* Called with dev->lock held */
Jens Axboe165125e2007-07-24 09:28:11 +02001257static void do_ubd_request(struct request_queue *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258{
Jeff Dike2adcec22007-05-06 14:51:37 -07001259 struct io_thread_req *io_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 struct request *req;
Tejun Heof81f2f72009-04-28 13:06:10 +09001261 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262
Jeff Dikea0044bd2007-05-06 14:51:36 -07001263 while(1){
Jeff Dike2a9529a2007-03-29 01:20:27 -07001264 struct ubd *dev = q->queuedata;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001265 if(dev->end_sg == 0){
Tejun Heo9934c8c2009-05-08 11:54:16 +09001266 struct request *req = blk_fetch_request(q);
Jeff Dikea0044bd2007-05-06 14:51:36 -07001267 if(req == NULL)
1268 return;
1269
1270 dev->request = req;
Tejun Heo47526902010-10-15 12:56:21 +02001271 dev->rq_pos = blk_rq_pos(req);
Jeff Dikea0044bd2007-05-06 14:51:36 -07001272 dev->start_sg = 0;
1273 dev->end_sg = blk_rq_map_sg(q, req, dev->sg);
Jeff Dike91acb212005-10-10 23:10:32 -04001274 }
Jeff Dikea0044bd2007-05-06 14:51:36 -07001275
1276 req = dev->request;
1277 while(dev->start_sg < dev->end_sg){
1278 struct scatterlist *sg = &dev->sg[dev->start_sg];
1279
Jeff Dike2adcec22007-05-06 14:51:37 -07001280 io_req = kmalloc(sizeof(struct io_thread_req),
Peter Zijlstra990c5582007-05-06 14:51:38 -07001281 GFP_ATOMIC);
Jeff Dike2adcec22007-05-06 14:51:37 -07001282 if(io_req == NULL){
1283 if(list_empty(&dev->restart))
1284 list_add(&dev->restart, &restart);
1285 return;
1286 }
1287 prepare_request(req, io_req,
Tejun Heo47526902010-10-15 12:56:21 +02001288 (unsigned long long)dev->rq_pos << 9,
Jens Axboe45711f12007-10-22 21:19:53 +02001289 sg->offset, sg->length, sg_page(sg));
Jeff Dikea0044bd2007-05-06 14:51:36 -07001290
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001291 n = os_write_file(thread_fd, &io_req,
1292 sizeof(struct io_thread_req *));
Jeff Dike2adcec22007-05-06 14:51:37 -07001293 if(n != sizeof(struct io_thread_req *)){
Jeff Dikea0044bd2007-05-06 14:51:36 -07001294 if(n != -EAGAIN)
1295 printk("write to io thread failed, "
1296 "errno = %d\n", -n);
1297 else if(list_empty(&dev->restart))
1298 list_add(&dev->restart, &restart);
Miklos Szeredi12429bf2007-11-28 16:21:52 -08001299 kfree(io_req);
Jeff Dikea0044bd2007-05-06 14:51:36 -07001300 return;
1301 }
1302
Tejun Heo47526902010-10-15 12:56:21 +02001303 dev->rq_pos += sg->length >> 9;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001304 dev->start_sg++;
1305 }
1306 dev->end_sg = 0;
1307 dev->request = NULL;
Jeff Dike91acb212005-10-10 23:10:32 -04001308 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309}
1310
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001311static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
1312{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001313 struct ubd *ubd_dev = bdev->bd_disk->private_data;
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001314
1315 geo->heads = 128;
1316 geo->sectors = 32;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001317 geo->cylinders = ubd_dev->size / (128 * 32 * 512);
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001318 return 0;
1319}
1320
Al Viroa625c992008-03-02 09:16:26 -05001321static int ubd_ioctl(struct block_device *bdev, fmode_t mode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 unsigned int cmd, unsigned long arg)
1323{
Al Viroa625c992008-03-02 09:16:26 -05001324 struct ubd *ubd_dev = bdev->bd_disk->private_data;
Bartlomiej Zolnierkiewicz73855e12009-04-01 21:42:21 +02001325 u16 ubd_id[ATA_ID_WORDS];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326
1327 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 struct cdrom_volctrl volume;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 case HDIO_GET_IDENTITY:
Bartlomiej Zolnierkiewicz73855e12009-04-01 21:42:21 +02001330 memset(&ubd_id, 0, ATA_ID_WORDS * 2);
1331 ubd_id[ATA_ID_CYLS] = ubd_dev->size / (128 * 32 * 512);
1332 ubd_id[ATA_ID_HEADS] = 128;
1333 ubd_id[ATA_ID_SECTORS] = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 if(copy_to_user((char __user *) arg, (char *) &ubd_id,
1335 sizeof(ubd_id)))
Jeff Dikedc764e52007-05-06 14:51:41 -07001336 return -EFAULT;
1337 return 0;
Jeff Dikeb8831a12007-02-10 01:44:17 -08001338
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 case CDROMVOLREAD:
1340 if(copy_from_user(&volume, (char __user *) arg, sizeof(volume)))
Jeff Dikedc764e52007-05-06 14:51:41 -07001341 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 volume.channel0 = 255;
1343 volume.channel1 = 255;
1344 volume.channel2 = 255;
1345 volume.channel3 = 255;
1346 if(copy_to_user((char __user *) arg, &volume, sizeof(volume)))
Jeff Dikedc764e52007-05-06 14:51:41 -07001347 return -EFAULT;
1348 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 }
Jeff Dikedc764e52007-05-06 14:51:41 -07001350 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351}
1352
Jeff Dike91acb212005-10-10 23:10:32 -04001353static int update_bitmap(struct io_thread_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354{
Jeff Dike91acb212005-10-10 23:10:32 -04001355 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356
Jeff Dike91acb212005-10-10 23:10:32 -04001357 if(req->cow_offset == -1)
Jeff Dikedc764e52007-05-06 14:51:41 -07001358 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359
Jeff Dike91acb212005-10-10 23:10:32 -04001360 n = os_seek_file(req->fds[1], req->cow_offset);
1361 if(n < 0){
1362 printk("do_io - bitmap lseek failed : err = %d\n", -n);
Jeff Dikedc764e52007-05-06 14:51:41 -07001363 return 1;
Jeff Dike91acb212005-10-10 23:10:32 -04001364 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001366 n = os_write_file(req->fds[1], &req->bitmap_words,
1367 sizeof(req->bitmap_words));
Jeff Dike91acb212005-10-10 23:10:32 -04001368 if(n != sizeof(req->bitmap_words)){
1369 printk("do_io - bitmap update failed, err = %d fd = %d\n", -n,
1370 req->fds[1]);
Jeff Dikedc764e52007-05-06 14:51:41 -07001371 return 1;
Jeff Dike91acb212005-10-10 23:10:32 -04001372 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373
Jeff Dikedc764e52007-05-06 14:51:41 -07001374 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375}
Jeff Dike91acb212005-10-10 23:10:32 -04001376
WANG Cong5dc62b12008-04-28 02:13:58 -07001377static void do_io(struct io_thread_req *req)
Jeff Dike91acb212005-10-10 23:10:32 -04001378{
1379 char *buf;
1380 unsigned long len;
1381 int n, nsectors, start, end, bit;
1382 int err;
1383 __u64 off;
1384
1385 nsectors = req->length / req->sectorsize;
1386 start = 0;
1387 do {
1388 bit = ubd_test_bit(start, (unsigned char *) &req->sector_mask);
1389 end = start;
1390 while((end < nsectors) &&
1391 (ubd_test_bit(end, (unsigned char *)
1392 &req->sector_mask) == bit))
1393 end++;
1394
1395 off = req->offset + req->offsets[bit] +
1396 start * req->sectorsize;
1397 len = (end - start) * req->sectorsize;
1398 buf = &req->buffer[start * req->sectorsize];
1399
1400 err = os_seek_file(req->fds[bit], off);
1401 if(err < 0){
1402 printk("do_io - lseek failed : err = %d\n", -err);
1403 req->error = 1;
1404 return;
1405 }
1406 if(req->op == UBD_READ){
1407 n = 0;
1408 do {
1409 buf = &buf[n];
1410 len -= n;
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001411 n = os_read_file(req->fds[bit], buf, len);
Jeff Dike91acb212005-10-10 23:10:32 -04001412 if (n < 0) {
1413 printk("do_io - read failed, err = %d "
1414 "fd = %d\n", -n, req->fds[bit]);
1415 req->error = 1;
1416 return;
1417 }
1418 } while((n < len) && (n != 0));
1419 if (n < len) memset(&buf[n], 0, len - n);
1420 } else {
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001421 n = os_write_file(req->fds[bit], buf, len);
Jeff Dike91acb212005-10-10 23:10:32 -04001422 if(n != len){
1423 printk("do_io - write failed err = %d "
1424 "fd = %d\n", -n, req->fds[bit]);
1425 req->error = 1;
1426 return;
1427 }
1428 }
1429
1430 start = end;
1431 } while(start < nsectors);
1432
1433 req->error = update_bitmap(req);
1434}
1435
1436/* Changed in start_io_thread, which is serialized by being called only
1437 * from ubd_init, which is an initcall.
1438 */
1439int kernel_fd = -1;
1440
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001441/* Only changed by the io thread. XXX: currently unused. */
1442static int io_count = 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001443
1444int io_thread(void *arg)
1445{
Jeff Dike2adcec22007-05-06 14:51:37 -07001446 struct io_thread_req *req;
Jeff Dike91acb212005-10-10 23:10:32 -04001447 int n;
1448
1449 ignore_sigwinch_sig();
1450 while(1){
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001451 n = os_read_file(kernel_fd, &req,
Jeff Dike2adcec22007-05-06 14:51:37 -07001452 sizeof(struct io_thread_req *));
1453 if(n != sizeof(struct io_thread_req *)){
Jeff Dike91acb212005-10-10 23:10:32 -04001454 if(n < 0)
1455 printk("io_thread - read failed, fd = %d, "
1456 "err = %d\n", kernel_fd, -n);
1457 else {
1458 printk("io_thread - short read, fd = %d, "
1459 "length = %d\n", kernel_fd, n);
1460 }
1461 continue;
1462 }
1463 io_count++;
Jeff Dike2adcec22007-05-06 14:51:37 -07001464 do_io(req);
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001465 n = os_write_file(kernel_fd, &req,
Jeff Dike2adcec22007-05-06 14:51:37 -07001466 sizeof(struct io_thread_req *));
1467 if(n != sizeof(struct io_thread_req *))
Jeff Dike91acb212005-10-10 23:10:32 -04001468 printk("io_thread - write failed, fd = %d, err = %d\n",
1469 kernel_fd, -n);
1470 }
Jeff Dike91acb212005-10-10 23:10:32 -04001471
Jeff Dike1b57e9c2006-01-06 00:18:49 -08001472 return 0;
1473}