blob: f3540270d09686d6ca6884c05f15481ae831ee0e [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
Anton Ivanov8c6157b2015-12-21 18:54:00 +0000538 err = os_pread_file(fd, buf, len, offset);
WANG Cong5dc62b12008-04-28 02:13:58 -0700539 if (err < 0)
540 return err;
541
542 return 0;
543}
544
545static int backing_file_mismatch(char *file, __u64 size, time_t mtime)
546{
547 unsigned long modtime;
548 unsigned long long actual;
549 int err;
550
551 err = os_file_modtime(file, &modtime);
552 if (err < 0) {
553 printk(KERN_ERR "Failed to get modification time of backing "
554 "file \"%s\", err = %d\n", file, -err);
555 return err;
556 }
557
558 err = os_file_size(file, &actual);
559 if (err < 0) {
560 printk(KERN_ERR "Failed to get size of backing file \"%s\", "
561 "err = %d\n", file, -err);
562 return err;
563 }
564
565 if (actual != size) {
566 /*__u64 can be a long on AMD64 and with %lu GCC complains; so
567 * the typecast.*/
568 printk(KERN_ERR "Size mismatch (%llu vs %llu) of COW header "
569 "vs backing file\n", (unsigned long long) size, actual);
570 return -EINVAL;
571 }
572 if (modtime != mtime) {
573 printk(KERN_ERR "mtime mismatch (%ld vs %ld) of COW header vs "
574 "backing file\n", mtime, modtime);
575 return -EINVAL;
576 }
577 return 0;
578}
579
580static int path_requires_switch(char *from_cmdline, char *from_cow, char *cow)
581{
582 struct uml_stat buf1, buf2;
583 int err;
584
585 if (from_cmdline == NULL)
586 return 0;
587 if (!strcmp(from_cmdline, from_cow))
588 return 0;
589
590 err = os_stat_file(from_cmdline, &buf1);
591 if (err < 0) {
592 printk(KERN_ERR "Couldn't stat '%s', err = %d\n", from_cmdline,
593 -err);
594 return 0;
595 }
596 err = os_stat_file(from_cow, &buf2);
597 if (err < 0) {
598 printk(KERN_ERR "Couldn't stat '%s', err = %d\n", from_cow,
599 -err);
600 return 1;
601 }
602 if ((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino))
603 return 0;
604
605 printk(KERN_ERR "Backing file mismatch - \"%s\" requested, "
606 "\"%s\" specified in COW header of \"%s\"\n",
607 from_cmdline, from_cow, cow);
608 return 1;
609}
610
611static int open_ubd_file(char *file, struct openflags *openflags, int shared,
612 char **backing_file_out, int *bitmap_offset_out,
613 unsigned long *bitmap_len_out, int *data_offset_out,
614 int *create_cow_out)
615{
616 time_t mtime;
617 unsigned long long size;
618 __u32 version, align;
619 char *backing_file;
620 int fd, err, sectorsize, asked_switch, mode = 0644;
621
622 fd = os_open_file(file, *openflags, mode);
623 if (fd < 0) {
624 if ((fd == -ENOENT) && (create_cow_out != NULL))
625 *create_cow_out = 1;
626 if (!openflags->w ||
627 ((fd != -EROFS) && (fd != -EACCES)))
628 return fd;
629 openflags->w = 0;
630 fd = os_open_file(file, *openflags, mode);
631 if (fd < 0)
632 return fd;
633 }
634
635 if (shared)
636 printk(KERN_INFO "Not locking \"%s\" on the host\n", file);
637 else {
638 err = os_lock_file(fd, openflags->w);
639 if (err < 0) {
640 printk(KERN_ERR "Failed to lock '%s', err = %d\n",
641 file, -err);
642 goto out_close;
643 }
644 }
645
646 /* Successful return case! */
647 if (backing_file_out == NULL)
648 return fd;
649
650 err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime,
651 &size, &sectorsize, &align, bitmap_offset_out);
652 if (err && (*backing_file_out != NULL)) {
653 printk(KERN_ERR "Failed to read COW header from COW file "
654 "\"%s\", errno = %d\n", file, -err);
655 goto out_close;
656 }
657 if (err)
658 return fd;
659
660 asked_switch = path_requires_switch(*backing_file_out, backing_file,
661 file);
662
663 /* Allow switching only if no mismatch. */
664 if (asked_switch && !backing_file_mismatch(*backing_file_out, size,
665 mtime)) {
666 printk(KERN_ERR "Switching backing file to '%s'\n",
667 *backing_file_out);
668 err = write_cow_header(file, fd, *backing_file_out,
669 sectorsize, align, &size);
670 if (err) {
671 printk(KERN_ERR "Switch failed, errno = %d\n", -err);
672 goto out_close;
673 }
674 } else {
675 *backing_file_out = backing_file;
676 err = backing_file_mismatch(*backing_file_out, size, mtime);
677 if (err)
678 goto out_close;
679 }
680
681 cow_sizes(version, size, sectorsize, align, *bitmap_offset_out,
682 bitmap_len_out, data_offset_out);
683
684 return fd;
685 out_close:
686 os_close_file(fd);
687 return err;
688}
689
690static int create_cow_file(char *cow_file, char *backing_file,
691 struct openflags flags,
692 int sectorsize, int alignment, int *bitmap_offset_out,
693 unsigned long *bitmap_len_out, int *data_offset_out)
694{
695 int err, fd;
696
697 flags.c = 1;
698 fd = open_ubd_file(cow_file, &flags, 0, NULL, NULL, NULL, NULL, NULL);
699 if (fd < 0) {
700 err = fd;
701 printk(KERN_ERR "Open of COW file '%s' failed, errno = %d\n",
702 cow_file, -err);
703 goto out;
704 }
705
706 err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment,
707 bitmap_offset_out, bitmap_len_out,
708 data_offset_out);
709 if (!err)
710 return fd;
711 os_close_file(fd);
712 out:
713 return err;
714}
715
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800716static void ubd_close_dev(struct ubd *ubd_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800718 os_close_file(ubd_dev->fd);
719 if(ubd_dev->cow.file == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 return;
721
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800722 os_close_file(ubd_dev->cow.fd);
723 vfree(ubd_dev->cow.bitmap);
724 ubd_dev->cow.bitmap = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725}
726
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800727static int ubd_open_dev(struct ubd *ubd_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728{
729 struct openflags flags;
730 char **back_ptr;
731 int err, create_cow, *create_ptr;
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800732 int fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800734 ubd_dev->openflags = ubd_dev->boot_openflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 create_cow = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800736 create_ptr = (ubd_dev->cow.file != NULL) ? &create_cow : NULL;
737 back_ptr = ubd_dev->no_cow ? NULL : &ubd_dev->cow.file;
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800738
739 fd = open_ubd_file(ubd_dev->file, &ubd_dev->openflags, ubd_dev->shared,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800740 back_ptr, &ubd_dev->cow.bitmap_offset,
741 &ubd_dev->cow.bitmap_len, &ubd_dev->cow.data_offset,
Jeff Dike6c29256c2006-03-27 01:14:37 -0800742 create_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800744 if((fd == -ENOENT) && create_cow){
745 fd = create_cow_file(ubd_dev->file, ubd_dev->cow.file,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800746 ubd_dev->openflags, 1 << 9, PAGE_SIZE,
747 &ubd_dev->cow.bitmap_offset,
748 &ubd_dev->cow.bitmap_len,
749 &ubd_dev->cow.data_offset);
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800750 if(fd >= 0){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 printk(KERN_INFO "Creating \"%s\" as COW file for "
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800752 "\"%s\"\n", ubd_dev->file, ubd_dev->cow.file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 }
754 }
755
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800756 if(fd < 0){
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800757 printk("Failed to open '%s', errno = %d\n", ubd_dev->file,
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800758 -fd);
759 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 }
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800761 ubd_dev->fd = fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800763 if(ubd_dev->cow.file != NULL){
Martin K. Petersen086fa5f2010-02-26 00:20:38 -0500764 blk_queue_max_hw_sectors(ubd_dev->queue, 8 * sizeof(long));
Jeff Dikef4768ff2007-08-22 14:01:53 -0700765
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 err = -ENOMEM;
Jesper Juhlda2486b2007-10-16 01:27:19 -0700767 ubd_dev->cow.bitmap = vmalloc(ubd_dev->cow.bitmap_len);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800768 if(ubd_dev->cow.bitmap == NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 printk(KERN_ERR "Failed to vmalloc COW bitmap\n");
770 goto error;
771 }
772 flush_tlb_kernel_vm();
773
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800774 err = read_cow_bitmap(ubd_dev->fd, ubd_dev->cow.bitmap,
775 ubd_dev->cow.bitmap_offset,
776 ubd_dev->cow.bitmap_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 if(err < 0)
778 goto error;
779
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800780 flags = ubd_dev->openflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 flags.w = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800782 err = open_ubd_file(ubd_dev->cow.file, &flags, ubd_dev->shared, NULL,
Jeff Dike6c29256c2006-03-27 01:14:37 -0800783 NULL, NULL, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 if(err < 0) goto error;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800785 ubd_dev->cow.fd = err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 }
Jeff Dikedc764e52007-05-06 14:51:41 -0700787 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 error:
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800789 os_close_file(ubd_dev->fd);
Jeff Dikedc764e52007-05-06 14:51:41 -0700790 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791}
792
Jeff Dike2e3f5252007-05-06 14:51:29 -0700793static void ubd_device_release(struct device *dev)
794{
Greg Kroah-Hartman8691b972009-05-04 12:40:54 -0700795 struct ubd *ubd_dev = dev_get_drvdata(dev);
Jeff Dike2e3f5252007-05-06 14:51:29 -0700796
797 blk_cleanup_queue(ubd_dev->queue);
798 *ubd_dev = ((struct ubd) DEFAULT_UBD);
799}
800
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800801static int ubd_disk_register(int major, u64 size, int unit,
Jeff Dikeb8831a12007-02-10 01:44:17 -0800802 struct gendisk **disk_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803{
Dan Williamsd72a5782016-06-20 10:44:32 -0700804 struct device *parent = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 struct gendisk *disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806
807 disk = alloc_disk(1 << UBD_SHIFT);
808 if(disk == NULL)
Jeff Dikedc764e52007-05-06 14:51:41 -0700809 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810
811 disk->major = major;
812 disk->first_minor = unit << UBD_SHIFT;
813 disk->fops = &ubd_blops;
814 set_capacity(disk, size / 512);
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700815 if (major == UBD_MAJOR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 sprintf(disk->disk_name, "ubd%c", 'a' + unit);
Greg Kroah-Hartmance7b0f42005-06-20 21:15:16 -0700817 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 sprintf(disk->disk_name, "ubd_fake%d", unit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819
820 /* sysfs register (not for ide fake devices) */
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700821 if (major == UBD_MAJOR) {
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800822 ubd_devs[unit].pdev.id = unit;
823 ubd_devs[unit].pdev.name = DRIVER_NAME;
Jeff Dike2e3f5252007-05-06 14:51:29 -0700824 ubd_devs[unit].pdev.dev.release = ubd_device_release;
Greg Kroah-Hartman8691b972009-05-04 12:40:54 -0700825 dev_set_drvdata(&ubd_devs[unit].pdev.dev, &ubd_devs[unit]);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800826 platform_device_register(&ubd_devs[unit].pdev);
Dan Williamsd72a5782016-06-20 10:44:32 -0700827 parent = &ubd_devs[unit].pdev.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 }
829
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800830 disk->private_data = &ubd_devs[unit];
Jeff Dike62f96cb2007-02-10 01:44:16 -0800831 disk->queue = ubd_devs[unit].queue;
Dan Williamsd72a5782016-06-20 10:44:32 -0700832 device_add_disk(parent, disk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833
834 *disk_out = disk;
835 return 0;
836}
837
838#define ROUND_BLOCK(n) ((n + ((1 << 9) - 1)) & (-1 << 9))
839
Jeff Dikef28169d2007-02-10 01:43:53 -0800840static int ubd_add(int n, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800842 struct ubd *ubd_dev = &ubd_devs[n];
Jeff Dikef28169d2007-02-10 01:43:53 -0800843 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800845 if(ubd_dev->file == NULL)
Jeff Dikeec7cf782005-09-03 15:57:29 -0700846 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800848 err = ubd_file_size(ubd_dev, &ubd_dev->size);
Jeff Dikef28169d2007-02-10 01:43:53 -0800849 if(err < 0){
850 *error_out = "Couldn't determine size of device's file";
Jeff Dike80c13742006-09-29 01:58:51 -0700851 goto out;
Jeff Dikef28169d2007-02-10 01:43:53 -0800852 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800854 ubd_dev->size = ROUND_BLOCK(ubd_dev->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855
Jeff Dikea0044bd2007-05-06 14:51:36 -0700856 INIT_LIST_HEAD(&ubd_dev->restart);
WANG Cong4f40c052007-11-05 14:50:59 -0800857 sg_init_table(ubd_dev->sg, MAX_SG);
Jeff Dikea0044bd2007-05-06 14:51:36 -0700858
Jeff Dike62f96cb2007-02-10 01:44:16 -0800859 err = -ENOMEM;
860 ubd_dev->queue = blk_init_queue(do_ubd_request, &ubd_dev->lock);
861 if (ubd_dev->queue == NULL) {
862 *error_out = "Failed to initialize device queue";
Jeff Dike80c13742006-09-29 01:58:51 -0700863 goto out;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800864 }
865 ubd_dev->queue->queuedata = ubd_dev;
Jens Axboef935a8c2016-03-30 10:19:17 -0600866 blk_queue_write_cache(ubd_dev->queue, true, false);
Jeff Dike62f96cb2007-02-10 01:44:16 -0800867
Martin K. Petersen8a783622010-02-26 00:20:39 -0500868 blk_queue_max_segments(ubd_dev->queue, MAX_SG);
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700869 err = ubd_disk_register(UBD_MAJOR, ubd_dev->size, n, &ubd_gendisk[n]);
Jeff Dike62f96cb2007-02-10 01:44:16 -0800870 if(err){
871 *error_out = "Failed to register device";
872 goto out_cleanup;
873 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800874
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700875 if (fake_major != UBD_MAJOR)
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800876 ubd_disk_register(fake_major, ubd_dev->size, n,
Jeff Dike62f96cb2007-02-10 01:44:16 -0800877 &fake_gendisk[n]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878
Jeff Dike83380cc2008-02-04 22:31:18 -0800879 /*
880 * Perhaps this should also be under the "if (fake_major)" above
881 * using the fake_disk->disk_name
882 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 if (fake_ide)
884 make_ide_entries(ubd_gendisk[n]->disk_name);
885
Jeff Dikeec7cf782005-09-03 15:57:29 -0700886 err = 0;
Jeff Dikeec7cf782005-09-03 15:57:29 -0700887out:
888 return err;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800889
890out_cleanup:
891 blk_cleanup_queue(ubd_dev->queue);
892 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893}
894
Jeff Dikef28169d2007-02-10 01:43:53 -0800895static int ubd_config(char *str, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896{
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800897 int n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898
Jeff Dikef28169d2007-02-10 01:43:53 -0800899 /* This string is possibly broken up and stored, so it's only
900 * freed if ubd_setup_common fails, or if only general options
901 * were set.
902 */
Jeff Dike970d6e32006-01-06 00:18:48 -0800903 str = kstrdup(str, GFP_KERNEL);
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800904 if (str == NULL) {
Jeff Dikef28169d2007-02-10 01:43:53 -0800905 *error_out = "Failed to allocate memory";
906 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 }
Jeff Dikef28169d2007-02-10 01:43:53 -0800908
909 ret = ubd_setup_common(str, &n, error_out);
910 if (ret)
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800911 goto err_free;
Jeff Dikef28169d2007-02-10 01:43:53 -0800912
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800913 if (n == -1) {
914 ret = 0;
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800915 goto err_free;
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800916 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917
Jeff Dikedc764e52007-05-06 14:51:41 -0700918 mutex_lock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -0800919 ret = ubd_add(n, error_out);
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800920 if (ret)
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800921 ubd_devs[n].file = NULL;
Jeff Dikedc764e52007-05-06 14:51:41 -0700922 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800924out:
Jeff Dikedc764e52007-05-06 14:51:41 -0700925 return ret;
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800926
927err_free:
928 kfree(str);
929 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930}
931
932static int ubd_get_config(char *name, char *str, int size, char **error_out)
933{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800934 struct ubd *ubd_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 int n, len = 0;
936
937 n = parse_unit(&name);
938 if((n >= MAX_DEV) || (n < 0)){
939 *error_out = "ubd_get_config : device number out of range";
Jeff Dikedc764e52007-05-06 14:51:41 -0700940 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 }
942
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800943 ubd_dev = &ubd_devs[n];
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800944 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800946 if(ubd_dev->file == NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 CONFIG_CHUNK(str, size, len, "", 1);
948 goto out;
949 }
950
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800951 CONFIG_CHUNK(str, size, len, ubd_dev->file, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800953 if(ubd_dev->cow.file != NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 CONFIG_CHUNK(str, size, len, ",", 0);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800955 CONFIG_CHUNK(str, size, len, ubd_dev->cow.file, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 }
957 else CONFIG_CHUNK(str, size, len, "", 1);
958
959 out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800960 mutex_unlock(&ubd_lock);
Jeff Dikedc764e52007-05-06 14:51:41 -0700961 return len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962}
963
Jeff Dike29d56cf2005-06-25 14:55:25 -0700964static int ubd_id(char **str, int *start_out, int *end_out)
965{
Jeff Dikedc764e52007-05-06 14:51:41 -0700966 int n;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700967
968 n = parse_unit(str);
Jeff Dikedc764e52007-05-06 14:51:41 -0700969 *start_out = 0;
970 *end_out = MAX_DEV - 1;
971 return n;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700972}
973
Jeff Dikef28169d2007-02-10 01:43:53 -0800974static int ubd_remove(int n, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975{
Jeff Dike2e3f5252007-05-06 14:51:29 -0700976 struct gendisk *disk = ubd_gendisk[n];
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800977 struct ubd *ubd_dev;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700978 int err = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800980 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800982 ubd_dev = &ubd_devs[n];
Jeff Dike29d56cf2005-06-25 14:55:25 -0700983
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800984 if(ubd_dev->file == NULL)
Jeff Dike29d56cf2005-06-25 14:55:25 -0700985 goto out;
986
987 /* you cannot remove a open disk */
988 err = -EBUSY;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800989 if(ubd_dev->count > 0)
Jeff Dike29d56cf2005-06-25 14:55:25 -0700990 goto out;
991
Jeff Dikedc764e52007-05-06 14:51:41 -0700992 ubd_gendisk[n] = NULL;
Jeff Dikeb47d2de2007-05-06 14:51:01 -0700993 if(disk != NULL){
994 del_gendisk(disk);
995 put_disk(disk);
996 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997
998 if(fake_gendisk[n] != NULL){
999 del_gendisk(fake_gendisk[n]);
1000 put_disk(fake_gendisk[n]);
1001 fake_gendisk[n] = NULL;
1002 }
1003
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 err = 0;
Jeff Dike2e3f5252007-05-06 14:51:29 -07001005 platform_device_unregister(&ubd_dev->pdev);
Jeff Dike29d56cf2005-06-25 14:55:25 -07001006out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -08001007 mutex_unlock(&ubd_lock);
Jeff Dike29d56cf2005-06-25 14:55:25 -07001008 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009}
1010
Jeff Dikef28169d2007-02-10 01:43:53 -08001011/* All these are called by mconsole in process context and without
Jeff Dikeb8831a12007-02-10 01:44:17 -08001012 * ubd-specific locks. The structure itself is const except for .list.
Jeff Dikef28169d2007-02-10 01:43:53 -08001013 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014static struct mc_device ubd_mc = {
Jeff Dike84f48d42007-02-10 01:44:01 -08001015 .list = LIST_HEAD_INIT(ubd_mc.list),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 .name = "ubd",
1017 .config = ubd_config,
Jeff Dikedc764e52007-05-06 14:51:41 -07001018 .get_config = ubd_get_config,
Jeff Dike29d56cf2005-06-25 14:55:25 -07001019 .id = ubd_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 .remove = ubd_remove,
1021};
1022
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001023static int __init ubd_mc_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024{
1025 mconsole_register_dev(&ubd_mc);
1026 return 0;
1027}
1028
1029__initcall(ubd_mc_init);
1030
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001031static int __init ubd0_init(void)
1032{
1033 struct ubd *ubd_dev = &ubd_devs[0];
1034
Jeff Dikeb8831a12007-02-10 01:44:17 -08001035 mutex_lock(&ubd_lock);
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001036 if(ubd_dev->file == NULL)
1037 ubd_dev->file = "root_fs";
Jeff Dikeb8831a12007-02-10 01:44:17 -08001038 mutex_unlock(&ubd_lock);
1039
Jeff Dikedc764e52007-05-06 14:51:41 -07001040 return 0;
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001041}
1042
1043__initcall(ubd0_init);
1044
Jeff Dikeb8831a12007-02-10 01:44:17 -08001045/* Used in ubd_init, which is an initcall */
Russell King3ae5eae2005-11-09 22:32:44 +00001046static struct platform_driver ubd_driver = {
1047 .driver = {
1048 .name = DRIVER_NAME,
1049 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050};
1051
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001052static int __init ubd_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053{
Jeff Dikef28169d2007-02-10 01:43:53 -08001054 char *error;
1055 int i, err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056
Christoph Hellwig792dd4f2009-03-31 15:23:39 -07001057 if (register_blkdev(UBD_MAJOR, "ubd"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 return -1;
1059
Christoph Hellwig792dd4f2009-03-31 15:23:39 -07001060 if (fake_major != UBD_MAJOR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 char name[sizeof("ubd_nnn\0")];
1062
1063 snprintf(name, sizeof(name), "ubd_%d", fake_major);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 if (register_blkdev(fake_major, "ubd"))
1065 return -1;
1066 }
Russell King3ae5eae2005-11-09 22:32:44 +00001067 platform_driver_register(&ubd_driver);
Jeff Dikedc764e52007-05-06 14:51:41 -07001068 mutex_lock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -08001069 for (i = 0; i < MAX_DEV; i++){
1070 err = ubd_add(i, &error);
1071 if(err)
1072 printk(KERN_ERR "Failed to initialize ubd device %d :"
1073 "%s\n", i, error);
1074 }
Jeff Dikedc764e52007-05-06 14:51:41 -07001075 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 return 0;
1077}
1078
1079late_initcall(ubd_init);
1080
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001081static int __init ubd_driver_init(void){
Jeff Dike91acb212005-10-10 23:10:32 -04001082 unsigned long stack;
1083 int err;
1084
1085 /* Set by CONFIG_BLK_DEV_UBD_SYNC or ubd=sync.*/
1086 if(global_openflags.s){
1087 printk(KERN_INFO "ubd: Synchronous mode\n");
1088 /* Letting ubd=sync be like using ubd#s= instead of ubd#= is
1089 * enough. So use anyway the io thread. */
1090 }
1091 stack = alloc_stack(0, 0);
Jeff Dike6c29256c2006-03-27 01:14:37 -08001092 io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *),
Jeff Dike91acb212005-10-10 23:10:32 -04001093 &thread_fd);
1094 if(io_pid < 0){
Jeff Dike6c29256c2006-03-27 01:14:37 -08001095 printk(KERN_ERR
Jeff Dike91acb212005-10-10 23:10:32 -04001096 "ubd : Failed to start I/O thread (errno = %d) - "
1097 "falling back to synchronous I/O\n", -io_pid);
1098 io_pid = -1;
Jeff Dikedc764e52007-05-06 14:51:41 -07001099 return 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001100 }
Jeff Dike6c29256c2006-03-27 01:14:37 -08001101 err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr,
Yong Zhangc0b79a92011-09-22 16:58:46 +08001102 0, "ubd", ubd_devs);
Jeff Dike91acb212005-10-10 23:10:32 -04001103 if(err != 0)
1104 printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err);
Jeff Dikef4c57a72006-03-31 02:30:10 -08001105 return 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001106}
1107
1108device_initcall(ubd_driver_init);
1109
Al Viroa625c992008-03-02 09:16:26 -05001110static int ubd_open(struct block_device *bdev, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111{
Al Viroa625c992008-03-02 09:16:26 -05001112 struct gendisk *disk = bdev->bd_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001113 struct ubd *ubd_dev = disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 int err = 0;
1115
Arnd Bergmann9a181c52010-09-11 18:38:03 +02001116 mutex_lock(&ubd_mutex);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001117 if(ubd_dev->count == 0){
1118 err = ubd_open_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 if(err){
1120 printk(KERN_ERR "%s: Can't open \"%s\": errno = %d\n",
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001121 disk->disk_name, ubd_dev->file, -err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 goto out;
1123 }
1124 }
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001125 ubd_dev->count++;
1126 set_disk_ro(disk, !ubd_dev->openflags.w);
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -07001127
1128 /* This should no more be needed. And it didn't work anyway to exclude
1129 * read-write remounting of filesystems.*/
Al Viroa625c992008-03-02 09:16:26 -05001130 /*if((mode & FMODE_WRITE) && !ubd_dev->openflags.w){
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -08001131 if(--ubd_dev->count == 0) ubd_close_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 err = -EROFS;
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -07001133 }*/
Arnd Bergmann6e9624b2010-08-07 18:25:34 +02001134out:
Arnd Bergmann9a181c52010-09-11 18:38:03 +02001135 mutex_unlock(&ubd_mutex);
Jeff Dikedc764e52007-05-06 14:51:41 -07001136 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137}
1138
Al Virodb2a1442013-05-05 21:52:57 -04001139static void ubd_release(struct gendisk *disk, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001141 struct ubd *ubd_dev = disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142
Arnd Bergmann9a181c52010-09-11 18:38:03 +02001143 mutex_lock(&ubd_mutex);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001144 if(--ubd_dev->count == 0)
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -08001145 ubd_close_dev(ubd_dev);
Arnd Bergmann9a181c52010-09-11 18:38:03 +02001146 mutex_unlock(&ubd_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147}
1148
Jeff Dike91acb212005-10-10 23:10:32 -04001149static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask,
1150 __u64 *cow_offset, unsigned long *bitmap,
1151 __u64 bitmap_offset, unsigned long *bitmap_words,
1152 __u64 bitmap_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153{
Jeff Dike91acb212005-10-10 23:10:32 -04001154 __u64 sector = io_offset >> 9;
1155 int i, update_bitmap = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156
Jeff Dike91acb212005-10-10 23:10:32 -04001157 for(i = 0; i < length >> 9; i++){
1158 if(cow_mask != NULL)
1159 ubd_set_bit(i, (unsigned char *) cow_mask);
1160 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
1161 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162
Jeff Dike91acb212005-10-10 23:10:32 -04001163 update_bitmap = 1;
1164 ubd_set_bit(sector + i, (unsigned char *) bitmap);
1165 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166
Jeff Dike91acb212005-10-10 23:10:32 -04001167 if(!update_bitmap)
1168 return;
1169
1170 *cow_offset = sector / (sizeof(unsigned long) * 8);
1171
1172 /* This takes care of the case where we're exactly at the end of the
1173 * device, and *cow_offset + 1 is off the end. So, just back it up
1174 * by one word. Thanks to Lynn Kerby for the fix and James McMechan
1175 * for the original diagnosis.
1176 */
Jiri Olsa6d074242008-05-12 14:01:56 -07001177 if (*cow_offset == (DIV_ROUND_UP(bitmap_len,
1178 sizeof(unsigned long)) - 1))
Jeff Dike91acb212005-10-10 23:10:32 -04001179 (*cow_offset)--;
1180
1181 bitmap_words[0] = bitmap[*cow_offset];
1182 bitmap_words[1] = bitmap[*cow_offset + 1];
1183
1184 *cow_offset *= sizeof(unsigned long);
1185 *cow_offset += bitmap_offset;
1186}
1187
1188static void cowify_req(struct io_thread_req *req, unsigned long *bitmap,
1189 __u64 bitmap_offset, __u64 bitmap_len)
1190{
1191 __u64 sector = req->offset >> 9;
1192 int i;
1193
1194 if(req->length > (sizeof(req->sector_mask) * 8) << 9)
1195 panic("Operation too long");
1196
1197 if(req->op == UBD_READ) {
1198 for(i = 0; i < req->length >> 9; i++){
1199 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
Jeff Dike6c29256c2006-03-27 01:14:37 -08001200 ubd_set_bit(i, (unsigned char *)
Jeff Dike91acb212005-10-10 23:10:32 -04001201 &req->sector_mask);
Jeff Dikedc764e52007-05-06 14:51:41 -07001202 }
Jeff Dike91acb212005-10-10 23:10:32 -04001203 }
1204 else cowify_bitmap(req->offset, req->length, &req->sector_mask,
1205 &req->cow_offset, bitmap, bitmap_offset,
1206 req->bitmap_words, bitmap_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207}
1208
Jeff Dike62f96cb2007-02-10 01:44:16 -08001209/* Called with dev->lock held */
Jeff Dikea0044bd2007-05-06 14:51:36 -07001210static void prepare_request(struct request *req, struct io_thread_req *io_req,
1211 unsigned long long offset, int page_offset,
1212 int len, struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213{
1214 struct gendisk *disk = req->rq_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001215 struct ubd *ubd_dev = disk->private_data;
Jeff Dike91acb212005-10-10 23:10:32 -04001216
Jeff Dike62f96cb2007-02-10 01:44:16 -08001217 io_req->req = req;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001218 io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd :
1219 ubd_dev->fd;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001220 io_req->fds[1] = ubd_dev->fd;
Jeff Dike91acb212005-10-10 23:10:32 -04001221 io_req->cow_offset = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 io_req->offset = offset;
1223 io_req->length = len;
1224 io_req->error = 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001225 io_req->sector_mask = 0;
1226
1227 io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 io_req->offsets[0] = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001229 io_req->offsets[1] = ubd_dev->cow.data_offset;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001230 io_req->buffer = page_address(page) + page_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 io_req->sectorsize = 1 << 9;
1232
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001233 if(ubd_dev->cow.file != NULL)
Jeff Dikea0044bd2007-05-06 14:51:36 -07001234 cowify_req(io_req, ubd_dev->cow.bitmap,
1235 ubd_dev->cow.bitmap_offset, ubd_dev->cow.bitmap_len);
Jeff Dike91acb212005-10-10 23:10:32 -04001236
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237}
1238
Jeff Dike62f96cb2007-02-10 01:44:16 -08001239/* Called with dev->lock held */
Richard Weinberger805f11a2013-08-18 13:30:06 +02001240static void prepare_flush_request(struct request *req,
1241 struct io_thread_req *io_req)
1242{
1243 struct gendisk *disk = req->rq_disk;
1244 struct ubd *ubd_dev = disk->private_data;
1245
1246 io_req->req = req;
1247 io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd :
1248 ubd_dev->fd;
1249 io_req->op = UBD_FLUSH;
1250}
1251
Richard Weinbergerbc1d72e2013-08-18 13:30:07 +02001252static bool submit_request(struct io_thread_req *io_req, struct ubd *dev)
1253{
1254 int n = os_write_file(thread_fd, &io_req,
1255 sizeof(io_req));
1256 if (n != sizeof(io_req)) {
1257 if (n != -EAGAIN)
1258 printk("write to io thread failed, "
1259 "errno = %d\n", -n);
1260 else if (list_empty(&dev->restart))
1261 list_add(&dev->restart, &restart);
1262
1263 kfree(io_req);
1264 return false;
1265 }
1266 return true;
1267}
1268
Richard Weinberger805f11a2013-08-18 13:30:06 +02001269/* Called with dev->lock held */
Jens Axboe165125e2007-07-24 09:28:11 +02001270static void do_ubd_request(struct request_queue *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271{
Jeff Dike2adcec22007-05-06 14:51:37 -07001272 struct io_thread_req *io_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 struct request *req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274
Jeff Dikea0044bd2007-05-06 14:51:36 -07001275 while(1){
Jeff Dike2a9529a2007-03-29 01:20:27 -07001276 struct ubd *dev = q->queuedata;
Thorsten Knabe2a236122014-08-23 15:47:38 +02001277 if(dev->request == NULL){
Tejun Heo9934c8c2009-05-08 11:54:16 +09001278 struct request *req = blk_fetch_request(q);
Jeff Dikea0044bd2007-05-06 14:51:36 -07001279 if(req == NULL)
1280 return;
1281
1282 dev->request = req;
Tejun Heo47526902010-10-15 12:56:21 +02001283 dev->rq_pos = blk_rq_pos(req);
Jeff Dikea0044bd2007-05-06 14:51:36 -07001284 dev->start_sg = 0;
1285 dev->end_sg = blk_rq_map_sg(q, req, dev->sg);
Jeff Dike91acb212005-10-10 23:10:32 -04001286 }
Jeff Dikea0044bd2007-05-06 14:51:36 -07001287
1288 req = dev->request;
Richard Weinberger805f11a2013-08-18 13:30:06 +02001289
Mike Christie3a5e02c2016-06-05 14:32:23 -05001290 if (req_op(req) == REQ_OP_FLUSH) {
Richard Weinberger805f11a2013-08-18 13:30:06 +02001291 io_req = kmalloc(sizeof(struct io_thread_req),
1292 GFP_ATOMIC);
1293 if (io_req == NULL) {
1294 if (list_empty(&dev->restart))
1295 list_add(&dev->restart, &restart);
1296 return;
1297 }
1298 prepare_flush_request(req, io_req);
Thorsten Knabe2a236122014-08-23 15:47:38 +02001299 if (submit_request(io_req, dev) == false)
1300 return;
Richard Weinberger805f11a2013-08-18 13:30:06 +02001301 }
1302
Jeff Dikea0044bd2007-05-06 14:51:36 -07001303 while(dev->start_sg < dev->end_sg){
1304 struct scatterlist *sg = &dev->sg[dev->start_sg];
1305
Jeff Dike2adcec22007-05-06 14:51:37 -07001306 io_req = kmalloc(sizeof(struct io_thread_req),
Peter Zijlstra990c5582007-05-06 14:51:38 -07001307 GFP_ATOMIC);
Jeff Dike2adcec22007-05-06 14:51:37 -07001308 if(io_req == NULL){
1309 if(list_empty(&dev->restart))
1310 list_add(&dev->restart, &restart);
1311 return;
1312 }
1313 prepare_request(req, io_req,
Tejun Heo47526902010-10-15 12:56:21 +02001314 (unsigned long long)dev->rq_pos << 9,
Jens Axboe45711f12007-10-22 21:19:53 +02001315 sg->offset, sg->length, sg_page(sg));
Jeff Dikea0044bd2007-05-06 14:51:36 -07001316
Richard Weinbergerbc1d72e2013-08-18 13:30:07 +02001317 if (submit_request(io_req, dev) == false)
Jeff Dikea0044bd2007-05-06 14:51:36 -07001318 return;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001319
Tejun Heo47526902010-10-15 12:56:21 +02001320 dev->rq_pos += sg->length >> 9;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001321 dev->start_sg++;
1322 }
1323 dev->end_sg = 0;
1324 dev->request = NULL;
Jeff Dike91acb212005-10-10 23:10:32 -04001325 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326}
1327
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001328static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
1329{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001330 struct ubd *ubd_dev = bdev->bd_disk->private_data;
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001331
1332 geo->heads = 128;
1333 geo->sectors = 32;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001334 geo->cylinders = ubd_dev->size / (128 * 32 * 512);
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001335 return 0;
1336}
1337
Al Viroa625c992008-03-02 09:16:26 -05001338static int ubd_ioctl(struct block_device *bdev, fmode_t mode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 unsigned int cmd, unsigned long arg)
1340{
Al Viroa625c992008-03-02 09:16:26 -05001341 struct ubd *ubd_dev = bdev->bd_disk->private_data;
Bartlomiej Zolnierkiewicz73855e12009-04-01 21:42:21 +02001342 u16 ubd_id[ATA_ID_WORDS];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343
1344 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 struct cdrom_volctrl volume;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 case HDIO_GET_IDENTITY:
Bartlomiej Zolnierkiewicz73855e12009-04-01 21:42:21 +02001347 memset(&ubd_id, 0, ATA_ID_WORDS * 2);
1348 ubd_id[ATA_ID_CYLS] = ubd_dev->size / (128 * 32 * 512);
1349 ubd_id[ATA_ID_HEADS] = 128;
1350 ubd_id[ATA_ID_SECTORS] = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 if(copy_to_user((char __user *) arg, (char *) &ubd_id,
1352 sizeof(ubd_id)))
Jeff Dikedc764e52007-05-06 14:51:41 -07001353 return -EFAULT;
1354 return 0;
Jeff Dikeb8831a12007-02-10 01:44:17 -08001355
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 case CDROMVOLREAD:
1357 if(copy_from_user(&volume, (char __user *) arg, sizeof(volume)))
Jeff Dikedc764e52007-05-06 14:51:41 -07001358 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 volume.channel0 = 255;
1360 volume.channel1 = 255;
1361 volume.channel2 = 255;
1362 volume.channel3 = 255;
1363 if(copy_to_user((char __user *) arg, &volume, sizeof(volume)))
Jeff Dikedc764e52007-05-06 14:51:41 -07001364 return -EFAULT;
1365 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 }
Jeff Dikedc764e52007-05-06 14:51:41 -07001367 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368}
1369
Jeff Dike91acb212005-10-10 23:10:32 -04001370static int update_bitmap(struct io_thread_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371{
Jeff Dike91acb212005-10-10 23:10:32 -04001372 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373
Jeff Dike91acb212005-10-10 23:10:32 -04001374 if(req->cow_offset == -1)
Jeff Dikedc764e52007-05-06 14:51:41 -07001375 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376
Anton Ivanov8c6157b2015-12-21 18:54:00 +00001377 n = os_pwrite_file(req->fds[1], &req->bitmap_words,
1378 sizeof(req->bitmap_words), req->cow_offset);
Jeff Dike91acb212005-10-10 23:10:32 -04001379 if(n != sizeof(req->bitmap_words)){
1380 printk("do_io - bitmap update failed, err = %d fd = %d\n", -n,
1381 req->fds[1]);
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 Dikedc764e52007-05-06 14:51:41 -07001385 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386}
Jeff Dike91acb212005-10-10 23:10:32 -04001387
WANG Cong5dc62b12008-04-28 02:13:58 -07001388static void do_io(struct io_thread_req *req)
Jeff Dike91acb212005-10-10 23:10:32 -04001389{
1390 char *buf;
1391 unsigned long len;
1392 int n, nsectors, start, end, bit;
Jeff Dike91acb212005-10-10 23:10:32 -04001393 __u64 off;
1394
Richard Weinberger805f11a2013-08-18 13:30:06 +02001395 if (req->op == UBD_FLUSH) {
1396 /* fds[0] is always either the rw image or our cow file */
1397 n = os_sync_file(req->fds[0]);
1398 if (n != 0) {
1399 printk("do_io - sync failed err = %d "
1400 "fd = %d\n", -n, req->fds[0]);
1401 req->error = 1;
1402 }
1403 return;
1404 }
1405
Jeff Dike91acb212005-10-10 23:10:32 -04001406 nsectors = req->length / req->sectorsize;
1407 start = 0;
1408 do {
1409 bit = ubd_test_bit(start, (unsigned char *) &req->sector_mask);
1410 end = start;
1411 while((end < nsectors) &&
1412 (ubd_test_bit(end, (unsigned char *)
1413 &req->sector_mask) == bit))
1414 end++;
1415
1416 off = req->offset + req->offsets[bit] +
1417 start * req->sectorsize;
1418 len = (end - start) * req->sectorsize;
1419 buf = &req->buffer[start * req->sectorsize];
1420
Jeff Dike91acb212005-10-10 23:10:32 -04001421 if(req->op == UBD_READ){
1422 n = 0;
1423 do {
1424 buf = &buf[n];
1425 len -= n;
Anton Ivanov8c6157b2015-12-21 18:54:00 +00001426 n = os_pread_file(req->fds[bit], buf, len, off);
Jeff Dike91acb212005-10-10 23:10:32 -04001427 if (n < 0) {
1428 printk("do_io - read failed, err = %d "
1429 "fd = %d\n", -n, req->fds[bit]);
1430 req->error = 1;
1431 return;
1432 }
1433 } while((n < len) && (n != 0));
1434 if (n < len) memset(&buf[n], 0, len - n);
1435 } else {
Anton Ivanov8c6157b2015-12-21 18:54:00 +00001436 n = os_pwrite_file(req->fds[bit], buf, len, off);
Jeff Dike91acb212005-10-10 23:10:32 -04001437 if(n != len){
1438 printk("do_io - write failed err = %d "
1439 "fd = %d\n", -n, req->fds[bit]);
1440 req->error = 1;
1441 return;
1442 }
1443 }
1444
1445 start = end;
1446 } while(start < nsectors);
1447
1448 req->error = update_bitmap(req);
1449}
1450
1451/* Changed in start_io_thread, which is serialized by being called only
1452 * from ubd_init, which is an initcall.
1453 */
1454int kernel_fd = -1;
1455
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001456/* Only changed by the io thread. XXX: currently unused. */
1457static int io_count = 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001458
1459int io_thread(void *arg)
1460{
Jeff Dike2adcec22007-05-06 14:51:37 -07001461 struct io_thread_req *req;
Jeff Dike91acb212005-10-10 23:10:32 -04001462 int n;
1463
Richard Weinberger91d44ff2013-08-18 13:30:08 +02001464 os_fix_helper_signals();
1465
Jeff Dike91acb212005-10-10 23:10:32 -04001466 while(1){
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001467 n = os_read_file(kernel_fd, &req,
Jeff Dike2adcec22007-05-06 14:51:37 -07001468 sizeof(struct io_thread_req *));
1469 if(n != sizeof(struct io_thread_req *)){
Jeff Dike91acb212005-10-10 23:10:32 -04001470 if(n < 0)
1471 printk("io_thread - read failed, fd = %d, "
1472 "err = %d\n", kernel_fd, -n);
1473 else {
1474 printk("io_thread - short read, fd = %d, "
1475 "length = %d\n", kernel_fd, n);
1476 }
1477 continue;
1478 }
1479 io_count++;
Jeff Dike2adcec22007-05-06 14:51:37 -07001480 do_io(req);
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001481 n = os_write_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 printk("io_thread - write failed, fd = %d, err = %d\n",
1485 kernel_fd, -n);
1486 }
Jeff Dike91acb212005-10-10 23:10:32 -04001487
Jeff Dike1b57e9c2006-01-06 00:18:49 -08001488 return 0;
1489}