blob: dcf5ea28a2815803977cc12757aa4b2c21a70e13 [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
WANG Congc0a92902008-02-04 22:30:41 -0800211static void make_ide_entries(const char *dev_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212{
213 struct proc_dir_entry *dir, *ent;
214 char name[64];
215
216 if(proc_ide_root == NULL) make_proc_ide();
217
218 dir = proc_mkdir(dev_name, proc_ide);
219 if(!dir) return;
220
Christoph Hellwig3f3942a2018-05-15 15:57:23 +0200221 ent = proc_create_single("media", S_IRUGO, dir,
222 fake_ide_media_proc_show);
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
Anton Ivanovf88f0bd2016-11-09 20:43:25 +0000445/* Function to read several request pointers at a time
446* handling fractional reads if (and as) needed
447*/
448
449static int bulk_req_safe_read(
450 int fd,
451 struct io_thread_req * (*request_buffer)[],
452 struct io_thread_req **remainder,
453 int *remainder_size,
454 int max_recs
455 )
456{
457 int n = 0;
458 int res = 0;
459
460 if (*remainder_size > 0) {
461 memmove(
462 (char *) request_buffer,
463 (char *) remainder, *remainder_size
464 );
465 n = *remainder_size;
466 }
467
468 res = os_read_file(
469 fd,
470 ((char *) request_buffer) + *remainder_size,
471 sizeof(struct io_thread_req *)*max_recs
472 - *remainder_size
473 );
474 if (res > 0) {
475 n += res;
476 if ((n % sizeof(struct io_thread_req *)) > 0) {
477 /*
478 * Read somehow returned not a multiple of dword
479 * theoretically possible, but never observed in the
480 * wild, so read routine must be able to handle it
481 */
482 *remainder_size = n % sizeof(struct io_thread_req *);
483 WARN(*remainder_size > 0, "UBD IPC read returned a partial result");
484 memmove(
485 remainder,
486 ((char *) request_buffer) +
487 (n/sizeof(struct io_thread_req *))*sizeof(struct io_thread_req *),
488 *remainder_size
489 );
490 n = n - *remainder_size;
491 }
492 } else {
493 n = res;
494 }
495 return n;
496}
497
Jeff Dike62f96cb2007-02-10 01:44:16 -0800498/* Called without dev->lock held, and only in interrupt context. */
Jeff Dike91acb212005-10-10 23:10:32 -0400499static void ubd_handler(void)
500{
Jeff Dikea0044bd2007-05-06 14:51:36 -0700501 struct ubd *ubd;
502 struct list_head *list, *next_ele;
503 unsigned long flags;
Jeff Dike91acb212005-10-10 23:10:32 -0400504 int n;
Anton Ivanovf88f0bd2016-11-09 20:43:25 +0000505 int count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506
Jeff Dikea0044bd2007-05-06 14:51:36 -0700507 while(1){
Anton Ivanovf88f0bd2016-11-09 20:43:25 +0000508 n = bulk_req_safe_read(
509 thread_fd,
510 irq_req_buffer,
511 &irq_remainder,
512 &irq_remainder_size,
513 UBD_REQ_BUFFER_SIZE
514 );
515 if (n < 0) {
Jeff Dikea0044bd2007-05-06 14:51:36 -0700516 if(n == -EAGAIN)
517 break;
518 printk(KERN_ERR "spurious interrupt in ubd_handler, "
519 "err = %d\n", -n);
520 return;
521 }
Anton Ivanovf88f0bd2016-11-09 20:43:25 +0000522 for (count = 0; count < n/sizeof(struct io_thread_req *); count++) {
523 blk_end_request(
524 (*irq_req_buffer)[count]->req,
Christoph Hellwig2a842ac2017-06-03 09:38:04 +0200525 BLK_STS_OK,
Anton Ivanovf88f0bd2016-11-09 20:43:25 +0000526 (*irq_req_buffer)[count]->length
527 );
528 kfree((*irq_req_buffer)[count]);
529 }
Jeff Dike91acb212005-10-10 23:10:32 -0400530 }
Jeff Dike62f96cb2007-02-10 01:44:16 -0800531 reactivate_fd(thread_fd, UBD_IRQ);
Jeff Dikea0044bd2007-05-06 14:51:36 -0700532
533 list_for_each_safe(list, next_ele, &restart){
534 ubd = container_of(list, struct ubd, restart);
535 list_del_init(&ubd->restart);
536 spin_lock_irqsave(&ubd->lock, flags);
537 do_ubd_request(ubd->queue);
538 spin_unlock_irqrestore(&ubd->lock, flags);
539 }
Jeff Dike91acb212005-10-10 23:10:32 -0400540}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541
Al Viro7bea96f2006-10-08 22:49:34 +0100542static irqreturn_t ubd_intr(int irq, void *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543{
Jeff Dike91acb212005-10-10 23:10:32 -0400544 ubd_handler();
Jeff Dikedc764e52007-05-06 14:51:41 -0700545 return IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546}
547
Jeff Dike91acb212005-10-10 23:10:32 -0400548/* Only changed by ubd_init, which is an initcall. */
549static int io_pid = -1;
550
WANG Cong5dc62b12008-04-28 02:13:58 -0700551static void kill_io_thread(void)
Jeff Dike91acb212005-10-10 23:10:32 -0400552{
Jeff Dike6c29256c2006-03-27 01:14:37 -0800553 if(io_pid != -1)
Jeff Dike91acb212005-10-10 23:10:32 -0400554 os_kill_process(io_pid, 1);
555}
556
557__uml_exitcall(kill_io_thread);
558
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800559static inline int ubd_file_size(struct ubd *ubd_dev, __u64 *size_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560{
561 char *file;
Richard Weinberger85356392011-11-02 13:17:27 +0100562 int fd;
563 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564
Richard Weinberger85356392011-11-02 13:17:27 +0100565 __u32 version;
566 __u32 align;
567 char *backing_file;
568 time_t mtime;
569 unsigned long long size;
570 int sector_size;
571 int bitmap_offset;
572
573 if (ubd_dev->file && ubd_dev->cow.file) {
574 file = ubd_dev->cow.file;
575
576 goto out;
577 }
578
Martin Pärteld4afcba2012-08-02 00:44:22 +0200579 fd = os_open_file(ubd_dev->file, of_read(OPENFLAGS()), 0);
Richard Weinberger85356392011-11-02 13:17:27 +0100580 if (fd < 0)
581 return fd;
582
583 err = read_cow_header(file_reader, &fd, &version, &backing_file, \
584 &mtime, &size, &sector_size, &align, &bitmap_offset);
585 os_close_file(fd);
586
587 if(err == -EINVAL)
588 file = ubd_dev->file;
589 else
590 file = backing_file;
591
592out:
Jeff Dikedc764e52007-05-06 14:51:41 -0700593 return os_file_size(file, size_out);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594}
595
WANG Cong5dc62b12008-04-28 02:13:58 -0700596static int read_cow_bitmap(int fd, void *buf, int offset, int len)
597{
598 int err;
599
Anton Ivanov8c6157b2015-12-21 18:54:00 +0000600 err = os_pread_file(fd, buf, len, offset);
WANG Cong5dc62b12008-04-28 02:13:58 -0700601 if (err < 0)
602 return err;
603
604 return 0;
605}
606
607static int backing_file_mismatch(char *file, __u64 size, time_t mtime)
608{
609 unsigned long modtime;
610 unsigned long long actual;
611 int err;
612
613 err = os_file_modtime(file, &modtime);
614 if (err < 0) {
615 printk(KERN_ERR "Failed to get modification time of backing "
616 "file \"%s\", err = %d\n", file, -err);
617 return err;
618 }
619
620 err = os_file_size(file, &actual);
621 if (err < 0) {
622 printk(KERN_ERR "Failed to get size of backing file \"%s\", "
623 "err = %d\n", file, -err);
624 return err;
625 }
626
627 if (actual != size) {
628 /*__u64 can be a long on AMD64 and with %lu GCC complains; so
629 * the typecast.*/
630 printk(KERN_ERR "Size mismatch (%llu vs %llu) of COW header "
631 "vs backing file\n", (unsigned long long) size, actual);
632 return -EINVAL;
633 }
634 if (modtime != mtime) {
635 printk(KERN_ERR "mtime mismatch (%ld vs %ld) of COW header vs "
636 "backing file\n", mtime, modtime);
637 return -EINVAL;
638 }
639 return 0;
640}
641
642static int path_requires_switch(char *from_cmdline, char *from_cow, char *cow)
643{
644 struct uml_stat buf1, buf2;
645 int err;
646
647 if (from_cmdline == NULL)
648 return 0;
649 if (!strcmp(from_cmdline, from_cow))
650 return 0;
651
652 err = os_stat_file(from_cmdline, &buf1);
653 if (err < 0) {
654 printk(KERN_ERR "Couldn't stat '%s', err = %d\n", from_cmdline,
655 -err);
656 return 0;
657 }
658 err = os_stat_file(from_cow, &buf2);
659 if (err < 0) {
660 printk(KERN_ERR "Couldn't stat '%s', err = %d\n", from_cow,
661 -err);
662 return 1;
663 }
664 if ((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino))
665 return 0;
666
667 printk(KERN_ERR "Backing file mismatch - \"%s\" requested, "
668 "\"%s\" specified in COW header of \"%s\"\n",
669 from_cmdline, from_cow, cow);
670 return 1;
671}
672
673static int open_ubd_file(char *file, struct openflags *openflags, int shared,
674 char **backing_file_out, int *bitmap_offset_out,
675 unsigned long *bitmap_len_out, int *data_offset_out,
676 int *create_cow_out)
677{
678 time_t mtime;
679 unsigned long long size;
680 __u32 version, align;
681 char *backing_file;
682 int fd, err, sectorsize, asked_switch, mode = 0644;
683
684 fd = os_open_file(file, *openflags, mode);
685 if (fd < 0) {
686 if ((fd == -ENOENT) && (create_cow_out != NULL))
687 *create_cow_out = 1;
688 if (!openflags->w ||
689 ((fd != -EROFS) && (fd != -EACCES)))
690 return fd;
691 openflags->w = 0;
692 fd = os_open_file(file, *openflags, mode);
693 if (fd < 0)
694 return fd;
695 }
696
697 if (shared)
698 printk(KERN_INFO "Not locking \"%s\" on the host\n", file);
699 else {
700 err = os_lock_file(fd, openflags->w);
701 if (err < 0) {
702 printk(KERN_ERR "Failed to lock '%s', err = %d\n",
703 file, -err);
704 goto out_close;
705 }
706 }
707
708 /* Successful return case! */
709 if (backing_file_out == NULL)
710 return fd;
711
712 err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime,
713 &size, &sectorsize, &align, bitmap_offset_out);
714 if (err && (*backing_file_out != NULL)) {
715 printk(KERN_ERR "Failed to read COW header from COW file "
716 "\"%s\", errno = %d\n", file, -err);
717 goto out_close;
718 }
719 if (err)
720 return fd;
721
722 asked_switch = path_requires_switch(*backing_file_out, backing_file,
723 file);
724
725 /* Allow switching only if no mismatch. */
726 if (asked_switch && !backing_file_mismatch(*backing_file_out, size,
727 mtime)) {
728 printk(KERN_ERR "Switching backing file to '%s'\n",
729 *backing_file_out);
730 err = write_cow_header(file, fd, *backing_file_out,
731 sectorsize, align, &size);
732 if (err) {
733 printk(KERN_ERR "Switch failed, errno = %d\n", -err);
734 goto out_close;
735 }
736 } else {
737 *backing_file_out = backing_file;
738 err = backing_file_mismatch(*backing_file_out, size, mtime);
739 if (err)
740 goto out_close;
741 }
742
743 cow_sizes(version, size, sectorsize, align, *bitmap_offset_out,
744 bitmap_len_out, data_offset_out);
745
746 return fd;
747 out_close:
748 os_close_file(fd);
749 return err;
750}
751
752static int create_cow_file(char *cow_file, char *backing_file,
753 struct openflags flags,
754 int sectorsize, int alignment, int *bitmap_offset_out,
755 unsigned long *bitmap_len_out, int *data_offset_out)
756{
757 int err, fd;
758
759 flags.c = 1;
760 fd = open_ubd_file(cow_file, &flags, 0, NULL, NULL, NULL, NULL, NULL);
761 if (fd < 0) {
762 err = fd;
763 printk(KERN_ERR "Open of COW file '%s' failed, errno = %d\n",
764 cow_file, -err);
765 goto out;
766 }
767
768 err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment,
769 bitmap_offset_out, bitmap_len_out,
770 data_offset_out);
771 if (!err)
772 return fd;
773 os_close_file(fd);
774 out:
775 return err;
776}
777
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800778static void ubd_close_dev(struct ubd *ubd_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800780 os_close_file(ubd_dev->fd);
781 if(ubd_dev->cow.file == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 return;
783
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800784 os_close_file(ubd_dev->cow.fd);
785 vfree(ubd_dev->cow.bitmap);
786 ubd_dev->cow.bitmap = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787}
788
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800789static int ubd_open_dev(struct ubd *ubd_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790{
791 struct openflags flags;
792 char **back_ptr;
793 int err, create_cow, *create_ptr;
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800794 int fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800796 ubd_dev->openflags = ubd_dev->boot_openflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 create_cow = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800798 create_ptr = (ubd_dev->cow.file != NULL) ? &create_cow : NULL;
799 back_ptr = ubd_dev->no_cow ? NULL : &ubd_dev->cow.file;
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800800
801 fd = open_ubd_file(ubd_dev->file, &ubd_dev->openflags, ubd_dev->shared,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800802 back_ptr, &ubd_dev->cow.bitmap_offset,
803 &ubd_dev->cow.bitmap_len, &ubd_dev->cow.data_offset,
Jeff Dike6c29256c2006-03-27 01:14:37 -0800804 create_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800806 if((fd == -ENOENT) && create_cow){
807 fd = create_cow_file(ubd_dev->file, ubd_dev->cow.file,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800808 ubd_dev->openflags, 1 << 9, PAGE_SIZE,
809 &ubd_dev->cow.bitmap_offset,
810 &ubd_dev->cow.bitmap_len,
811 &ubd_dev->cow.data_offset);
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800812 if(fd >= 0){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 printk(KERN_INFO "Creating \"%s\" as COW file for "
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800814 "\"%s\"\n", ubd_dev->file, ubd_dev->cow.file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 }
816 }
817
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800818 if(fd < 0){
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800819 printk("Failed to open '%s', errno = %d\n", ubd_dev->file,
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800820 -fd);
821 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 }
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800823 ubd_dev->fd = fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800825 if(ubd_dev->cow.file != NULL){
Martin K. Petersen086fa5f2010-02-26 00:20:38 -0500826 blk_queue_max_hw_sectors(ubd_dev->queue, 8 * sizeof(long));
Jeff Dikef4768ff2007-08-22 14:01:53 -0700827
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 err = -ENOMEM;
Jesper Juhlda2486b2007-10-16 01:27:19 -0700829 ubd_dev->cow.bitmap = vmalloc(ubd_dev->cow.bitmap_len);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800830 if(ubd_dev->cow.bitmap == NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 printk(KERN_ERR "Failed to vmalloc COW bitmap\n");
832 goto error;
833 }
834 flush_tlb_kernel_vm();
835
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800836 err = read_cow_bitmap(ubd_dev->fd, ubd_dev->cow.bitmap,
837 ubd_dev->cow.bitmap_offset,
838 ubd_dev->cow.bitmap_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 if(err < 0)
840 goto error;
841
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800842 flags = ubd_dev->openflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 flags.w = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800844 err = open_ubd_file(ubd_dev->cow.file, &flags, ubd_dev->shared, NULL,
Jeff Dike6c29256c2006-03-27 01:14:37 -0800845 NULL, NULL, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 if(err < 0) goto error;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800847 ubd_dev->cow.fd = err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 }
Jeff Dikedc764e52007-05-06 14:51:41 -0700849 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 error:
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800851 os_close_file(ubd_dev->fd);
Jeff Dikedc764e52007-05-06 14:51:41 -0700852 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853}
854
Jeff Dike2e3f5252007-05-06 14:51:29 -0700855static void ubd_device_release(struct device *dev)
856{
Greg Kroah-Hartman8691b972009-05-04 12:40:54 -0700857 struct ubd *ubd_dev = dev_get_drvdata(dev);
Jeff Dike2e3f5252007-05-06 14:51:29 -0700858
859 blk_cleanup_queue(ubd_dev->queue);
860 *ubd_dev = ((struct ubd) DEFAULT_UBD);
861}
862
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800863static int ubd_disk_register(int major, u64 size, int unit,
Jeff Dikeb8831a12007-02-10 01:44:17 -0800864 struct gendisk **disk_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865{
Dan Williamsd72a5782016-06-20 10:44:32 -0700866 struct device *parent = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 struct gendisk *disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868
869 disk = alloc_disk(1 << UBD_SHIFT);
870 if(disk == NULL)
Jeff Dikedc764e52007-05-06 14:51:41 -0700871 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872
873 disk->major = major;
874 disk->first_minor = unit << UBD_SHIFT;
875 disk->fops = &ubd_blops;
876 set_capacity(disk, size / 512);
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700877 if (major == UBD_MAJOR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 sprintf(disk->disk_name, "ubd%c", 'a' + unit);
Greg Kroah-Hartmance7b0f42005-06-20 21:15:16 -0700879 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 sprintf(disk->disk_name, "ubd_fake%d", unit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881
882 /* sysfs register (not for ide fake devices) */
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700883 if (major == UBD_MAJOR) {
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800884 ubd_devs[unit].pdev.id = unit;
885 ubd_devs[unit].pdev.name = DRIVER_NAME;
Jeff Dike2e3f5252007-05-06 14:51:29 -0700886 ubd_devs[unit].pdev.dev.release = ubd_device_release;
Greg Kroah-Hartman8691b972009-05-04 12:40:54 -0700887 dev_set_drvdata(&ubd_devs[unit].pdev.dev, &ubd_devs[unit]);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800888 platform_device_register(&ubd_devs[unit].pdev);
Dan Williamsd72a5782016-06-20 10:44:32 -0700889 parent = &ubd_devs[unit].pdev.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 }
891
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800892 disk->private_data = &ubd_devs[unit];
Jeff Dike62f96cb2007-02-10 01:44:16 -0800893 disk->queue = ubd_devs[unit].queue;
Dan Williamsd72a5782016-06-20 10:44:32 -0700894 device_add_disk(parent, disk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895
896 *disk_out = disk;
897 return 0;
898}
899
900#define ROUND_BLOCK(n) ((n + ((1 << 9) - 1)) & (-1 << 9))
901
Jeff Dikef28169d2007-02-10 01:43:53 -0800902static int ubd_add(int n, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800904 struct ubd *ubd_dev = &ubd_devs[n];
Jeff Dikef28169d2007-02-10 01:43:53 -0800905 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800907 if(ubd_dev->file == NULL)
Jeff Dikeec7cf782005-09-03 15:57:29 -0700908 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800910 err = ubd_file_size(ubd_dev, &ubd_dev->size);
Jeff Dikef28169d2007-02-10 01:43:53 -0800911 if(err < 0){
912 *error_out = "Couldn't determine size of device's file";
Jeff Dike80c13742006-09-29 01:58:51 -0700913 goto out;
Jeff Dikef28169d2007-02-10 01:43:53 -0800914 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800916 ubd_dev->size = ROUND_BLOCK(ubd_dev->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917
Jeff Dikea0044bd2007-05-06 14:51:36 -0700918 INIT_LIST_HEAD(&ubd_dev->restart);
WANG Cong4f40c052007-11-05 14:50:59 -0800919 sg_init_table(ubd_dev->sg, MAX_SG);
Jeff Dikea0044bd2007-05-06 14:51:36 -0700920
Jeff Dike62f96cb2007-02-10 01:44:16 -0800921 err = -ENOMEM;
922 ubd_dev->queue = blk_init_queue(do_ubd_request, &ubd_dev->lock);
923 if (ubd_dev->queue == NULL) {
924 *error_out = "Failed to initialize device queue";
Jeff Dike80c13742006-09-29 01:58:51 -0700925 goto out;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800926 }
927 ubd_dev->queue->queuedata = ubd_dev;
Jens Axboef935a8c2016-03-30 10:19:17 -0600928 blk_queue_write_cache(ubd_dev->queue, true, false);
Jeff Dike62f96cb2007-02-10 01:44:16 -0800929
Martin K. Petersen8a783622010-02-26 00:20:39 -0500930 blk_queue_max_segments(ubd_dev->queue, MAX_SG);
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700931 err = ubd_disk_register(UBD_MAJOR, ubd_dev->size, n, &ubd_gendisk[n]);
Jeff Dike62f96cb2007-02-10 01:44:16 -0800932 if(err){
933 *error_out = "Failed to register device";
934 goto out_cleanup;
935 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800936
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700937 if (fake_major != UBD_MAJOR)
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800938 ubd_disk_register(fake_major, ubd_dev->size, n,
Jeff Dike62f96cb2007-02-10 01:44:16 -0800939 &fake_gendisk[n]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940
Jeff Dike83380cc2008-02-04 22:31:18 -0800941 /*
942 * Perhaps this should also be under the "if (fake_major)" above
943 * using the fake_disk->disk_name
944 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 if (fake_ide)
946 make_ide_entries(ubd_gendisk[n]->disk_name);
947
Jeff Dikeec7cf782005-09-03 15:57:29 -0700948 err = 0;
Jeff Dikeec7cf782005-09-03 15:57:29 -0700949out:
950 return err;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800951
952out_cleanup:
953 blk_cleanup_queue(ubd_dev->queue);
954 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955}
956
Jeff Dikef28169d2007-02-10 01:43:53 -0800957static int ubd_config(char *str, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958{
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800959 int n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960
Jeff Dikef28169d2007-02-10 01:43:53 -0800961 /* This string is possibly broken up and stored, so it's only
962 * freed if ubd_setup_common fails, or if only general options
963 * were set.
964 */
Jeff Dike970d6e32006-01-06 00:18:48 -0800965 str = kstrdup(str, GFP_KERNEL);
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800966 if (str == NULL) {
Jeff Dikef28169d2007-02-10 01:43:53 -0800967 *error_out = "Failed to allocate memory";
968 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 }
Jeff Dikef28169d2007-02-10 01:43:53 -0800970
971 ret = ubd_setup_common(str, &n, error_out);
972 if (ret)
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800973 goto err_free;
Jeff Dikef28169d2007-02-10 01:43:53 -0800974
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800975 if (n == -1) {
976 ret = 0;
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800977 goto err_free;
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800978 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979
Jeff Dikedc764e52007-05-06 14:51:41 -0700980 mutex_lock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -0800981 ret = ubd_add(n, error_out);
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800982 if (ret)
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800983 ubd_devs[n].file = NULL;
Jeff Dikedc764e52007-05-06 14:51:41 -0700984 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800986out:
Jeff Dikedc764e52007-05-06 14:51:41 -0700987 return ret;
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800988
989err_free:
990 kfree(str);
991 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992}
993
994static int ubd_get_config(char *name, char *str, int size, char **error_out)
995{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800996 struct ubd *ubd_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 int n, len = 0;
998
999 n = parse_unit(&name);
1000 if((n >= MAX_DEV) || (n < 0)){
1001 *error_out = "ubd_get_config : device number out of range";
Jeff Dikedc764e52007-05-06 14:51:41 -07001002 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 }
1004
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001005 ubd_dev = &ubd_devs[n];
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -08001006 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001008 if(ubd_dev->file == NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 CONFIG_CHUNK(str, size, len, "", 1);
1010 goto out;
1011 }
1012
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001013 CONFIG_CHUNK(str, size, len, ubd_dev->file, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001015 if(ubd_dev->cow.file != NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 CONFIG_CHUNK(str, size, len, ",", 0);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001017 CONFIG_CHUNK(str, size, len, ubd_dev->cow.file, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 }
1019 else CONFIG_CHUNK(str, size, len, "", 1);
1020
1021 out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -08001022 mutex_unlock(&ubd_lock);
Jeff Dikedc764e52007-05-06 14:51:41 -07001023 return len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024}
1025
Jeff Dike29d56cf2005-06-25 14:55:25 -07001026static int ubd_id(char **str, int *start_out, int *end_out)
1027{
Jeff Dikedc764e52007-05-06 14:51:41 -07001028 int n;
Jeff Dike29d56cf2005-06-25 14:55:25 -07001029
1030 n = parse_unit(str);
Jeff Dikedc764e52007-05-06 14:51:41 -07001031 *start_out = 0;
1032 *end_out = MAX_DEV - 1;
1033 return n;
Jeff Dike29d56cf2005-06-25 14:55:25 -07001034}
1035
Jeff Dikef28169d2007-02-10 01:43:53 -08001036static int ubd_remove(int n, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037{
Jeff Dike2e3f5252007-05-06 14:51:29 -07001038 struct gendisk *disk = ubd_gendisk[n];
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001039 struct ubd *ubd_dev;
Jeff Dike29d56cf2005-06-25 14:55:25 -07001040 int err = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -08001042 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001044 ubd_dev = &ubd_devs[n];
Jeff Dike29d56cf2005-06-25 14:55:25 -07001045
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001046 if(ubd_dev->file == NULL)
Jeff Dike29d56cf2005-06-25 14:55:25 -07001047 goto out;
1048
1049 /* you cannot remove a open disk */
1050 err = -EBUSY;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001051 if(ubd_dev->count > 0)
Jeff Dike29d56cf2005-06-25 14:55:25 -07001052 goto out;
1053
Jeff Dikedc764e52007-05-06 14:51:41 -07001054 ubd_gendisk[n] = NULL;
Jeff Dikeb47d2de2007-05-06 14:51:01 -07001055 if(disk != NULL){
1056 del_gendisk(disk);
1057 put_disk(disk);
1058 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059
1060 if(fake_gendisk[n] != NULL){
1061 del_gendisk(fake_gendisk[n]);
1062 put_disk(fake_gendisk[n]);
1063 fake_gendisk[n] = NULL;
1064 }
1065
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 err = 0;
Jeff Dike2e3f5252007-05-06 14:51:29 -07001067 platform_device_unregister(&ubd_dev->pdev);
Jeff Dike29d56cf2005-06-25 14:55:25 -07001068out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -08001069 mutex_unlock(&ubd_lock);
Jeff Dike29d56cf2005-06-25 14:55:25 -07001070 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071}
1072
Jeff Dikef28169d2007-02-10 01:43:53 -08001073/* All these are called by mconsole in process context and without
Jeff Dikeb8831a12007-02-10 01:44:17 -08001074 * ubd-specific locks. The structure itself is const except for .list.
Jeff Dikef28169d2007-02-10 01:43:53 -08001075 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076static struct mc_device ubd_mc = {
Jeff Dike84f48d42007-02-10 01:44:01 -08001077 .list = LIST_HEAD_INIT(ubd_mc.list),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 .name = "ubd",
1079 .config = ubd_config,
Jeff Dikedc764e52007-05-06 14:51:41 -07001080 .get_config = ubd_get_config,
Jeff Dike29d56cf2005-06-25 14:55:25 -07001081 .id = ubd_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 .remove = ubd_remove,
1083};
1084
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001085static int __init ubd_mc_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086{
1087 mconsole_register_dev(&ubd_mc);
1088 return 0;
1089}
1090
1091__initcall(ubd_mc_init);
1092
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001093static int __init ubd0_init(void)
1094{
1095 struct ubd *ubd_dev = &ubd_devs[0];
1096
Jeff Dikeb8831a12007-02-10 01:44:17 -08001097 mutex_lock(&ubd_lock);
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001098 if(ubd_dev->file == NULL)
1099 ubd_dev->file = "root_fs";
Jeff Dikeb8831a12007-02-10 01:44:17 -08001100 mutex_unlock(&ubd_lock);
1101
Jeff Dikedc764e52007-05-06 14:51:41 -07001102 return 0;
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001103}
1104
1105__initcall(ubd0_init);
1106
Jeff Dikeb8831a12007-02-10 01:44:17 -08001107/* Used in ubd_init, which is an initcall */
Russell King3ae5eae2005-11-09 22:32:44 +00001108static struct platform_driver ubd_driver = {
1109 .driver = {
1110 .name = DRIVER_NAME,
1111 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112};
1113
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001114static int __init ubd_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115{
Jeff Dikef28169d2007-02-10 01:43:53 -08001116 char *error;
1117 int i, err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118
Christoph Hellwig792dd4f2009-03-31 15:23:39 -07001119 if (register_blkdev(UBD_MAJOR, "ubd"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 return -1;
1121
Christoph Hellwig792dd4f2009-03-31 15:23:39 -07001122 if (fake_major != UBD_MAJOR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 char name[sizeof("ubd_nnn\0")];
1124
1125 snprintf(name, sizeof(name), "ubd_%d", fake_major);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 if (register_blkdev(fake_major, "ubd"))
1127 return -1;
1128 }
Anton Ivanovf88f0bd2016-11-09 20:43:25 +00001129
1130 irq_req_buffer = kmalloc(
1131 sizeof(struct io_thread_req *) * UBD_REQ_BUFFER_SIZE,
1132 GFP_KERNEL
1133 );
1134 irq_remainder = 0;
1135
1136 if (irq_req_buffer == NULL) {
1137 printk(KERN_ERR "Failed to initialize ubd buffering\n");
1138 return -1;
1139 }
1140 io_req_buffer = kmalloc(
1141 sizeof(struct io_thread_req *) * UBD_REQ_BUFFER_SIZE,
1142 GFP_KERNEL
1143 );
1144
1145 io_remainder = 0;
1146
1147 if (io_req_buffer == NULL) {
1148 printk(KERN_ERR "Failed to initialize ubd buffering\n");
1149 return -1;
1150 }
Russell King3ae5eae2005-11-09 22:32:44 +00001151 platform_driver_register(&ubd_driver);
Jeff Dikedc764e52007-05-06 14:51:41 -07001152 mutex_lock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -08001153 for (i = 0; i < MAX_DEV; i++){
1154 err = ubd_add(i, &error);
1155 if(err)
1156 printk(KERN_ERR "Failed to initialize ubd device %d :"
1157 "%s\n", i, error);
1158 }
Jeff Dikedc764e52007-05-06 14:51:41 -07001159 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 return 0;
1161}
1162
1163late_initcall(ubd_init);
1164
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001165static int __init ubd_driver_init(void){
Jeff Dike91acb212005-10-10 23:10:32 -04001166 unsigned long stack;
1167 int err;
1168
1169 /* Set by CONFIG_BLK_DEV_UBD_SYNC or ubd=sync.*/
1170 if(global_openflags.s){
1171 printk(KERN_INFO "ubd: Synchronous mode\n");
1172 /* Letting ubd=sync be like using ubd#s= instead of ubd#= is
1173 * enough. So use anyway the io thread. */
1174 }
1175 stack = alloc_stack(0, 0);
Jeff Dike6c29256c2006-03-27 01:14:37 -08001176 io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *),
Jeff Dike91acb212005-10-10 23:10:32 -04001177 &thread_fd);
1178 if(io_pid < 0){
Jeff Dike6c29256c2006-03-27 01:14:37 -08001179 printk(KERN_ERR
Jeff Dike91acb212005-10-10 23:10:32 -04001180 "ubd : Failed to start I/O thread (errno = %d) - "
1181 "falling back to synchronous I/O\n", -io_pid);
1182 io_pid = -1;
Jeff Dikedc764e52007-05-06 14:51:41 -07001183 return 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001184 }
Jeff Dike6c29256c2006-03-27 01:14:37 -08001185 err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr,
Yong Zhangc0b79a92011-09-22 16:58:46 +08001186 0, "ubd", ubd_devs);
Jeff Dike91acb212005-10-10 23:10:32 -04001187 if(err != 0)
1188 printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err);
Jeff Dikef4c57a72006-03-31 02:30:10 -08001189 return 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001190}
1191
1192device_initcall(ubd_driver_init);
1193
Al Viroa625c992008-03-02 09:16:26 -05001194static int ubd_open(struct block_device *bdev, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195{
Al Viroa625c992008-03-02 09:16:26 -05001196 struct gendisk *disk = bdev->bd_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001197 struct ubd *ubd_dev = disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 int err = 0;
1199
Arnd Bergmann9a181c52010-09-11 18:38:03 +02001200 mutex_lock(&ubd_mutex);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001201 if(ubd_dev->count == 0){
1202 err = ubd_open_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 if(err){
1204 printk(KERN_ERR "%s: Can't open \"%s\": errno = %d\n",
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001205 disk->disk_name, ubd_dev->file, -err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 goto out;
1207 }
1208 }
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001209 ubd_dev->count++;
1210 set_disk_ro(disk, !ubd_dev->openflags.w);
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -07001211
1212 /* This should no more be needed. And it didn't work anyway to exclude
1213 * read-write remounting of filesystems.*/
Al Viroa625c992008-03-02 09:16:26 -05001214 /*if((mode & FMODE_WRITE) && !ubd_dev->openflags.w){
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -08001215 if(--ubd_dev->count == 0) ubd_close_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 err = -EROFS;
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -07001217 }*/
Arnd Bergmann6e9624b2010-08-07 18:25:34 +02001218out:
Arnd Bergmann9a181c52010-09-11 18:38:03 +02001219 mutex_unlock(&ubd_mutex);
Jeff Dikedc764e52007-05-06 14:51:41 -07001220 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221}
1222
Al Virodb2a1442013-05-05 21:52:57 -04001223static void ubd_release(struct gendisk *disk, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001225 struct ubd *ubd_dev = disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226
Arnd Bergmann9a181c52010-09-11 18:38:03 +02001227 mutex_lock(&ubd_mutex);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001228 if(--ubd_dev->count == 0)
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -08001229 ubd_close_dev(ubd_dev);
Arnd Bergmann9a181c52010-09-11 18:38:03 +02001230 mutex_unlock(&ubd_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231}
1232
Jeff Dike91acb212005-10-10 23:10:32 -04001233static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask,
1234 __u64 *cow_offset, unsigned long *bitmap,
1235 __u64 bitmap_offset, unsigned long *bitmap_words,
1236 __u64 bitmap_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237{
Jeff Dike91acb212005-10-10 23:10:32 -04001238 __u64 sector = io_offset >> 9;
1239 int i, update_bitmap = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240
Jeff Dike91acb212005-10-10 23:10:32 -04001241 for(i = 0; i < length >> 9; i++){
1242 if(cow_mask != NULL)
1243 ubd_set_bit(i, (unsigned char *) cow_mask);
1244 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
1245 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246
Jeff Dike91acb212005-10-10 23:10:32 -04001247 update_bitmap = 1;
1248 ubd_set_bit(sector + i, (unsigned char *) bitmap);
1249 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250
Jeff Dike91acb212005-10-10 23:10:32 -04001251 if(!update_bitmap)
1252 return;
1253
1254 *cow_offset = sector / (sizeof(unsigned long) * 8);
1255
1256 /* This takes care of the case where we're exactly at the end of the
1257 * device, and *cow_offset + 1 is off the end. So, just back it up
1258 * by one word. Thanks to Lynn Kerby for the fix and James McMechan
1259 * for the original diagnosis.
1260 */
Jiri Olsa6d074242008-05-12 14:01:56 -07001261 if (*cow_offset == (DIV_ROUND_UP(bitmap_len,
1262 sizeof(unsigned long)) - 1))
Jeff Dike91acb212005-10-10 23:10:32 -04001263 (*cow_offset)--;
1264
1265 bitmap_words[0] = bitmap[*cow_offset];
1266 bitmap_words[1] = bitmap[*cow_offset + 1];
1267
1268 *cow_offset *= sizeof(unsigned long);
1269 *cow_offset += bitmap_offset;
1270}
1271
1272static void cowify_req(struct io_thread_req *req, unsigned long *bitmap,
1273 __u64 bitmap_offset, __u64 bitmap_len)
1274{
1275 __u64 sector = req->offset >> 9;
1276 int i;
1277
1278 if(req->length > (sizeof(req->sector_mask) * 8) << 9)
1279 panic("Operation too long");
1280
1281 if(req->op == UBD_READ) {
1282 for(i = 0; i < req->length >> 9; i++){
1283 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
Jeff Dike6c29256c2006-03-27 01:14:37 -08001284 ubd_set_bit(i, (unsigned char *)
Jeff Dike91acb212005-10-10 23:10:32 -04001285 &req->sector_mask);
Jeff Dikedc764e52007-05-06 14:51:41 -07001286 }
Jeff Dike91acb212005-10-10 23:10:32 -04001287 }
1288 else cowify_bitmap(req->offset, req->length, &req->sector_mask,
1289 &req->cow_offset, bitmap, bitmap_offset,
1290 req->bitmap_words, bitmap_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291}
1292
Jeff Dike62f96cb2007-02-10 01:44:16 -08001293/* Called with dev->lock held */
Jeff Dikea0044bd2007-05-06 14:51:36 -07001294static void prepare_request(struct request *req, struct io_thread_req *io_req,
1295 unsigned long long offset, int page_offset,
1296 int len, struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297{
1298 struct gendisk *disk = req->rq_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001299 struct ubd *ubd_dev = disk->private_data;
Jeff Dike91acb212005-10-10 23:10:32 -04001300
Jeff Dike62f96cb2007-02-10 01:44:16 -08001301 io_req->req = req;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001302 io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd :
1303 ubd_dev->fd;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001304 io_req->fds[1] = ubd_dev->fd;
Jeff Dike91acb212005-10-10 23:10:32 -04001305 io_req->cow_offset = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 io_req->offset = offset;
1307 io_req->length = len;
1308 io_req->error = 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001309 io_req->sector_mask = 0;
1310
1311 io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 io_req->offsets[0] = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001313 io_req->offsets[1] = ubd_dev->cow.data_offset;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001314 io_req->buffer = page_address(page) + page_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 io_req->sectorsize = 1 << 9;
1316
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001317 if(ubd_dev->cow.file != NULL)
Jeff Dikea0044bd2007-05-06 14:51:36 -07001318 cowify_req(io_req, ubd_dev->cow.bitmap,
1319 ubd_dev->cow.bitmap_offset, ubd_dev->cow.bitmap_len);
Jeff Dike91acb212005-10-10 23:10:32 -04001320
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321}
1322
Jeff Dike62f96cb2007-02-10 01:44:16 -08001323/* Called with dev->lock held */
Richard Weinberger805f11a2013-08-18 13:30:06 +02001324static void prepare_flush_request(struct request *req,
1325 struct io_thread_req *io_req)
1326{
1327 struct gendisk *disk = req->rq_disk;
1328 struct ubd *ubd_dev = disk->private_data;
1329
1330 io_req->req = req;
1331 io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd :
1332 ubd_dev->fd;
1333 io_req->op = UBD_FLUSH;
1334}
1335
Richard Weinbergerbc1d72e2013-08-18 13:30:07 +02001336static bool submit_request(struct io_thread_req *io_req, struct ubd *dev)
1337{
1338 int n = os_write_file(thread_fd, &io_req,
1339 sizeof(io_req));
1340 if (n != sizeof(io_req)) {
1341 if (n != -EAGAIN)
1342 printk("write to io thread failed, "
1343 "errno = %d\n", -n);
1344 else if (list_empty(&dev->restart))
1345 list_add(&dev->restart, &restart);
1346
1347 kfree(io_req);
1348 return false;
1349 }
1350 return true;
1351}
1352
Richard Weinberger805f11a2013-08-18 13:30:06 +02001353/* Called with dev->lock held */
Jens Axboe165125e2007-07-24 09:28:11 +02001354static void do_ubd_request(struct request_queue *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355{
Jeff Dike2adcec22007-05-06 14:51:37 -07001356 struct io_thread_req *io_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 struct request *req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358
Jeff Dikea0044bd2007-05-06 14:51:36 -07001359 while(1){
Jeff Dike2a9529a2007-03-29 01:20:27 -07001360 struct ubd *dev = q->queuedata;
Thorsten Knabe2a236122014-08-23 15:47:38 +02001361 if(dev->request == NULL){
Tejun Heo9934c8c2009-05-08 11:54:16 +09001362 struct request *req = blk_fetch_request(q);
Jeff Dikea0044bd2007-05-06 14:51:36 -07001363 if(req == NULL)
1364 return;
1365
1366 dev->request = req;
Tejun Heo47526902010-10-15 12:56:21 +02001367 dev->rq_pos = blk_rq_pos(req);
Jeff Dikea0044bd2007-05-06 14:51:36 -07001368 dev->start_sg = 0;
1369 dev->end_sg = blk_rq_map_sg(q, req, dev->sg);
Jeff Dike91acb212005-10-10 23:10:32 -04001370 }
Jeff Dikea0044bd2007-05-06 14:51:36 -07001371
1372 req = dev->request;
Richard Weinberger805f11a2013-08-18 13:30:06 +02001373
Mike Christie3a5e02c2016-06-05 14:32:23 -05001374 if (req_op(req) == REQ_OP_FLUSH) {
Richard Weinberger805f11a2013-08-18 13:30:06 +02001375 io_req = kmalloc(sizeof(struct io_thread_req),
1376 GFP_ATOMIC);
1377 if (io_req == NULL) {
1378 if (list_empty(&dev->restart))
1379 list_add(&dev->restart, &restart);
1380 return;
1381 }
1382 prepare_flush_request(req, io_req);
Thorsten Knabe2a236122014-08-23 15:47:38 +02001383 if (submit_request(io_req, dev) == false)
1384 return;
Richard Weinberger805f11a2013-08-18 13:30:06 +02001385 }
1386
Jeff Dikea0044bd2007-05-06 14:51:36 -07001387 while(dev->start_sg < dev->end_sg){
1388 struct scatterlist *sg = &dev->sg[dev->start_sg];
1389
Jeff Dike2adcec22007-05-06 14:51:37 -07001390 io_req = kmalloc(sizeof(struct io_thread_req),
Peter Zijlstra990c5582007-05-06 14:51:38 -07001391 GFP_ATOMIC);
Jeff Dike2adcec22007-05-06 14:51:37 -07001392 if(io_req == NULL){
1393 if(list_empty(&dev->restart))
1394 list_add(&dev->restart, &restart);
1395 return;
1396 }
1397 prepare_request(req, io_req,
Tejun Heo47526902010-10-15 12:56:21 +02001398 (unsigned long long)dev->rq_pos << 9,
Jens Axboe45711f12007-10-22 21:19:53 +02001399 sg->offset, sg->length, sg_page(sg));
Jeff Dikea0044bd2007-05-06 14:51:36 -07001400
Richard Weinbergerbc1d72e2013-08-18 13:30:07 +02001401 if (submit_request(io_req, dev) == false)
Jeff Dikea0044bd2007-05-06 14:51:36 -07001402 return;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001403
Tejun Heo47526902010-10-15 12:56:21 +02001404 dev->rq_pos += sg->length >> 9;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001405 dev->start_sg++;
1406 }
1407 dev->end_sg = 0;
1408 dev->request = NULL;
Jeff Dike91acb212005-10-10 23:10:32 -04001409 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410}
1411
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001412static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
1413{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001414 struct ubd *ubd_dev = bdev->bd_disk->private_data;
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001415
1416 geo->heads = 128;
1417 geo->sectors = 32;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001418 geo->cylinders = ubd_dev->size / (128 * 32 * 512);
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001419 return 0;
1420}
1421
Al Viroa625c992008-03-02 09:16:26 -05001422static int ubd_ioctl(struct block_device *bdev, fmode_t mode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 unsigned int cmd, unsigned long arg)
1424{
Al Viroa625c992008-03-02 09:16:26 -05001425 struct ubd *ubd_dev = bdev->bd_disk->private_data;
Bartlomiej Zolnierkiewicz73855e12009-04-01 21:42:21 +02001426 u16 ubd_id[ATA_ID_WORDS];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427
1428 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429 struct cdrom_volctrl volume;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 case HDIO_GET_IDENTITY:
Bartlomiej Zolnierkiewicz73855e12009-04-01 21:42:21 +02001431 memset(&ubd_id, 0, ATA_ID_WORDS * 2);
1432 ubd_id[ATA_ID_CYLS] = ubd_dev->size / (128 * 32 * 512);
1433 ubd_id[ATA_ID_HEADS] = 128;
1434 ubd_id[ATA_ID_SECTORS] = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 if(copy_to_user((char __user *) arg, (char *) &ubd_id,
1436 sizeof(ubd_id)))
Jeff Dikedc764e52007-05-06 14:51:41 -07001437 return -EFAULT;
1438 return 0;
Jeff Dikeb8831a12007-02-10 01:44:17 -08001439
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440 case CDROMVOLREAD:
1441 if(copy_from_user(&volume, (char __user *) arg, sizeof(volume)))
Jeff Dikedc764e52007-05-06 14:51:41 -07001442 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 volume.channel0 = 255;
1444 volume.channel1 = 255;
1445 volume.channel2 = 255;
1446 volume.channel3 = 255;
1447 if(copy_to_user((char __user *) arg, &volume, sizeof(volume)))
Jeff Dikedc764e52007-05-06 14:51:41 -07001448 return -EFAULT;
1449 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450 }
Jeff Dikedc764e52007-05-06 14:51:41 -07001451 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452}
1453
Jeff Dike91acb212005-10-10 23:10:32 -04001454static int update_bitmap(struct io_thread_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455{
Jeff Dike91acb212005-10-10 23:10:32 -04001456 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457
Jeff Dike91acb212005-10-10 23:10:32 -04001458 if(req->cow_offset == -1)
Jeff Dikedc764e52007-05-06 14:51:41 -07001459 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460
Anton Ivanov8c6157b2015-12-21 18:54:00 +00001461 n = os_pwrite_file(req->fds[1], &req->bitmap_words,
1462 sizeof(req->bitmap_words), req->cow_offset);
Jeff Dike91acb212005-10-10 23:10:32 -04001463 if(n != sizeof(req->bitmap_words)){
1464 printk("do_io - bitmap update failed, err = %d fd = %d\n", -n,
1465 req->fds[1]);
Jeff Dikedc764e52007-05-06 14:51:41 -07001466 return 1;
Jeff Dike91acb212005-10-10 23:10:32 -04001467 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468
Jeff Dikedc764e52007-05-06 14:51:41 -07001469 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470}
Jeff Dike91acb212005-10-10 23:10:32 -04001471
WANG Cong5dc62b12008-04-28 02:13:58 -07001472static void do_io(struct io_thread_req *req)
Jeff Dike91acb212005-10-10 23:10:32 -04001473{
1474 char *buf;
1475 unsigned long len;
1476 int n, nsectors, start, end, bit;
Jeff Dike91acb212005-10-10 23:10:32 -04001477 __u64 off;
1478
Richard Weinberger805f11a2013-08-18 13:30:06 +02001479 if (req->op == UBD_FLUSH) {
1480 /* fds[0] is always either the rw image or our cow file */
1481 n = os_sync_file(req->fds[0]);
1482 if (n != 0) {
1483 printk("do_io - sync failed err = %d "
1484 "fd = %d\n", -n, req->fds[0]);
1485 req->error = 1;
1486 }
1487 return;
1488 }
1489
Jeff Dike91acb212005-10-10 23:10:32 -04001490 nsectors = req->length / req->sectorsize;
1491 start = 0;
1492 do {
1493 bit = ubd_test_bit(start, (unsigned char *) &req->sector_mask);
1494 end = start;
1495 while((end < nsectors) &&
1496 (ubd_test_bit(end, (unsigned char *)
1497 &req->sector_mask) == bit))
1498 end++;
1499
1500 off = req->offset + req->offsets[bit] +
1501 start * req->sectorsize;
1502 len = (end - start) * req->sectorsize;
1503 buf = &req->buffer[start * req->sectorsize];
1504
Jeff Dike91acb212005-10-10 23:10:32 -04001505 if(req->op == UBD_READ){
1506 n = 0;
1507 do {
1508 buf = &buf[n];
1509 len -= n;
Anton Ivanov8c6157b2015-12-21 18:54:00 +00001510 n = os_pread_file(req->fds[bit], buf, len, off);
Jeff Dike91acb212005-10-10 23:10:32 -04001511 if (n < 0) {
1512 printk("do_io - read failed, err = %d "
1513 "fd = %d\n", -n, req->fds[bit]);
1514 req->error = 1;
1515 return;
1516 }
1517 } while((n < len) && (n != 0));
1518 if (n < len) memset(&buf[n], 0, len - n);
1519 } else {
Anton Ivanov8c6157b2015-12-21 18:54:00 +00001520 n = os_pwrite_file(req->fds[bit], buf, len, off);
Jeff Dike91acb212005-10-10 23:10:32 -04001521 if(n != len){
1522 printk("do_io - write failed err = %d "
1523 "fd = %d\n", -n, req->fds[bit]);
1524 req->error = 1;
1525 return;
1526 }
1527 }
1528
1529 start = end;
1530 } while(start < nsectors);
1531
1532 req->error = update_bitmap(req);
1533}
1534
1535/* Changed in start_io_thread, which is serialized by being called only
1536 * from ubd_init, which is an initcall.
1537 */
1538int kernel_fd = -1;
1539
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001540/* Only changed by the io thread. XXX: currently unused. */
1541static int io_count = 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001542
1543int io_thread(void *arg)
1544{
Anton Ivanovf88f0bd2016-11-09 20:43:25 +00001545 int n, count, written, res;
Jeff Dike91acb212005-10-10 23:10:32 -04001546
Richard Weinberger91d44ff2013-08-18 13:30:08 +02001547 os_fix_helper_signals();
1548
Jeff Dike91acb212005-10-10 23:10:32 -04001549 while(1){
Anton Ivanovf88f0bd2016-11-09 20:43:25 +00001550 n = bulk_req_safe_read(
1551 kernel_fd,
1552 io_req_buffer,
1553 &io_remainder,
1554 &io_remainder_size,
1555 UBD_REQ_BUFFER_SIZE
1556 );
1557 if (n < 0) {
1558 if (n == -EAGAIN) {
1559 ubd_read_poll(-1);
1560 continue;
1561 } else {
Jeff Dike91acb212005-10-10 23:10:32 -04001562 printk("io_thread - read failed, fd = %d, "
Anton Ivanovf88f0bd2016-11-09 20:43:25 +00001563 "err = %d,"
1564 "reminder = %d\n",
1565 kernel_fd, -n, io_remainder_size);
Jeff Dike91acb212005-10-10 23:10:32 -04001566 }
Jeff Dike91acb212005-10-10 23:10:32 -04001567 }
Anton Ivanovf88f0bd2016-11-09 20:43:25 +00001568
1569 for (count = 0; count < n/sizeof(struct io_thread_req *); count++) {
1570 io_count++;
1571 do_io((*io_req_buffer)[count]);
1572 }
1573
1574 written = 0;
1575
1576 do {
1577 res = os_write_file(kernel_fd, ((char *) io_req_buffer) + written, n);
Anton Ivanovff6a1792017-11-20 21:17:58 +00001578 if (res >= 0) {
Anton Ivanovf88f0bd2016-11-09 20:43:25 +00001579 written += res;
1580 } else {
1581 if (res != -EAGAIN) {
Anton Ivanovff6a1792017-11-20 21:17:58 +00001582 printk("io_thread - write failed, fd = %d, "
Anton Ivanovf88f0bd2016-11-09 20:43:25 +00001583 "err = %d\n", kernel_fd, -n);
1584 }
1585 }
1586 if (written < n) {
1587 ubd_write_poll(-1);
1588 }
1589 } while (written < n);
Jeff Dike91acb212005-10-10 23:10:32 -04001590 }
Jeff Dike91acb212005-10-10 23:10:32 -04001591
Jeff Dike1b57e9c2006-01-06 00:18:49 -08001592 return 0;
1593}