blob: 1812bc81715b75ec47dcdd6f5ae9971c4fe03412 [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
Al Viro8ea3c062011-08-18 18:04:41 -040022#include <linux/module.h>
23#include <linux/init.h>
24#include <linux/blkdev.h>
25#include <linux/ata.h>
26#include <linux/hdreg.h>
27#include <linux/cdrom.h>
28#include <linux/proc_fs.h>
29#include <linux/seq_file.h>
30#include <linux/ctype.h>
31#include <linux/slab.h>
32#include <linux/vmalloc.h>
33#include <linux/platform_device.h>
34#include <linux/scatterlist.h>
35#include <asm/tlbflush.h>
Al Viro37185b32012-10-08 03:27:32 +010036#include <kern_util.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#include "mconsole_kern.h"
Al Viro37185b32012-10-08 03:27:32 +010038#include <init.h>
39#include <irq_kern.h>
Al Viro8ea3c062011-08-18 18:04:41 -040040#include "ubd.h"
Al Viro37185b32012-10-08 03:27:32 +010041#include <os.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include "cow.h"
43
Richard Weinberger805f11a2013-08-18 13:30:06 +020044enum ubd_req { UBD_READ, UBD_WRITE, UBD_FLUSH };
Linus Torvalds1da177e2005-04-16 15:20:36 -070045
46struct io_thread_req {
Jeff Dike62f96cb2007-02-10 01:44:16 -080047 struct request *req;
Jeff Dike91acb212005-10-10 23:10:32 -040048 enum ubd_req op;
Linus Torvalds1da177e2005-04-16 15:20:36 -070049 int fds[2];
50 unsigned long offsets[2];
51 unsigned long long offset;
52 unsigned long length;
53 char *buffer;
54 int sectorsize;
Jeff Dike91acb212005-10-10 23:10:32 -040055 unsigned long sector_mask;
56 unsigned long long cow_offset;
57 unsigned long bitmap_words[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 int error;
59};
60
Jeff Dike91acb212005-10-10 23:10:32 -040061static inline int ubd_test_bit(__u64 bit, unsigned char *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -070062{
63 __u64 n;
64 int bits, off;
65
Jeff Dike91acb212005-10-10 23:10:32 -040066 bits = sizeof(data[0]) * 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -070067 n = bit / bits;
68 off = bit % bits;
Jeff Dikedc764e52007-05-06 14:51:41 -070069 return (data[n] & (1 << off)) != 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070070}
71
Jeff Dike91acb212005-10-10 23:10:32 -040072static inline void ubd_set_bit(__u64 bit, unsigned char *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -070073{
74 __u64 n;
75 int bits, off;
76
Jeff Dike91acb212005-10-10 23:10:32 -040077 bits = sizeof(data[0]) * 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -070078 n = bit / bits;
79 off = bit % bits;
Jeff Dike91acb212005-10-10 23:10:32 -040080 data[n] |= (1 << off);
Linus Torvalds1da177e2005-04-16 15:20:36 -070081}
82/*End stuff from ubd_user.h*/
83
84#define DRIVER_NAME "uml-blkdev"
85
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -080086static DEFINE_MUTEX(ubd_lock);
Arnd Bergmann9a181c52010-09-11 18:38:03 +020087static DEFINE_MUTEX(ubd_mutex); /* replaces BKL, might not be needed */
Linus Torvalds1da177e2005-04-16 15:20:36 -070088
Al Viroa625c992008-03-02 09:16:26 -050089static int ubd_open(struct block_device *bdev, fmode_t mode);
Al Virodb2a1442013-05-05 21:52:57 -040090static void ubd_release(struct gendisk *disk, fmode_t mode);
Al Viroa625c992008-03-02 09:16:26 -050091static int ubd_ioctl(struct block_device *bdev, fmode_t mode,
Linus Torvalds1da177e2005-04-16 15:20:36 -070092 unsigned int cmd, unsigned long arg);
Christoph Hellwiga885c8c2006-01-08 01:02:50 -080093static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo);
Linus Torvalds1da177e2005-04-16 15:20:36 -070094
Paolo 'Blaisorblade' Giarrusso97d88ac2006-10-30 22:07:03 -080095#define MAX_DEV (16)
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
Alexey Dobriyan83d5cde2009-09-21 17:01:13 -070097static const struct block_device_operations ubd_blops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070098 .owner = THIS_MODULE,
Al Viroa625c992008-03-02 09:16:26 -050099 .open = ubd_open,
100 .release = ubd_release,
101 .ioctl = ubd_ioctl,
Christoph Hellwiga885c8c2006-01-08 01:02:50 -0800102 .getgeo = ubd_getgeo,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103};
104
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105/* Protected by ubd_lock */
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700106static int fake_major = UBD_MAJOR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107static struct gendisk *ubd_gendisk[MAX_DEV];
108static struct gendisk *fake_gendisk[MAX_DEV];
Jeff Dike6c29256c2006-03-27 01:14:37 -0800109
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110#ifdef CONFIG_BLK_DEV_UBD_SYNC
111#define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 1, .c = 0, \
112 .cl = 1 })
113#else
114#define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 0, .c = 0, \
115 .cl = 1 })
116#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117static struct openflags global_openflags = OPEN_FLAGS;
118
119struct cow {
Paolo 'Blaisorblade' Giarrusso2a9d32f2006-10-30 22:07:04 -0800120 /* backing file name */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 char *file;
Paolo 'Blaisorblade' Giarrusso2a9d32f2006-10-30 22:07:04 -0800122 /* backing file fd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 int fd;
124 unsigned long *bitmap;
125 unsigned long bitmap_len;
126 int bitmap_offset;
Jeff Dikedc764e52007-05-06 14:51:41 -0700127 int data_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128};
129
Jeff Dikea0044bd2007-05-06 14:51:36 -0700130#define MAX_SG 64
131
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132struct ubd {
Jeff Dikea0044bd2007-05-06 14:51:36 -0700133 struct list_head restart;
Paolo 'Blaisorblade' Giarrusso2a9d32f2006-10-30 22:07:04 -0800134 /* name (and fd, below) of the file opened for writing, either the
135 * backing or the cow file. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 char *file;
137 int count;
138 int fd;
139 __u64 size;
140 struct openflags boot_openflags;
141 struct openflags openflags;
Paolo 'Blaisorblade' Giarrusso84e945e2006-10-30 22:07:10 -0800142 unsigned shared:1;
143 unsigned no_cow:1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144 struct cow cow;
145 struct platform_device pdev;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800146 struct request_queue *queue;
147 spinlock_t lock;
Jeff Dikea0044bd2007-05-06 14:51:36 -0700148 struct scatterlist sg[MAX_SG];
149 struct request *request;
150 int start_sg, end_sg;
Tejun Heo47526902010-10-15 12:56:21 +0200151 sector_t rq_pos;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152};
153
154#define DEFAULT_COW { \
155 .file = NULL, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700156 .fd = -1, \
157 .bitmap = NULL, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 .bitmap_offset = 0, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700159 .data_offset = 0, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160}
161
162#define DEFAULT_UBD { \
163 .file = NULL, \
164 .count = 0, \
165 .fd = -1, \
166 .size = -1, \
167 .boot_openflags = OPEN_FLAGS, \
168 .openflags = OPEN_FLAGS, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700169 .no_cow = 0, \
Jeff Dike6c29256c2006-03-27 01:14:37 -0800170 .shared = 0, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700171 .cow = DEFAULT_COW, \
Thomas Gleixner22e65002011-01-23 15:21:25 +0100172 .lock = __SPIN_LOCK_UNLOCKED(ubd_devs.lock), \
Jeff Dikea0044bd2007-05-06 14:51:36 -0700173 .request = NULL, \
174 .start_sg = 0, \
175 .end_sg = 0, \
Tejun Heo47526902010-10-15 12:56:21 +0200176 .rq_pos = 0, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177}
178
Jeff Dikeb8831a12007-02-10 01:44:17 -0800179/* Protected by ubd_lock */
WANG Cong5dc62b12008-04-28 02:13:58 -0700180static struct ubd ubd_devs[MAX_DEV] = { [0 ... MAX_DEV - 1] = DEFAULT_UBD };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182/* Only changed by fake_ide_setup which is a setup */
183static int fake_ide = 0;
184static struct proc_dir_entry *proc_ide_root = NULL;
185static struct proc_dir_entry *proc_ide = NULL;
186
187static void make_proc_ide(void)
188{
189 proc_ide_root = proc_mkdir("ide", NULL);
190 proc_ide = proc_mkdir("ide0", proc_ide_root);
191}
192
Alexey Dobriyan6613c5e2009-12-14 18:00:11 -0800193static int fake_ide_media_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194{
Alexey Dobriyan6613c5e2009-12-14 18:00:11 -0800195 seq_puts(m, "disk\n");
196 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197}
198
Alexey Dobriyan6613c5e2009-12-14 18:00:11 -0800199static int fake_ide_media_proc_open(struct inode *inode, struct file *file)
200{
201 return single_open(file, fake_ide_media_proc_show, NULL);
202}
203
204static const struct file_operations fake_ide_media_proc_fops = {
205 .owner = THIS_MODULE,
206 .open = fake_ide_media_proc_open,
207 .read = seq_read,
208 .llseek = seq_lseek,
209 .release = single_release,
210};
211
WANG Congc0a92902008-02-04 22:30:41 -0800212static void make_ide_entries(const char *dev_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213{
214 struct proc_dir_entry *dir, *ent;
215 char name[64];
216
217 if(proc_ide_root == NULL) make_proc_ide();
218
219 dir = proc_mkdir(dev_name, proc_ide);
220 if(!dir) return;
221
Alexey Dobriyan6613c5e2009-12-14 18:00:11 -0800222 ent = proc_create("media", S_IRUGO, dir, &fake_ide_media_proc_fops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 if(!ent) return;
WANG Congc0a92902008-02-04 22:30:41 -0800224 snprintf(name, sizeof(name), "ide0/%s", dev_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 proc_symlink(dev_name, proc_ide_root, name);
226}
227
228static int fake_ide_setup(char *str)
229{
230 fake_ide = 1;
Jeff Dikedc764e52007-05-06 14:51:41 -0700231 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232}
233
234__setup("fake_ide", fake_ide_setup);
235
236__uml_help(fake_ide_setup,
237"fake_ide\n"
238" Create ide0 entries that map onto ubd devices.\n\n"
239);
240
241static int parse_unit(char **ptr)
242{
243 char *str = *ptr, *end;
244 int n = -1;
245
246 if(isdigit(*str)) {
247 n = simple_strtoul(str, &end, 0);
248 if(end == str)
Jeff Dikedc764e52007-05-06 14:51:41 -0700249 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 *ptr = end;
251 }
Paolo 'Blaisorblade' Giarrusso97d88ac2006-10-30 22:07:03 -0800252 else if (('a' <= *str) && (*str <= 'z')) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 n = *str - 'a';
254 str++;
255 *ptr = str;
256 }
Jeff Dikedc764e52007-05-06 14:51:41 -0700257 return n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258}
259
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800260/* If *index_out == -1 at exit, the passed option was a general one;
261 * otherwise, the str pointer is used (and owned) inside ubd_devs array, so it
262 * should not be freed on exit.
263 */
Jeff Dikef28169d2007-02-10 01:43:53 -0800264static int ubd_setup_common(char *str, int *index_out, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800266 struct ubd *ubd_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 struct openflags flags = global_openflags;
268 char *backing_file;
Jeff Dikeb8831a12007-02-10 01:44:17 -0800269 int n, err = 0, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270
271 if(index_out) *index_out = -1;
272 n = *str;
273 if(n == '='){
274 char *end;
275 int major;
276
277 str++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 if(!strcmp(str, "sync")){
279 global_openflags = of_sync(global_openflags);
Jeff Dikeb8831a12007-02-10 01:44:17 -0800280 goto out1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 }
282
Jeff Dikef28169d2007-02-10 01:43:53 -0800283 err = -EINVAL;
Jeff Dikeb8831a12007-02-10 01:44:17 -0800284 major = simple_strtoul(str, &end, 0);
285 if((*end != '\0') || (end == str)){
286 *error_out = "Didn't parse major number";
287 goto out1;
288 }
289
Jeff Dikef28169d2007-02-10 01:43:53 -0800290 mutex_lock(&ubd_lock);
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700291 if (fake_major != UBD_MAJOR) {
Jeff Dikef28169d2007-02-10 01:43:53 -0800292 *error_out = "Can't assign a fake major twice";
293 goto out1;
294 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800295
Jeff Dikef28169d2007-02-10 01:43:53 -0800296 fake_major = major;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297
298 printk(KERN_INFO "Setting extra ubd major number to %d\n",
299 major);
Jeff Dikef28169d2007-02-10 01:43:53 -0800300 err = 0;
301 out1:
302 mutex_unlock(&ubd_lock);
303 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 }
305
306 n = parse_unit(&str);
307 if(n < 0){
Jeff Dikef28169d2007-02-10 01:43:53 -0800308 *error_out = "Couldn't parse device number";
309 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 }
311 if(n >= MAX_DEV){
Jeff Dikef28169d2007-02-10 01:43:53 -0800312 *error_out = "Device number out of range";
313 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 }
315
Jeff Dikef28169d2007-02-10 01:43:53 -0800316 err = -EBUSY;
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800317 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800319 ubd_dev = &ubd_devs[n];
320 if(ubd_dev->file != NULL){
Jeff Dikef28169d2007-02-10 01:43:53 -0800321 *error_out = "Device is already configured";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 goto out;
323 }
324
325 if (index_out)
326 *index_out = n;
327
Jeff Dikef28169d2007-02-10 01:43:53 -0800328 err = -EINVAL;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800329 for (i = 0; i < sizeof("rscd="); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 switch (*str) {
331 case 'r':
332 flags.w = 0;
333 break;
334 case 's':
335 flags.s = 1;
336 break;
337 case 'd':
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800338 ubd_dev->no_cow = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 break;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800340 case 'c':
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800341 ubd_dev->shared = 1;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800342 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 case '=':
344 str++;
345 goto break_loop;
346 default:
Jeff Dikef28169d2007-02-10 01:43:53 -0800347 *error_out = "Expected '=' or flag letter "
348 "(r, s, c, or d)";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 goto out;
350 }
351 str++;
352 }
353
Jeff Dikef28169d2007-02-10 01:43:53 -0800354 if (*str == '=')
355 *error_out = "Too many flags specified";
356 else
357 *error_out = "Missing '='";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 goto out;
359
360break_loop:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 backing_file = strchr(str, ',');
362
Jeff Dikef28169d2007-02-10 01:43:53 -0800363 if (backing_file == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 backing_file = strchr(str, ':');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365
Jeff Dikef28169d2007-02-10 01:43:53 -0800366 if(backing_file != NULL){
367 if(ubd_dev->no_cow){
368 *error_out = "Can't specify both 'd' and a cow file";
369 goto out;
370 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 else {
372 *backing_file = '\0';
373 backing_file++;
374 }
375 }
Jeff Dikef28169d2007-02-10 01:43:53 -0800376 err = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800377 ubd_dev->file = str;
378 ubd_dev->cow.file = backing_file;
379 ubd_dev->boot_openflags = flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800381 mutex_unlock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -0800382 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383}
384
385static int ubd_setup(char *str)
386{
Jeff Dikef28169d2007-02-10 01:43:53 -0800387 char *error;
388 int err;
389
390 err = ubd_setup_common(str, NULL, &error);
391 if(err)
392 printk(KERN_ERR "Failed to initialize device with \"%s\" : "
393 "%s\n", str, error);
394 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395}
396
397__setup("ubd", ubd_setup);
398__uml_help(ubd_setup,
399"ubd<n><flags>=<filename>[(:|,)<filename2>]\n"
400" This is used to associate a device with a file in the underlying\n"
401" filesystem. When specifying two filenames, the first one is the\n"
402" COW name and the second is the backing file name. As separator you can\n"
403" use either a ':' or a ',': the first one allows writing things like;\n"
404" ubd0=~/Uml/root_cow:~/Uml/root_backing_file\n"
405" while with a ',' the shell would not expand the 2nd '~'.\n"
Jeff Dikef28169d2007-02-10 01:43:53 -0800406" When using only one filename, UML will detect whether to treat it like\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407" a COW file or a backing file. To override this detection, add the 'd'\n"
408" flag:\n"
409" ubd0d=BackingFile\n"
410" Usually, there is a filesystem in the file, but \n"
411" that's not required. Swap devices containing swap files can be\n"
412" specified like this. Also, a file which doesn't contain a\n"
413" filesystem can have its contents read in the virtual \n"
414" machine by running 'dd' on the device. <n> must be in the range\n"
415" 0 to 7. Appending an 'r' to the number will cause that device\n"
416" to be mounted read-only. For example ubd1r=./ext_fs. Appending\n"
Jeff Dike20ede452008-02-04 22:30:37 -0800417" an 's' will cause data to be written to disk on the host immediately.\n"
418" 'c' will cause the device to be treated as being shared between multiple\n"
419" UMLs and file locking will be turned off - this is appropriate for a\n"
420" cluster filesystem and inappropriate at almost all other times.\n\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421);
422
Jeff Dike8299ca52008-02-04 22:30:48 -0800423static int udb_setup(char *str)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424{
425 printk("udb%s specified on command line is almost certainly a ubd -> "
426 "udb TYPO\n", str);
Jeff Dikedc764e52007-05-06 14:51:41 -0700427 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428}
429
430__setup("udb", udb_setup);
431__uml_help(udb_setup,
432"udb\n"
Jeff Dike0894e272005-05-28 15:51:55 -0700433" This option is here solely to catch ubd -> udb typos, which can be\n"
434" to impossible to catch visually unless you specifically look for\n"
435" them. The only result of any option starting with 'udb' is an error\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436" in the boot output.\n\n"
437);
438
Jens Axboe165125e2007-07-24 09:28:11 +0200439static void do_ubd_request(struct request_queue * q);
Jeff Dike91acb212005-10-10 23:10:32 -0400440
441/* Only changed by ubd_init, which is an initcall. */
WANG Cong5dc62b12008-04-28 02:13:58 -0700442static int thread_fd = -1;
Jeff Dikea0044bd2007-05-06 14:51:36 -0700443static LIST_HEAD(restart);
444
Paolo 'Blaisorblade' Giarrusso2fe30a32006-10-30 22:07:09 -0800445/* XXX - move this inside ubd_intr. */
Jeff Dike62f96cb2007-02-10 01:44:16 -0800446/* Called without dev->lock held, and only in interrupt context. */
Jeff Dike91acb212005-10-10 23:10:32 -0400447static void ubd_handler(void)
448{
Jeff Dike2adcec22007-05-06 14:51:37 -0700449 struct io_thread_req *req;
Jeff Dikea0044bd2007-05-06 14:51:36 -0700450 struct ubd *ubd;
451 struct list_head *list, *next_ele;
452 unsigned long flags;
Jeff Dike91acb212005-10-10 23:10:32 -0400453 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454
Jeff Dikea0044bd2007-05-06 14:51:36 -0700455 while(1){
Jeff Dikea6ea4cc2007-05-06 14:51:43 -0700456 n = os_read_file(thread_fd, &req,
457 sizeof(struct io_thread_req *));
Jeff Dikea0044bd2007-05-06 14:51:36 -0700458 if(n != sizeof(req)){
459 if(n == -EAGAIN)
460 break;
461 printk(KERN_ERR "spurious interrupt in ubd_handler, "
462 "err = %d\n", -n);
463 return;
464 }
465
Tejun Heo4d6c84d2009-04-28 13:06:09 +0900466 blk_end_request(req->req, 0, req->length);
Jeff Dike2adcec22007-05-06 14:51:37 -0700467 kfree(req);
Jeff Dike91acb212005-10-10 23:10:32 -0400468 }
Jeff Dike62f96cb2007-02-10 01:44:16 -0800469 reactivate_fd(thread_fd, UBD_IRQ);
Jeff Dikea0044bd2007-05-06 14:51:36 -0700470
471 list_for_each_safe(list, next_ele, &restart){
472 ubd = container_of(list, struct ubd, restart);
473 list_del_init(&ubd->restart);
474 spin_lock_irqsave(&ubd->lock, flags);
475 do_ubd_request(ubd->queue);
476 spin_unlock_irqrestore(&ubd->lock, flags);
477 }
Jeff Dike91acb212005-10-10 23:10:32 -0400478}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479
Al Viro7bea96f2006-10-08 22:49:34 +0100480static irqreturn_t ubd_intr(int irq, void *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481{
Jeff Dike91acb212005-10-10 23:10:32 -0400482 ubd_handler();
Jeff Dikedc764e52007-05-06 14:51:41 -0700483 return IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484}
485
Jeff Dike91acb212005-10-10 23:10:32 -0400486/* Only changed by ubd_init, which is an initcall. */
487static int io_pid = -1;
488
WANG Cong5dc62b12008-04-28 02:13:58 -0700489static void kill_io_thread(void)
Jeff Dike91acb212005-10-10 23:10:32 -0400490{
Jeff Dike6c29256c2006-03-27 01:14:37 -0800491 if(io_pid != -1)
Jeff Dike91acb212005-10-10 23:10:32 -0400492 os_kill_process(io_pid, 1);
493}
494
495__uml_exitcall(kill_io_thread);
496
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800497static inline int ubd_file_size(struct ubd *ubd_dev, __u64 *size_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498{
499 char *file;
Richard Weinberger85356392011-11-02 13:17:27 +0100500 int fd;
501 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502
Richard Weinberger85356392011-11-02 13:17:27 +0100503 __u32 version;
504 __u32 align;
505 char *backing_file;
506 time_t mtime;
507 unsigned long long size;
508 int sector_size;
509 int bitmap_offset;
510
511 if (ubd_dev->file && ubd_dev->cow.file) {
512 file = ubd_dev->cow.file;
513
514 goto out;
515 }
516
Martin Pärteld4afcba2012-08-02 00:44:22 +0200517 fd = os_open_file(ubd_dev->file, of_read(OPENFLAGS()), 0);
Richard Weinberger85356392011-11-02 13:17:27 +0100518 if (fd < 0)
519 return fd;
520
521 err = read_cow_header(file_reader, &fd, &version, &backing_file, \
522 &mtime, &size, &sector_size, &align, &bitmap_offset);
523 os_close_file(fd);
524
525 if(err == -EINVAL)
526 file = ubd_dev->file;
527 else
528 file = backing_file;
529
530out:
Jeff Dikedc764e52007-05-06 14:51:41 -0700531 return os_file_size(file, size_out);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532}
533
WANG Cong5dc62b12008-04-28 02:13:58 -0700534static int read_cow_bitmap(int fd, void *buf, int offset, int len)
535{
536 int err;
537
538 err = os_seek_file(fd, offset);
539 if (err < 0)
540 return err;
541
542 err = os_read_file(fd, buf, len);
543 if (err < 0)
544 return err;
545
546 return 0;
547}
548
549static int backing_file_mismatch(char *file, __u64 size, time_t mtime)
550{
551 unsigned long modtime;
552 unsigned long long actual;
553 int err;
554
555 err = os_file_modtime(file, &modtime);
556 if (err < 0) {
557 printk(KERN_ERR "Failed to get modification time of backing "
558 "file \"%s\", err = %d\n", file, -err);
559 return err;
560 }
561
562 err = os_file_size(file, &actual);
563 if (err < 0) {
564 printk(KERN_ERR "Failed to get size of backing file \"%s\", "
565 "err = %d\n", file, -err);
566 return err;
567 }
568
569 if (actual != size) {
570 /*__u64 can be a long on AMD64 and with %lu GCC complains; so
571 * the typecast.*/
572 printk(KERN_ERR "Size mismatch (%llu vs %llu) of COW header "
573 "vs backing file\n", (unsigned long long) size, actual);
574 return -EINVAL;
575 }
576 if (modtime != mtime) {
577 printk(KERN_ERR "mtime mismatch (%ld vs %ld) of COW header vs "
578 "backing file\n", mtime, modtime);
579 return -EINVAL;
580 }
581 return 0;
582}
583
584static int path_requires_switch(char *from_cmdline, char *from_cow, char *cow)
585{
586 struct uml_stat buf1, buf2;
587 int err;
588
589 if (from_cmdline == NULL)
590 return 0;
591 if (!strcmp(from_cmdline, from_cow))
592 return 0;
593
594 err = os_stat_file(from_cmdline, &buf1);
595 if (err < 0) {
596 printk(KERN_ERR "Couldn't stat '%s', err = %d\n", from_cmdline,
597 -err);
598 return 0;
599 }
600 err = os_stat_file(from_cow, &buf2);
601 if (err < 0) {
602 printk(KERN_ERR "Couldn't stat '%s', err = %d\n", from_cow,
603 -err);
604 return 1;
605 }
606 if ((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino))
607 return 0;
608
609 printk(KERN_ERR "Backing file mismatch - \"%s\" requested, "
610 "\"%s\" specified in COW header of \"%s\"\n",
611 from_cmdline, from_cow, cow);
612 return 1;
613}
614
615static int open_ubd_file(char *file, struct openflags *openflags, int shared,
616 char **backing_file_out, int *bitmap_offset_out,
617 unsigned long *bitmap_len_out, int *data_offset_out,
618 int *create_cow_out)
619{
620 time_t mtime;
621 unsigned long long size;
622 __u32 version, align;
623 char *backing_file;
624 int fd, err, sectorsize, asked_switch, mode = 0644;
625
626 fd = os_open_file(file, *openflags, mode);
627 if (fd < 0) {
628 if ((fd == -ENOENT) && (create_cow_out != NULL))
629 *create_cow_out = 1;
630 if (!openflags->w ||
631 ((fd != -EROFS) && (fd != -EACCES)))
632 return fd;
633 openflags->w = 0;
634 fd = os_open_file(file, *openflags, mode);
635 if (fd < 0)
636 return fd;
637 }
638
639 if (shared)
640 printk(KERN_INFO "Not locking \"%s\" on the host\n", file);
641 else {
642 err = os_lock_file(fd, openflags->w);
643 if (err < 0) {
644 printk(KERN_ERR "Failed to lock '%s', err = %d\n",
645 file, -err);
646 goto out_close;
647 }
648 }
649
650 /* Successful return case! */
651 if (backing_file_out == NULL)
652 return fd;
653
654 err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime,
655 &size, &sectorsize, &align, bitmap_offset_out);
656 if (err && (*backing_file_out != NULL)) {
657 printk(KERN_ERR "Failed to read COW header from COW file "
658 "\"%s\", errno = %d\n", file, -err);
659 goto out_close;
660 }
661 if (err)
662 return fd;
663
664 asked_switch = path_requires_switch(*backing_file_out, backing_file,
665 file);
666
667 /* Allow switching only if no mismatch. */
668 if (asked_switch && !backing_file_mismatch(*backing_file_out, size,
669 mtime)) {
670 printk(KERN_ERR "Switching backing file to '%s'\n",
671 *backing_file_out);
672 err = write_cow_header(file, fd, *backing_file_out,
673 sectorsize, align, &size);
674 if (err) {
675 printk(KERN_ERR "Switch failed, errno = %d\n", -err);
676 goto out_close;
677 }
678 } else {
679 *backing_file_out = backing_file;
680 err = backing_file_mismatch(*backing_file_out, size, mtime);
681 if (err)
682 goto out_close;
683 }
684
685 cow_sizes(version, size, sectorsize, align, *bitmap_offset_out,
686 bitmap_len_out, data_offset_out);
687
688 return fd;
689 out_close:
690 os_close_file(fd);
691 return err;
692}
693
694static int create_cow_file(char *cow_file, char *backing_file,
695 struct openflags flags,
696 int sectorsize, int alignment, int *bitmap_offset_out,
697 unsigned long *bitmap_len_out, int *data_offset_out)
698{
699 int err, fd;
700
701 flags.c = 1;
702 fd = open_ubd_file(cow_file, &flags, 0, NULL, NULL, NULL, NULL, NULL);
703 if (fd < 0) {
704 err = fd;
705 printk(KERN_ERR "Open of COW file '%s' failed, errno = %d\n",
706 cow_file, -err);
707 goto out;
708 }
709
710 err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment,
711 bitmap_offset_out, bitmap_len_out,
712 data_offset_out);
713 if (!err)
714 return fd;
715 os_close_file(fd);
716 out:
717 return err;
718}
719
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800720static void ubd_close_dev(struct ubd *ubd_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800722 os_close_file(ubd_dev->fd);
723 if(ubd_dev->cow.file == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 return;
725
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800726 os_close_file(ubd_dev->cow.fd);
727 vfree(ubd_dev->cow.bitmap);
728 ubd_dev->cow.bitmap = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729}
730
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800731static int ubd_open_dev(struct ubd *ubd_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732{
733 struct openflags flags;
734 char **back_ptr;
735 int err, create_cow, *create_ptr;
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800736 int fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800738 ubd_dev->openflags = ubd_dev->boot_openflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 create_cow = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800740 create_ptr = (ubd_dev->cow.file != NULL) ? &create_cow : NULL;
741 back_ptr = ubd_dev->no_cow ? NULL : &ubd_dev->cow.file;
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800742
743 fd = open_ubd_file(ubd_dev->file, &ubd_dev->openflags, ubd_dev->shared,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800744 back_ptr, &ubd_dev->cow.bitmap_offset,
745 &ubd_dev->cow.bitmap_len, &ubd_dev->cow.data_offset,
Jeff Dike6c29256c2006-03-27 01:14:37 -0800746 create_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800748 if((fd == -ENOENT) && create_cow){
749 fd = create_cow_file(ubd_dev->file, ubd_dev->cow.file,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800750 ubd_dev->openflags, 1 << 9, PAGE_SIZE,
751 &ubd_dev->cow.bitmap_offset,
752 &ubd_dev->cow.bitmap_len,
753 &ubd_dev->cow.data_offset);
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800754 if(fd >= 0){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 printk(KERN_INFO "Creating \"%s\" as COW file for "
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800756 "\"%s\"\n", ubd_dev->file, ubd_dev->cow.file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 }
758 }
759
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800760 if(fd < 0){
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800761 printk("Failed to open '%s', errno = %d\n", ubd_dev->file,
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800762 -fd);
763 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 }
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800765 ubd_dev->fd = fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800767 if(ubd_dev->cow.file != NULL){
Martin K. Petersen086fa5f2010-02-26 00:20:38 -0500768 blk_queue_max_hw_sectors(ubd_dev->queue, 8 * sizeof(long));
Jeff Dikef4768ff2007-08-22 14:01:53 -0700769
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 err = -ENOMEM;
Jesper Juhlda2486b2007-10-16 01:27:19 -0700771 ubd_dev->cow.bitmap = vmalloc(ubd_dev->cow.bitmap_len);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800772 if(ubd_dev->cow.bitmap == NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 printk(KERN_ERR "Failed to vmalloc COW bitmap\n");
774 goto error;
775 }
776 flush_tlb_kernel_vm();
777
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800778 err = read_cow_bitmap(ubd_dev->fd, ubd_dev->cow.bitmap,
779 ubd_dev->cow.bitmap_offset,
780 ubd_dev->cow.bitmap_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 if(err < 0)
782 goto error;
783
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800784 flags = ubd_dev->openflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 flags.w = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800786 err = open_ubd_file(ubd_dev->cow.file, &flags, ubd_dev->shared, NULL,
Jeff Dike6c29256c2006-03-27 01:14:37 -0800787 NULL, NULL, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 if(err < 0) goto error;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800789 ubd_dev->cow.fd = err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 }
Jeff Dikedc764e52007-05-06 14:51:41 -0700791 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 error:
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800793 os_close_file(ubd_dev->fd);
Jeff Dikedc764e52007-05-06 14:51:41 -0700794 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795}
796
Jeff Dike2e3f5252007-05-06 14:51:29 -0700797static void ubd_device_release(struct device *dev)
798{
Greg Kroah-Hartman8691b972009-05-04 12:40:54 -0700799 struct ubd *ubd_dev = dev_get_drvdata(dev);
Jeff Dike2e3f5252007-05-06 14:51:29 -0700800
801 blk_cleanup_queue(ubd_dev->queue);
802 *ubd_dev = ((struct ubd) DEFAULT_UBD);
803}
804
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800805static int ubd_disk_register(int major, u64 size, int unit,
Jeff Dikeb8831a12007-02-10 01:44:17 -0800806 struct gendisk **disk_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807{
808 struct gendisk *disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809
810 disk = alloc_disk(1 << UBD_SHIFT);
811 if(disk == NULL)
Jeff Dikedc764e52007-05-06 14:51:41 -0700812 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813
814 disk->major = major;
815 disk->first_minor = unit << UBD_SHIFT;
816 disk->fops = &ubd_blops;
817 set_capacity(disk, size / 512);
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700818 if (major == UBD_MAJOR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 sprintf(disk->disk_name, "ubd%c", 'a' + unit);
Greg Kroah-Hartmance7b0f42005-06-20 21:15:16 -0700820 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 sprintf(disk->disk_name, "ubd_fake%d", unit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822
823 /* sysfs register (not for ide fake devices) */
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700824 if (major == UBD_MAJOR) {
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800825 ubd_devs[unit].pdev.id = unit;
826 ubd_devs[unit].pdev.name = DRIVER_NAME;
Jeff Dike2e3f5252007-05-06 14:51:29 -0700827 ubd_devs[unit].pdev.dev.release = ubd_device_release;
Greg Kroah-Hartman8691b972009-05-04 12:40:54 -0700828 dev_set_drvdata(&ubd_devs[unit].pdev.dev, &ubd_devs[unit]);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800829 platform_device_register(&ubd_devs[unit].pdev);
830 disk->driverfs_dev = &ubd_devs[unit].pdev.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 }
832
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800833 disk->private_data = &ubd_devs[unit];
Jeff Dike62f96cb2007-02-10 01:44:16 -0800834 disk->queue = ubd_devs[unit].queue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 add_disk(disk);
836
837 *disk_out = disk;
838 return 0;
839}
840
841#define ROUND_BLOCK(n) ((n + ((1 << 9) - 1)) & (-1 << 9))
842
Jeff Dikef28169d2007-02-10 01:43:53 -0800843static int ubd_add(int n, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800845 struct ubd *ubd_dev = &ubd_devs[n];
Jeff Dikef28169d2007-02-10 01:43:53 -0800846 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800848 if(ubd_dev->file == NULL)
Jeff Dikeec7cf782005-09-03 15:57:29 -0700849 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800851 err = ubd_file_size(ubd_dev, &ubd_dev->size);
Jeff Dikef28169d2007-02-10 01:43:53 -0800852 if(err < 0){
853 *error_out = "Couldn't determine size of device's file";
Jeff Dike80c13742006-09-29 01:58:51 -0700854 goto out;
Jeff Dikef28169d2007-02-10 01:43:53 -0800855 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800857 ubd_dev->size = ROUND_BLOCK(ubd_dev->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858
Jeff Dikea0044bd2007-05-06 14:51:36 -0700859 INIT_LIST_HEAD(&ubd_dev->restart);
WANG Cong4f40c052007-11-05 14:50:59 -0800860 sg_init_table(ubd_dev->sg, MAX_SG);
Jeff Dikea0044bd2007-05-06 14:51:36 -0700861
Jeff Dike62f96cb2007-02-10 01:44:16 -0800862 err = -ENOMEM;
863 ubd_dev->queue = blk_init_queue(do_ubd_request, &ubd_dev->lock);
864 if (ubd_dev->queue == NULL) {
865 *error_out = "Failed to initialize device queue";
Jeff Dike80c13742006-09-29 01:58:51 -0700866 goto out;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800867 }
868 ubd_dev->queue->queuedata = ubd_dev;
Richard Weinberger805f11a2013-08-18 13:30:06 +0200869 blk_queue_flush(ubd_dev->queue, REQ_FLUSH);
Jeff Dike62f96cb2007-02-10 01:44:16 -0800870
Martin K. Petersen8a783622010-02-26 00:20:39 -0500871 blk_queue_max_segments(ubd_dev->queue, MAX_SG);
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700872 err = ubd_disk_register(UBD_MAJOR, ubd_dev->size, n, &ubd_gendisk[n]);
Jeff Dike62f96cb2007-02-10 01:44:16 -0800873 if(err){
874 *error_out = "Failed to register device";
875 goto out_cleanup;
876 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800877
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700878 if (fake_major != UBD_MAJOR)
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800879 ubd_disk_register(fake_major, ubd_dev->size, n,
Jeff Dike62f96cb2007-02-10 01:44:16 -0800880 &fake_gendisk[n]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881
Jeff Dike83380cc2008-02-04 22:31:18 -0800882 /*
883 * Perhaps this should also be under the "if (fake_major)" above
884 * using the fake_disk->disk_name
885 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 if (fake_ide)
887 make_ide_entries(ubd_gendisk[n]->disk_name);
888
Jeff Dikeec7cf782005-09-03 15:57:29 -0700889 err = 0;
Jeff Dikeec7cf782005-09-03 15:57:29 -0700890out:
891 return err;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800892
893out_cleanup:
894 blk_cleanup_queue(ubd_dev->queue);
895 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896}
897
Jeff Dikef28169d2007-02-10 01:43:53 -0800898static int ubd_config(char *str, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899{
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800900 int n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901
Jeff Dikef28169d2007-02-10 01:43:53 -0800902 /* This string is possibly broken up and stored, so it's only
903 * freed if ubd_setup_common fails, or if only general options
904 * were set.
905 */
Jeff Dike970d6e32006-01-06 00:18:48 -0800906 str = kstrdup(str, GFP_KERNEL);
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800907 if (str == NULL) {
Jeff Dikef28169d2007-02-10 01:43:53 -0800908 *error_out = "Failed to allocate memory";
909 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 }
Jeff Dikef28169d2007-02-10 01:43:53 -0800911
912 ret = ubd_setup_common(str, &n, error_out);
913 if (ret)
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800914 goto err_free;
Jeff Dikef28169d2007-02-10 01:43:53 -0800915
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800916 if (n == -1) {
917 ret = 0;
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800918 goto err_free;
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800919 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920
Jeff Dikedc764e52007-05-06 14:51:41 -0700921 mutex_lock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -0800922 ret = ubd_add(n, error_out);
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800923 if (ret)
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800924 ubd_devs[n].file = NULL;
Jeff Dikedc764e52007-05-06 14:51:41 -0700925 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800927out:
Jeff Dikedc764e52007-05-06 14:51:41 -0700928 return ret;
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800929
930err_free:
931 kfree(str);
932 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933}
934
935static int ubd_get_config(char *name, char *str, int size, char **error_out)
936{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800937 struct ubd *ubd_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 int n, len = 0;
939
940 n = parse_unit(&name);
941 if((n >= MAX_DEV) || (n < 0)){
942 *error_out = "ubd_get_config : device number out of range";
Jeff Dikedc764e52007-05-06 14:51:41 -0700943 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 }
945
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800946 ubd_dev = &ubd_devs[n];
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800947 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800949 if(ubd_dev->file == NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 CONFIG_CHUNK(str, size, len, "", 1);
951 goto out;
952 }
953
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800954 CONFIG_CHUNK(str, size, len, ubd_dev->file, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800956 if(ubd_dev->cow.file != NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 CONFIG_CHUNK(str, size, len, ",", 0);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800958 CONFIG_CHUNK(str, size, len, ubd_dev->cow.file, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 }
960 else CONFIG_CHUNK(str, size, len, "", 1);
961
962 out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800963 mutex_unlock(&ubd_lock);
Jeff Dikedc764e52007-05-06 14:51:41 -0700964 return len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965}
966
Jeff Dike29d56cf2005-06-25 14:55:25 -0700967static int ubd_id(char **str, int *start_out, int *end_out)
968{
Jeff Dikedc764e52007-05-06 14:51:41 -0700969 int n;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700970
971 n = parse_unit(str);
Jeff Dikedc764e52007-05-06 14:51:41 -0700972 *start_out = 0;
973 *end_out = MAX_DEV - 1;
974 return n;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700975}
976
Jeff Dikef28169d2007-02-10 01:43:53 -0800977static int ubd_remove(int n, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978{
Jeff Dike2e3f5252007-05-06 14:51:29 -0700979 struct gendisk *disk = ubd_gendisk[n];
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800980 struct ubd *ubd_dev;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700981 int err = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800983 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800985 ubd_dev = &ubd_devs[n];
Jeff Dike29d56cf2005-06-25 14:55:25 -0700986
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800987 if(ubd_dev->file == NULL)
Jeff Dike29d56cf2005-06-25 14:55:25 -0700988 goto out;
989
990 /* you cannot remove a open disk */
991 err = -EBUSY;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800992 if(ubd_dev->count > 0)
Jeff Dike29d56cf2005-06-25 14:55:25 -0700993 goto out;
994
Jeff Dikedc764e52007-05-06 14:51:41 -0700995 ubd_gendisk[n] = NULL;
Jeff Dikeb47d2de2007-05-06 14:51:01 -0700996 if(disk != NULL){
997 del_gendisk(disk);
998 put_disk(disk);
999 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000
1001 if(fake_gendisk[n] != NULL){
1002 del_gendisk(fake_gendisk[n]);
1003 put_disk(fake_gendisk[n]);
1004 fake_gendisk[n] = NULL;
1005 }
1006
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 err = 0;
Jeff Dike2e3f5252007-05-06 14:51:29 -07001008 platform_device_unregister(&ubd_dev->pdev);
Jeff Dike29d56cf2005-06-25 14:55:25 -07001009out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -08001010 mutex_unlock(&ubd_lock);
Jeff Dike29d56cf2005-06-25 14:55:25 -07001011 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012}
1013
Jeff Dikef28169d2007-02-10 01:43:53 -08001014/* All these are called by mconsole in process context and without
Jeff Dikeb8831a12007-02-10 01:44:17 -08001015 * ubd-specific locks. The structure itself is const except for .list.
Jeff Dikef28169d2007-02-10 01:43:53 -08001016 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017static struct mc_device ubd_mc = {
Jeff Dike84f48d42007-02-10 01:44:01 -08001018 .list = LIST_HEAD_INIT(ubd_mc.list),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 .name = "ubd",
1020 .config = ubd_config,
Jeff Dikedc764e52007-05-06 14:51:41 -07001021 .get_config = ubd_get_config,
Jeff Dike29d56cf2005-06-25 14:55:25 -07001022 .id = ubd_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 .remove = ubd_remove,
1024};
1025
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001026static int __init ubd_mc_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027{
1028 mconsole_register_dev(&ubd_mc);
1029 return 0;
1030}
1031
1032__initcall(ubd_mc_init);
1033
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001034static int __init ubd0_init(void)
1035{
1036 struct ubd *ubd_dev = &ubd_devs[0];
1037
Jeff Dikeb8831a12007-02-10 01:44:17 -08001038 mutex_lock(&ubd_lock);
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001039 if(ubd_dev->file == NULL)
1040 ubd_dev->file = "root_fs";
Jeff Dikeb8831a12007-02-10 01:44:17 -08001041 mutex_unlock(&ubd_lock);
1042
Jeff Dikedc764e52007-05-06 14:51:41 -07001043 return 0;
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001044}
1045
1046__initcall(ubd0_init);
1047
Jeff Dikeb8831a12007-02-10 01:44:17 -08001048/* Used in ubd_init, which is an initcall */
Russell King3ae5eae2005-11-09 22:32:44 +00001049static struct platform_driver ubd_driver = {
1050 .driver = {
1051 .name = DRIVER_NAME,
1052 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053};
1054
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001055static int __init ubd_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056{
Jeff Dikef28169d2007-02-10 01:43:53 -08001057 char *error;
1058 int i, err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059
Christoph Hellwig792dd4f2009-03-31 15:23:39 -07001060 if (register_blkdev(UBD_MAJOR, "ubd"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 return -1;
1062
Christoph Hellwig792dd4f2009-03-31 15:23:39 -07001063 if (fake_major != UBD_MAJOR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 char name[sizeof("ubd_nnn\0")];
1065
1066 snprintf(name, sizeof(name), "ubd_%d", fake_major);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 if (register_blkdev(fake_major, "ubd"))
1068 return -1;
1069 }
Russell King3ae5eae2005-11-09 22:32:44 +00001070 platform_driver_register(&ubd_driver);
Jeff Dikedc764e52007-05-06 14:51:41 -07001071 mutex_lock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -08001072 for (i = 0; i < MAX_DEV; i++){
1073 err = ubd_add(i, &error);
1074 if(err)
1075 printk(KERN_ERR "Failed to initialize ubd device %d :"
1076 "%s\n", i, error);
1077 }
Jeff Dikedc764e52007-05-06 14:51:41 -07001078 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 return 0;
1080}
1081
1082late_initcall(ubd_init);
1083
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001084static int __init ubd_driver_init(void){
Jeff Dike91acb212005-10-10 23:10:32 -04001085 unsigned long stack;
1086 int err;
1087
1088 /* Set by CONFIG_BLK_DEV_UBD_SYNC or ubd=sync.*/
1089 if(global_openflags.s){
1090 printk(KERN_INFO "ubd: Synchronous mode\n");
1091 /* Letting ubd=sync be like using ubd#s= instead of ubd#= is
1092 * enough. So use anyway the io thread. */
1093 }
1094 stack = alloc_stack(0, 0);
Jeff Dike6c29256c2006-03-27 01:14:37 -08001095 io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *),
Jeff Dike91acb212005-10-10 23:10:32 -04001096 &thread_fd);
1097 if(io_pid < 0){
Jeff Dike6c29256c2006-03-27 01:14:37 -08001098 printk(KERN_ERR
Jeff Dike91acb212005-10-10 23:10:32 -04001099 "ubd : Failed to start I/O thread (errno = %d) - "
1100 "falling back to synchronous I/O\n", -io_pid);
1101 io_pid = -1;
Jeff Dikedc764e52007-05-06 14:51:41 -07001102 return 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001103 }
Jeff Dike6c29256c2006-03-27 01:14:37 -08001104 err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr,
Yong Zhangc0b79a92011-09-22 16:58:46 +08001105 0, "ubd", ubd_devs);
Jeff Dike91acb212005-10-10 23:10:32 -04001106 if(err != 0)
1107 printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err);
Jeff Dikef4c57a72006-03-31 02:30:10 -08001108 return 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001109}
1110
1111device_initcall(ubd_driver_init);
1112
Al Viroa625c992008-03-02 09:16:26 -05001113static int ubd_open(struct block_device *bdev, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114{
Al Viroa625c992008-03-02 09:16:26 -05001115 struct gendisk *disk = bdev->bd_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001116 struct ubd *ubd_dev = disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 int err = 0;
1118
Arnd Bergmann9a181c52010-09-11 18:38:03 +02001119 mutex_lock(&ubd_mutex);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001120 if(ubd_dev->count == 0){
1121 err = ubd_open_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 if(err){
1123 printk(KERN_ERR "%s: Can't open \"%s\": errno = %d\n",
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001124 disk->disk_name, ubd_dev->file, -err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 goto out;
1126 }
1127 }
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001128 ubd_dev->count++;
1129 set_disk_ro(disk, !ubd_dev->openflags.w);
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -07001130
1131 /* This should no more be needed. And it didn't work anyway to exclude
1132 * read-write remounting of filesystems.*/
Al Viroa625c992008-03-02 09:16:26 -05001133 /*if((mode & FMODE_WRITE) && !ubd_dev->openflags.w){
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -08001134 if(--ubd_dev->count == 0) ubd_close_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 err = -EROFS;
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -07001136 }*/
Arnd Bergmann6e9624b2010-08-07 18:25:34 +02001137out:
Arnd Bergmann9a181c52010-09-11 18:38:03 +02001138 mutex_unlock(&ubd_mutex);
Jeff Dikedc764e52007-05-06 14:51:41 -07001139 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140}
1141
Al Virodb2a1442013-05-05 21:52:57 -04001142static void ubd_release(struct gendisk *disk, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001144 struct ubd *ubd_dev = disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145
Arnd Bergmann9a181c52010-09-11 18:38:03 +02001146 mutex_lock(&ubd_mutex);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001147 if(--ubd_dev->count == 0)
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -08001148 ubd_close_dev(ubd_dev);
Arnd Bergmann9a181c52010-09-11 18:38:03 +02001149 mutex_unlock(&ubd_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150}
1151
Jeff Dike91acb212005-10-10 23:10:32 -04001152static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask,
1153 __u64 *cow_offset, unsigned long *bitmap,
1154 __u64 bitmap_offset, unsigned long *bitmap_words,
1155 __u64 bitmap_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156{
Jeff Dike91acb212005-10-10 23:10:32 -04001157 __u64 sector = io_offset >> 9;
1158 int i, update_bitmap = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159
Jeff Dike91acb212005-10-10 23:10:32 -04001160 for(i = 0; i < length >> 9; i++){
1161 if(cow_mask != NULL)
1162 ubd_set_bit(i, (unsigned char *) cow_mask);
1163 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
1164 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165
Jeff Dike91acb212005-10-10 23:10:32 -04001166 update_bitmap = 1;
1167 ubd_set_bit(sector + i, (unsigned char *) bitmap);
1168 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169
Jeff Dike91acb212005-10-10 23:10:32 -04001170 if(!update_bitmap)
1171 return;
1172
1173 *cow_offset = sector / (sizeof(unsigned long) * 8);
1174
1175 /* This takes care of the case where we're exactly at the end of the
1176 * device, and *cow_offset + 1 is off the end. So, just back it up
1177 * by one word. Thanks to Lynn Kerby for the fix and James McMechan
1178 * for the original diagnosis.
1179 */
Jiri Olsa6d074242008-05-12 14:01:56 -07001180 if (*cow_offset == (DIV_ROUND_UP(bitmap_len,
1181 sizeof(unsigned long)) - 1))
Jeff Dike91acb212005-10-10 23:10:32 -04001182 (*cow_offset)--;
1183
1184 bitmap_words[0] = bitmap[*cow_offset];
1185 bitmap_words[1] = bitmap[*cow_offset + 1];
1186
1187 *cow_offset *= sizeof(unsigned long);
1188 *cow_offset += bitmap_offset;
1189}
1190
1191static void cowify_req(struct io_thread_req *req, unsigned long *bitmap,
1192 __u64 bitmap_offset, __u64 bitmap_len)
1193{
1194 __u64 sector = req->offset >> 9;
1195 int i;
1196
1197 if(req->length > (sizeof(req->sector_mask) * 8) << 9)
1198 panic("Operation too long");
1199
1200 if(req->op == UBD_READ) {
1201 for(i = 0; i < req->length >> 9; i++){
1202 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
Jeff Dike6c29256c2006-03-27 01:14:37 -08001203 ubd_set_bit(i, (unsigned char *)
Jeff Dike91acb212005-10-10 23:10:32 -04001204 &req->sector_mask);
Jeff Dikedc764e52007-05-06 14:51:41 -07001205 }
Jeff Dike91acb212005-10-10 23:10:32 -04001206 }
1207 else cowify_bitmap(req->offset, req->length, &req->sector_mask,
1208 &req->cow_offset, bitmap, bitmap_offset,
1209 req->bitmap_words, bitmap_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210}
1211
Jeff Dike62f96cb2007-02-10 01:44:16 -08001212/* Called with dev->lock held */
Jeff Dikea0044bd2007-05-06 14:51:36 -07001213static void prepare_request(struct request *req, struct io_thread_req *io_req,
1214 unsigned long long offset, int page_offset,
1215 int len, struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216{
1217 struct gendisk *disk = req->rq_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001218 struct ubd *ubd_dev = disk->private_data;
Jeff Dike91acb212005-10-10 23:10:32 -04001219
Jeff Dike62f96cb2007-02-10 01:44:16 -08001220 io_req->req = req;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001221 io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd :
1222 ubd_dev->fd;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001223 io_req->fds[1] = ubd_dev->fd;
Jeff Dike91acb212005-10-10 23:10:32 -04001224 io_req->cow_offset = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 io_req->offset = offset;
1226 io_req->length = len;
1227 io_req->error = 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001228 io_req->sector_mask = 0;
1229
1230 io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 io_req->offsets[0] = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001232 io_req->offsets[1] = ubd_dev->cow.data_offset;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001233 io_req->buffer = page_address(page) + page_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 io_req->sectorsize = 1 << 9;
1235
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001236 if(ubd_dev->cow.file != NULL)
Jeff Dikea0044bd2007-05-06 14:51:36 -07001237 cowify_req(io_req, ubd_dev->cow.bitmap,
1238 ubd_dev->cow.bitmap_offset, ubd_dev->cow.bitmap_len);
Jeff Dike91acb212005-10-10 23:10:32 -04001239
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240}
1241
Jeff Dike62f96cb2007-02-10 01:44:16 -08001242/* Called with dev->lock held */
Richard Weinberger805f11a2013-08-18 13:30:06 +02001243static void prepare_flush_request(struct request *req,
1244 struct io_thread_req *io_req)
1245{
1246 struct gendisk *disk = req->rq_disk;
1247 struct ubd *ubd_dev = disk->private_data;
1248
1249 io_req->req = req;
1250 io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd :
1251 ubd_dev->fd;
1252 io_req->op = UBD_FLUSH;
1253}
1254
Richard Weinbergerbc1d72e2013-08-18 13:30:07 +02001255static bool submit_request(struct io_thread_req *io_req, struct ubd *dev)
1256{
1257 int n = os_write_file(thread_fd, &io_req,
1258 sizeof(io_req));
1259 if (n != sizeof(io_req)) {
1260 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);
1265
1266 kfree(io_req);
1267 return false;
1268 }
1269 return true;
1270}
1271
Richard Weinberger805f11a2013-08-18 13:30:06 +02001272/* Called with dev->lock held */
Jens Axboe165125e2007-07-24 09:28:11 +02001273static void do_ubd_request(struct request_queue *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274{
Jeff Dike2adcec22007-05-06 14:51:37 -07001275 struct io_thread_req *io_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 struct request *req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277
Jeff Dikea0044bd2007-05-06 14:51:36 -07001278 while(1){
Jeff Dike2a9529a2007-03-29 01:20:27 -07001279 struct ubd *dev = q->queuedata;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001280 if(dev->end_sg == 0){
Tejun Heo9934c8c2009-05-08 11:54:16 +09001281 struct request *req = blk_fetch_request(q);
Jeff Dikea0044bd2007-05-06 14:51:36 -07001282 if(req == NULL)
1283 return;
1284
1285 dev->request = req;
Tejun Heo47526902010-10-15 12:56:21 +02001286 dev->rq_pos = blk_rq_pos(req);
Jeff Dikea0044bd2007-05-06 14:51:36 -07001287 dev->start_sg = 0;
1288 dev->end_sg = blk_rq_map_sg(q, req, dev->sg);
Jeff Dike91acb212005-10-10 23:10:32 -04001289 }
Jeff Dikea0044bd2007-05-06 14:51:36 -07001290
1291 req = dev->request;
Richard Weinberger805f11a2013-08-18 13:30:06 +02001292
1293 if (req->cmd_flags & REQ_FLUSH) {
1294 io_req = kmalloc(sizeof(struct io_thread_req),
1295 GFP_ATOMIC);
1296 if (io_req == NULL) {
1297 if (list_empty(&dev->restart))
1298 list_add(&dev->restart, &restart);
1299 return;
1300 }
1301 prepare_flush_request(req, io_req);
Richard Weinbergerbc1d72e2013-08-18 13:30:07 +02001302 submit_request(io_req, dev);
Richard Weinberger805f11a2013-08-18 13:30:06 +02001303 }
1304
Jeff Dikea0044bd2007-05-06 14:51:36 -07001305 while(dev->start_sg < dev->end_sg){
1306 struct scatterlist *sg = &dev->sg[dev->start_sg];
1307
Jeff Dike2adcec22007-05-06 14:51:37 -07001308 io_req = kmalloc(sizeof(struct io_thread_req),
Peter Zijlstra990c5582007-05-06 14:51:38 -07001309 GFP_ATOMIC);
Jeff Dike2adcec22007-05-06 14:51:37 -07001310 if(io_req == NULL){
1311 if(list_empty(&dev->restart))
1312 list_add(&dev->restart, &restart);
1313 return;
1314 }
1315 prepare_request(req, io_req,
Tejun Heo47526902010-10-15 12:56:21 +02001316 (unsigned long long)dev->rq_pos << 9,
Jens Axboe45711f12007-10-22 21:19:53 +02001317 sg->offset, sg->length, sg_page(sg));
Jeff Dikea0044bd2007-05-06 14:51:36 -07001318
Richard Weinbergerbc1d72e2013-08-18 13:30:07 +02001319 if (submit_request(io_req, dev) == false)
Jeff Dikea0044bd2007-05-06 14:51:36 -07001320 return;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001321
Tejun Heo47526902010-10-15 12:56:21 +02001322 dev->rq_pos += sg->length >> 9;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001323 dev->start_sg++;
1324 }
1325 dev->end_sg = 0;
1326 dev->request = NULL;
Jeff Dike91acb212005-10-10 23:10:32 -04001327 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328}
1329
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001330static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
1331{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001332 struct ubd *ubd_dev = bdev->bd_disk->private_data;
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001333
1334 geo->heads = 128;
1335 geo->sectors = 32;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001336 geo->cylinders = ubd_dev->size / (128 * 32 * 512);
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001337 return 0;
1338}
1339
Al Viroa625c992008-03-02 09:16:26 -05001340static int ubd_ioctl(struct block_device *bdev, fmode_t mode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 unsigned int cmd, unsigned long arg)
1342{
Al Viroa625c992008-03-02 09:16:26 -05001343 struct ubd *ubd_dev = bdev->bd_disk->private_data;
Bartlomiej Zolnierkiewicz73855e12009-04-01 21:42:21 +02001344 u16 ubd_id[ATA_ID_WORDS];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345
1346 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 struct cdrom_volctrl volume;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 case HDIO_GET_IDENTITY:
Bartlomiej Zolnierkiewicz73855e12009-04-01 21:42:21 +02001349 memset(&ubd_id, 0, ATA_ID_WORDS * 2);
1350 ubd_id[ATA_ID_CYLS] = ubd_dev->size / (128 * 32 * 512);
1351 ubd_id[ATA_ID_HEADS] = 128;
1352 ubd_id[ATA_ID_SECTORS] = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 if(copy_to_user((char __user *) arg, (char *) &ubd_id,
1354 sizeof(ubd_id)))
Jeff Dikedc764e52007-05-06 14:51:41 -07001355 return -EFAULT;
1356 return 0;
Jeff Dikeb8831a12007-02-10 01:44:17 -08001357
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 case CDROMVOLREAD:
1359 if(copy_from_user(&volume, (char __user *) arg, sizeof(volume)))
Jeff Dikedc764e52007-05-06 14:51:41 -07001360 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 volume.channel0 = 255;
1362 volume.channel1 = 255;
1363 volume.channel2 = 255;
1364 volume.channel3 = 255;
1365 if(copy_to_user((char __user *) arg, &volume, sizeof(volume)))
Jeff Dikedc764e52007-05-06 14:51:41 -07001366 return -EFAULT;
1367 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 }
Jeff Dikedc764e52007-05-06 14:51:41 -07001369 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370}
1371
Jeff Dike91acb212005-10-10 23:10:32 -04001372static int update_bitmap(struct io_thread_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373{
Jeff Dike91acb212005-10-10 23:10:32 -04001374 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375
Jeff Dike91acb212005-10-10 23:10:32 -04001376 if(req->cow_offset == -1)
Jeff Dikedc764e52007-05-06 14:51:41 -07001377 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378
Jeff Dike91acb212005-10-10 23:10:32 -04001379 n = os_seek_file(req->fds[1], req->cow_offset);
1380 if(n < 0){
1381 printk("do_io - bitmap lseek failed : err = %d\n", -n);
Jeff Dikedc764e52007-05-06 14:51:41 -07001382 return 1;
Jeff Dike91acb212005-10-10 23:10:32 -04001383 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001385 n = os_write_file(req->fds[1], &req->bitmap_words,
1386 sizeof(req->bitmap_words));
Jeff Dike91acb212005-10-10 23:10:32 -04001387 if(n != sizeof(req->bitmap_words)){
1388 printk("do_io - bitmap update failed, err = %d fd = %d\n", -n,
1389 req->fds[1]);
Jeff Dikedc764e52007-05-06 14:51:41 -07001390 return 1;
Jeff Dike91acb212005-10-10 23:10:32 -04001391 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392
Jeff Dikedc764e52007-05-06 14:51:41 -07001393 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394}
Jeff Dike91acb212005-10-10 23:10:32 -04001395
WANG Cong5dc62b12008-04-28 02:13:58 -07001396static void do_io(struct io_thread_req *req)
Jeff Dike91acb212005-10-10 23:10:32 -04001397{
1398 char *buf;
1399 unsigned long len;
1400 int n, nsectors, start, end, bit;
1401 int err;
1402 __u64 off;
1403
Richard Weinberger805f11a2013-08-18 13:30:06 +02001404 if (req->op == UBD_FLUSH) {
1405 /* fds[0] is always either the rw image or our cow file */
1406 n = os_sync_file(req->fds[0]);
1407 if (n != 0) {
1408 printk("do_io - sync failed err = %d "
1409 "fd = %d\n", -n, req->fds[0]);
1410 req->error = 1;
1411 }
1412 return;
1413 }
1414
Jeff Dike91acb212005-10-10 23:10:32 -04001415 nsectors = req->length / req->sectorsize;
1416 start = 0;
1417 do {
1418 bit = ubd_test_bit(start, (unsigned char *) &req->sector_mask);
1419 end = start;
1420 while((end < nsectors) &&
1421 (ubd_test_bit(end, (unsigned char *)
1422 &req->sector_mask) == bit))
1423 end++;
1424
1425 off = req->offset + req->offsets[bit] +
1426 start * req->sectorsize;
1427 len = (end - start) * req->sectorsize;
1428 buf = &req->buffer[start * req->sectorsize];
1429
1430 err = os_seek_file(req->fds[bit], off);
1431 if(err < 0){
1432 printk("do_io - lseek failed : err = %d\n", -err);
1433 req->error = 1;
1434 return;
1435 }
1436 if(req->op == UBD_READ){
1437 n = 0;
1438 do {
1439 buf = &buf[n];
1440 len -= n;
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001441 n = os_read_file(req->fds[bit], buf, len);
Jeff Dike91acb212005-10-10 23:10:32 -04001442 if (n < 0) {
1443 printk("do_io - read failed, err = %d "
1444 "fd = %d\n", -n, req->fds[bit]);
1445 req->error = 1;
1446 return;
1447 }
1448 } while((n < len) && (n != 0));
1449 if (n < len) memset(&buf[n], 0, len - n);
1450 } else {
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001451 n = os_write_file(req->fds[bit], buf, len);
Jeff Dike91acb212005-10-10 23:10:32 -04001452 if(n != len){
1453 printk("do_io - write failed err = %d "
1454 "fd = %d\n", -n, req->fds[bit]);
1455 req->error = 1;
1456 return;
1457 }
1458 }
1459
1460 start = end;
1461 } while(start < nsectors);
1462
1463 req->error = update_bitmap(req);
1464}
1465
1466/* Changed in start_io_thread, which is serialized by being called only
1467 * from ubd_init, which is an initcall.
1468 */
1469int kernel_fd = -1;
1470
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001471/* Only changed by the io thread. XXX: currently unused. */
1472static int io_count = 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001473
1474int io_thread(void *arg)
1475{
Jeff Dike2adcec22007-05-06 14:51:37 -07001476 struct io_thread_req *req;
Jeff Dike91acb212005-10-10 23:10:32 -04001477 int n;
1478
1479 ignore_sigwinch_sig();
1480 while(1){
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001481 n = os_read_file(kernel_fd, &req,
Jeff Dike2adcec22007-05-06 14:51:37 -07001482 sizeof(struct io_thread_req *));
1483 if(n != sizeof(struct io_thread_req *)){
Jeff Dike91acb212005-10-10 23:10:32 -04001484 if(n < 0)
1485 printk("io_thread - read failed, fd = %d, "
1486 "err = %d\n", kernel_fd, -n);
1487 else {
1488 printk("io_thread - short read, fd = %d, "
1489 "length = %d\n", kernel_fd, n);
1490 }
1491 continue;
1492 }
1493 io_count++;
Jeff Dike2adcec22007-05-06 14:51:37 -07001494 do_io(req);
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001495 n = os_write_file(kernel_fd, &req,
Jeff Dike2adcec22007-05-06 14:51:37 -07001496 sizeof(struct io_thread_req *));
1497 if(n != sizeof(struct io_thread_req *))
Jeff Dike91acb212005-10-10 23:10:32 -04001498 printk("io_thread - write failed, fd = %d, err = %d\n",
1499 kernel_fd, -n);
1500 }
Jeff Dike91acb212005-10-10 23:10:32 -04001501
Jeff Dike1b57e9c2006-01-06 00:18:49 -08001502 return 0;
1503}