blob: 85410279beab63d611af485b27f729727aa5988d [file] [log] [blame]
Jeff Dike6c29256c2006-03-27 01:14:37 -08001/*
Anton Ivanovf88f0bd2016-11-09 20:43:25 +00002 * Copyright (C) 2015-2016 Anton Ivanov (aivanov@brocade.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
4 * Licensed under the GPL
5 */
6
7/* 2001-09-28...2002-04-17
8 * Partition stuff by James_McMechan@hotmail.com
9 * old style ubd by setting UBD_SHIFT to 0
10 * 2002-09-27...2002-10-18 massive tinkering for 2.5
11 * partitions have changed in 2.5
12 * 2003-01-29 more tinkering for 2.5.59-1
13 * This should now address the sysfs problems and has
14 * the symlink for devfs to allow for booting with
15 * the common /dev/ubd/discX/... names rather than
16 * only /dev/ubdN/discN this version also has lots of
17 * clean ups preparing for ubd-many.
18 * James McMechan
19 */
20
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#define UBD_SHIFT 4
22
Al Viro8ea3c062011-08-18 18:04:41 -040023#include <linux/module.h>
24#include <linux/init.h>
25#include <linux/blkdev.h>
26#include <linux/ata.h>
27#include <linux/hdreg.h>
28#include <linux/cdrom.h>
29#include <linux/proc_fs.h>
30#include <linux/seq_file.h>
31#include <linux/ctype.h>
32#include <linux/slab.h>
33#include <linux/vmalloc.h>
34#include <linux/platform_device.h>
35#include <linux/scatterlist.h>
36#include <asm/tlbflush.h>
Al Viro37185b32012-10-08 03:27:32 +010037#include <kern_util.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include "mconsole_kern.h"
Al Viro37185b32012-10-08 03:27:32 +010039#include <init.h>
40#include <irq_kern.h>
Al Viro8ea3c062011-08-18 18:04:41 -040041#include "ubd.h"
Al Viro37185b32012-10-08 03:27:32 +010042#include <os.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include "cow.h"
44
Richard Weinberger805f11a2013-08-18 13:30:06 +020045enum ubd_req { UBD_READ, UBD_WRITE, UBD_FLUSH };
Linus Torvalds1da177e2005-04-16 15:20:36 -070046
47struct io_thread_req {
Jeff Dike62f96cb2007-02-10 01:44:16 -080048 struct request *req;
Jeff Dike91acb212005-10-10 23:10:32 -040049 enum ubd_req op;
Linus Torvalds1da177e2005-04-16 15:20:36 -070050 int fds[2];
51 unsigned long offsets[2];
52 unsigned long long offset;
53 unsigned long length;
54 char *buffer;
55 int sectorsize;
Jeff Dike91acb212005-10-10 23:10:32 -040056 unsigned long sector_mask;
57 unsigned long long cow_offset;
58 unsigned long bitmap_words[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -070059 int error;
60};
61
Anton Ivanovf88f0bd2016-11-09 20:43:25 +000062
63static struct io_thread_req * (*irq_req_buffer)[];
64static struct io_thread_req *irq_remainder;
65static int irq_remainder_size;
66
67static struct io_thread_req * (*io_req_buffer)[];
68static struct io_thread_req *io_remainder;
69static int io_remainder_size;
70
71
72
Jeff Dike91acb212005-10-10 23:10:32 -040073static inline int ubd_test_bit(__u64 bit, unsigned char *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -070074{
75 __u64 n;
76 int bits, off;
77
Jeff Dike91acb212005-10-10 23:10:32 -040078 bits = sizeof(data[0]) * 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -070079 n = bit / bits;
80 off = bit % bits;
Jeff Dikedc764e52007-05-06 14:51:41 -070081 return (data[n] & (1 << off)) != 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070082}
83
Jeff Dike91acb212005-10-10 23:10:32 -040084static inline void ubd_set_bit(__u64 bit, unsigned char *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -070085{
86 __u64 n;
87 int bits, off;
88
Jeff Dike91acb212005-10-10 23:10:32 -040089 bits = sizeof(data[0]) * 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -070090 n = bit / bits;
91 off = bit % bits;
Jeff Dike91acb212005-10-10 23:10:32 -040092 data[n] |= (1 << off);
Linus Torvalds1da177e2005-04-16 15:20:36 -070093}
94/*End stuff from ubd_user.h*/
95
96#define DRIVER_NAME "uml-blkdev"
97
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -080098static DEFINE_MUTEX(ubd_lock);
Arnd Bergmann9a181c52010-09-11 18:38:03 +020099static DEFINE_MUTEX(ubd_mutex); /* replaces BKL, might not be needed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100
Al Viroa625c992008-03-02 09:16:26 -0500101static int ubd_open(struct block_device *bdev, fmode_t mode);
Al Virodb2a1442013-05-05 21:52:57 -0400102static void ubd_release(struct gendisk *disk, fmode_t mode);
Al Viroa625c992008-03-02 09:16:26 -0500103static int ubd_ioctl(struct block_device *bdev, fmode_t mode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 unsigned int cmd, unsigned long arg);
Christoph Hellwiga885c8c2006-01-08 01:02:50 -0800105static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106
Paolo 'Blaisorblade' Giarrusso97d88ac2006-10-30 22:07:03 -0800107#define MAX_DEV (16)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108
Alexey Dobriyan83d5cde2009-09-21 17:01:13 -0700109static const struct block_device_operations ubd_blops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 .owner = THIS_MODULE,
Al Viroa625c992008-03-02 09:16:26 -0500111 .open = ubd_open,
112 .release = ubd_release,
113 .ioctl = ubd_ioctl,
Christoph Hellwiga885c8c2006-01-08 01:02:50 -0800114 .getgeo = ubd_getgeo,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115};
116
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117/* Protected by ubd_lock */
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700118static int fake_major = UBD_MAJOR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119static struct gendisk *ubd_gendisk[MAX_DEV];
120static struct gendisk *fake_gendisk[MAX_DEV];
Jeff Dike6c29256c2006-03-27 01:14:37 -0800121
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122#ifdef CONFIG_BLK_DEV_UBD_SYNC
123#define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 1, .c = 0, \
124 .cl = 1 })
125#else
126#define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 0, .c = 0, \
127 .cl = 1 })
128#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129static struct openflags global_openflags = OPEN_FLAGS;
130
131struct cow {
Paolo 'Blaisorblade' Giarrusso2a9d32f2006-10-30 22:07:04 -0800132 /* backing file name */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133 char *file;
Paolo 'Blaisorblade' Giarrusso2a9d32f2006-10-30 22:07:04 -0800134 /* backing file fd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 int fd;
136 unsigned long *bitmap;
137 unsigned long bitmap_len;
138 int bitmap_offset;
Jeff Dikedc764e52007-05-06 14:51:41 -0700139 int data_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140};
141
Jeff Dikea0044bd2007-05-06 14:51:36 -0700142#define MAX_SG 64
143
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144struct ubd {
Jeff Dikea0044bd2007-05-06 14:51:36 -0700145 struct list_head restart;
Paolo 'Blaisorblade' Giarrusso2a9d32f2006-10-30 22:07:04 -0800146 /* name (and fd, below) of the file opened for writing, either the
147 * backing or the cow file. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 char *file;
149 int count;
150 int fd;
151 __u64 size;
152 struct openflags boot_openflags;
153 struct openflags openflags;
Paolo 'Blaisorblade' Giarrusso84e945e2006-10-30 22:07:10 -0800154 unsigned shared:1;
155 unsigned no_cow:1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 struct cow cow;
157 struct platform_device pdev;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800158 struct request_queue *queue;
159 spinlock_t lock;
Jeff Dikea0044bd2007-05-06 14:51:36 -0700160 struct scatterlist sg[MAX_SG];
161 struct request *request;
162 int start_sg, end_sg;
Tejun Heo47526902010-10-15 12:56:21 +0200163 sector_t rq_pos;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164};
165
166#define DEFAULT_COW { \
167 .file = NULL, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700168 .fd = -1, \
169 .bitmap = NULL, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 .bitmap_offset = 0, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700171 .data_offset = 0, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172}
173
174#define DEFAULT_UBD { \
175 .file = NULL, \
176 .count = 0, \
177 .fd = -1, \
178 .size = -1, \
179 .boot_openflags = OPEN_FLAGS, \
180 .openflags = OPEN_FLAGS, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700181 .no_cow = 0, \
Jeff Dike6c29256c2006-03-27 01:14:37 -0800182 .shared = 0, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700183 .cow = DEFAULT_COW, \
Thomas Gleixner22e65002011-01-23 15:21:25 +0100184 .lock = __SPIN_LOCK_UNLOCKED(ubd_devs.lock), \
Jeff Dikea0044bd2007-05-06 14:51:36 -0700185 .request = NULL, \
186 .start_sg = 0, \
187 .end_sg = 0, \
Tejun Heo47526902010-10-15 12:56:21 +0200188 .rq_pos = 0, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189}
190
Jeff Dikeb8831a12007-02-10 01:44:17 -0800191/* Protected by ubd_lock */
WANG Cong5dc62b12008-04-28 02:13:58 -0700192static struct ubd ubd_devs[MAX_DEV] = { [0 ... MAX_DEV - 1] = DEFAULT_UBD };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194/* Only changed by fake_ide_setup which is a setup */
195static int fake_ide = 0;
196static struct proc_dir_entry *proc_ide_root = NULL;
197static struct proc_dir_entry *proc_ide = NULL;
198
199static void make_proc_ide(void)
200{
201 proc_ide_root = proc_mkdir("ide", NULL);
202 proc_ide = proc_mkdir("ide0", proc_ide_root);
203}
204
Alexey Dobriyan6613c5e2009-12-14 18:00:11 -0800205static int fake_ide_media_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206{
Alexey Dobriyan6613c5e2009-12-14 18:00:11 -0800207 seq_puts(m, "disk\n");
208 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209}
210
Alexey Dobriyan6613c5e2009-12-14 18:00:11 -0800211static int fake_ide_media_proc_open(struct inode *inode, struct file *file)
212{
213 return single_open(file, fake_ide_media_proc_show, NULL);
214}
215
216static const struct file_operations fake_ide_media_proc_fops = {
217 .owner = THIS_MODULE,
218 .open = fake_ide_media_proc_open,
219 .read = seq_read,
220 .llseek = seq_lseek,
221 .release = single_release,
222};
223
WANG Congc0a92902008-02-04 22:30:41 -0800224static void make_ide_entries(const char *dev_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225{
226 struct proc_dir_entry *dir, *ent;
227 char name[64];
228
229 if(proc_ide_root == NULL) make_proc_ide();
230
231 dir = proc_mkdir(dev_name, proc_ide);
232 if(!dir) return;
233
Alexey Dobriyan6613c5e2009-12-14 18:00:11 -0800234 ent = proc_create("media", S_IRUGO, dir, &fake_ide_media_proc_fops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 if(!ent) return;
WANG Congc0a92902008-02-04 22:30:41 -0800236 snprintf(name, sizeof(name), "ide0/%s", dev_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 proc_symlink(dev_name, proc_ide_root, name);
238}
239
240static int fake_ide_setup(char *str)
241{
242 fake_ide = 1;
Jeff Dikedc764e52007-05-06 14:51:41 -0700243 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244}
245
246__setup("fake_ide", fake_ide_setup);
247
248__uml_help(fake_ide_setup,
249"fake_ide\n"
250" Create ide0 entries that map onto ubd devices.\n\n"
251);
252
253static int parse_unit(char **ptr)
254{
255 char *str = *ptr, *end;
256 int n = -1;
257
258 if(isdigit(*str)) {
259 n = simple_strtoul(str, &end, 0);
260 if(end == str)
Jeff Dikedc764e52007-05-06 14:51:41 -0700261 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 *ptr = end;
263 }
Paolo 'Blaisorblade' Giarrusso97d88ac2006-10-30 22:07:03 -0800264 else if (('a' <= *str) && (*str <= 'z')) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 n = *str - 'a';
266 str++;
267 *ptr = str;
268 }
Jeff Dikedc764e52007-05-06 14:51:41 -0700269 return n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270}
271
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800272/* If *index_out == -1 at exit, the passed option was a general one;
273 * otherwise, the str pointer is used (and owned) inside ubd_devs array, so it
274 * should not be freed on exit.
275 */
Jeff Dikef28169d2007-02-10 01:43:53 -0800276static int ubd_setup_common(char *str, int *index_out, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800278 struct ubd *ubd_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 struct openflags flags = global_openflags;
280 char *backing_file;
Jeff Dikeb8831a12007-02-10 01:44:17 -0800281 int n, err = 0, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282
283 if(index_out) *index_out = -1;
284 n = *str;
285 if(n == '='){
286 char *end;
287 int major;
288
289 str++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 if(!strcmp(str, "sync")){
291 global_openflags = of_sync(global_openflags);
Jeff Dikeb8831a12007-02-10 01:44:17 -0800292 goto out1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 }
294
Jeff Dikef28169d2007-02-10 01:43:53 -0800295 err = -EINVAL;
Jeff Dikeb8831a12007-02-10 01:44:17 -0800296 major = simple_strtoul(str, &end, 0);
297 if((*end != '\0') || (end == str)){
298 *error_out = "Didn't parse major number";
299 goto out1;
300 }
301
Jeff Dikef28169d2007-02-10 01:43:53 -0800302 mutex_lock(&ubd_lock);
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700303 if (fake_major != UBD_MAJOR) {
Jeff Dikef28169d2007-02-10 01:43:53 -0800304 *error_out = "Can't assign a fake major twice";
305 goto out1;
306 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800307
Jeff Dikef28169d2007-02-10 01:43:53 -0800308 fake_major = major;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309
310 printk(KERN_INFO "Setting extra ubd major number to %d\n",
311 major);
Jeff Dikef28169d2007-02-10 01:43:53 -0800312 err = 0;
313 out1:
314 mutex_unlock(&ubd_lock);
315 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 }
317
318 n = parse_unit(&str);
319 if(n < 0){
Jeff Dikef28169d2007-02-10 01:43:53 -0800320 *error_out = "Couldn't parse device number";
321 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 }
323 if(n >= MAX_DEV){
Jeff Dikef28169d2007-02-10 01:43:53 -0800324 *error_out = "Device number out of range";
325 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 }
327
Jeff Dikef28169d2007-02-10 01:43:53 -0800328 err = -EBUSY;
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800329 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800331 ubd_dev = &ubd_devs[n];
332 if(ubd_dev->file != NULL){
Jeff Dikef28169d2007-02-10 01:43:53 -0800333 *error_out = "Device is already configured";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 goto out;
335 }
336
337 if (index_out)
338 *index_out = n;
339
Jeff Dikef28169d2007-02-10 01:43:53 -0800340 err = -EINVAL;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800341 for (i = 0; i < sizeof("rscd="); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 switch (*str) {
343 case 'r':
344 flags.w = 0;
345 break;
346 case 's':
347 flags.s = 1;
348 break;
349 case 'd':
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800350 ubd_dev->no_cow = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 break;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800352 case 'c':
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800353 ubd_dev->shared = 1;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800354 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 case '=':
356 str++;
357 goto break_loop;
358 default:
Jeff Dikef28169d2007-02-10 01:43:53 -0800359 *error_out = "Expected '=' or flag letter "
360 "(r, s, c, or d)";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 goto out;
362 }
363 str++;
364 }
365
Jeff Dikef28169d2007-02-10 01:43:53 -0800366 if (*str == '=')
367 *error_out = "Too many flags specified";
368 else
369 *error_out = "Missing '='";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 goto out;
371
372break_loop:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 backing_file = strchr(str, ',');
374
Jeff Dikef28169d2007-02-10 01:43:53 -0800375 if (backing_file == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 backing_file = strchr(str, ':');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377
Jeff Dikef28169d2007-02-10 01:43:53 -0800378 if(backing_file != NULL){
379 if(ubd_dev->no_cow){
380 *error_out = "Can't specify both 'd' and a cow file";
381 goto out;
382 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 else {
384 *backing_file = '\0';
385 backing_file++;
386 }
387 }
Jeff Dikef28169d2007-02-10 01:43:53 -0800388 err = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800389 ubd_dev->file = str;
390 ubd_dev->cow.file = backing_file;
391 ubd_dev->boot_openflags = flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800393 mutex_unlock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -0800394 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395}
396
397static int ubd_setup(char *str)
398{
Jeff Dikef28169d2007-02-10 01:43:53 -0800399 char *error;
400 int err;
401
402 err = ubd_setup_common(str, NULL, &error);
403 if(err)
404 printk(KERN_ERR "Failed to initialize device with \"%s\" : "
405 "%s\n", str, error);
406 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407}
408
409__setup("ubd", ubd_setup);
410__uml_help(ubd_setup,
411"ubd<n><flags>=<filename>[(:|,)<filename2>]\n"
412" This is used to associate a device with a file in the underlying\n"
413" filesystem. When specifying two filenames, the first one is the\n"
414" COW name and the second is the backing file name. As separator you can\n"
415" use either a ':' or a ',': the first one allows writing things like;\n"
416" ubd0=~/Uml/root_cow:~/Uml/root_backing_file\n"
417" while with a ',' the shell would not expand the 2nd '~'.\n"
Jeff Dikef28169d2007-02-10 01:43:53 -0800418" When using only one filename, UML will detect whether to treat it like\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419" a COW file or a backing file. To override this detection, add the 'd'\n"
420" flag:\n"
421" ubd0d=BackingFile\n"
422" Usually, there is a filesystem in the file, but \n"
423" that's not required. Swap devices containing swap files can be\n"
424" specified like this. Also, a file which doesn't contain a\n"
425" filesystem can have its contents read in the virtual \n"
426" machine by running 'dd' on the device. <n> must be in the range\n"
427" 0 to 7. Appending an 'r' to the number will cause that device\n"
428" to be mounted read-only. For example ubd1r=./ext_fs. Appending\n"
Jeff Dike20ede452008-02-04 22:30:37 -0800429" an 's' will cause data to be written to disk on the host immediately.\n"
430" 'c' will cause the device to be treated as being shared between multiple\n"
431" UMLs and file locking will be turned off - this is appropriate for a\n"
432" cluster filesystem and inappropriate at almost all other times.\n\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433);
434
Jeff Dike8299ca52008-02-04 22:30:48 -0800435static int udb_setup(char *str)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436{
437 printk("udb%s specified on command line is almost certainly a ubd -> "
438 "udb TYPO\n", str);
Jeff Dikedc764e52007-05-06 14:51:41 -0700439 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440}
441
442__setup("udb", udb_setup);
443__uml_help(udb_setup,
444"udb\n"
Jeff Dike0894e272005-05-28 15:51:55 -0700445" This option is here solely to catch ubd -> udb typos, which can be\n"
446" to impossible to catch visually unless you specifically look for\n"
447" them. The only result of any option starting with 'udb' is an error\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448" in the boot output.\n\n"
449);
450
Jens Axboe165125e2007-07-24 09:28:11 +0200451static void do_ubd_request(struct request_queue * q);
Jeff Dike91acb212005-10-10 23:10:32 -0400452
453/* Only changed by ubd_init, which is an initcall. */
WANG Cong5dc62b12008-04-28 02:13:58 -0700454static int thread_fd = -1;
Jeff Dikea0044bd2007-05-06 14:51:36 -0700455static LIST_HEAD(restart);
456
Anton Ivanovf88f0bd2016-11-09 20:43:25 +0000457/* Function to read several request pointers at a time
458* handling fractional reads if (and as) needed
459*/
460
461static int bulk_req_safe_read(
462 int fd,
463 struct io_thread_req * (*request_buffer)[],
464 struct io_thread_req **remainder,
465 int *remainder_size,
466 int max_recs
467 )
468{
469 int n = 0;
470 int res = 0;
471
472 if (*remainder_size > 0) {
473 memmove(
474 (char *) request_buffer,
475 (char *) remainder, *remainder_size
476 );
477 n = *remainder_size;
478 }
479
480 res = os_read_file(
481 fd,
482 ((char *) request_buffer) + *remainder_size,
483 sizeof(struct io_thread_req *)*max_recs
484 - *remainder_size
485 );
486 if (res > 0) {
487 n += res;
488 if ((n % sizeof(struct io_thread_req *)) > 0) {
489 /*
490 * Read somehow returned not a multiple of dword
491 * theoretically possible, but never observed in the
492 * wild, so read routine must be able to handle it
493 */
494 *remainder_size = n % sizeof(struct io_thread_req *);
495 WARN(*remainder_size > 0, "UBD IPC read returned a partial result");
496 memmove(
497 remainder,
498 ((char *) request_buffer) +
499 (n/sizeof(struct io_thread_req *))*sizeof(struct io_thread_req *),
500 *remainder_size
501 );
502 n = n - *remainder_size;
503 }
504 } else {
505 n = res;
506 }
507 return n;
508}
509
Jeff Dike62f96cb2007-02-10 01:44:16 -0800510/* Called without dev->lock held, and only in interrupt context. */
Jeff Dike91acb212005-10-10 23:10:32 -0400511static void ubd_handler(void)
512{
Jeff Dikea0044bd2007-05-06 14:51:36 -0700513 struct ubd *ubd;
514 struct list_head *list, *next_ele;
515 unsigned long flags;
Jeff Dike91acb212005-10-10 23:10:32 -0400516 int n;
Anton Ivanovf88f0bd2016-11-09 20:43:25 +0000517 int count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518
Jeff Dikea0044bd2007-05-06 14:51:36 -0700519 while(1){
Anton Ivanovf88f0bd2016-11-09 20:43:25 +0000520 n = bulk_req_safe_read(
521 thread_fd,
522 irq_req_buffer,
523 &irq_remainder,
524 &irq_remainder_size,
525 UBD_REQ_BUFFER_SIZE
526 );
527 if (n < 0) {
Jeff Dikea0044bd2007-05-06 14:51:36 -0700528 if(n == -EAGAIN)
529 break;
530 printk(KERN_ERR "spurious interrupt in ubd_handler, "
531 "err = %d\n", -n);
532 return;
533 }
Anton Ivanovf88f0bd2016-11-09 20:43:25 +0000534 for (count = 0; count < n/sizeof(struct io_thread_req *); count++) {
535 blk_end_request(
536 (*irq_req_buffer)[count]->req,
537 0,
538 (*irq_req_buffer)[count]->length
539 );
540 kfree((*irq_req_buffer)[count]);
541 }
Jeff Dike91acb212005-10-10 23:10:32 -0400542 }
Jeff Dike62f96cb2007-02-10 01:44:16 -0800543 reactivate_fd(thread_fd, UBD_IRQ);
Jeff Dikea0044bd2007-05-06 14:51:36 -0700544
545 list_for_each_safe(list, next_ele, &restart){
546 ubd = container_of(list, struct ubd, restart);
547 list_del_init(&ubd->restart);
548 spin_lock_irqsave(&ubd->lock, flags);
549 do_ubd_request(ubd->queue);
550 spin_unlock_irqrestore(&ubd->lock, flags);
551 }
Jeff Dike91acb212005-10-10 23:10:32 -0400552}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553
Al Viro7bea96f2006-10-08 22:49:34 +0100554static irqreturn_t ubd_intr(int irq, void *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555{
Jeff Dike91acb212005-10-10 23:10:32 -0400556 ubd_handler();
Jeff Dikedc764e52007-05-06 14:51:41 -0700557 return IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558}
559
Jeff Dike91acb212005-10-10 23:10:32 -0400560/* Only changed by ubd_init, which is an initcall. */
561static int io_pid = -1;
562
WANG Cong5dc62b12008-04-28 02:13:58 -0700563static void kill_io_thread(void)
Jeff Dike91acb212005-10-10 23:10:32 -0400564{
Jeff Dike6c29256c2006-03-27 01:14:37 -0800565 if(io_pid != -1)
Jeff Dike91acb212005-10-10 23:10:32 -0400566 os_kill_process(io_pid, 1);
567}
568
569__uml_exitcall(kill_io_thread);
570
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800571static inline int ubd_file_size(struct ubd *ubd_dev, __u64 *size_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572{
573 char *file;
Richard Weinberger85356392011-11-02 13:17:27 +0100574 int fd;
575 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576
Richard Weinberger85356392011-11-02 13:17:27 +0100577 __u32 version;
578 __u32 align;
579 char *backing_file;
580 time_t mtime;
581 unsigned long long size;
582 int sector_size;
583 int bitmap_offset;
584
585 if (ubd_dev->file && ubd_dev->cow.file) {
586 file = ubd_dev->cow.file;
587
588 goto out;
589 }
590
Martin Pärteld4afcba2012-08-02 00:44:22 +0200591 fd = os_open_file(ubd_dev->file, of_read(OPENFLAGS()), 0);
Richard Weinberger85356392011-11-02 13:17:27 +0100592 if (fd < 0)
593 return fd;
594
595 err = read_cow_header(file_reader, &fd, &version, &backing_file, \
596 &mtime, &size, &sector_size, &align, &bitmap_offset);
597 os_close_file(fd);
598
599 if(err == -EINVAL)
600 file = ubd_dev->file;
601 else
602 file = backing_file;
603
604out:
Jeff Dikedc764e52007-05-06 14:51:41 -0700605 return os_file_size(file, size_out);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606}
607
WANG Cong5dc62b12008-04-28 02:13:58 -0700608static int read_cow_bitmap(int fd, void *buf, int offset, int len)
609{
610 int err;
611
Anton Ivanov8c6157b2015-12-21 18:54:00 +0000612 err = os_pread_file(fd, buf, len, offset);
WANG Cong5dc62b12008-04-28 02:13:58 -0700613 if (err < 0)
614 return err;
615
616 return 0;
617}
618
619static int backing_file_mismatch(char *file, __u64 size, time_t mtime)
620{
621 unsigned long modtime;
622 unsigned long long actual;
623 int err;
624
625 err = os_file_modtime(file, &modtime);
626 if (err < 0) {
627 printk(KERN_ERR "Failed to get modification time of backing "
628 "file \"%s\", err = %d\n", file, -err);
629 return err;
630 }
631
632 err = os_file_size(file, &actual);
633 if (err < 0) {
634 printk(KERN_ERR "Failed to get size of backing file \"%s\", "
635 "err = %d\n", file, -err);
636 return err;
637 }
638
639 if (actual != size) {
640 /*__u64 can be a long on AMD64 and with %lu GCC complains; so
641 * the typecast.*/
642 printk(KERN_ERR "Size mismatch (%llu vs %llu) of COW header "
643 "vs backing file\n", (unsigned long long) size, actual);
644 return -EINVAL;
645 }
646 if (modtime != mtime) {
647 printk(KERN_ERR "mtime mismatch (%ld vs %ld) of COW header vs "
648 "backing file\n", mtime, modtime);
649 return -EINVAL;
650 }
651 return 0;
652}
653
654static int path_requires_switch(char *from_cmdline, char *from_cow, char *cow)
655{
656 struct uml_stat buf1, buf2;
657 int err;
658
659 if (from_cmdline == NULL)
660 return 0;
661 if (!strcmp(from_cmdline, from_cow))
662 return 0;
663
664 err = os_stat_file(from_cmdline, &buf1);
665 if (err < 0) {
666 printk(KERN_ERR "Couldn't stat '%s', err = %d\n", from_cmdline,
667 -err);
668 return 0;
669 }
670 err = os_stat_file(from_cow, &buf2);
671 if (err < 0) {
672 printk(KERN_ERR "Couldn't stat '%s', err = %d\n", from_cow,
673 -err);
674 return 1;
675 }
676 if ((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino))
677 return 0;
678
679 printk(KERN_ERR "Backing file mismatch - \"%s\" requested, "
680 "\"%s\" specified in COW header of \"%s\"\n",
681 from_cmdline, from_cow, cow);
682 return 1;
683}
684
685static int open_ubd_file(char *file, struct openflags *openflags, int shared,
686 char **backing_file_out, int *bitmap_offset_out,
687 unsigned long *bitmap_len_out, int *data_offset_out,
688 int *create_cow_out)
689{
690 time_t mtime;
691 unsigned long long size;
692 __u32 version, align;
693 char *backing_file;
694 int fd, err, sectorsize, asked_switch, mode = 0644;
695
696 fd = os_open_file(file, *openflags, mode);
697 if (fd < 0) {
698 if ((fd == -ENOENT) && (create_cow_out != NULL))
699 *create_cow_out = 1;
700 if (!openflags->w ||
701 ((fd != -EROFS) && (fd != -EACCES)))
702 return fd;
703 openflags->w = 0;
704 fd = os_open_file(file, *openflags, mode);
705 if (fd < 0)
706 return fd;
707 }
708
709 if (shared)
710 printk(KERN_INFO "Not locking \"%s\" on the host\n", file);
711 else {
712 err = os_lock_file(fd, openflags->w);
713 if (err < 0) {
714 printk(KERN_ERR "Failed to lock '%s', err = %d\n",
715 file, -err);
716 goto out_close;
717 }
718 }
719
720 /* Successful return case! */
721 if (backing_file_out == NULL)
722 return fd;
723
724 err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime,
725 &size, &sectorsize, &align, bitmap_offset_out);
726 if (err && (*backing_file_out != NULL)) {
727 printk(KERN_ERR "Failed to read COW header from COW file "
728 "\"%s\", errno = %d\n", file, -err);
729 goto out_close;
730 }
731 if (err)
732 return fd;
733
734 asked_switch = path_requires_switch(*backing_file_out, backing_file,
735 file);
736
737 /* Allow switching only if no mismatch. */
738 if (asked_switch && !backing_file_mismatch(*backing_file_out, size,
739 mtime)) {
740 printk(KERN_ERR "Switching backing file to '%s'\n",
741 *backing_file_out);
742 err = write_cow_header(file, fd, *backing_file_out,
743 sectorsize, align, &size);
744 if (err) {
745 printk(KERN_ERR "Switch failed, errno = %d\n", -err);
746 goto out_close;
747 }
748 } else {
749 *backing_file_out = backing_file;
750 err = backing_file_mismatch(*backing_file_out, size, mtime);
751 if (err)
752 goto out_close;
753 }
754
755 cow_sizes(version, size, sectorsize, align, *bitmap_offset_out,
756 bitmap_len_out, data_offset_out);
757
758 return fd;
759 out_close:
760 os_close_file(fd);
761 return err;
762}
763
764static int create_cow_file(char *cow_file, char *backing_file,
765 struct openflags flags,
766 int sectorsize, int alignment, int *bitmap_offset_out,
767 unsigned long *bitmap_len_out, int *data_offset_out)
768{
769 int err, fd;
770
771 flags.c = 1;
772 fd = open_ubd_file(cow_file, &flags, 0, NULL, NULL, NULL, NULL, NULL);
773 if (fd < 0) {
774 err = fd;
775 printk(KERN_ERR "Open of COW file '%s' failed, errno = %d\n",
776 cow_file, -err);
777 goto out;
778 }
779
780 err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment,
781 bitmap_offset_out, bitmap_len_out,
782 data_offset_out);
783 if (!err)
784 return fd;
785 os_close_file(fd);
786 out:
787 return err;
788}
789
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800790static void ubd_close_dev(struct ubd *ubd_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800792 os_close_file(ubd_dev->fd);
793 if(ubd_dev->cow.file == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 return;
795
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800796 os_close_file(ubd_dev->cow.fd);
797 vfree(ubd_dev->cow.bitmap);
798 ubd_dev->cow.bitmap = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799}
800
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800801static int ubd_open_dev(struct ubd *ubd_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802{
803 struct openflags flags;
804 char **back_ptr;
805 int err, create_cow, *create_ptr;
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800806 int fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800808 ubd_dev->openflags = ubd_dev->boot_openflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 create_cow = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800810 create_ptr = (ubd_dev->cow.file != NULL) ? &create_cow : NULL;
811 back_ptr = ubd_dev->no_cow ? NULL : &ubd_dev->cow.file;
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800812
813 fd = open_ubd_file(ubd_dev->file, &ubd_dev->openflags, ubd_dev->shared,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800814 back_ptr, &ubd_dev->cow.bitmap_offset,
815 &ubd_dev->cow.bitmap_len, &ubd_dev->cow.data_offset,
Jeff Dike6c29256c2006-03-27 01:14:37 -0800816 create_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800818 if((fd == -ENOENT) && create_cow){
819 fd = create_cow_file(ubd_dev->file, ubd_dev->cow.file,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800820 ubd_dev->openflags, 1 << 9, PAGE_SIZE,
821 &ubd_dev->cow.bitmap_offset,
822 &ubd_dev->cow.bitmap_len,
823 &ubd_dev->cow.data_offset);
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800824 if(fd >= 0){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 printk(KERN_INFO "Creating \"%s\" as COW file for "
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800826 "\"%s\"\n", ubd_dev->file, ubd_dev->cow.file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 }
828 }
829
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800830 if(fd < 0){
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800831 printk("Failed to open '%s', errno = %d\n", ubd_dev->file,
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800832 -fd);
833 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 }
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800835 ubd_dev->fd = fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800837 if(ubd_dev->cow.file != NULL){
Martin K. Petersen086fa5f2010-02-26 00:20:38 -0500838 blk_queue_max_hw_sectors(ubd_dev->queue, 8 * sizeof(long));
Jeff Dikef4768ff2007-08-22 14:01:53 -0700839
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 err = -ENOMEM;
Jesper Juhlda2486b2007-10-16 01:27:19 -0700841 ubd_dev->cow.bitmap = vmalloc(ubd_dev->cow.bitmap_len);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800842 if(ubd_dev->cow.bitmap == NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 printk(KERN_ERR "Failed to vmalloc COW bitmap\n");
844 goto error;
845 }
846 flush_tlb_kernel_vm();
847
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800848 err = read_cow_bitmap(ubd_dev->fd, ubd_dev->cow.bitmap,
849 ubd_dev->cow.bitmap_offset,
850 ubd_dev->cow.bitmap_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 if(err < 0)
852 goto error;
853
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800854 flags = ubd_dev->openflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 flags.w = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800856 err = open_ubd_file(ubd_dev->cow.file, &flags, ubd_dev->shared, NULL,
Jeff Dike6c29256c2006-03-27 01:14:37 -0800857 NULL, NULL, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 if(err < 0) goto error;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800859 ubd_dev->cow.fd = err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 }
Jeff Dikedc764e52007-05-06 14:51:41 -0700861 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 error:
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800863 os_close_file(ubd_dev->fd);
Jeff Dikedc764e52007-05-06 14:51:41 -0700864 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865}
866
Jeff Dike2e3f5252007-05-06 14:51:29 -0700867static void ubd_device_release(struct device *dev)
868{
Greg Kroah-Hartman8691b972009-05-04 12:40:54 -0700869 struct ubd *ubd_dev = dev_get_drvdata(dev);
Jeff Dike2e3f5252007-05-06 14:51:29 -0700870
871 blk_cleanup_queue(ubd_dev->queue);
872 *ubd_dev = ((struct ubd) DEFAULT_UBD);
873}
874
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800875static int ubd_disk_register(int major, u64 size, int unit,
Jeff Dikeb8831a12007-02-10 01:44:17 -0800876 struct gendisk **disk_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877{
Dan Williamsd72a5782016-06-20 10:44:32 -0700878 struct device *parent = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 struct gendisk *disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880
881 disk = alloc_disk(1 << UBD_SHIFT);
882 if(disk == NULL)
Jeff Dikedc764e52007-05-06 14:51:41 -0700883 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884
885 disk->major = major;
886 disk->first_minor = unit << UBD_SHIFT;
887 disk->fops = &ubd_blops;
888 set_capacity(disk, size / 512);
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700889 if (major == UBD_MAJOR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 sprintf(disk->disk_name, "ubd%c", 'a' + unit);
Greg Kroah-Hartmance7b0f42005-06-20 21:15:16 -0700891 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 sprintf(disk->disk_name, "ubd_fake%d", unit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893
894 /* sysfs register (not for ide fake devices) */
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700895 if (major == UBD_MAJOR) {
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800896 ubd_devs[unit].pdev.id = unit;
897 ubd_devs[unit].pdev.name = DRIVER_NAME;
Jeff Dike2e3f5252007-05-06 14:51:29 -0700898 ubd_devs[unit].pdev.dev.release = ubd_device_release;
Greg Kroah-Hartman8691b972009-05-04 12:40:54 -0700899 dev_set_drvdata(&ubd_devs[unit].pdev.dev, &ubd_devs[unit]);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800900 platform_device_register(&ubd_devs[unit].pdev);
Dan Williamsd72a5782016-06-20 10:44:32 -0700901 parent = &ubd_devs[unit].pdev.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 }
903
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800904 disk->private_data = &ubd_devs[unit];
Jeff Dike62f96cb2007-02-10 01:44:16 -0800905 disk->queue = ubd_devs[unit].queue;
Dan Williamsd72a5782016-06-20 10:44:32 -0700906 device_add_disk(parent, disk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907
908 *disk_out = disk;
909 return 0;
910}
911
912#define ROUND_BLOCK(n) ((n + ((1 << 9) - 1)) & (-1 << 9))
913
Jeff Dikef28169d2007-02-10 01:43:53 -0800914static int ubd_add(int n, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800916 struct ubd *ubd_dev = &ubd_devs[n];
Jeff Dikef28169d2007-02-10 01:43:53 -0800917 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800919 if(ubd_dev->file == NULL)
Jeff Dikeec7cf782005-09-03 15:57:29 -0700920 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800922 err = ubd_file_size(ubd_dev, &ubd_dev->size);
Jeff Dikef28169d2007-02-10 01:43:53 -0800923 if(err < 0){
924 *error_out = "Couldn't determine size of device's file";
Jeff Dike80c13742006-09-29 01:58:51 -0700925 goto out;
Jeff Dikef28169d2007-02-10 01:43:53 -0800926 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800928 ubd_dev->size = ROUND_BLOCK(ubd_dev->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929
Jeff Dikea0044bd2007-05-06 14:51:36 -0700930 INIT_LIST_HEAD(&ubd_dev->restart);
WANG Cong4f40c052007-11-05 14:50:59 -0800931 sg_init_table(ubd_dev->sg, MAX_SG);
Jeff Dikea0044bd2007-05-06 14:51:36 -0700932
Jeff Dike62f96cb2007-02-10 01:44:16 -0800933 err = -ENOMEM;
934 ubd_dev->queue = blk_init_queue(do_ubd_request, &ubd_dev->lock);
935 if (ubd_dev->queue == NULL) {
936 *error_out = "Failed to initialize device queue";
Jeff Dike80c13742006-09-29 01:58:51 -0700937 goto out;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800938 }
939 ubd_dev->queue->queuedata = ubd_dev;
Jens Axboef935a8c2016-03-30 10:19:17 -0600940 blk_queue_write_cache(ubd_dev->queue, true, false);
Jeff Dike62f96cb2007-02-10 01:44:16 -0800941
Martin K. Petersen8a783622010-02-26 00:20:39 -0500942 blk_queue_max_segments(ubd_dev->queue, MAX_SG);
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700943 err = ubd_disk_register(UBD_MAJOR, ubd_dev->size, n, &ubd_gendisk[n]);
Jeff Dike62f96cb2007-02-10 01:44:16 -0800944 if(err){
945 *error_out = "Failed to register device";
946 goto out_cleanup;
947 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800948
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700949 if (fake_major != UBD_MAJOR)
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800950 ubd_disk_register(fake_major, ubd_dev->size, n,
Jeff Dike62f96cb2007-02-10 01:44:16 -0800951 &fake_gendisk[n]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952
Jeff Dike83380cc2008-02-04 22:31:18 -0800953 /*
954 * Perhaps this should also be under the "if (fake_major)" above
955 * using the fake_disk->disk_name
956 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 if (fake_ide)
958 make_ide_entries(ubd_gendisk[n]->disk_name);
959
Jeff Dikeec7cf782005-09-03 15:57:29 -0700960 err = 0;
Jeff Dikeec7cf782005-09-03 15:57:29 -0700961out:
962 return err;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800963
964out_cleanup:
965 blk_cleanup_queue(ubd_dev->queue);
966 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967}
968
Jeff Dikef28169d2007-02-10 01:43:53 -0800969static int ubd_config(char *str, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970{
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800971 int n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972
Jeff Dikef28169d2007-02-10 01:43:53 -0800973 /* This string is possibly broken up and stored, so it's only
974 * freed if ubd_setup_common fails, or if only general options
975 * were set.
976 */
Jeff Dike970d6e32006-01-06 00:18:48 -0800977 str = kstrdup(str, GFP_KERNEL);
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800978 if (str == NULL) {
Jeff Dikef28169d2007-02-10 01:43:53 -0800979 *error_out = "Failed to allocate memory";
980 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 }
Jeff Dikef28169d2007-02-10 01:43:53 -0800982
983 ret = ubd_setup_common(str, &n, error_out);
984 if (ret)
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800985 goto err_free;
Jeff Dikef28169d2007-02-10 01:43:53 -0800986
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800987 if (n == -1) {
988 ret = 0;
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800989 goto err_free;
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800990 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991
Jeff Dikedc764e52007-05-06 14:51:41 -0700992 mutex_lock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -0800993 ret = ubd_add(n, error_out);
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800994 if (ret)
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800995 ubd_devs[n].file = NULL;
Jeff Dikedc764e52007-05-06 14:51:41 -0700996 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800998out:
Jeff Dikedc764e52007-05-06 14:51:41 -0700999 return ret;
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -08001000
1001err_free:
1002 kfree(str);
1003 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004}
1005
1006static int ubd_get_config(char *name, char *str, int size, char **error_out)
1007{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001008 struct ubd *ubd_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 int n, len = 0;
1010
1011 n = parse_unit(&name);
1012 if((n >= MAX_DEV) || (n < 0)){
1013 *error_out = "ubd_get_config : device number out of range";
Jeff Dikedc764e52007-05-06 14:51:41 -07001014 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 }
1016
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001017 ubd_dev = &ubd_devs[n];
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -08001018 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001020 if(ubd_dev->file == NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 CONFIG_CHUNK(str, size, len, "", 1);
1022 goto out;
1023 }
1024
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001025 CONFIG_CHUNK(str, size, len, ubd_dev->file, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001027 if(ubd_dev->cow.file != NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 CONFIG_CHUNK(str, size, len, ",", 0);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001029 CONFIG_CHUNK(str, size, len, ubd_dev->cow.file, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 }
1031 else CONFIG_CHUNK(str, size, len, "", 1);
1032
1033 out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -08001034 mutex_unlock(&ubd_lock);
Jeff Dikedc764e52007-05-06 14:51:41 -07001035 return len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036}
1037
Jeff Dike29d56cf2005-06-25 14:55:25 -07001038static int ubd_id(char **str, int *start_out, int *end_out)
1039{
Jeff Dikedc764e52007-05-06 14:51:41 -07001040 int n;
Jeff Dike29d56cf2005-06-25 14:55:25 -07001041
1042 n = parse_unit(str);
Jeff Dikedc764e52007-05-06 14:51:41 -07001043 *start_out = 0;
1044 *end_out = MAX_DEV - 1;
1045 return n;
Jeff Dike29d56cf2005-06-25 14:55:25 -07001046}
1047
Jeff Dikef28169d2007-02-10 01:43:53 -08001048static int ubd_remove(int n, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049{
Jeff Dike2e3f5252007-05-06 14:51:29 -07001050 struct gendisk *disk = ubd_gendisk[n];
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001051 struct ubd *ubd_dev;
Jeff Dike29d56cf2005-06-25 14:55:25 -07001052 int err = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -08001054 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001056 ubd_dev = &ubd_devs[n];
Jeff Dike29d56cf2005-06-25 14:55:25 -07001057
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001058 if(ubd_dev->file == NULL)
Jeff Dike29d56cf2005-06-25 14:55:25 -07001059 goto out;
1060
1061 /* you cannot remove a open disk */
1062 err = -EBUSY;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001063 if(ubd_dev->count > 0)
Jeff Dike29d56cf2005-06-25 14:55:25 -07001064 goto out;
1065
Jeff Dikedc764e52007-05-06 14:51:41 -07001066 ubd_gendisk[n] = NULL;
Jeff Dikeb47d2de2007-05-06 14:51:01 -07001067 if(disk != NULL){
1068 del_gendisk(disk);
1069 put_disk(disk);
1070 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071
1072 if(fake_gendisk[n] != NULL){
1073 del_gendisk(fake_gendisk[n]);
1074 put_disk(fake_gendisk[n]);
1075 fake_gendisk[n] = NULL;
1076 }
1077
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 err = 0;
Jeff Dike2e3f5252007-05-06 14:51:29 -07001079 platform_device_unregister(&ubd_dev->pdev);
Jeff Dike29d56cf2005-06-25 14:55:25 -07001080out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -08001081 mutex_unlock(&ubd_lock);
Jeff Dike29d56cf2005-06-25 14:55:25 -07001082 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083}
1084
Jeff Dikef28169d2007-02-10 01:43:53 -08001085/* All these are called by mconsole in process context and without
Jeff Dikeb8831a12007-02-10 01:44:17 -08001086 * ubd-specific locks. The structure itself is const except for .list.
Jeff Dikef28169d2007-02-10 01:43:53 -08001087 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088static struct mc_device ubd_mc = {
Jeff Dike84f48d42007-02-10 01:44:01 -08001089 .list = LIST_HEAD_INIT(ubd_mc.list),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 .name = "ubd",
1091 .config = ubd_config,
Jeff Dikedc764e52007-05-06 14:51:41 -07001092 .get_config = ubd_get_config,
Jeff Dike29d56cf2005-06-25 14:55:25 -07001093 .id = ubd_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 .remove = ubd_remove,
1095};
1096
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001097static int __init ubd_mc_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098{
1099 mconsole_register_dev(&ubd_mc);
1100 return 0;
1101}
1102
1103__initcall(ubd_mc_init);
1104
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001105static int __init ubd0_init(void)
1106{
1107 struct ubd *ubd_dev = &ubd_devs[0];
1108
Jeff Dikeb8831a12007-02-10 01:44:17 -08001109 mutex_lock(&ubd_lock);
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001110 if(ubd_dev->file == NULL)
1111 ubd_dev->file = "root_fs";
Jeff Dikeb8831a12007-02-10 01:44:17 -08001112 mutex_unlock(&ubd_lock);
1113
Jeff Dikedc764e52007-05-06 14:51:41 -07001114 return 0;
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001115}
1116
1117__initcall(ubd0_init);
1118
Jeff Dikeb8831a12007-02-10 01:44:17 -08001119/* Used in ubd_init, which is an initcall */
Russell King3ae5eae2005-11-09 22:32:44 +00001120static struct platform_driver ubd_driver = {
1121 .driver = {
1122 .name = DRIVER_NAME,
1123 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124};
1125
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001126static int __init ubd_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127{
Jeff Dikef28169d2007-02-10 01:43:53 -08001128 char *error;
1129 int i, err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130
Christoph Hellwig792dd4f2009-03-31 15:23:39 -07001131 if (register_blkdev(UBD_MAJOR, "ubd"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 return -1;
1133
Christoph Hellwig792dd4f2009-03-31 15:23:39 -07001134 if (fake_major != UBD_MAJOR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 char name[sizeof("ubd_nnn\0")];
1136
1137 snprintf(name, sizeof(name), "ubd_%d", fake_major);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 if (register_blkdev(fake_major, "ubd"))
1139 return -1;
1140 }
Anton Ivanovf88f0bd2016-11-09 20:43:25 +00001141
1142 irq_req_buffer = kmalloc(
1143 sizeof(struct io_thread_req *) * UBD_REQ_BUFFER_SIZE,
1144 GFP_KERNEL
1145 );
1146 irq_remainder = 0;
1147
1148 if (irq_req_buffer == NULL) {
1149 printk(KERN_ERR "Failed to initialize ubd buffering\n");
1150 return -1;
1151 }
1152 io_req_buffer = kmalloc(
1153 sizeof(struct io_thread_req *) * UBD_REQ_BUFFER_SIZE,
1154 GFP_KERNEL
1155 );
1156
1157 io_remainder = 0;
1158
1159 if (io_req_buffer == NULL) {
1160 printk(KERN_ERR "Failed to initialize ubd buffering\n");
1161 return -1;
1162 }
Russell King3ae5eae2005-11-09 22:32:44 +00001163 platform_driver_register(&ubd_driver);
Jeff Dikedc764e52007-05-06 14:51:41 -07001164 mutex_lock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -08001165 for (i = 0; i < MAX_DEV; i++){
1166 err = ubd_add(i, &error);
1167 if(err)
1168 printk(KERN_ERR "Failed to initialize ubd device %d :"
1169 "%s\n", i, error);
1170 }
Jeff Dikedc764e52007-05-06 14:51:41 -07001171 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 return 0;
1173}
1174
1175late_initcall(ubd_init);
1176
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001177static int __init ubd_driver_init(void){
Jeff Dike91acb212005-10-10 23:10:32 -04001178 unsigned long stack;
1179 int err;
1180
1181 /* Set by CONFIG_BLK_DEV_UBD_SYNC or ubd=sync.*/
1182 if(global_openflags.s){
1183 printk(KERN_INFO "ubd: Synchronous mode\n");
1184 /* Letting ubd=sync be like using ubd#s= instead of ubd#= is
1185 * enough. So use anyway the io thread. */
1186 }
1187 stack = alloc_stack(0, 0);
Jeff Dike6c29256c2006-03-27 01:14:37 -08001188 io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *),
Jeff Dike91acb212005-10-10 23:10:32 -04001189 &thread_fd);
1190 if(io_pid < 0){
Jeff Dike6c29256c2006-03-27 01:14:37 -08001191 printk(KERN_ERR
Jeff Dike91acb212005-10-10 23:10:32 -04001192 "ubd : Failed to start I/O thread (errno = %d) - "
1193 "falling back to synchronous I/O\n", -io_pid);
1194 io_pid = -1;
Jeff Dikedc764e52007-05-06 14:51:41 -07001195 return 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001196 }
Jeff Dike6c29256c2006-03-27 01:14:37 -08001197 err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr,
Yong Zhangc0b79a92011-09-22 16:58:46 +08001198 0, "ubd", ubd_devs);
Jeff Dike91acb212005-10-10 23:10:32 -04001199 if(err != 0)
1200 printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err);
Jeff Dikef4c57a72006-03-31 02:30:10 -08001201 return 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001202}
1203
1204device_initcall(ubd_driver_init);
1205
Al Viroa625c992008-03-02 09:16:26 -05001206static int ubd_open(struct block_device *bdev, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207{
Al Viroa625c992008-03-02 09:16:26 -05001208 struct gendisk *disk = bdev->bd_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001209 struct ubd *ubd_dev = disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 int err = 0;
1211
Arnd Bergmann9a181c52010-09-11 18:38:03 +02001212 mutex_lock(&ubd_mutex);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001213 if(ubd_dev->count == 0){
1214 err = ubd_open_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215 if(err){
1216 printk(KERN_ERR "%s: Can't open \"%s\": errno = %d\n",
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001217 disk->disk_name, ubd_dev->file, -err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 goto out;
1219 }
1220 }
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001221 ubd_dev->count++;
1222 set_disk_ro(disk, !ubd_dev->openflags.w);
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -07001223
1224 /* This should no more be needed. And it didn't work anyway to exclude
1225 * read-write remounting of filesystems.*/
Al Viroa625c992008-03-02 09:16:26 -05001226 /*if((mode & FMODE_WRITE) && !ubd_dev->openflags.w){
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -08001227 if(--ubd_dev->count == 0) ubd_close_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 err = -EROFS;
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -07001229 }*/
Arnd Bergmann6e9624b2010-08-07 18:25:34 +02001230out:
Arnd Bergmann9a181c52010-09-11 18:38:03 +02001231 mutex_unlock(&ubd_mutex);
Jeff Dikedc764e52007-05-06 14:51:41 -07001232 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233}
1234
Al Virodb2a1442013-05-05 21:52:57 -04001235static void ubd_release(struct gendisk *disk, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001237 struct ubd *ubd_dev = disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238
Arnd Bergmann9a181c52010-09-11 18:38:03 +02001239 mutex_lock(&ubd_mutex);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001240 if(--ubd_dev->count == 0)
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -08001241 ubd_close_dev(ubd_dev);
Arnd Bergmann9a181c52010-09-11 18:38:03 +02001242 mutex_unlock(&ubd_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243}
1244
Jeff Dike91acb212005-10-10 23:10:32 -04001245static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask,
1246 __u64 *cow_offset, unsigned long *bitmap,
1247 __u64 bitmap_offset, unsigned long *bitmap_words,
1248 __u64 bitmap_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249{
Jeff Dike91acb212005-10-10 23:10:32 -04001250 __u64 sector = io_offset >> 9;
1251 int i, update_bitmap = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252
Jeff Dike91acb212005-10-10 23:10:32 -04001253 for(i = 0; i < length >> 9; i++){
1254 if(cow_mask != NULL)
1255 ubd_set_bit(i, (unsigned char *) cow_mask);
1256 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
1257 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258
Jeff Dike91acb212005-10-10 23:10:32 -04001259 update_bitmap = 1;
1260 ubd_set_bit(sector + i, (unsigned char *) bitmap);
1261 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262
Jeff Dike91acb212005-10-10 23:10:32 -04001263 if(!update_bitmap)
1264 return;
1265
1266 *cow_offset = sector / (sizeof(unsigned long) * 8);
1267
1268 /* This takes care of the case where we're exactly at the end of the
1269 * device, and *cow_offset + 1 is off the end. So, just back it up
1270 * by one word. Thanks to Lynn Kerby for the fix and James McMechan
1271 * for the original diagnosis.
1272 */
Jiri Olsa6d074242008-05-12 14:01:56 -07001273 if (*cow_offset == (DIV_ROUND_UP(bitmap_len,
1274 sizeof(unsigned long)) - 1))
Jeff Dike91acb212005-10-10 23:10:32 -04001275 (*cow_offset)--;
1276
1277 bitmap_words[0] = bitmap[*cow_offset];
1278 bitmap_words[1] = bitmap[*cow_offset + 1];
1279
1280 *cow_offset *= sizeof(unsigned long);
1281 *cow_offset += bitmap_offset;
1282}
1283
1284static void cowify_req(struct io_thread_req *req, unsigned long *bitmap,
1285 __u64 bitmap_offset, __u64 bitmap_len)
1286{
1287 __u64 sector = req->offset >> 9;
1288 int i;
1289
1290 if(req->length > (sizeof(req->sector_mask) * 8) << 9)
1291 panic("Operation too long");
1292
1293 if(req->op == UBD_READ) {
1294 for(i = 0; i < req->length >> 9; i++){
1295 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
Jeff Dike6c29256c2006-03-27 01:14:37 -08001296 ubd_set_bit(i, (unsigned char *)
Jeff Dike91acb212005-10-10 23:10:32 -04001297 &req->sector_mask);
Jeff Dikedc764e52007-05-06 14:51:41 -07001298 }
Jeff Dike91acb212005-10-10 23:10:32 -04001299 }
1300 else cowify_bitmap(req->offset, req->length, &req->sector_mask,
1301 &req->cow_offset, bitmap, bitmap_offset,
1302 req->bitmap_words, bitmap_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303}
1304
Jeff Dike62f96cb2007-02-10 01:44:16 -08001305/* Called with dev->lock held */
Jeff Dikea0044bd2007-05-06 14:51:36 -07001306static void prepare_request(struct request *req, struct io_thread_req *io_req,
1307 unsigned long long offset, int page_offset,
1308 int len, struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309{
1310 struct gendisk *disk = req->rq_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001311 struct ubd *ubd_dev = disk->private_data;
Jeff Dike91acb212005-10-10 23:10:32 -04001312
Jeff Dike62f96cb2007-02-10 01:44:16 -08001313 io_req->req = req;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001314 io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd :
1315 ubd_dev->fd;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001316 io_req->fds[1] = ubd_dev->fd;
Jeff Dike91acb212005-10-10 23:10:32 -04001317 io_req->cow_offset = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 io_req->offset = offset;
1319 io_req->length = len;
1320 io_req->error = 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001321 io_req->sector_mask = 0;
1322
1323 io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 io_req->offsets[0] = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001325 io_req->offsets[1] = ubd_dev->cow.data_offset;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001326 io_req->buffer = page_address(page) + page_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 io_req->sectorsize = 1 << 9;
1328
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001329 if(ubd_dev->cow.file != NULL)
Jeff Dikea0044bd2007-05-06 14:51:36 -07001330 cowify_req(io_req, ubd_dev->cow.bitmap,
1331 ubd_dev->cow.bitmap_offset, ubd_dev->cow.bitmap_len);
Jeff Dike91acb212005-10-10 23:10:32 -04001332
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333}
1334
Jeff Dike62f96cb2007-02-10 01:44:16 -08001335/* Called with dev->lock held */
Richard Weinberger805f11a2013-08-18 13:30:06 +02001336static void prepare_flush_request(struct request *req,
1337 struct io_thread_req *io_req)
1338{
1339 struct gendisk *disk = req->rq_disk;
1340 struct ubd *ubd_dev = disk->private_data;
1341
1342 io_req->req = req;
1343 io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd :
1344 ubd_dev->fd;
1345 io_req->op = UBD_FLUSH;
1346}
1347
Richard Weinbergerbc1d72e2013-08-18 13:30:07 +02001348static bool submit_request(struct io_thread_req *io_req, struct ubd *dev)
1349{
1350 int n = os_write_file(thread_fd, &io_req,
1351 sizeof(io_req));
1352 if (n != sizeof(io_req)) {
1353 if (n != -EAGAIN)
1354 printk("write to io thread failed, "
1355 "errno = %d\n", -n);
1356 else if (list_empty(&dev->restart))
1357 list_add(&dev->restart, &restart);
1358
1359 kfree(io_req);
1360 return false;
1361 }
1362 return true;
1363}
1364
Richard Weinberger805f11a2013-08-18 13:30:06 +02001365/* Called with dev->lock held */
Jens Axboe165125e2007-07-24 09:28:11 +02001366static void do_ubd_request(struct request_queue *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367{
Jeff Dike2adcec22007-05-06 14:51:37 -07001368 struct io_thread_req *io_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 struct request *req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370
Jeff Dikea0044bd2007-05-06 14:51:36 -07001371 while(1){
Jeff Dike2a9529a2007-03-29 01:20:27 -07001372 struct ubd *dev = q->queuedata;
Thorsten Knabe2a236122014-08-23 15:47:38 +02001373 if(dev->request == NULL){
Tejun Heo9934c8c2009-05-08 11:54:16 +09001374 struct request *req = blk_fetch_request(q);
Jeff Dikea0044bd2007-05-06 14:51:36 -07001375 if(req == NULL)
1376 return;
1377
1378 dev->request = req;
Tejun Heo47526902010-10-15 12:56:21 +02001379 dev->rq_pos = blk_rq_pos(req);
Jeff Dikea0044bd2007-05-06 14:51:36 -07001380 dev->start_sg = 0;
1381 dev->end_sg = blk_rq_map_sg(q, req, dev->sg);
Jeff Dike91acb212005-10-10 23:10:32 -04001382 }
Jeff Dikea0044bd2007-05-06 14:51:36 -07001383
1384 req = dev->request;
Richard Weinberger805f11a2013-08-18 13:30:06 +02001385
Mike Christie3a5e02c2016-06-05 14:32:23 -05001386 if (req_op(req) == REQ_OP_FLUSH) {
Richard Weinberger805f11a2013-08-18 13:30:06 +02001387 io_req = kmalloc(sizeof(struct io_thread_req),
1388 GFP_ATOMIC);
1389 if (io_req == NULL) {
1390 if (list_empty(&dev->restart))
1391 list_add(&dev->restart, &restart);
1392 return;
1393 }
1394 prepare_flush_request(req, io_req);
Thorsten Knabe2a236122014-08-23 15:47:38 +02001395 if (submit_request(io_req, dev) == false)
1396 return;
Richard Weinberger805f11a2013-08-18 13:30:06 +02001397 }
1398
Jeff Dikea0044bd2007-05-06 14:51:36 -07001399 while(dev->start_sg < dev->end_sg){
1400 struct scatterlist *sg = &dev->sg[dev->start_sg];
1401
Jeff Dike2adcec22007-05-06 14:51:37 -07001402 io_req = kmalloc(sizeof(struct io_thread_req),
Peter Zijlstra990c5582007-05-06 14:51:38 -07001403 GFP_ATOMIC);
Jeff Dike2adcec22007-05-06 14:51:37 -07001404 if(io_req == NULL){
1405 if(list_empty(&dev->restart))
1406 list_add(&dev->restart, &restart);
1407 return;
1408 }
1409 prepare_request(req, io_req,
Tejun Heo47526902010-10-15 12:56:21 +02001410 (unsigned long long)dev->rq_pos << 9,
Jens Axboe45711f12007-10-22 21:19:53 +02001411 sg->offset, sg->length, sg_page(sg));
Jeff Dikea0044bd2007-05-06 14:51:36 -07001412
Richard Weinbergerbc1d72e2013-08-18 13:30:07 +02001413 if (submit_request(io_req, dev) == false)
Jeff Dikea0044bd2007-05-06 14:51:36 -07001414 return;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001415
Tejun Heo47526902010-10-15 12:56:21 +02001416 dev->rq_pos += sg->length >> 9;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001417 dev->start_sg++;
1418 }
1419 dev->end_sg = 0;
1420 dev->request = NULL;
Jeff Dike91acb212005-10-10 23:10:32 -04001421 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422}
1423
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001424static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
1425{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001426 struct ubd *ubd_dev = bdev->bd_disk->private_data;
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001427
1428 geo->heads = 128;
1429 geo->sectors = 32;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001430 geo->cylinders = ubd_dev->size / (128 * 32 * 512);
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001431 return 0;
1432}
1433
Al Viroa625c992008-03-02 09:16:26 -05001434static int ubd_ioctl(struct block_device *bdev, fmode_t mode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 unsigned int cmd, unsigned long arg)
1436{
Al Viroa625c992008-03-02 09:16:26 -05001437 struct ubd *ubd_dev = bdev->bd_disk->private_data;
Bartlomiej Zolnierkiewicz73855e12009-04-01 21:42:21 +02001438 u16 ubd_id[ATA_ID_WORDS];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439
1440 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 struct cdrom_volctrl volume;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 case HDIO_GET_IDENTITY:
Bartlomiej Zolnierkiewicz73855e12009-04-01 21:42:21 +02001443 memset(&ubd_id, 0, ATA_ID_WORDS * 2);
1444 ubd_id[ATA_ID_CYLS] = ubd_dev->size / (128 * 32 * 512);
1445 ubd_id[ATA_ID_HEADS] = 128;
1446 ubd_id[ATA_ID_SECTORS] = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447 if(copy_to_user((char __user *) arg, (char *) &ubd_id,
1448 sizeof(ubd_id)))
Jeff Dikedc764e52007-05-06 14:51:41 -07001449 return -EFAULT;
1450 return 0;
Jeff Dikeb8831a12007-02-10 01:44:17 -08001451
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 case CDROMVOLREAD:
1453 if(copy_from_user(&volume, (char __user *) arg, sizeof(volume)))
Jeff Dikedc764e52007-05-06 14:51:41 -07001454 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 volume.channel0 = 255;
1456 volume.channel1 = 255;
1457 volume.channel2 = 255;
1458 volume.channel3 = 255;
1459 if(copy_to_user((char __user *) arg, &volume, sizeof(volume)))
Jeff Dikedc764e52007-05-06 14:51:41 -07001460 return -EFAULT;
1461 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 }
Jeff Dikedc764e52007-05-06 14:51:41 -07001463 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464}
1465
Jeff Dike91acb212005-10-10 23:10:32 -04001466static int update_bitmap(struct io_thread_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467{
Jeff Dike91acb212005-10-10 23:10:32 -04001468 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469
Jeff Dike91acb212005-10-10 23:10:32 -04001470 if(req->cow_offset == -1)
Jeff Dikedc764e52007-05-06 14:51:41 -07001471 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472
Anton Ivanov8c6157b2015-12-21 18:54:00 +00001473 n = os_pwrite_file(req->fds[1], &req->bitmap_words,
1474 sizeof(req->bitmap_words), req->cow_offset);
Jeff Dike91acb212005-10-10 23:10:32 -04001475 if(n != sizeof(req->bitmap_words)){
1476 printk("do_io - bitmap update failed, err = %d fd = %d\n", -n,
1477 req->fds[1]);
Jeff Dikedc764e52007-05-06 14:51:41 -07001478 return 1;
Jeff Dike91acb212005-10-10 23:10:32 -04001479 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480
Jeff Dikedc764e52007-05-06 14:51:41 -07001481 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482}
Jeff Dike91acb212005-10-10 23:10:32 -04001483
WANG Cong5dc62b12008-04-28 02:13:58 -07001484static void do_io(struct io_thread_req *req)
Jeff Dike91acb212005-10-10 23:10:32 -04001485{
1486 char *buf;
1487 unsigned long len;
1488 int n, nsectors, start, end, bit;
Jeff Dike91acb212005-10-10 23:10:32 -04001489 __u64 off;
1490
Richard Weinberger805f11a2013-08-18 13:30:06 +02001491 if (req->op == UBD_FLUSH) {
1492 /* fds[0] is always either the rw image or our cow file */
1493 n = os_sync_file(req->fds[0]);
1494 if (n != 0) {
1495 printk("do_io - sync failed err = %d "
1496 "fd = %d\n", -n, req->fds[0]);
1497 req->error = 1;
1498 }
1499 return;
1500 }
1501
Jeff Dike91acb212005-10-10 23:10:32 -04001502 nsectors = req->length / req->sectorsize;
1503 start = 0;
1504 do {
1505 bit = ubd_test_bit(start, (unsigned char *) &req->sector_mask);
1506 end = start;
1507 while((end < nsectors) &&
1508 (ubd_test_bit(end, (unsigned char *)
1509 &req->sector_mask) == bit))
1510 end++;
1511
1512 off = req->offset + req->offsets[bit] +
1513 start * req->sectorsize;
1514 len = (end - start) * req->sectorsize;
1515 buf = &req->buffer[start * req->sectorsize];
1516
Jeff Dike91acb212005-10-10 23:10:32 -04001517 if(req->op == UBD_READ){
1518 n = 0;
1519 do {
1520 buf = &buf[n];
1521 len -= n;
Anton Ivanov8c6157b2015-12-21 18:54:00 +00001522 n = os_pread_file(req->fds[bit], buf, len, off);
Jeff Dike91acb212005-10-10 23:10:32 -04001523 if (n < 0) {
1524 printk("do_io - read failed, err = %d "
1525 "fd = %d\n", -n, req->fds[bit]);
1526 req->error = 1;
1527 return;
1528 }
1529 } while((n < len) && (n != 0));
1530 if (n < len) memset(&buf[n], 0, len - n);
1531 } else {
Anton Ivanov8c6157b2015-12-21 18:54:00 +00001532 n = os_pwrite_file(req->fds[bit], buf, len, off);
Jeff Dike91acb212005-10-10 23:10:32 -04001533 if(n != len){
1534 printk("do_io - write failed err = %d "
1535 "fd = %d\n", -n, req->fds[bit]);
1536 req->error = 1;
1537 return;
1538 }
1539 }
1540
1541 start = end;
1542 } while(start < nsectors);
1543
1544 req->error = update_bitmap(req);
1545}
1546
1547/* Changed in start_io_thread, which is serialized by being called only
1548 * from ubd_init, which is an initcall.
1549 */
1550int kernel_fd = -1;
1551
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001552/* Only changed by the io thread. XXX: currently unused. */
1553static int io_count = 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001554
1555int io_thread(void *arg)
1556{
Anton Ivanovf88f0bd2016-11-09 20:43:25 +00001557 int n, count, written, res;
Jeff Dike91acb212005-10-10 23:10:32 -04001558
Richard Weinberger91d44ff2013-08-18 13:30:08 +02001559 os_fix_helper_signals();
1560
Jeff Dike91acb212005-10-10 23:10:32 -04001561 while(1){
Anton Ivanovf88f0bd2016-11-09 20:43:25 +00001562 n = bulk_req_safe_read(
1563 kernel_fd,
1564 io_req_buffer,
1565 &io_remainder,
1566 &io_remainder_size,
1567 UBD_REQ_BUFFER_SIZE
1568 );
1569 if (n < 0) {
1570 if (n == -EAGAIN) {
1571 ubd_read_poll(-1);
1572 continue;
1573 } else {
Jeff Dike91acb212005-10-10 23:10:32 -04001574 printk("io_thread - read failed, fd = %d, "
Anton Ivanovf88f0bd2016-11-09 20:43:25 +00001575 "err = %d,"
1576 "reminder = %d\n",
1577 kernel_fd, -n, io_remainder_size);
Jeff Dike91acb212005-10-10 23:10:32 -04001578 }
Jeff Dike91acb212005-10-10 23:10:32 -04001579 }
Anton Ivanovf88f0bd2016-11-09 20:43:25 +00001580
1581 for (count = 0; count < n/sizeof(struct io_thread_req *); count++) {
1582 io_count++;
1583 do_io((*io_req_buffer)[count]);
1584 }
1585
1586 written = 0;
1587
1588 do {
1589 res = os_write_file(kernel_fd, ((char *) io_req_buffer) + written, n);
1590 if (res > 0) {
1591 written += res;
1592 } else {
1593 if (res != -EAGAIN) {
1594 printk("io_thread - read failed, fd = %d, "
1595 "err = %d\n", kernel_fd, -n);
1596 }
1597 }
1598 if (written < n) {
1599 ubd_write_poll(-1);
1600 }
1601 } while (written < n);
Jeff Dike91acb212005-10-10 23:10:32 -04001602 }
Jeff Dike91acb212005-10-10 23:10:32 -04001603
Jeff Dike1b57e9c2006-01-06 00:18:49 -08001604 return 0;
1605}