blob: c1ff6903b622126789945164c0a33101d0a7943a [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"
34#include "linux/vmalloc.h"
35#include "linux/blkpg.h"
36#include "linux/genhd.h"
37#include "linux/spinlock.h"
Russell Kingd052d1b2005-10-29 19:07:23 +010038#include "linux/platform_device.h"
WANG Cong23464ff2007-10-24 13:07:11 +020039#include "linux/scatterlist.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070040#include "asm/segment.h"
41#include "asm/uaccess.h"
42#include "asm/irq.h"
43#include "asm/types.h"
44#include "asm/tlbflush.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070045#include "mem_user.h"
46#include "kern_util.h"
47#include "kern.h"
48#include "mconsole_kern.h"
49#include "init.h"
50#include "irq_user.h"
51#include "irq_kern.h"
52#include "ubd_user.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070053#include "os.h"
54#include "mem.h"
55#include "mem_kern.h"
56#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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101
Al Viroa625c992008-03-02 09:16:26 -0500102static int ubd_open(struct block_device *bdev, fmode_t mode);
103static int ubd_release(struct gendisk *disk, fmode_t mode);
104static int ubd_ioctl(struct block_device *bdev, fmode_t mode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 unsigned int cmd, unsigned long arg);
Christoph Hellwiga885c8c2006-01-08 01:02:50 -0800106static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107
Paolo 'Blaisorblade' Giarrusso97d88ac2006-10-30 22:07:03 -0800108#define MAX_DEV (16)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109
Alexey Dobriyan83d5cde2009-09-21 17:01:13 -0700110static const struct block_device_operations ubd_blops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 .owner = THIS_MODULE,
Al Viroa625c992008-03-02 09:16:26 -0500112 .open = ubd_open,
113 .release = ubd_release,
114 .ioctl = ubd_ioctl,
Christoph Hellwiga885c8c2006-01-08 01:02:50 -0800115 .getgeo = ubd_getgeo,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116};
117
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118/* Protected by ubd_lock */
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700119static int fake_major = UBD_MAJOR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120static struct gendisk *ubd_gendisk[MAX_DEV];
121static struct gendisk *fake_gendisk[MAX_DEV];
Jeff Dike6c29256c2006-03-27 01:14:37 -0800122
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123#ifdef CONFIG_BLK_DEV_UBD_SYNC
124#define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 1, .c = 0, \
125 .cl = 1 })
126#else
127#define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 0, .c = 0, \
128 .cl = 1 })
129#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130static struct openflags global_openflags = OPEN_FLAGS;
131
132struct cow {
Paolo 'Blaisorblade' Giarrusso2a9d32f2006-10-30 22:07:04 -0800133 /* backing file name */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 char *file;
Paolo 'Blaisorblade' Giarrusso2a9d32f2006-10-30 22:07:04 -0800135 /* backing file fd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 int fd;
137 unsigned long *bitmap;
138 unsigned long bitmap_len;
139 int bitmap_offset;
Jeff Dikedc764e52007-05-06 14:51:41 -0700140 int data_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141};
142
Jeff Dikea0044bd2007-05-06 14:51:36 -0700143#define MAX_SG 64
144
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145struct ubd {
Jeff Dikea0044bd2007-05-06 14:51:36 -0700146 struct list_head restart;
Paolo 'Blaisorblade' Giarrusso2a9d32f2006-10-30 22:07:04 -0800147 /* name (and fd, below) of the file opened for writing, either the
148 * backing or the cow file. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 char *file;
150 int count;
151 int fd;
152 __u64 size;
153 struct openflags boot_openflags;
154 struct openflags openflags;
Paolo 'Blaisorblade' Giarrusso84e945e2006-10-30 22:07:10 -0800155 unsigned shared:1;
156 unsigned no_cow:1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 struct cow cow;
158 struct platform_device pdev;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800159 struct request_queue *queue;
160 spinlock_t lock;
Jeff Dikea0044bd2007-05-06 14:51:36 -0700161 struct scatterlist sg[MAX_SG];
162 struct request *request;
163 int start_sg, end_sg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164};
165
166#define DEFAULT_COW { \
167 .file = NULL, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700168 .fd = -1, \
169 .bitmap = NULL, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 .bitmap_offset = 0, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700171 .data_offset = 0, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172}
173
174#define DEFAULT_UBD { \
175 .file = NULL, \
176 .count = 0, \
177 .fd = -1, \
178 .size = -1, \
179 .boot_openflags = OPEN_FLAGS, \
180 .openflags = OPEN_FLAGS, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700181 .no_cow = 0, \
Jeff Dike6c29256c2006-03-27 01:14:37 -0800182 .shared = 0, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700183 .cow = DEFAULT_COW, \
Jeff Dike62f96cb2007-02-10 01:44:16 -0800184 .lock = SPIN_LOCK_UNLOCKED, \
Jeff Dikea0044bd2007-05-06 14:51:36 -0700185 .request = NULL, \
186 .start_sg = 0, \
187 .end_sg = 0, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188}
189
Jeff Dikeb8831a12007-02-10 01:44:17 -0800190/* Protected by ubd_lock */
WANG Cong5dc62b12008-04-28 02:13:58 -0700191static struct ubd ubd_devs[MAX_DEV] = { [0 ... MAX_DEV - 1] = DEFAULT_UBD };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193/* Only changed by fake_ide_setup which is a setup */
194static int fake_ide = 0;
195static struct proc_dir_entry *proc_ide_root = NULL;
196static struct proc_dir_entry *proc_ide = NULL;
197
198static void make_proc_ide(void)
199{
200 proc_ide_root = proc_mkdir("ide", NULL);
201 proc_ide = proc_mkdir("ide0", proc_ide_root);
202}
203
Alexey Dobriyan6613c5e2009-12-14 18:00:11 -0800204static int fake_ide_media_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205{
Alexey Dobriyan6613c5e2009-12-14 18:00:11 -0800206 seq_puts(m, "disk\n");
207 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208}
209
Alexey Dobriyan6613c5e2009-12-14 18:00:11 -0800210static int fake_ide_media_proc_open(struct inode *inode, struct file *file)
211{
212 return single_open(file, fake_ide_media_proc_show, NULL);
213}
214
215static const struct file_operations fake_ide_media_proc_fops = {
216 .owner = THIS_MODULE,
217 .open = fake_ide_media_proc_open,
218 .read = seq_read,
219 .llseek = seq_lseek,
220 .release = single_release,
221};
222
WANG Congc0a92902008-02-04 22:30:41 -0800223static void make_ide_entries(const char *dev_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224{
225 struct proc_dir_entry *dir, *ent;
226 char name[64];
227
228 if(proc_ide_root == NULL) make_proc_ide();
229
230 dir = proc_mkdir(dev_name, proc_ide);
231 if(!dir) return;
232
Alexey Dobriyan6613c5e2009-12-14 18:00:11 -0800233 ent = proc_create("media", S_IRUGO, dir, &fake_ide_media_proc_fops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 if(!ent) return;
WANG Congc0a92902008-02-04 22:30:41 -0800235 snprintf(name, sizeof(name), "ide0/%s", dev_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 proc_symlink(dev_name, proc_ide_root, name);
237}
238
239static int fake_ide_setup(char *str)
240{
241 fake_ide = 1;
Jeff Dikedc764e52007-05-06 14:51:41 -0700242 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243}
244
245__setup("fake_ide", fake_ide_setup);
246
247__uml_help(fake_ide_setup,
248"fake_ide\n"
249" Create ide0 entries that map onto ubd devices.\n\n"
250);
251
252static int parse_unit(char **ptr)
253{
254 char *str = *ptr, *end;
255 int n = -1;
256
257 if(isdigit(*str)) {
258 n = simple_strtoul(str, &end, 0);
259 if(end == str)
Jeff Dikedc764e52007-05-06 14:51:41 -0700260 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 *ptr = end;
262 }
Paolo 'Blaisorblade' Giarrusso97d88ac2006-10-30 22:07:03 -0800263 else if (('a' <= *str) && (*str <= 'z')) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 n = *str - 'a';
265 str++;
266 *ptr = str;
267 }
Jeff Dikedc764e52007-05-06 14:51:41 -0700268 return n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269}
270
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800271/* If *index_out == -1 at exit, the passed option was a general one;
272 * otherwise, the str pointer is used (and owned) inside ubd_devs array, so it
273 * should not be freed on exit.
274 */
Jeff Dikef28169d2007-02-10 01:43:53 -0800275static int ubd_setup_common(char *str, int *index_out, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800277 struct ubd *ubd_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 struct openflags flags = global_openflags;
279 char *backing_file;
Jeff Dikeb8831a12007-02-10 01:44:17 -0800280 int n, err = 0, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281
282 if(index_out) *index_out = -1;
283 n = *str;
284 if(n == '='){
285 char *end;
286 int major;
287
288 str++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 if(!strcmp(str, "sync")){
290 global_openflags = of_sync(global_openflags);
Jeff Dikeb8831a12007-02-10 01:44:17 -0800291 goto out1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 }
293
Jeff Dikef28169d2007-02-10 01:43:53 -0800294 err = -EINVAL;
Jeff Dikeb8831a12007-02-10 01:44:17 -0800295 major = simple_strtoul(str, &end, 0);
296 if((*end != '\0') || (end == str)){
297 *error_out = "Didn't parse major number";
298 goto out1;
299 }
300
Jeff Dikef28169d2007-02-10 01:43:53 -0800301 mutex_lock(&ubd_lock);
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700302 if (fake_major != UBD_MAJOR) {
Jeff Dikef28169d2007-02-10 01:43:53 -0800303 *error_out = "Can't assign a fake major twice";
304 goto out1;
305 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800306
Jeff Dikef28169d2007-02-10 01:43:53 -0800307 fake_major = major;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308
309 printk(KERN_INFO "Setting extra ubd major number to %d\n",
310 major);
Jeff Dikef28169d2007-02-10 01:43:53 -0800311 err = 0;
312 out1:
313 mutex_unlock(&ubd_lock);
314 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 }
316
317 n = parse_unit(&str);
318 if(n < 0){
Jeff Dikef28169d2007-02-10 01:43:53 -0800319 *error_out = "Couldn't parse device number";
320 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 }
322 if(n >= MAX_DEV){
Jeff Dikef28169d2007-02-10 01:43:53 -0800323 *error_out = "Device number out of range";
324 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 }
326
Jeff Dikef28169d2007-02-10 01:43:53 -0800327 err = -EBUSY;
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800328 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800330 ubd_dev = &ubd_devs[n];
331 if(ubd_dev->file != NULL){
Jeff Dikef28169d2007-02-10 01:43:53 -0800332 *error_out = "Device is already configured";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 goto out;
334 }
335
336 if (index_out)
337 *index_out = n;
338
Jeff Dikef28169d2007-02-10 01:43:53 -0800339 err = -EINVAL;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800340 for (i = 0; i < sizeof("rscd="); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 switch (*str) {
342 case 'r':
343 flags.w = 0;
344 break;
345 case 's':
346 flags.s = 1;
347 break;
348 case 'd':
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800349 ubd_dev->no_cow = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 break;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800351 case 'c':
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800352 ubd_dev->shared = 1;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800353 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 case '=':
355 str++;
356 goto break_loop;
357 default:
Jeff Dikef28169d2007-02-10 01:43:53 -0800358 *error_out = "Expected '=' or flag letter "
359 "(r, s, c, or d)";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 goto out;
361 }
362 str++;
363 }
364
Jeff Dikef28169d2007-02-10 01:43:53 -0800365 if (*str == '=')
366 *error_out = "Too many flags specified";
367 else
368 *error_out = "Missing '='";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 goto out;
370
371break_loop:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 backing_file = strchr(str, ',');
373
Jeff Dikef28169d2007-02-10 01:43:53 -0800374 if (backing_file == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 backing_file = strchr(str, ':');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376
Jeff Dikef28169d2007-02-10 01:43:53 -0800377 if(backing_file != NULL){
378 if(ubd_dev->no_cow){
379 *error_out = "Can't specify both 'd' and a cow file";
380 goto out;
381 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 else {
383 *backing_file = '\0';
384 backing_file++;
385 }
386 }
Jeff Dikef28169d2007-02-10 01:43:53 -0800387 err = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800388 ubd_dev->file = str;
389 ubd_dev->cow.file = backing_file;
390 ubd_dev->boot_openflags = flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800392 mutex_unlock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -0800393 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394}
395
396static int ubd_setup(char *str)
397{
Jeff Dikef28169d2007-02-10 01:43:53 -0800398 char *error;
399 int err;
400
401 err = ubd_setup_common(str, NULL, &error);
402 if(err)
403 printk(KERN_ERR "Failed to initialize device with \"%s\" : "
404 "%s\n", str, error);
405 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406}
407
408__setup("ubd", ubd_setup);
409__uml_help(ubd_setup,
410"ubd<n><flags>=<filename>[(:|,)<filename2>]\n"
411" This is used to associate a device with a file in the underlying\n"
412" filesystem. When specifying two filenames, the first one is the\n"
413" COW name and the second is the backing file name. As separator you can\n"
414" use either a ':' or a ',': the first one allows writing things like;\n"
415" ubd0=~/Uml/root_cow:~/Uml/root_backing_file\n"
416" while with a ',' the shell would not expand the 2nd '~'.\n"
Jeff Dikef28169d2007-02-10 01:43:53 -0800417" When using only one filename, UML will detect whether to treat it like\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418" a COW file or a backing file. To override this detection, add the 'd'\n"
419" flag:\n"
420" ubd0d=BackingFile\n"
421" Usually, there is a filesystem in the file, but \n"
422" that's not required. Swap devices containing swap files can be\n"
423" specified like this. Also, a file which doesn't contain a\n"
424" filesystem can have its contents read in the virtual \n"
425" machine by running 'dd' on the device. <n> must be in the range\n"
426" 0 to 7. Appending an 'r' to the number will cause that device\n"
427" to be mounted read-only. For example ubd1r=./ext_fs. Appending\n"
Jeff Dike20ede452008-02-04 22:30:37 -0800428" an 's' will cause data to be written to disk on the host immediately.\n"
429" 'c' will cause the device to be treated as being shared between multiple\n"
430" UMLs and file locking will be turned off - this is appropriate for a\n"
431" cluster filesystem and inappropriate at almost all other times.\n\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432);
433
Jeff Dike8299ca52008-02-04 22:30:48 -0800434static int udb_setup(char *str)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435{
436 printk("udb%s specified on command line is almost certainly a ubd -> "
437 "udb TYPO\n", str);
Jeff Dikedc764e52007-05-06 14:51:41 -0700438 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439}
440
441__setup("udb", udb_setup);
442__uml_help(udb_setup,
443"udb\n"
Jeff Dike0894e272005-05-28 15:51:55 -0700444" This option is here solely to catch ubd -> udb typos, which can be\n"
445" to impossible to catch visually unless you specifically look for\n"
446" them. The only result of any option starting with 'udb' is an error\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447" in the boot output.\n\n"
448);
449
Jens Axboe165125e2007-07-24 09:28:11 +0200450static void do_ubd_request(struct request_queue * q);
Jeff Dike91acb212005-10-10 23:10:32 -0400451
452/* Only changed by ubd_init, which is an initcall. */
WANG Cong5dc62b12008-04-28 02:13:58 -0700453static int thread_fd = -1;
Jeff Dikea0044bd2007-05-06 14:51:36 -0700454static LIST_HEAD(restart);
455
Paolo 'Blaisorblade' Giarrusso2fe30a32006-10-30 22:07:09 -0800456/* XXX - move this inside ubd_intr. */
Jeff Dike62f96cb2007-02-10 01:44:16 -0800457/* Called without dev->lock held, and only in interrupt context. */
Jeff Dike91acb212005-10-10 23:10:32 -0400458static void ubd_handler(void)
459{
Jeff Dike2adcec22007-05-06 14:51:37 -0700460 struct io_thread_req *req;
Jeff Dikea0044bd2007-05-06 14:51:36 -0700461 struct ubd *ubd;
462 struct list_head *list, *next_ele;
463 unsigned long flags;
Jeff Dike91acb212005-10-10 23:10:32 -0400464 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465
Jeff Dikea0044bd2007-05-06 14:51:36 -0700466 while(1){
Jeff Dikea6ea4cc2007-05-06 14:51:43 -0700467 n = os_read_file(thread_fd, &req,
468 sizeof(struct io_thread_req *));
Jeff Dikea0044bd2007-05-06 14:51:36 -0700469 if(n != sizeof(req)){
470 if(n == -EAGAIN)
471 break;
472 printk(KERN_ERR "spurious interrupt in ubd_handler, "
473 "err = %d\n", -n);
474 return;
475 }
476
Tejun Heo4d6c84d2009-04-28 13:06:09 +0900477 blk_end_request(req->req, 0, req->length);
Jeff Dike2adcec22007-05-06 14:51:37 -0700478 kfree(req);
Jeff Dike91acb212005-10-10 23:10:32 -0400479 }
Jeff Dike62f96cb2007-02-10 01:44:16 -0800480 reactivate_fd(thread_fd, UBD_IRQ);
Jeff Dikea0044bd2007-05-06 14:51:36 -0700481
482 list_for_each_safe(list, next_ele, &restart){
483 ubd = container_of(list, struct ubd, restart);
484 list_del_init(&ubd->restart);
485 spin_lock_irqsave(&ubd->lock, flags);
486 do_ubd_request(ubd->queue);
487 spin_unlock_irqrestore(&ubd->lock, flags);
488 }
Jeff Dike91acb212005-10-10 23:10:32 -0400489}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490
Al Viro7bea96f2006-10-08 22:49:34 +0100491static irqreturn_t ubd_intr(int irq, void *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492{
Jeff Dike91acb212005-10-10 23:10:32 -0400493 ubd_handler();
Jeff Dikedc764e52007-05-06 14:51:41 -0700494 return IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495}
496
Jeff Dike91acb212005-10-10 23:10:32 -0400497/* Only changed by ubd_init, which is an initcall. */
498static int io_pid = -1;
499
WANG Cong5dc62b12008-04-28 02:13:58 -0700500static void kill_io_thread(void)
Jeff Dike91acb212005-10-10 23:10:32 -0400501{
Jeff Dike6c29256c2006-03-27 01:14:37 -0800502 if(io_pid != -1)
Jeff Dike91acb212005-10-10 23:10:32 -0400503 os_kill_process(io_pid, 1);
504}
505
506__uml_exitcall(kill_io_thread);
507
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800508static inline int ubd_file_size(struct ubd *ubd_dev, __u64 *size_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509{
510 char *file;
511
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800512 file = ubd_dev->cow.file ? ubd_dev->cow.file : ubd_dev->file;
Jeff Dikedc764e52007-05-06 14:51:41 -0700513 return os_file_size(file, size_out);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514}
515
WANG Cong5dc62b12008-04-28 02:13:58 -0700516static int read_cow_bitmap(int fd, void *buf, int offset, int len)
517{
518 int err;
519
520 err = os_seek_file(fd, offset);
521 if (err < 0)
522 return err;
523
524 err = os_read_file(fd, buf, len);
525 if (err < 0)
526 return err;
527
528 return 0;
529}
530
531static int backing_file_mismatch(char *file, __u64 size, time_t mtime)
532{
533 unsigned long modtime;
534 unsigned long long actual;
535 int err;
536
537 err = os_file_modtime(file, &modtime);
538 if (err < 0) {
539 printk(KERN_ERR "Failed to get modification time of backing "
540 "file \"%s\", err = %d\n", file, -err);
541 return err;
542 }
543
544 err = os_file_size(file, &actual);
545 if (err < 0) {
546 printk(KERN_ERR "Failed to get size of backing file \"%s\", "
547 "err = %d\n", file, -err);
548 return err;
549 }
550
551 if (actual != size) {
552 /*__u64 can be a long on AMD64 and with %lu GCC complains; so
553 * the typecast.*/
554 printk(KERN_ERR "Size mismatch (%llu vs %llu) of COW header "
555 "vs backing file\n", (unsigned long long) size, actual);
556 return -EINVAL;
557 }
558 if (modtime != mtime) {
559 printk(KERN_ERR "mtime mismatch (%ld vs %ld) of COW header vs "
560 "backing file\n", mtime, modtime);
561 return -EINVAL;
562 }
563 return 0;
564}
565
566static int path_requires_switch(char *from_cmdline, char *from_cow, char *cow)
567{
568 struct uml_stat buf1, buf2;
569 int err;
570
571 if (from_cmdline == NULL)
572 return 0;
573 if (!strcmp(from_cmdline, from_cow))
574 return 0;
575
576 err = os_stat_file(from_cmdline, &buf1);
577 if (err < 0) {
578 printk(KERN_ERR "Couldn't stat '%s', err = %d\n", from_cmdline,
579 -err);
580 return 0;
581 }
582 err = os_stat_file(from_cow, &buf2);
583 if (err < 0) {
584 printk(KERN_ERR "Couldn't stat '%s', err = %d\n", from_cow,
585 -err);
586 return 1;
587 }
588 if ((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino))
589 return 0;
590
591 printk(KERN_ERR "Backing file mismatch - \"%s\" requested, "
592 "\"%s\" specified in COW header of \"%s\"\n",
593 from_cmdline, from_cow, cow);
594 return 1;
595}
596
597static int open_ubd_file(char *file, struct openflags *openflags, int shared,
598 char **backing_file_out, int *bitmap_offset_out,
599 unsigned long *bitmap_len_out, int *data_offset_out,
600 int *create_cow_out)
601{
602 time_t mtime;
603 unsigned long long size;
604 __u32 version, align;
605 char *backing_file;
606 int fd, err, sectorsize, asked_switch, mode = 0644;
607
608 fd = os_open_file(file, *openflags, mode);
609 if (fd < 0) {
610 if ((fd == -ENOENT) && (create_cow_out != NULL))
611 *create_cow_out = 1;
612 if (!openflags->w ||
613 ((fd != -EROFS) && (fd != -EACCES)))
614 return fd;
615 openflags->w = 0;
616 fd = os_open_file(file, *openflags, mode);
617 if (fd < 0)
618 return fd;
619 }
620
621 if (shared)
622 printk(KERN_INFO "Not locking \"%s\" on the host\n", file);
623 else {
624 err = os_lock_file(fd, openflags->w);
625 if (err < 0) {
626 printk(KERN_ERR "Failed to lock '%s', err = %d\n",
627 file, -err);
628 goto out_close;
629 }
630 }
631
632 /* Successful return case! */
633 if (backing_file_out == NULL)
634 return fd;
635
636 err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime,
637 &size, &sectorsize, &align, bitmap_offset_out);
638 if (err && (*backing_file_out != NULL)) {
639 printk(KERN_ERR "Failed to read COW header from COW file "
640 "\"%s\", errno = %d\n", file, -err);
641 goto out_close;
642 }
643 if (err)
644 return fd;
645
646 asked_switch = path_requires_switch(*backing_file_out, backing_file,
647 file);
648
649 /* Allow switching only if no mismatch. */
650 if (asked_switch && !backing_file_mismatch(*backing_file_out, size,
651 mtime)) {
652 printk(KERN_ERR "Switching backing file to '%s'\n",
653 *backing_file_out);
654 err = write_cow_header(file, fd, *backing_file_out,
655 sectorsize, align, &size);
656 if (err) {
657 printk(KERN_ERR "Switch failed, errno = %d\n", -err);
658 goto out_close;
659 }
660 } else {
661 *backing_file_out = backing_file;
662 err = backing_file_mismatch(*backing_file_out, size, mtime);
663 if (err)
664 goto out_close;
665 }
666
667 cow_sizes(version, size, sectorsize, align, *bitmap_offset_out,
668 bitmap_len_out, data_offset_out);
669
670 return fd;
671 out_close:
672 os_close_file(fd);
673 return err;
674}
675
676static int create_cow_file(char *cow_file, char *backing_file,
677 struct openflags flags,
678 int sectorsize, int alignment, int *bitmap_offset_out,
679 unsigned long *bitmap_len_out, int *data_offset_out)
680{
681 int err, fd;
682
683 flags.c = 1;
684 fd = open_ubd_file(cow_file, &flags, 0, NULL, NULL, NULL, NULL, NULL);
685 if (fd < 0) {
686 err = fd;
687 printk(KERN_ERR "Open of COW file '%s' failed, errno = %d\n",
688 cow_file, -err);
689 goto out;
690 }
691
692 err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment,
693 bitmap_offset_out, bitmap_len_out,
694 data_offset_out);
695 if (!err)
696 return fd;
697 os_close_file(fd);
698 out:
699 return err;
700}
701
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800702static void ubd_close_dev(struct ubd *ubd_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800704 os_close_file(ubd_dev->fd);
705 if(ubd_dev->cow.file == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 return;
707
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800708 os_close_file(ubd_dev->cow.fd);
709 vfree(ubd_dev->cow.bitmap);
710 ubd_dev->cow.bitmap = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711}
712
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800713static int ubd_open_dev(struct ubd *ubd_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714{
715 struct openflags flags;
716 char **back_ptr;
717 int err, create_cow, *create_ptr;
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800718 int fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800720 ubd_dev->openflags = ubd_dev->boot_openflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 create_cow = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800722 create_ptr = (ubd_dev->cow.file != NULL) ? &create_cow : NULL;
723 back_ptr = ubd_dev->no_cow ? NULL : &ubd_dev->cow.file;
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800724
725 fd = open_ubd_file(ubd_dev->file, &ubd_dev->openflags, ubd_dev->shared,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800726 back_ptr, &ubd_dev->cow.bitmap_offset,
727 &ubd_dev->cow.bitmap_len, &ubd_dev->cow.data_offset,
Jeff Dike6c29256c2006-03-27 01:14:37 -0800728 create_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800730 if((fd == -ENOENT) && create_cow){
731 fd = create_cow_file(ubd_dev->file, ubd_dev->cow.file,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800732 ubd_dev->openflags, 1 << 9, PAGE_SIZE,
733 &ubd_dev->cow.bitmap_offset,
734 &ubd_dev->cow.bitmap_len,
735 &ubd_dev->cow.data_offset);
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800736 if(fd >= 0){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 printk(KERN_INFO "Creating \"%s\" as COW file for "
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800738 "\"%s\"\n", ubd_dev->file, ubd_dev->cow.file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 }
740 }
741
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800742 if(fd < 0){
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800743 printk("Failed to open '%s', errno = %d\n", ubd_dev->file,
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800744 -fd);
745 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 }
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800747 ubd_dev->fd = fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800749 if(ubd_dev->cow.file != NULL){
Martin K. Petersen086fa5f2010-02-26 00:20:38 -0500750 blk_queue_max_hw_sectors(ubd_dev->queue, 8 * sizeof(long));
Jeff Dikef4768ff2007-08-22 14:01:53 -0700751
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 err = -ENOMEM;
Jesper Juhlda2486b2007-10-16 01:27:19 -0700753 ubd_dev->cow.bitmap = vmalloc(ubd_dev->cow.bitmap_len);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800754 if(ubd_dev->cow.bitmap == NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 printk(KERN_ERR "Failed to vmalloc COW bitmap\n");
756 goto error;
757 }
758 flush_tlb_kernel_vm();
759
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800760 err = read_cow_bitmap(ubd_dev->fd, ubd_dev->cow.bitmap,
761 ubd_dev->cow.bitmap_offset,
762 ubd_dev->cow.bitmap_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 if(err < 0)
764 goto error;
765
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800766 flags = ubd_dev->openflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 flags.w = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800768 err = open_ubd_file(ubd_dev->cow.file, &flags, ubd_dev->shared, NULL,
Jeff Dike6c29256c2006-03-27 01:14:37 -0800769 NULL, NULL, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 if(err < 0) goto error;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800771 ubd_dev->cow.fd = err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 }
Jeff Dikedc764e52007-05-06 14:51:41 -0700773 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 error:
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800775 os_close_file(ubd_dev->fd);
Jeff Dikedc764e52007-05-06 14:51:41 -0700776 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777}
778
Jeff Dike2e3f5252007-05-06 14:51:29 -0700779static void ubd_device_release(struct device *dev)
780{
Greg Kroah-Hartman8691b972009-05-04 12:40:54 -0700781 struct ubd *ubd_dev = dev_get_drvdata(dev);
Jeff Dike2e3f5252007-05-06 14:51:29 -0700782
783 blk_cleanup_queue(ubd_dev->queue);
784 *ubd_dev = ((struct ubd) DEFAULT_UBD);
785}
786
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800787static int ubd_disk_register(int major, u64 size, int unit,
Jeff Dikeb8831a12007-02-10 01:44:17 -0800788 struct gendisk **disk_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789{
790 struct gendisk *disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791
792 disk = alloc_disk(1 << UBD_SHIFT);
793 if(disk == NULL)
Jeff Dikedc764e52007-05-06 14:51:41 -0700794 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795
796 disk->major = major;
797 disk->first_minor = unit << UBD_SHIFT;
798 disk->fops = &ubd_blops;
799 set_capacity(disk, size / 512);
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700800 if (major == UBD_MAJOR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 sprintf(disk->disk_name, "ubd%c", 'a' + unit);
Greg Kroah-Hartmance7b0f42005-06-20 21:15:16 -0700802 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 sprintf(disk->disk_name, "ubd_fake%d", unit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804
805 /* sysfs register (not for ide fake devices) */
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700806 if (major == UBD_MAJOR) {
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800807 ubd_devs[unit].pdev.id = unit;
808 ubd_devs[unit].pdev.name = DRIVER_NAME;
Jeff Dike2e3f5252007-05-06 14:51:29 -0700809 ubd_devs[unit].pdev.dev.release = ubd_device_release;
Greg Kroah-Hartman8691b972009-05-04 12:40:54 -0700810 dev_set_drvdata(&ubd_devs[unit].pdev.dev, &ubd_devs[unit]);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800811 platform_device_register(&ubd_devs[unit].pdev);
812 disk->driverfs_dev = &ubd_devs[unit].pdev.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 }
814
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800815 disk->private_data = &ubd_devs[unit];
Jeff Dike62f96cb2007-02-10 01:44:16 -0800816 disk->queue = ubd_devs[unit].queue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 add_disk(disk);
818
819 *disk_out = disk;
820 return 0;
821}
822
823#define ROUND_BLOCK(n) ((n + ((1 << 9) - 1)) & (-1 << 9))
824
Jeff Dikef28169d2007-02-10 01:43:53 -0800825static int ubd_add(int n, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800827 struct ubd *ubd_dev = &ubd_devs[n];
Jeff Dikef28169d2007-02-10 01:43:53 -0800828 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800830 if(ubd_dev->file == NULL)
Jeff Dikeec7cf782005-09-03 15:57:29 -0700831 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800833 err = ubd_file_size(ubd_dev, &ubd_dev->size);
Jeff Dikef28169d2007-02-10 01:43:53 -0800834 if(err < 0){
835 *error_out = "Couldn't determine size of device's file";
Jeff Dike80c13742006-09-29 01:58:51 -0700836 goto out;
Jeff Dikef28169d2007-02-10 01:43:53 -0800837 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800839 ubd_dev->size = ROUND_BLOCK(ubd_dev->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840
Jeff Dikea0044bd2007-05-06 14:51:36 -0700841 INIT_LIST_HEAD(&ubd_dev->restart);
WANG Cong4f40c052007-11-05 14:50:59 -0800842 sg_init_table(ubd_dev->sg, MAX_SG);
Jeff Dikea0044bd2007-05-06 14:51:36 -0700843
Jeff Dike62f96cb2007-02-10 01:44:16 -0800844 err = -ENOMEM;
845 ubd_dev->queue = blk_init_queue(do_ubd_request, &ubd_dev->lock);
846 if (ubd_dev->queue == NULL) {
847 *error_out = "Failed to initialize device queue";
Jeff Dike80c13742006-09-29 01:58:51 -0700848 goto out;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800849 }
850 ubd_dev->queue->queuedata = ubd_dev;
851
Martin K. Petersen8a783622010-02-26 00:20:39 -0500852 blk_queue_max_segments(ubd_dev->queue, MAX_SG);
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700853 err = ubd_disk_register(UBD_MAJOR, ubd_dev->size, n, &ubd_gendisk[n]);
Jeff Dike62f96cb2007-02-10 01:44:16 -0800854 if(err){
855 *error_out = "Failed to register device";
856 goto out_cleanup;
857 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800858
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700859 if (fake_major != UBD_MAJOR)
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800860 ubd_disk_register(fake_major, ubd_dev->size, n,
Jeff Dike62f96cb2007-02-10 01:44:16 -0800861 &fake_gendisk[n]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862
Jeff Dike83380cc2008-02-04 22:31:18 -0800863 /*
864 * Perhaps this should also be under the "if (fake_major)" above
865 * using the fake_disk->disk_name
866 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 if (fake_ide)
868 make_ide_entries(ubd_gendisk[n]->disk_name);
869
Jeff Dikeec7cf782005-09-03 15:57:29 -0700870 err = 0;
Jeff Dikeec7cf782005-09-03 15:57:29 -0700871out:
872 return err;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800873
874out_cleanup:
875 blk_cleanup_queue(ubd_dev->queue);
876 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877}
878
Jeff Dikef28169d2007-02-10 01:43:53 -0800879static int ubd_config(char *str, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880{
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800881 int n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882
Jeff Dikef28169d2007-02-10 01:43:53 -0800883 /* This string is possibly broken up and stored, so it's only
884 * freed if ubd_setup_common fails, or if only general options
885 * were set.
886 */
Jeff Dike970d6e32006-01-06 00:18:48 -0800887 str = kstrdup(str, GFP_KERNEL);
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800888 if (str == NULL) {
Jeff Dikef28169d2007-02-10 01:43:53 -0800889 *error_out = "Failed to allocate memory";
890 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 }
Jeff Dikef28169d2007-02-10 01:43:53 -0800892
893 ret = ubd_setup_common(str, &n, error_out);
894 if (ret)
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800895 goto err_free;
Jeff Dikef28169d2007-02-10 01:43:53 -0800896
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800897 if (n == -1) {
898 ret = 0;
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800899 goto err_free;
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800900 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901
Jeff Dikedc764e52007-05-06 14:51:41 -0700902 mutex_lock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -0800903 ret = ubd_add(n, error_out);
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800904 if (ret)
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800905 ubd_devs[n].file = NULL;
Jeff Dikedc764e52007-05-06 14:51:41 -0700906 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800908out:
Jeff Dikedc764e52007-05-06 14:51:41 -0700909 return ret;
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800910
911err_free:
912 kfree(str);
913 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914}
915
916static int ubd_get_config(char *name, char *str, int size, char **error_out)
917{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800918 struct ubd *ubd_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 int n, len = 0;
920
921 n = parse_unit(&name);
922 if((n >= MAX_DEV) || (n < 0)){
923 *error_out = "ubd_get_config : device number out of range";
Jeff Dikedc764e52007-05-06 14:51:41 -0700924 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 }
926
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800927 ubd_dev = &ubd_devs[n];
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800928 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800930 if(ubd_dev->file == NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 CONFIG_CHUNK(str, size, len, "", 1);
932 goto out;
933 }
934
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800935 CONFIG_CHUNK(str, size, len, ubd_dev->file, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800937 if(ubd_dev->cow.file != NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 CONFIG_CHUNK(str, size, len, ",", 0);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800939 CONFIG_CHUNK(str, size, len, ubd_dev->cow.file, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 }
941 else CONFIG_CHUNK(str, size, len, "", 1);
942
943 out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800944 mutex_unlock(&ubd_lock);
Jeff Dikedc764e52007-05-06 14:51:41 -0700945 return len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946}
947
Jeff Dike29d56cf2005-06-25 14:55:25 -0700948static int ubd_id(char **str, int *start_out, int *end_out)
949{
Jeff Dikedc764e52007-05-06 14:51:41 -0700950 int n;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700951
952 n = parse_unit(str);
Jeff Dikedc764e52007-05-06 14:51:41 -0700953 *start_out = 0;
954 *end_out = MAX_DEV - 1;
955 return n;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700956}
957
Jeff Dikef28169d2007-02-10 01:43:53 -0800958static int ubd_remove(int n, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959{
Jeff Dike2e3f5252007-05-06 14:51:29 -0700960 struct gendisk *disk = ubd_gendisk[n];
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800961 struct ubd *ubd_dev;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700962 int err = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800964 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800966 ubd_dev = &ubd_devs[n];
Jeff Dike29d56cf2005-06-25 14:55:25 -0700967
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800968 if(ubd_dev->file == NULL)
Jeff Dike29d56cf2005-06-25 14:55:25 -0700969 goto out;
970
971 /* you cannot remove a open disk */
972 err = -EBUSY;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800973 if(ubd_dev->count > 0)
Jeff Dike29d56cf2005-06-25 14:55:25 -0700974 goto out;
975
Jeff Dikedc764e52007-05-06 14:51:41 -0700976 ubd_gendisk[n] = NULL;
Jeff Dikeb47d2de2007-05-06 14:51:01 -0700977 if(disk != NULL){
978 del_gendisk(disk);
979 put_disk(disk);
980 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981
982 if(fake_gendisk[n] != NULL){
983 del_gendisk(fake_gendisk[n]);
984 put_disk(fake_gendisk[n]);
985 fake_gendisk[n] = NULL;
986 }
987
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 err = 0;
Jeff Dike2e3f5252007-05-06 14:51:29 -0700989 platform_device_unregister(&ubd_dev->pdev);
Jeff Dike29d56cf2005-06-25 14:55:25 -0700990out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800991 mutex_unlock(&ubd_lock);
Jeff Dike29d56cf2005-06-25 14:55:25 -0700992 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993}
994
Jeff Dikef28169d2007-02-10 01:43:53 -0800995/* All these are called by mconsole in process context and without
Jeff Dikeb8831a12007-02-10 01:44:17 -0800996 * ubd-specific locks. The structure itself is const except for .list.
Jeff Dikef28169d2007-02-10 01:43:53 -0800997 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998static struct mc_device ubd_mc = {
Jeff Dike84f48d42007-02-10 01:44:01 -0800999 .list = LIST_HEAD_INIT(ubd_mc.list),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 .name = "ubd",
1001 .config = ubd_config,
Jeff Dikedc764e52007-05-06 14:51:41 -07001002 .get_config = ubd_get_config,
Jeff Dike29d56cf2005-06-25 14:55:25 -07001003 .id = ubd_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 .remove = ubd_remove,
1005};
1006
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001007static int __init ubd_mc_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008{
1009 mconsole_register_dev(&ubd_mc);
1010 return 0;
1011}
1012
1013__initcall(ubd_mc_init);
1014
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001015static int __init ubd0_init(void)
1016{
1017 struct ubd *ubd_dev = &ubd_devs[0];
1018
Jeff Dikeb8831a12007-02-10 01:44:17 -08001019 mutex_lock(&ubd_lock);
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001020 if(ubd_dev->file == NULL)
1021 ubd_dev->file = "root_fs";
Jeff Dikeb8831a12007-02-10 01:44:17 -08001022 mutex_unlock(&ubd_lock);
1023
Jeff Dikedc764e52007-05-06 14:51:41 -07001024 return 0;
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001025}
1026
1027__initcall(ubd0_init);
1028
Jeff Dikeb8831a12007-02-10 01:44:17 -08001029/* Used in ubd_init, which is an initcall */
Russell King3ae5eae2005-11-09 22:32:44 +00001030static struct platform_driver ubd_driver = {
1031 .driver = {
1032 .name = DRIVER_NAME,
1033 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034};
1035
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001036static int __init ubd_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037{
Jeff Dikef28169d2007-02-10 01:43:53 -08001038 char *error;
1039 int i, err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040
Christoph Hellwig792dd4f2009-03-31 15:23:39 -07001041 if (register_blkdev(UBD_MAJOR, "ubd"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 return -1;
1043
Christoph Hellwig792dd4f2009-03-31 15:23:39 -07001044 if (fake_major != UBD_MAJOR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 char name[sizeof("ubd_nnn\0")];
1046
1047 snprintf(name, sizeof(name), "ubd_%d", fake_major);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 if (register_blkdev(fake_major, "ubd"))
1049 return -1;
1050 }
Russell King3ae5eae2005-11-09 22:32:44 +00001051 platform_driver_register(&ubd_driver);
Jeff Dikedc764e52007-05-06 14:51:41 -07001052 mutex_lock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -08001053 for (i = 0; i < MAX_DEV; i++){
1054 err = ubd_add(i, &error);
1055 if(err)
1056 printk(KERN_ERR "Failed to initialize ubd device %d :"
1057 "%s\n", i, error);
1058 }
Jeff Dikedc764e52007-05-06 14:51:41 -07001059 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 return 0;
1061}
1062
1063late_initcall(ubd_init);
1064
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001065static int __init ubd_driver_init(void){
Jeff Dike91acb212005-10-10 23:10:32 -04001066 unsigned long stack;
1067 int err;
1068
1069 /* Set by CONFIG_BLK_DEV_UBD_SYNC or ubd=sync.*/
1070 if(global_openflags.s){
1071 printk(KERN_INFO "ubd: Synchronous mode\n");
1072 /* Letting ubd=sync be like using ubd#s= instead of ubd#= is
1073 * enough. So use anyway the io thread. */
1074 }
1075 stack = alloc_stack(0, 0);
Jeff Dike6c29256c2006-03-27 01:14:37 -08001076 io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *),
Jeff Dike91acb212005-10-10 23:10:32 -04001077 &thread_fd);
1078 if(io_pid < 0){
Jeff Dike6c29256c2006-03-27 01:14:37 -08001079 printk(KERN_ERR
Jeff Dike91acb212005-10-10 23:10:32 -04001080 "ubd : Failed to start I/O thread (errno = %d) - "
1081 "falling back to synchronous I/O\n", -io_pid);
1082 io_pid = -1;
Jeff Dikedc764e52007-05-06 14:51:41 -07001083 return 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001084 }
Jeff Dike6c29256c2006-03-27 01:14:37 -08001085 err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001086 IRQF_DISABLED, "ubd", ubd_devs);
Jeff Dike91acb212005-10-10 23:10:32 -04001087 if(err != 0)
1088 printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err);
Jeff Dikef4c57a72006-03-31 02:30:10 -08001089 return 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001090}
1091
1092device_initcall(ubd_driver_init);
1093
Al Viroa625c992008-03-02 09:16:26 -05001094static int ubd_open(struct block_device *bdev, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095{
Al Viroa625c992008-03-02 09:16:26 -05001096 struct gendisk *disk = bdev->bd_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001097 struct ubd *ubd_dev = disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 int err = 0;
1099
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001100 if(ubd_dev->count == 0){
1101 err = ubd_open_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 if(err){
1103 printk(KERN_ERR "%s: Can't open \"%s\": errno = %d\n",
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001104 disk->disk_name, ubd_dev->file, -err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 goto out;
1106 }
1107 }
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001108 ubd_dev->count++;
1109 set_disk_ro(disk, !ubd_dev->openflags.w);
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -07001110
1111 /* This should no more be needed. And it didn't work anyway to exclude
1112 * read-write remounting of filesystems.*/
Al Viroa625c992008-03-02 09:16:26 -05001113 /*if((mode & FMODE_WRITE) && !ubd_dev->openflags.w){
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -08001114 if(--ubd_dev->count == 0) ubd_close_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 err = -EROFS;
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -07001116 }*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 out:
Jeff Dikedc764e52007-05-06 14:51:41 -07001118 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119}
1120
Al Viroa625c992008-03-02 09:16:26 -05001121static int ubd_release(struct gendisk *disk, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001123 struct ubd *ubd_dev = disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001125 if(--ubd_dev->count == 0)
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -08001126 ubd_close_dev(ubd_dev);
Jeff Dikedc764e52007-05-06 14:51:41 -07001127 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128}
1129
Jeff Dike91acb212005-10-10 23:10:32 -04001130static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask,
1131 __u64 *cow_offset, unsigned long *bitmap,
1132 __u64 bitmap_offset, unsigned long *bitmap_words,
1133 __u64 bitmap_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134{
Jeff Dike91acb212005-10-10 23:10:32 -04001135 __u64 sector = io_offset >> 9;
1136 int i, update_bitmap = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137
Jeff Dike91acb212005-10-10 23:10:32 -04001138 for(i = 0; i < length >> 9; i++){
1139 if(cow_mask != NULL)
1140 ubd_set_bit(i, (unsigned char *) cow_mask);
1141 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
1142 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143
Jeff Dike91acb212005-10-10 23:10:32 -04001144 update_bitmap = 1;
1145 ubd_set_bit(sector + i, (unsigned char *) bitmap);
1146 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147
Jeff Dike91acb212005-10-10 23:10:32 -04001148 if(!update_bitmap)
1149 return;
1150
1151 *cow_offset = sector / (sizeof(unsigned long) * 8);
1152
1153 /* This takes care of the case where we're exactly at the end of the
1154 * device, and *cow_offset + 1 is off the end. So, just back it up
1155 * by one word. Thanks to Lynn Kerby for the fix and James McMechan
1156 * for the original diagnosis.
1157 */
Jiri Olsa6d074242008-05-12 14:01:56 -07001158 if (*cow_offset == (DIV_ROUND_UP(bitmap_len,
1159 sizeof(unsigned long)) - 1))
Jeff Dike91acb212005-10-10 23:10:32 -04001160 (*cow_offset)--;
1161
1162 bitmap_words[0] = bitmap[*cow_offset];
1163 bitmap_words[1] = bitmap[*cow_offset + 1];
1164
1165 *cow_offset *= sizeof(unsigned long);
1166 *cow_offset += bitmap_offset;
1167}
1168
1169static void cowify_req(struct io_thread_req *req, unsigned long *bitmap,
1170 __u64 bitmap_offset, __u64 bitmap_len)
1171{
1172 __u64 sector = req->offset >> 9;
1173 int i;
1174
1175 if(req->length > (sizeof(req->sector_mask) * 8) << 9)
1176 panic("Operation too long");
1177
1178 if(req->op == UBD_READ) {
1179 for(i = 0; i < req->length >> 9; i++){
1180 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
Jeff Dike6c29256c2006-03-27 01:14:37 -08001181 ubd_set_bit(i, (unsigned char *)
Jeff Dike91acb212005-10-10 23:10:32 -04001182 &req->sector_mask);
Jeff Dikedc764e52007-05-06 14:51:41 -07001183 }
Jeff Dike91acb212005-10-10 23:10:32 -04001184 }
1185 else cowify_bitmap(req->offset, req->length, &req->sector_mask,
1186 &req->cow_offset, bitmap, bitmap_offset,
1187 req->bitmap_words, bitmap_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188}
1189
Jeff Dike62f96cb2007-02-10 01:44:16 -08001190/* Called with dev->lock held */
Jeff Dikea0044bd2007-05-06 14:51:36 -07001191static void prepare_request(struct request *req, struct io_thread_req *io_req,
1192 unsigned long long offset, int page_offset,
1193 int len, struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194{
1195 struct gendisk *disk = req->rq_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001196 struct ubd *ubd_dev = disk->private_data;
Jeff Dike91acb212005-10-10 23:10:32 -04001197
Jeff Dike62f96cb2007-02-10 01:44:16 -08001198 io_req->req = req;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001199 io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd :
1200 ubd_dev->fd;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001201 io_req->fds[1] = ubd_dev->fd;
Jeff Dike91acb212005-10-10 23:10:32 -04001202 io_req->cow_offset = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 io_req->offset = offset;
1204 io_req->length = len;
1205 io_req->error = 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001206 io_req->sector_mask = 0;
1207
1208 io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209 io_req->offsets[0] = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001210 io_req->offsets[1] = ubd_dev->cow.data_offset;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001211 io_req->buffer = page_address(page) + page_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 io_req->sectorsize = 1 << 9;
1213
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001214 if(ubd_dev->cow.file != NULL)
Jeff Dikea0044bd2007-05-06 14:51:36 -07001215 cowify_req(io_req, ubd_dev->cow.bitmap,
1216 ubd_dev->cow.bitmap_offset, ubd_dev->cow.bitmap_len);
Jeff Dike91acb212005-10-10 23:10:32 -04001217
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218}
1219
Jeff Dike62f96cb2007-02-10 01:44:16 -08001220/* Called with dev->lock held */
Jens Axboe165125e2007-07-24 09:28:11 +02001221static void do_ubd_request(struct request_queue *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222{
Jeff Dike2adcec22007-05-06 14:51:37 -07001223 struct io_thread_req *io_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 struct request *req;
Tejun Heof81f2f72009-04-28 13:06:10 +09001225 sector_t sector;
1226 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227
Jeff Dikea0044bd2007-05-06 14:51:36 -07001228 while(1){
Jeff Dike2a9529a2007-03-29 01:20:27 -07001229 struct ubd *dev = q->queuedata;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001230 if(dev->end_sg == 0){
Tejun Heo9934c8c2009-05-08 11:54:16 +09001231 struct request *req = blk_fetch_request(q);
Jeff Dikea0044bd2007-05-06 14:51:36 -07001232 if(req == NULL)
1233 return;
1234
1235 dev->request = req;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001236 dev->start_sg = 0;
1237 dev->end_sg = blk_rq_map_sg(q, req, dev->sg);
Jeff Dike91acb212005-10-10 23:10:32 -04001238 }
Jeff Dikea0044bd2007-05-06 14:51:36 -07001239
1240 req = dev->request;
Tejun Heo83096eb2009-05-07 22:24:39 +09001241 sector = blk_rq_pos(req);
Jeff Dikea0044bd2007-05-06 14:51:36 -07001242 while(dev->start_sg < dev->end_sg){
1243 struct scatterlist *sg = &dev->sg[dev->start_sg];
1244
Jeff Dike2adcec22007-05-06 14:51:37 -07001245 io_req = kmalloc(sizeof(struct io_thread_req),
Peter Zijlstra990c5582007-05-06 14:51:38 -07001246 GFP_ATOMIC);
Jeff Dike2adcec22007-05-06 14:51:37 -07001247 if(io_req == NULL){
1248 if(list_empty(&dev->restart))
1249 list_add(&dev->restart, &restart);
1250 return;
1251 }
1252 prepare_request(req, io_req,
Tejun Heof81f2f72009-04-28 13:06:10 +09001253 (unsigned long long)sector << 9,
Jens Axboe45711f12007-10-22 21:19:53 +02001254 sg->offset, sg->length, sg_page(sg));
Jeff Dikea0044bd2007-05-06 14:51:36 -07001255
Tejun Heof81f2f72009-04-28 13:06:10 +09001256 sector += sg->length >> 9;
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001257 n = os_write_file(thread_fd, &io_req,
1258 sizeof(struct io_thread_req *));
Jeff Dike2adcec22007-05-06 14:51:37 -07001259 if(n != sizeof(struct io_thread_req *)){
Jeff Dikea0044bd2007-05-06 14:51:36 -07001260 if(n != -EAGAIN)
1261 printk("write to io thread failed, "
1262 "errno = %d\n", -n);
1263 else if(list_empty(&dev->restart))
1264 list_add(&dev->restart, &restart);
Miklos Szeredi12429bf2007-11-28 16:21:52 -08001265 kfree(io_req);
Jeff Dikea0044bd2007-05-06 14:51:36 -07001266 return;
1267 }
1268
Jeff Dikea0044bd2007-05-06 14:51:36 -07001269 dev->start_sg++;
1270 }
1271 dev->end_sg = 0;
1272 dev->request = NULL;
Jeff Dike91acb212005-10-10 23:10:32 -04001273 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274}
1275
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001276static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
1277{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001278 struct ubd *ubd_dev = bdev->bd_disk->private_data;
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001279
1280 geo->heads = 128;
1281 geo->sectors = 32;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001282 geo->cylinders = ubd_dev->size / (128 * 32 * 512);
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001283 return 0;
1284}
1285
Al Viroa625c992008-03-02 09:16:26 -05001286static int ubd_ioctl(struct block_device *bdev, fmode_t mode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 unsigned int cmd, unsigned long arg)
1288{
Al Viroa625c992008-03-02 09:16:26 -05001289 struct ubd *ubd_dev = bdev->bd_disk->private_data;
Bartlomiej Zolnierkiewicz73855e12009-04-01 21:42:21 +02001290 u16 ubd_id[ATA_ID_WORDS];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291
1292 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293 struct cdrom_volctrl volume;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 case HDIO_GET_IDENTITY:
Bartlomiej Zolnierkiewicz73855e12009-04-01 21:42:21 +02001295 memset(&ubd_id, 0, ATA_ID_WORDS * 2);
1296 ubd_id[ATA_ID_CYLS] = ubd_dev->size / (128 * 32 * 512);
1297 ubd_id[ATA_ID_HEADS] = 128;
1298 ubd_id[ATA_ID_SECTORS] = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299 if(copy_to_user((char __user *) arg, (char *) &ubd_id,
1300 sizeof(ubd_id)))
Jeff Dikedc764e52007-05-06 14:51:41 -07001301 return -EFAULT;
1302 return 0;
Jeff Dikeb8831a12007-02-10 01:44:17 -08001303
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 case CDROMVOLREAD:
1305 if(copy_from_user(&volume, (char __user *) arg, sizeof(volume)))
Jeff Dikedc764e52007-05-06 14:51:41 -07001306 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 volume.channel0 = 255;
1308 volume.channel1 = 255;
1309 volume.channel2 = 255;
1310 volume.channel3 = 255;
1311 if(copy_to_user((char __user *) arg, &volume, sizeof(volume)))
Jeff Dikedc764e52007-05-06 14:51:41 -07001312 return -EFAULT;
1313 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 }
Jeff Dikedc764e52007-05-06 14:51:41 -07001315 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316}
1317
Jeff Dike91acb212005-10-10 23:10:32 -04001318static int update_bitmap(struct io_thread_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319{
Jeff Dike91acb212005-10-10 23:10:32 -04001320 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321
Jeff Dike91acb212005-10-10 23:10:32 -04001322 if(req->cow_offset == -1)
Jeff Dikedc764e52007-05-06 14:51:41 -07001323 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324
Jeff Dike91acb212005-10-10 23:10:32 -04001325 n = os_seek_file(req->fds[1], req->cow_offset);
1326 if(n < 0){
1327 printk("do_io - bitmap lseek failed : err = %d\n", -n);
Jeff Dikedc764e52007-05-06 14:51:41 -07001328 return 1;
Jeff Dike91acb212005-10-10 23:10:32 -04001329 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001331 n = os_write_file(req->fds[1], &req->bitmap_words,
1332 sizeof(req->bitmap_words));
Jeff Dike91acb212005-10-10 23:10:32 -04001333 if(n != sizeof(req->bitmap_words)){
1334 printk("do_io - bitmap update failed, err = %d fd = %d\n", -n,
1335 req->fds[1]);
Jeff Dikedc764e52007-05-06 14:51:41 -07001336 return 1;
Jeff Dike91acb212005-10-10 23:10:32 -04001337 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338
Jeff Dikedc764e52007-05-06 14:51:41 -07001339 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340}
Jeff Dike91acb212005-10-10 23:10:32 -04001341
WANG Cong5dc62b12008-04-28 02:13:58 -07001342static void do_io(struct io_thread_req *req)
Jeff Dike91acb212005-10-10 23:10:32 -04001343{
1344 char *buf;
1345 unsigned long len;
1346 int n, nsectors, start, end, bit;
1347 int err;
1348 __u64 off;
1349
1350 nsectors = req->length / req->sectorsize;
1351 start = 0;
1352 do {
1353 bit = ubd_test_bit(start, (unsigned char *) &req->sector_mask);
1354 end = start;
1355 while((end < nsectors) &&
1356 (ubd_test_bit(end, (unsigned char *)
1357 &req->sector_mask) == bit))
1358 end++;
1359
1360 off = req->offset + req->offsets[bit] +
1361 start * req->sectorsize;
1362 len = (end - start) * req->sectorsize;
1363 buf = &req->buffer[start * req->sectorsize];
1364
1365 err = os_seek_file(req->fds[bit], off);
1366 if(err < 0){
1367 printk("do_io - lseek failed : err = %d\n", -err);
1368 req->error = 1;
1369 return;
1370 }
1371 if(req->op == UBD_READ){
1372 n = 0;
1373 do {
1374 buf = &buf[n];
1375 len -= n;
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001376 n = os_read_file(req->fds[bit], buf, len);
Jeff Dike91acb212005-10-10 23:10:32 -04001377 if (n < 0) {
1378 printk("do_io - read failed, err = %d "
1379 "fd = %d\n", -n, req->fds[bit]);
1380 req->error = 1;
1381 return;
1382 }
1383 } while((n < len) && (n != 0));
1384 if (n < len) memset(&buf[n], 0, len - n);
1385 } else {
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001386 n = os_write_file(req->fds[bit], buf, len);
Jeff Dike91acb212005-10-10 23:10:32 -04001387 if(n != len){
1388 printk("do_io - write failed err = %d "
1389 "fd = %d\n", -n, req->fds[bit]);
1390 req->error = 1;
1391 return;
1392 }
1393 }
1394
1395 start = end;
1396 } while(start < nsectors);
1397
1398 req->error = update_bitmap(req);
1399}
1400
1401/* Changed in start_io_thread, which is serialized by being called only
1402 * from ubd_init, which is an initcall.
1403 */
1404int kernel_fd = -1;
1405
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001406/* Only changed by the io thread. XXX: currently unused. */
1407static int io_count = 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001408
1409int io_thread(void *arg)
1410{
Jeff Dike2adcec22007-05-06 14:51:37 -07001411 struct io_thread_req *req;
Jeff Dike91acb212005-10-10 23:10:32 -04001412 int n;
1413
1414 ignore_sigwinch_sig();
1415 while(1){
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001416 n = os_read_file(kernel_fd, &req,
Jeff Dike2adcec22007-05-06 14:51:37 -07001417 sizeof(struct io_thread_req *));
1418 if(n != sizeof(struct io_thread_req *)){
Jeff Dike91acb212005-10-10 23:10:32 -04001419 if(n < 0)
1420 printk("io_thread - read failed, fd = %d, "
1421 "err = %d\n", kernel_fd, -n);
1422 else {
1423 printk("io_thread - short read, fd = %d, "
1424 "length = %d\n", kernel_fd, n);
1425 }
1426 continue;
1427 }
1428 io_count++;
Jeff Dike2adcec22007-05-06 14:51:37 -07001429 do_io(req);
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001430 n = os_write_file(kernel_fd, &req,
Jeff Dike2adcec22007-05-06 14:51:37 -07001431 sizeof(struct io_thread_req *));
1432 if(n != sizeof(struct io_thread_req *))
Jeff Dike91acb212005-10-10 23:10:32 -04001433 printk("io_thread - write failed, fd = %d, err = %d\n",
1434 kernel_fd, -n);
1435 }
Jeff Dike91acb212005-10-10 23:10:32 -04001436
Jeff Dike1b57e9c2006-01-06 00:18:49 -08001437 return 0;
1438}