blob: 0491e40d6968d9916f4dfaef93bd28d7c694145d [file] [log] [blame]
Jeff Dike6c29256c2006-03-27 01:14:37 -08001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6/* 2001-09-28...2002-04-17
7 * Partition stuff by James_McMechan@hotmail.com
8 * old style ubd by setting UBD_SHIFT to 0
9 * 2002-09-27...2002-10-18 massive tinkering for 2.5
10 * partitions have changed in 2.5
11 * 2003-01-29 more tinkering for 2.5.59-1
12 * This should now address the sysfs problems and has
13 * the symlink for devfs to allow for booting with
14 * the common /dev/ubd/discX/... names rather than
15 * only /dev/ubdN/discN this version also has lots of
16 * clean ups preparing for ubd-many.
17 * James McMechan
18 */
19
Linus Torvalds1da177e2005-04-16 15:20:36 -070020#define UBD_SHIFT 4
21
Jeff Dikee16f5352007-06-08 13:46:54 -070022#include "linux/kernel.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include "linux/module.h"
24#include "linux/blkdev.h"
Bartlomiej Zolnierkiewicz73855e12009-04-01 21:42:21 +020025#include "linux/ata.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include "linux/hdreg.h"
27#include "linux/init.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include "linux/cdrom.h"
29#include "linux/proc_fs.h"
Alexey Dobriyan6613c5e2009-12-14 18:00:11 -080030#include "linux/seq_file.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include "linux/ctype.h"
32#include "linux/capability.h"
33#include "linux/mm.h"
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090034#include "linux/slab.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include "linux/vmalloc.h"
Arnd Bergmann9a181c52010-09-11 18:38:03 +020036#include "linux/mutex.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#include "linux/blkpg.h"
38#include "linux/genhd.h"
39#include "linux/spinlock.h"
Russell Kingd052d1b2005-10-29 19:07:23 +010040#include "linux/platform_device.h"
WANG Cong23464ff2007-10-24 13:07:11 +020041#include "linux/scatterlist.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include "asm/segment.h"
43#include "asm/uaccess.h"
44#include "asm/irq.h"
45#include "asm/types.h"
46#include "asm/tlbflush.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070047#include "mem_user.h"
48#include "kern_util.h"
49#include "kern.h"
50#include "mconsole_kern.h"
51#include "init.h"
52#include "irq_user.h"
53#include "irq_kern.h"
54#include "ubd_user.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070055#include "os.h"
56#include "mem.h"
57#include "mem_kern.h"
58#include "cow.h"
59
Jeff Dike7b9014c2005-05-20 13:59:11 -070060enum ubd_req { UBD_READ, UBD_WRITE };
Linus Torvalds1da177e2005-04-16 15:20:36 -070061
62struct io_thread_req {
Jeff Dike62f96cb2007-02-10 01:44:16 -080063 struct request *req;
Jeff Dike91acb212005-10-10 23:10:32 -040064 enum ubd_req op;
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 int fds[2];
66 unsigned long offsets[2];
67 unsigned long long offset;
68 unsigned long length;
69 char *buffer;
70 int sectorsize;
Jeff Dike91acb212005-10-10 23:10:32 -040071 unsigned long sector_mask;
72 unsigned long long cow_offset;
73 unsigned long bitmap_words[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -070074 int error;
75};
76
Jeff Dike91acb212005-10-10 23:10:32 -040077static inline int ubd_test_bit(__u64 bit, unsigned char *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -070078{
79 __u64 n;
80 int bits, off;
81
Jeff Dike91acb212005-10-10 23:10:32 -040082 bits = sizeof(data[0]) * 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -070083 n = bit / bits;
84 off = bit % bits;
Jeff Dikedc764e52007-05-06 14:51:41 -070085 return (data[n] & (1 << off)) != 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070086}
87
Jeff Dike91acb212005-10-10 23:10:32 -040088static inline void ubd_set_bit(__u64 bit, unsigned char *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -070089{
90 __u64 n;
91 int bits, off;
92
Jeff Dike91acb212005-10-10 23:10:32 -040093 bits = sizeof(data[0]) * 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -070094 n = bit / bits;
95 off = bit % bits;
Jeff Dike91acb212005-10-10 23:10:32 -040096 data[n] |= (1 << off);
Linus Torvalds1da177e2005-04-16 15:20:36 -070097}
98/*End stuff from ubd_user.h*/
99
100#define DRIVER_NAME "uml-blkdev"
101
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800102static DEFINE_MUTEX(ubd_lock);
Arnd Bergmann9a181c52010-09-11 18:38:03 +0200103static DEFINE_MUTEX(ubd_mutex); /* replaces BKL, might not be needed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104
Al Viroa625c992008-03-02 09:16:26 -0500105static int ubd_open(struct block_device *bdev, fmode_t mode);
106static int ubd_release(struct gendisk *disk, fmode_t mode);
107static int ubd_ioctl(struct block_device *bdev, fmode_t mode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 unsigned int cmd, unsigned long arg);
Christoph Hellwiga885c8c2006-01-08 01:02:50 -0800109static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110
Paolo 'Blaisorblade' Giarrusso97d88ac2006-10-30 22:07:03 -0800111#define MAX_DEV (16)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112
Alexey Dobriyan83d5cde2009-09-21 17:01:13 -0700113static const struct block_device_operations ubd_blops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114 .owner = THIS_MODULE,
Al Viroa625c992008-03-02 09:16:26 -0500115 .open = ubd_open,
116 .release = ubd_release,
117 .ioctl = ubd_ioctl,
Christoph Hellwiga885c8c2006-01-08 01:02:50 -0800118 .getgeo = ubd_getgeo,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119};
120
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121/* Protected by ubd_lock */
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700122static int fake_major = UBD_MAJOR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123static struct gendisk *ubd_gendisk[MAX_DEV];
124static struct gendisk *fake_gendisk[MAX_DEV];
Jeff Dike6c29256c2006-03-27 01:14:37 -0800125
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126#ifdef CONFIG_BLK_DEV_UBD_SYNC
127#define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 1, .c = 0, \
128 .cl = 1 })
129#else
130#define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 0, .c = 0, \
131 .cl = 1 })
132#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133static struct openflags global_openflags = OPEN_FLAGS;
134
135struct cow {
Paolo 'Blaisorblade' Giarrusso2a9d32f2006-10-30 22:07:04 -0800136 /* backing file name */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 char *file;
Paolo 'Blaisorblade' Giarrusso2a9d32f2006-10-30 22:07:04 -0800138 /* backing file fd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 int fd;
140 unsigned long *bitmap;
141 unsigned long bitmap_len;
142 int bitmap_offset;
Jeff Dikedc764e52007-05-06 14:51:41 -0700143 int data_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144};
145
Jeff Dikea0044bd2007-05-06 14:51:36 -0700146#define MAX_SG 64
147
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148struct ubd {
Jeff Dikea0044bd2007-05-06 14:51:36 -0700149 struct list_head restart;
Paolo 'Blaisorblade' Giarrusso2a9d32f2006-10-30 22:07:04 -0800150 /* name (and fd, below) of the file opened for writing, either the
151 * backing or the cow file. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 char *file;
153 int count;
154 int fd;
155 __u64 size;
156 struct openflags boot_openflags;
157 struct openflags openflags;
Paolo 'Blaisorblade' Giarrusso84e945e2006-10-30 22:07:10 -0800158 unsigned shared:1;
159 unsigned no_cow:1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 struct cow cow;
161 struct platform_device pdev;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800162 struct request_queue *queue;
163 spinlock_t lock;
Jeff Dikea0044bd2007-05-06 14:51:36 -0700164 struct scatterlist sg[MAX_SG];
165 struct request *request;
166 int start_sg, end_sg;
Tejun Heo47526902010-10-15 12:56:21 +0200167 sector_t rq_pos;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168};
169
170#define DEFAULT_COW { \
171 .file = NULL, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700172 .fd = -1, \
173 .bitmap = NULL, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 .bitmap_offset = 0, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700175 .data_offset = 0, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176}
177
178#define DEFAULT_UBD { \
179 .file = NULL, \
180 .count = 0, \
181 .fd = -1, \
182 .size = -1, \
183 .boot_openflags = OPEN_FLAGS, \
184 .openflags = OPEN_FLAGS, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700185 .no_cow = 0, \
Jeff Dike6c29256c2006-03-27 01:14:37 -0800186 .shared = 0, \
Jeff Dikedc764e52007-05-06 14:51:41 -0700187 .cow = DEFAULT_COW, \
Thomas Gleixner22e65002011-01-23 15:21:25 +0100188 .lock = __SPIN_LOCK_UNLOCKED(ubd_devs.lock), \
Jeff Dikea0044bd2007-05-06 14:51:36 -0700189 .request = NULL, \
190 .start_sg = 0, \
191 .end_sg = 0, \
Tejun Heo47526902010-10-15 12:56:21 +0200192 .rq_pos = 0, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193}
194
Jeff Dikeb8831a12007-02-10 01:44:17 -0800195/* Protected by ubd_lock */
WANG Cong5dc62b12008-04-28 02:13:58 -0700196static struct ubd ubd_devs[MAX_DEV] = { [0 ... MAX_DEV - 1] = DEFAULT_UBD };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198/* Only changed by fake_ide_setup which is a setup */
199static int fake_ide = 0;
200static struct proc_dir_entry *proc_ide_root = NULL;
201static struct proc_dir_entry *proc_ide = NULL;
202
203static void make_proc_ide(void)
204{
205 proc_ide_root = proc_mkdir("ide", NULL);
206 proc_ide = proc_mkdir("ide0", proc_ide_root);
207}
208
Alexey Dobriyan6613c5e2009-12-14 18:00:11 -0800209static int fake_ide_media_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210{
Alexey Dobriyan6613c5e2009-12-14 18:00:11 -0800211 seq_puts(m, "disk\n");
212 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213}
214
Alexey Dobriyan6613c5e2009-12-14 18:00:11 -0800215static int fake_ide_media_proc_open(struct inode *inode, struct file *file)
216{
217 return single_open(file, fake_ide_media_proc_show, NULL);
218}
219
220static const struct file_operations fake_ide_media_proc_fops = {
221 .owner = THIS_MODULE,
222 .open = fake_ide_media_proc_open,
223 .read = seq_read,
224 .llseek = seq_lseek,
225 .release = single_release,
226};
227
WANG Congc0a92902008-02-04 22:30:41 -0800228static void make_ide_entries(const char *dev_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229{
230 struct proc_dir_entry *dir, *ent;
231 char name[64];
232
233 if(proc_ide_root == NULL) make_proc_ide();
234
235 dir = proc_mkdir(dev_name, proc_ide);
236 if(!dir) return;
237
Alexey Dobriyan6613c5e2009-12-14 18:00:11 -0800238 ent = proc_create("media", S_IRUGO, dir, &fake_ide_media_proc_fops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 if(!ent) return;
WANG Congc0a92902008-02-04 22:30:41 -0800240 snprintf(name, sizeof(name), "ide0/%s", dev_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 proc_symlink(dev_name, proc_ide_root, name);
242}
243
244static int fake_ide_setup(char *str)
245{
246 fake_ide = 1;
Jeff Dikedc764e52007-05-06 14:51:41 -0700247 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248}
249
250__setup("fake_ide", fake_ide_setup);
251
252__uml_help(fake_ide_setup,
253"fake_ide\n"
254" Create ide0 entries that map onto ubd devices.\n\n"
255);
256
257static int parse_unit(char **ptr)
258{
259 char *str = *ptr, *end;
260 int n = -1;
261
262 if(isdigit(*str)) {
263 n = simple_strtoul(str, &end, 0);
264 if(end == str)
Jeff Dikedc764e52007-05-06 14:51:41 -0700265 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 *ptr = end;
267 }
Paolo 'Blaisorblade' Giarrusso97d88ac2006-10-30 22:07:03 -0800268 else if (('a' <= *str) && (*str <= 'z')) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 n = *str - 'a';
270 str++;
271 *ptr = str;
272 }
Jeff Dikedc764e52007-05-06 14:51:41 -0700273 return n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274}
275
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800276/* If *index_out == -1 at exit, the passed option was a general one;
277 * otherwise, the str pointer is used (and owned) inside ubd_devs array, so it
278 * should not be freed on exit.
279 */
Jeff Dikef28169d2007-02-10 01:43:53 -0800280static int ubd_setup_common(char *str, int *index_out, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800282 struct ubd *ubd_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 struct openflags flags = global_openflags;
284 char *backing_file;
Jeff Dikeb8831a12007-02-10 01:44:17 -0800285 int n, err = 0, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286
287 if(index_out) *index_out = -1;
288 n = *str;
289 if(n == '='){
290 char *end;
291 int major;
292
293 str++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 if(!strcmp(str, "sync")){
295 global_openflags = of_sync(global_openflags);
Jeff Dikeb8831a12007-02-10 01:44:17 -0800296 goto out1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 }
298
Jeff Dikef28169d2007-02-10 01:43:53 -0800299 err = -EINVAL;
Jeff Dikeb8831a12007-02-10 01:44:17 -0800300 major = simple_strtoul(str, &end, 0);
301 if((*end != '\0') || (end == str)){
302 *error_out = "Didn't parse major number";
303 goto out1;
304 }
305
Jeff Dikef28169d2007-02-10 01:43:53 -0800306 mutex_lock(&ubd_lock);
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700307 if (fake_major != UBD_MAJOR) {
Jeff Dikef28169d2007-02-10 01:43:53 -0800308 *error_out = "Can't assign a fake major twice";
309 goto out1;
310 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800311
Jeff Dikef28169d2007-02-10 01:43:53 -0800312 fake_major = major;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313
314 printk(KERN_INFO "Setting extra ubd major number to %d\n",
315 major);
Jeff Dikef28169d2007-02-10 01:43:53 -0800316 err = 0;
317 out1:
318 mutex_unlock(&ubd_lock);
319 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 }
321
322 n = parse_unit(&str);
323 if(n < 0){
Jeff Dikef28169d2007-02-10 01:43:53 -0800324 *error_out = "Couldn't parse device number";
325 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 }
327 if(n >= MAX_DEV){
Jeff Dikef28169d2007-02-10 01:43:53 -0800328 *error_out = "Device number out of range";
329 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 }
331
Jeff Dikef28169d2007-02-10 01:43:53 -0800332 err = -EBUSY;
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800333 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800335 ubd_dev = &ubd_devs[n];
336 if(ubd_dev->file != NULL){
Jeff Dikef28169d2007-02-10 01:43:53 -0800337 *error_out = "Device is already configured";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 goto out;
339 }
340
341 if (index_out)
342 *index_out = n;
343
Jeff Dikef28169d2007-02-10 01:43:53 -0800344 err = -EINVAL;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800345 for (i = 0; i < sizeof("rscd="); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 switch (*str) {
347 case 'r':
348 flags.w = 0;
349 break;
350 case 's':
351 flags.s = 1;
352 break;
353 case 'd':
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800354 ubd_dev->no_cow = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 break;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800356 case 'c':
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800357 ubd_dev->shared = 1;
Jeff Dike6c29256c2006-03-27 01:14:37 -0800358 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 case '=':
360 str++;
361 goto break_loop;
362 default:
Jeff Dikef28169d2007-02-10 01:43:53 -0800363 *error_out = "Expected '=' or flag letter "
364 "(r, s, c, or d)";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 goto out;
366 }
367 str++;
368 }
369
Jeff Dikef28169d2007-02-10 01:43:53 -0800370 if (*str == '=')
371 *error_out = "Too many flags specified";
372 else
373 *error_out = "Missing '='";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 goto out;
375
376break_loop:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 backing_file = strchr(str, ',');
378
Jeff Dikef28169d2007-02-10 01:43:53 -0800379 if (backing_file == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 backing_file = strchr(str, ':');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381
Jeff Dikef28169d2007-02-10 01:43:53 -0800382 if(backing_file != NULL){
383 if(ubd_dev->no_cow){
384 *error_out = "Can't specify both 'd' and a cow file";
385 goto out;
386 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 else {
388 *backing_file = '\0';
389 backing_file++;
390 }
391 }
Jeff Dikef28169d2007-02-10 01:43:53 -0800392 err = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800393 ubd_dev->file = str;
394 ubd_dev->cow.file = backing_file;
395 ubd_dev->boot_openflags = flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800397 mutex_unlock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -0800398 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399}
400
401static int ubd_setup(char *str)
402{
Jeff Dikef28169d2007-02-10 01:43:53 -0800403 char *error;
404 int err;
405
406 err = ubd_setup_common(str, NULL, &error);
407 if(err)
408 printk(KERN_ERR "Failed to initialize device with \"%s\" : "
409 "%s\n", str, error);
410 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411}
412
413__setup("ubd", ubd_setup);
414__uml_help(ubd_setup,
415"ubd<n><flags>=<filename>[(:|,)<filename2>]\n"
416" This is used to associate a device with a file in the underlying\n"
417" filesystem. When specifying two filenames, the first one is the\n"
418" COW name and the second is the backing file name. As separator you can\n"
419" use either a ':' or a ',': the first one allows writing things like;\n"
420" ubd0=~/Uml/root_cow:~/Uml/root_backing_file\n"
421" while with a ',' the shell would not expand the 2nd '~'.\n"
Jeff Dikef28169d2007-02-10 01:43:53 -0800422" When using only one filename, UML will detect whether to treat it like\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423" a COW file or a backing file. To override this detection, add the 'd'\n"
424" flag:\n"
425" ubd0d=BackingFile\n"
426" Usually, there is a filesystem in the file, but \n"
427" that's not required. Swap devices containing swap files can be\n"
428" specified like this. Also, a file which doesn't contain a\n"
429" filesystem can have its contents read in the virtual \n"
430" machine by running 'dd' on the device. <n> must be in the range\n"
431" 0 to 7. Appending an 'r' to the number will cause that device\n"
432" to be mounted read-only. For example ubd1r=./ext_fs. Appending\n"
Jeff Dike20ede452008-02-04 22:30:37 -0800433" an 's' will cause data to be written to disk on the host immediately.\n"
434" 'c' will cause the device to be treated as being shared between multiple\n"
435" UMLs and file locking will be turned off - this is appropriate for a\n"
436" cluster filesystem and inappropriate at almost all other times.\n\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437);
438
Jeff Dike8299ca52008-02-04 22:30:48 -0800439static int udb_setup(char *str)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440{
441 printk("udb%s specified on command line is almost certainly a ubd -> "
442 "udb TYPO\n", str);
Jeff Dikedc764e52007-05-06 14:51:41 -0700443 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444}
445
446__setup("udb", udb_setup);
447__uml_help(udb_setup,
448"udb\n"
Jeff Dike0894e272005-05-28 15:51:55 -0700449" This option is here solely to catch ubd -> udb typos, which can be\n"
450" to impossible to catch visually unless you specifically look for\n"
451" them. The only result of any option starting with 'udb' is an error\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452" in the boot output.\n\n"
453);
454
Jens Axboe165125e2007-07-24 09:28:11 +0200455static void do_ubd_request(struct request_queue * q);
Jeff Dike91acb212005-10-10 23:10:32 -0400456
457/* Only changed by ubd_init, which is an initcall. */
WANG Cong5dc62b12008-04-28 02:13:58 -0700458static int thread_fd = -1;
Jeff Dikea0044bd2007-05-06 14:51:36 -0700459static LIST_HEAD(restart);
460
Paolo 'Blaisorblade' Giarrusso2fe30a32006-10-30 22:07:09 -0800461/* XXX - move this inside ubd_intr. */
Jeff Dike62f96cb2007-02-10 01:44:16 -0800462/* Called without dev->lock held, and only in interrupt context. */
Jeff Dike91acb212005-10-10 23:10:32 -0400463static void ubd_handler(void)
464{
Jeff Dike2adcec22007-05-06 14:51:37 -0700465 struct io_thread_req *req;
Jeff Dikea0044bd2007-05-06 14:51:36 -0700466 struct ubd *ubd;
467 struct list_head *list, *next_ele;
468 unsigned long flags;
Jeff Dike91acb212005-10-10 23:10:32 -0400469 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470
Jeff Dikea0044bd2007-05-06 14:51:36 -0700471 while(1){
Jeff Dikea6ea4cc2007-05-06 14:51:43 -0700472 n = os_read_file(thread_fd, &req,
473 sizeof(struct io_thread_req *));
Jeff Dikea0044bd2007-05-06 14:51:36 -0700474 if(n != sizeof(req)){
475 if(n == -EAGAIN)
476 break;
477 printk(KERN_ERR "spurious interrupt in ubd_handler, "
478 "err = %d\n", -n);
479 return;
480 }
481
Tejun Heo4d6c84d2009-04-28 13:06:09 +0900482 blk_end_request(req->req, 0, req->length);
Jeff Dike2adcec22007-05-06 14:51:37 -0700483 kfree(req);
Jeff Dike91acb212005-10-10 23:10:32 -0400484 }
Jeff Dike62f96cb2007-02-10 01:44:16 -0800485 reactivate_fd(thread_fd, UBD_IRQ);
Jeff Dikea0044bd2007-05-06 14:51:36 -0700486
487 list_for_each_safe(list, next_ele, &restart){
488 ubd = container_of(list, struct ubd, restart);
489 list_del_init(&ubd->restart);
490 spin_lock_irqsave(&ubd->lock, flags);
491 do_ubd_request(ubd->queue);
492 spin_unlock_irqrestore(&ubd->lock, flags);
493 }
Jeff Dike91acb212005-10-10 23:10:32 -0400494}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495
Al Viro7bea96f2006-10-08 22:49:34 +0100496static irqreturn_t ubd_intr(int irq, void *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497{
Jeff Dike91acb212005-10-10 23:10:32 -0400498 ubd_handler();
Jeff Dikedc764e52007-05-06 14:51:41 -0700499 return IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500}
501
Jeff Dike91acb212005-10-10 23:10:32 -0400502/* Only changed by ubd_init, which is an initcall. */
503static int io_pid = -1;
504
WANG Cong5dc62b12008-04-28 02:13:58 -0700505static void kill_io_thread(void)
Jeff Dike91acb212005-10-10 23:10:32 -0400506{
Jeff Dike6c29256c2006-03-27 01:14:37 -0800507 if(io_pid != -1)
Jeff Dike91acb212005-10-10 23:10:32 -0400508 os_kill_process(io_pid, 1);
509}
510
511__uml_exitcall(kill_io_thread);
512
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800513static inline int ubd_file_size(struct ubd *ubd_dev, __u64 *size_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514{
515 char *file;
Richard Weinberger5f0d9e02011-11-02 13:17:27 +0100516 int fd;
517 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518
Richard Weinberger5f0d9e02011-11-02 13:17:27 +0100519 __u32 version;
520 __u32 align;
521 char *backing_file;
522 time_t mtime;
523 unsigned long long size;
524 int sector_size;
525 int bitmap_offset;
526
527 if (ubd_dev->file && ubd_dev->cow.file) {
528 file = ubd_dev->cow.file;
529
530 goto out;
531 }
532
533 fd = os_open_file(ubd_dev->file, global_openflags, 0);
534 if (fd < 0)
535 return fd;
536
537 err = read_cow_header(file_reader, &fd, &version, &backing_file, \
538 &mtime, &size, &sector_size, &align, &bitmap_offset);
539 os_close_file(fd);
540
541 if(err == -EINVAL)
542 file = ubd_dev->file;
543 else
544 file = backing_file;
545
546out:
Jeff Dikedc764e52007-05-06 14:51:41 -0700547 return os_file_size(file, size_out);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548}
549
WANG Cong5dc62b12008-04-28 02:13:58 -0700550static int read_cow_bitmap(int fd, void *buf, int offset, int len)
551{
552 int err;
553
554 err = os_seek_file(fd, offset);
555 if (err < 0)
556 return err;
557
558 err = os_read_file(fd, buf, len);
559 if (err < 0)
560 return err;
561
562 return 0;
563}
564
565static int backing_file_mismatch(char *file, __u64 size, time_t mtime)
566{
567 unsigned long modtime;
568 unsigned long long actual;
569 int err;
570
571 err = os_file_modtime(file, &modtime);
572 if (err < 0) {
573 printk(KERN_ERR "Failed to get modification time of backing "
574 "file \"%s\", err = %d\n", file, -err);
575 return err;
576 }
577
578 err = os_file_size(file, &actual);
579 if (err < 0) {
580 printk(KERN_ERR "Failed to get size of backing file \"%s\", "
581 "err = %d\n", file, -err);
582 return err;
583 }
584
585 if (actual != size) {
586 /*__u64 can be a long on AMD64 and with %lu GCC complains; so
587 * the typecast.*/
588 printk(KERN_ERR "Size mismatch (%llu vs %llu) of COW header "
589 "vs backing file\n", (unsigned long long) size, actual);
590 return -EINVAL;
591 }
592 if (modtime != mtime) {
593 printk(KERN_ERR "mtime mismatch (%ld vs %ld) of COW header vs "
594 "backing file\n", mtime, modtime);
595 return -EINVAL;
596 }
597 return 0;
598}
599
600static int path_requires_switch(char *from_cmdline, char *from_cow, char *cow)
601{
602 struct uml_stat buf1, buf2;
603 int err;
604
605 if (from_cmdline == NULL)
606 return 0;
607 if (!strcmp(from_cmdline, from_cow))
608 return 0;
609
610 err = os_stat_file(from_cmdline, &buf1);
611 if (err < 0) {
612 printk(KERN_ERR "Couldn't stat '%s', err = %d\n", from_cmdline,
613 -err);
614 return 0;
615 }
616 err = os_stat_file(from_cow, &buf2);
617 if (err < 0) {
618 printk(KERN_ERR "Couldn't stat '%s', err = %d\n", from_cow,
619 -err);
620 return 1;
621 }
622 if ((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino))
623 return 0;
624
625 printk(KERN_ERR "Backing file mismatch - \"%s\" requested, "
626 "\"%s\" specified in COW header of \"%s\"\n",
627 from_cmdline, from_cow, cow);
628 return 1;
629}
630
631static int open_ubd_file(char *file, struct openflags *openflags, int shared,
632 char **backing_file_out, int *bitmap_offset_out,
633 unsigned long *bitmap_len_out, int *data_offset_out,
634 int *create_cow_out)
635{
636 time_t mtime;
637 unsigned long long size;
638 __u32 version, align;
639 char *backing_file;
640 int fd, err, sectorsize, asked_switch, mode = 0644;
641
642 fd = os_open_file(file, *openflags, mode);
643 if (fd < 0) {
644 if ((fd == -ENOENT) && (create_cow_out != NULL))
645 *create_cow_out = 1;
646 if (!openflags->w ||
647 ((fd != -EROFS) && (fd != -EACCES)))
648 return fd;
649 openflags->w = 0;
650 fd = os_open_file(file, *openflags, mode);
651 if (fd < 0)
652 return fd;
653 }
654
655 if (shared)
656 printk(KERN_INFO "Not locking \"%s\" on the host\n", file);
657 else {
658 err = os_lock_file(fd, openflags->w);
659 if (err < 0) {
660 printk(KERN_ERR "Failed to lock '%s', err = %d\n",
661 file, -err);
662 goto out_close;
663 }
664 }
665
666 /* Successful return case! */
667 if (backing_file_out == NULL)
668 return fd;
669
670 err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime,
671 &size, &sectorsize, &align, bitmap_offset_out);
672 if (err && (*backing_file_out != NULL)) {
673 printk(KERN_ERR "Failed to read COW header from COW file "
674 "\"%s\", errno = %d\n", file, -err);
675 goto out_close;
676 }
677 if (err)
678 return fd;
679
680 asked_switch = path_requires_switch(*backing_file_out, backing_file,
681 file);
682
683 /* Allow switching only if no mismatch. */
684 if (asked_switch && !backing_file_mismatch(*backing_file_out, size,
685 mtime)) {
686 printk(KERN_ERR "Switching backing file to '%s'\n",
687 *backing_file_out);
688 err = write_cow_header(file, fd, *backing_file_out,
689 sectorsize, align, &size);
690 if (err) {
691 printk(KERN_ERR "Switch failed, errno = %d\n", -err);
692 goto out_close;
693 }
694 } else {
695 *backing_file_out = backing_file;
696 err = backing_file_mismatch(*backing_file_out, size, mtime);
697 if (err)
698 goto out_close;
699 }
700
701 cow_sizes(version, size, sectorsize, align, *bitmap_offset_out,
702 bitmap_len_out, data_offset_out);
703
704 return fd;
705 out_close:
706 os_close_file(fd);
707 return err;
708}
709
710static int create_cow_file(char *cow_file, char *backing_file,
711 struct openflags flags,
712 int sectorsize, int alignment, int *bitmap_offset_out,
713 unsigned long *bitmap_len_out, int *data_offset_out)
714{
715 int err, fd;
716
717 flags.c = 1;
718 fd = open_ubd_file(cow_file, &flags, 0, NULL, NULL, NULL, NULL, NULL);
719 if (fd < 0) {
720 err = fd;
721 printk(KERN_ERR "Open of COW file '%s' failed, errno = %d\n",
722 cow_file, -err);
723 goto out;
724 }
725
726 err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment,
727 bitmap_offset_out, bitmap_len_out,
728 data_offset_out);
729 if (!err)
730 return fd;
731 os_close_file(fd);
732 out:
733 return err;
734}
735
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800736static void ubd_close_dev(struct ubd *ubd_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800738 os_close_file(ubd_dev->fd);
739 if(ubd_dev->cow.file == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 return;
741
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800742 os_close_file(ubd_dev->cow.fd);
743 vfree(ubd_dev->cow.bitmap);
744 ubd_dev->cow.bitmap = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745}
746
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800747static int ubd_open_dev(struct ubd *ubd_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748{
749 struct openflags flags;
750 char **back_ptr;
751 int err, create_cow, *create_ptr;
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800752 int fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800754 ubd_dev->openflags = ubd_dev->boot_openflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 create_cow = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800756 create_ptr = (ubd_dev->cow.file != NULL) ? &create_cow : NULL;
757 back_ptr = ubd_dev->no_cow ? NULL : &ubd_dev->cow.file;
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800758
759 fd = open_ubd_file(ubd_dev->file, &ubd_dev->openflags, ubd_dev->shared,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800760 back_ptr, &ubd_dev->cow.bitmap_offset,
761 &ubd_dev->cow.bitmap_len, &ubd_dev->cow.data_offset,
Jeff Dike6c29256c2006-03-27 01:14:37 -0800762 create_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800764 if((fd == -ENOENT) && create_cow){
765 fd = create_cow_file(ubd_dev->file, ubd_dev->cow.file,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800766 ubd_dev->openflags, 1 << 9, PAGE_SIZE,
767 &ubd_dev->cow.bitmap_offset,
768 &ubd_dev->cow.bitmap_len,
769 &ubd_dev->cow.data_offset);
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800770 if(fd >= 0){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 printk(KERN_INFO "Creating \"%s\" as COW file for "
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800772 "\"%s\"\n", ubd_dev->file, ubd_dev->cow.file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 }
774 }
775
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800776 if(fd < 0){
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800777 printk("Failed to open '%s', errno = %d\n", ubd_dev->file,
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800778 -fd);
779 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 }
Paolo 'Blaisorblade' Giarrusso0bf16bf2006-10-30 22:07:11 -0800781 ubd_dev->fd = fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800783 if(ubd_dev->cow.file != NULL){
Martin K. Petersen086fa5f2010-02-26 00:20:38 -0500784 blk_queue_max_hw_sectors(ubd_dev->queue, 8 * sizeof(long));
Jeff Dikef4768ff2007-08-22 14:01:53 -0700785
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 err = -ENOMEM;
Jesper Juhlda2486b2007-10-16 01:27:19 -0700787 ubd_dev->cow.bitmap = vmalloc(ubd_dev->cow.bitmap_len);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800788 if(ubd_dev->cow.bitmap == NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 printk(KERN_ERR "Failed to vmalloc COW bitmap\n");
790 goto error;
791 }
792 flush_tlb_kernel_vm();
793
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800794 err = read_cow_bitmap(ubd_dev->fd, ubd_dev->cow.bitmap,
795 ubd_dev->cow.bitmap_offset,
796 ubd_dev->cow.bitmap_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 if(err < 0)
798 goto error;
799
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800800 flags = ubd_dev->openflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 flags.w = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800802 err = open_ubd_file(ubd_dev->cow.file, &flags, ubd_dev->shared, NULL,
Jeff Dike6c29256c2006-03-27 01:14:37 -0800803 NULL, NULL, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 if(err < 0) goto error;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800805 ubd_dev->cow.fd = err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 }
Jeff Dikedc764e52007-05-06 14:51:41 -0700807 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 error:
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800809 os_close_file(ubd_dev->fd);
Jeff Dikedc764e52007-05-06 14:51:41 -0700810 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811}
812
Jeff Dike2e3f5252007-05-06 14:51:29 -0700813static void ubd_device_release(struct device *dev)
814{
Greg Kroah-Hartman8691b972009-05-04 12:40:54 -0700815 struct ubd *ubd_dev = dev_get_drvdata(dev);
Jeff Dike2e3f5252007-05-06 14:51:29 -0700816
817 blk_cleanup_queue(ubd_dev->queue);
818 *ubd_dev = ((struct ubd) DEFAULT_UBD);
819}
820
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800821static int ubd_disk_register(int major, u64 size, int unit,
Jeff Dikeb8831a12007-02-10 01:44:17 -0800822 struct gendisk **disk_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823{
824 struct gendisk *disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825
826 disk = alloc_disk(1 << UBD_SHIFT);
827 if(disk == NULL)
Jeff Dikedc764e52007-05-06 14:51:41 -0700828 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829
830 disk->major = major;
831 disk->first_minor = unit << UBD_SHIFT;
832 disk->fops = &ubd_blops;
833 set_capacity(disk, size / 512);
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700834 if (major == UBD_MAJOR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 sprintf(disk->disk_name, "ubd%c", 'a' + unit);
Greg Kroah-Hartmance7b0f42005-06-20 21:15:16 -0700836 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 sprintf(disk->disk_name, "ubd_fake%d", unit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838
839 /* sysfs register (not for ide fake devices) */
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700840 if (major == UBD_MAJOR) {
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800841 ubd_devs[unit].pdev.id = unit;
842 ubd_devs[unit].pdev.name = DRIVER_NAME;
Jeff Dike2e3f5252007-05-06 14:51:29 -0700843 ubd_devs[unit].pdev.dev.release = ubd_device_release;
Greg Kroah-Hartman8691b972009-05-04 12:40:54 -0700844 dev_set_drvdata(&ubd_devs[unit].pdev.dev, &ubd_devs[unit]);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800845 platform_device_register(&ubd_devs[unit].pdev);
846 disk->driverfs_dev = &ubd_devs[unit].pdev.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 }
848
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800849 disk->private_data = &ubd_devs[unit];
Jeff Dike62f96cb2007-02-10 01:44:16 -0800850 disk->queue = ubd_devs[unit].queue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 add_disk(disk);
852
853 *disk_out = disk;
854 return 0;
855}
856
857#define ROUND_BLOCK(n) ((n + ((1 << 9) - 1)) & (-1 << 9))
858
Jeff Dikef28169d2007-02-10 01:43:53 -0800859static int ubd_add(int n, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800861 struct ubd *ubd_dev = &ubd_devs[n];
Jeff Dikef28169d2007-02-10 01:43:53 -0800862 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800864 if(ubd_dev->file == NULL)
Jeff Dikeec7cf782005-09-03 15:57:29 -0700865 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800867 err = ubd_file_size(ubd_dev, &ubd_dev->size);
Jeff Dikef28169d2007-02-10 01:43:53 -0800868 if(err < 0){
869 *error_out = "Couldn't determine size of device's file";
Jeff Dike80c13742006-09-29 01:58:51 -0700870 goto out;
Jeff Dikef28169d2007-02-10 01:43:53 -0800871 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800873 ubd_dev->size = ROUND_BLOCK(ubd_dev->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874
Jeff Dikea0044bd2007-05-06 14:51:36 -0700875 INIT_LIST_HEAD(&ubd_dev->restart);
WANG Cong4f40c052007-11-05 14:50:59 -0800876 sg_init_table(ubd_dev->sg, MAX_SG);
Jeff Dikea0044bd2007-05-06 14:51:36 -0700877
Jeff Dike62f96cb2007-02-10 01:44:16 -0800878 err = -ENOMEM;
879 ubd_dev->queue = blk_init_queue(do_ubd_request, &ubd_dev->lock);
880 if (ubd_dev->queue == NULL) {
881 *error_out = "Failed to initialize device queue";
Jeff Dike80c13742006-09-29 01:58:51 -0700882 goto out;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800883 }
884 ubd_dev->queue->queuedata = ubd_dev;
885
Martin K. Petersen8a783622010-02-26 00:20:39 -0500886 blk_queue_max_segments(ubd_dev->queue, MAX_SG);
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700887 err = ubd_disk_register(UBD_MAJOR, ubd_dev->size, n, &ubd_gendisk[n]);
Jeff Dike62f96cb2007-02-10 01:44:16 -0800888 if(err){
889 *error_out = "Failed to register device";
890 goto out_cleanup;
891 }
Jeff Dike6c29256c2006-03-27 01:14:37 -0800892
Christoph Hellwig792dd4f2009-03-31 15:23:39 -0700893 if (fake_major != UBD_MAJOR)
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -0800894 ubd_disk_register(fake_major, ubd_dev->size, n,
Jeff Dike62f96cb2007-02-10 01:44:16 -0800895 &fake_gendisk[n]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896
Jeff Dike83380cc2008-02-04 22:31:18 -0800897 /*
898 * Perhaps this should also be under the "if (fake_major)" above
899 * using the fake_disk->disk_name
900 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 if (fake_ide)
902 make_ide_entries(ubd_gendisk[n]->disk_name);
903
Jeff Dikeec7cf782005-09-03 15:57:29 -0700904 err = 0;
Jeff Dikeec7cf782005-09-03 15:57:29 -0700905out:
906 return err;
Jeff Dike62f96cb2007-02-10 01:44:16 -0800907
908out_cleanup:
909 blk_cleanup_queue(ubd_dev->queue);
910 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911}
912
Jeff Dikef28169d2007-02-10 01:43:53 -0800913static int ubd_config(char *str, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914{
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800915 int n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916
Jeff Dikef28169d2007-02-10 01:43:53 -0800917 /* This string is possibly broken up and stored, so it's only
918 * freed if ubd_setup_common fails, or if only general options
919 * were set.
920 */
Jeff Dike970d6e32006-01-06 00:18:48 -0800921 str = kstrdup(str, GFP_KERNEL);
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800922 if (str == NULL) {
Jeff Dikef28169d2007-02-10 01:43:53 -0800923 *error_out = "Failed to allocate memory";
924 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 }
Jeff Dikef28169d2007-02-10 01:43:53 -0800926
927 ret = ubd_setup_common(str, &n, error_out);
928 if (ret)
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800929 goto err_free;
Jeff Dikef28169d2007-02-10 01:43:53 -0800930
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800931 if (n == -1) {
932 ret = 0;
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -0800933 goto err_free;
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800934 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935
Jeff Dikedc764e52007-05-06 14:51:41 -0700936 mutex_lock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -0800937 ret = ubd_add(n, error_out);
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800938 if (ret)
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800939 ubd_devs[n].file = NULL;
Jeff Dikedc764e52007-05-06 14:51:41 -0700940 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800942out:
Jeff Dikedc764e52007-05-06 14:51:41 -0700943 return ret;
Paolo 'Blaisorblade' Giarrussoe7f65522006-10-30 22:07:09 -0800944
945err_free:
946 kfree(str);
947 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948}
949
950static int ubd_get_config(char *name, char *str, int size, char **error_out)
951{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800952 struct ubd *ubd_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 int n, len = 0;
954
955 n = parse_unit(&name);
956 if((n >= MAX_DEV) || (n < 0)){
957 *error_out = "ubd_get_config : device number out of range";
Jeff Dikedc764e52007-05-06 14:51:41 -0700958 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 }
960
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800961 ubd_dev = &ubd_devs[n];
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800962 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800964 if(ubd_dev->file == NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 CONFIG_CHUNK(str, size, len, "", 1);
966 goto out;
967 }
968
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800969 CONFIG_CHUNK(str, size, len, ubd_dev->file, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800971 if(ubd_dev->cow.file != NULL){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 CONFIG_CHUNK(str, size, len, ",", 0);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800973 CONFIG_CHUNK(str, size, len, ubd_dev->cow.file, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 }
975 else CONFIG_CHUNK(str, size, len, "", 1);
976
977 out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800978 mutex_unlock(&ubd_lock);
Jeff Dikedc764e52007-05-06 14:51:41 -0700979 return len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980}
981
Jeff Dike29d56cf2005-06-25 14:55:25 -0700982static int ubd_id(char **str, int *start_out, int *end_out)
983{
Jeff Dikedc764e52007-05-06 14:51:41 -0700984 int n;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700985
986 n = parse_unit(str);
Jeff Dikedc764e52007-05-06 14:51:41 -0700987 *start_out = 0;
988 *end_out = MAX_DEV - 1;
989 return n;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700990}
991
Jeff Dikef28169d2007-02-10 01:43:53 -0800992static int ubd_remove(int n, char **error_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993{
Jeff Dike2e3f5252007-05-06 14:51:29 -0700994 struct gendisk *disk = ubd_gendisk[n];
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -0800995 struct ubd *ubd_dev;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700996 int err = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -0800998 mutex_lock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001000 ubd_dev = &ubd_devs[n];
Jeff Dike29d56cf2005-06-25 14:55:25 -07001001
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001002 if(ubd_dev->file == NULL)
Jeff Dike29d56cf2005-06-25 14:55:25 -07001003 goto out;
1004
1005 /* you cannot remove a open disk */
1006 err = -EBUSY;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001007 if(ubd_dev->count > 0)
Jeff Dike29d56cf2005-06-25 14:55:25 -07001008 goto out;
1009
Jeff Dikedc764e52007-05-06 14:51:41 -07001010 ubd_gendisk[n] = NULL;
Jeff Dikeb47d2de2007-05-06 14:51:01 -07001011 if(disk != NULL){
1012 del_gendisk(disk);
1013 put_disk(disk);
1014 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015
1016 if(fake_gendisk[n] != NULL){
1017 del_gendisk(fake_gendisk[n]);
1018 put_disk(fake_gendisk[n]);
1019 fake_gendisk[n] = NULL;
1020 }
1021
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 err = 0;
Jeff Dike2e3f5252007-05-06 14:51:29 -07001023 platform_device_unregister(&ubd_dev->pdev);
Jeff Dike29d56cf2005-06-25 14:55:25 -07001024out:
Paolo 'Blaisorblade' Giarrussod7fb2c32006-10-30 22:07:07 -08001025 mutex_unlock(&ubd_lock);
Jeff Dike29d56cf2005-06-25 14:55:25 -07001026 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027}
1028
Jeff Dikef28169d2007-02-10 01:43:53 -08001029/* All these are called by mconsole in process context and without
Jeff Dikeb8831a12007-02-10 01:44:17 -08001030 * ubd-specific locks. The structure itself is const except for .list.
Jeff Dikef28169d2007-02-10 01:43:53 -08001031 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032static struct mc_device ubd_mc = {
Jeff Dike84f48d42007-02-10 01:44:01 -08001033 .list = LIST_HEAD_INIT(ubd_mc.list),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 .name = "ubd",
1035 .config = ubd_config,
Jeff Dikedc764e52007-05-06 14:51:41 -07001036 .get_config = ubd_get_config,
Jeff Dike29d56cf2005-06-25 14:55:25 -07001037 .id = ubd_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 .remove = ubd_remove,
1039};
1040
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001041static int __init ubd_mc_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042{
1043 mconsole_register_dev(&ubd_mc);
1044 return 0;
1045}
1046
1047__initcall(ubd_mc_init);
1048
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001049static int __init ubd0_init(void)
1050{
1051 struct ubd *ubd_dev = &ubd_devs[0];
1052
Jeff Dikeb8831a12007-02-10 01:44:17 -08001053 mutex_lock(&ubd_lock);
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001054 if(ubd_dev->file == NULL)
1055 ubd_dev->file = "root_fs";
Jeff Dikeb8831a12007-02-10 01:44:17 -08001056 mutex_unlock(&ubd_lock);
1057
Jeff Dikedc764e52007-05-06 14:51:41 -07001058 return 0;
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001059}
1060
1061__initcall(ubd0_init);
1062
Jeff Dikeb8831a12007-02-10 01:44:17 -08001063/* Used in ubd_init, which is an initcall */
Russell King3ae5eae2005-11-09 22:32:44 +00001064static struct platform_driver ubd_driver = {
1065 .driver = {
1066 .name = DRIVER_NAME,
1067 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068};
1069
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001070static int __init ubd_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071{
Jeff Dikef28169d2007-02-10 01:43:53 -08001072 char *error;
1073 int i, err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074
Christoph Hellwig792dd4f2009-03-31 15:23:39 -07001075 if (register_blkdev(UBD_MAJOR, "ubd"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 return -1;
1077
Christoph Hellwig792dd4f2009-03-31 15:23:39 -07001078 if (fake_major != UBD_MAJOR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 char name[sizeof("ubd_nnn\0")];
1080
1081 snprintf(name, sizeof(name), "ubd_%d", fake_major);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 if (register_blkdev(fake_major, "ubd"))
1083 return -1;
1084 }
Russell King3ae5eae2005-11-09 22:32:44 +00001085 platform_driver_register(&ubd_driver);
Jeff Dikedc764e52007-05-06 14:51:41 -07001086 mutex_lock(&ubd_lock);
Jeff Dikef28169d2007-02-10 01:43:53 -08001087 for (i = 0; i < MAX_DEV; i++){
1088 err = ubd_add(i, &error);
1089 if(err)
1090 printk(KERN_ERR "Failed to initialize ubd device %d :"
1091 "%s\n", i, error);
1092 }
Jeff Dikedc764e52007-05-06 14:51:41 -07001093 mutex_unlock(&ubd_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 return 0;
1095}
1096
1097late_initcall(ubd_init);
1098
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001099static int __init ubd_driver_init(void){
Jeff Dike91acb212005-10-10 23:10:32 -04001100 unsigned long stack;
1101 int err;
1102
1103 /* Set by CONFIG_BLK_DEV_UBD_SYNC or ubd=sync.*/
1104 if(global_openflags.s){
1105 printk(KERN_INFO "ubd: Synchronous mode\n");
1106 /* Letting ubd=sync be like using ubd#s= instead of ubd#= is
1107 * enough. So use anyway the io thread. */
1108 }
1109 stack = alloc_stack(0, 0);
Jeff Dike6c29256c2006-03-27 01:14:37 -08001110 io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *),
Jeff Dike91acb212005-10-10 23:10:32 -04001111 &thread_fd);
1112 if(io_pid < 0){
Jeff Dike6c29256c2006-03-27 01:14:37 -08001113 printk(KERN_ERR
Jeff Dike91acb212005-10-10 23:10:32 -04001114 "ubd : Failed to start I/O thread (errno = %d) - "
1115 "falling back to synchronous I/O\n", -io_pid);
1116 io_pid = -1;
Jeff Dikedc764e52007-05-06 14:51:41 -07001117 return 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001118 }
Jeff Dike6c29256c2006-03-27 01:14:37 -08001119 err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr,
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001120 IRQF_DISABLED, "ubd", ubd_devs);
Jeff Dike91acb212005-10-10 23:10:32 -04001121 if(err != 0)
1122 printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err);
Jeff Dikef4c57a72006-03-31 02:30:10 -08001123 return 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001124}
1125
1126device_initcall(ubd_driver_init);
1127
Al Viroa625c992008-03-02 09:16:26 -05001128static int ubd_open(struct block_device *bdev, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129{
Al Viroa625c992008-03-02 09:16:26 -05001130 struct gendisk *disk = bdev->bd_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001131 struct ubd *ubd_dev = disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 int err = 0;
1133
Arnd Bergmann9a181c52010-09-11 18:38:03 +02001134 mutex_lock(&ubd_mutex);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001135 if(ubd_dev->count == 0){
1136 err = ubd_open_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 if(err){
1138 printk(KERN_ERR "%s: Can't open \"%s\": errno = %d\n",
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001139 disk->disk_name, ubd_dev->file, -err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 goto out;
1141 }
1142 }
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001143 ubd_dev->count++;
1144 set_disk_ro(disk, !ubd_dev->openflags.w);
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -07001145
1146 /* This should no more be needed. And it didn't work anyway to exclude
1147 * read-write remounting of filesystems.*/
Al Viroa625c992008-03-02 09:16:26 -05001148 /*if((mode & FMODE_WRITE) && !ubd_dev->openflags.w){
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -08001149 if(--ubd_dev->count == 0) ubd_close_dev(ubd_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 err = -EROFS;
Paolo 'Blaisorblade' Giarrusso2c49be92005-05-01 08:58:57 -07001151 }*/
Arnd Bergmann6e9624b2010-08-07 18:25:34 +02001152out:
Arnd Bergmann9a181c52010-09-11 18:38:03 +02001153 mutex_unlock(&ubd_mutex);
Jeff Dikedc764e52007-05-06 14:51:41 -07001154 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155}
1156
Al Viroa625c992008-03-02 09:16:26 -05001157static int ubd_release(struct gendisk *disk, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001159 struct ubd *ubd_dev = disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160
Arnd Bergmann9a181c52010-09-11 18:38:03 +02001161 mutex_lock(&ubd_mutex);
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001162 if(--ubd_dev->count == 0)
Paolo 'Blaisorblade' Giarrusso5f75a4f2006-10-30 22:07:06 -08001163 ubd_close_dev(ubd_dev);
Arnd Bergmann9a181c52010-09-11 18:38:03 +02001164 mutex_unlock(&ubd_mutex);
Jeff Dikedc764e52007-05-06 14:51:41 -07001165 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166}
1167
Jeff Dike91acb212005-10-10 23:10:32 -04001168static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask,
1169 __u64 *cow_offset, unsigned long *bitmap,
1170 __u64 bitmap_offset, unsigned long *bitmap_words,
1171 __u64 bitmap_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172{
Jeff Dike91acb212005-10-10 23:10:32 -04001173 __u64 sector = io_offset >> 9;
1174 int i, update_bitmap = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175
Jeff Dike91acb212005-10-10 23:10:32 -04001176 for(i = 0; i < length >> 9; i++){
1177 if(cow_mask != NULL)
1178 ubd_set_bit(i, (unsigned char *) cow_mask);
1179 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
1180 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181
Jeff Dike91acb212005-10-10 23:10:32 -04001182 update_bitmap = 1;
1183 ubd_set_bit(sector + i, (unsigned char *) bitmap);
1184 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185
Jeff Dike91acb212005-10-10 23:10:32 -04001186 if(!update_bitmap)
1187 return;
1188
1189 *cow_offset = sector / (sizeof(unsigned long) * 8);
1190
1191 /* This takes care of the case where we're exactly at the end of the
1192 * device, and *cow_offset + 1 is off the end. So, just back it up
1193 * by one word. Thanks to Lynn Kerby for the fix and James McMechan
1194 * for the original diagnosis.
1195 */
Jiri Olsa6d074242008-05-12 14:01:56 -07001196 if (*cow_offset == (DIV_ROUND_UP(bitmap_len,
1197 sizeof(unsigned long)) - 1))
Jeff Dike91acb212005-10-10 23:10:32 -04001198 (*cow_offset)--;
1199
1200 bitmap_words[0] = bitmap[*cow_offset];
1201 bitmap_words[1] = bitmap[*cow_offset + 1];
1202
1203 *cow_offset *= sizeof(unsigned long);
1204 *cow_offset += bitmap_offset;
1205}
1206
1207static void cowify_req(struct io_thread_req *req, unsigned long *bitmap,
1208 __u64 bitmap_offset, __u64 bitmap_len)
1209{
1210 __u64 sector = req->offset >> 9;
1211 int i;
1212
1213 if(req->length > (sizeof(req->sector_mask) * 8) << 9)
1214 panic("Operation too long");
1215
1216 if(req->op == UBD_READ) {
1217 for(i = 0; i < req->length >> 9; i++){
1218 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
Jeff Dike6c29256c2006-03-27 01:14:37 -08001219 ubd_set_bit(i, (unsigned char *)
Jeff Dike91acb212005-10-10 23:10:32 -04001220 &req->sector_mask);
Jeff Dikedc764e52007-05-06 14:51:41 -07001221 }
Jeff Dike91acb212005-10-10 23:10:32 -04001222 }
1223 else cowify_bitmap(req->offset, req->length, &req->sector_mask,
1224 &req->cow_offset, bitmap, bitmap_offset,
1225 req->bitmap_words, bitmap_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226}
1227
Jeff Dike62f96cb2007-02-10 01:44:16 -08001228/* Called with dev->lock held */
Jeff Dikea0044bd2007-05-06 14:51:36 -07001229static void prepare_request(struct request *req, struct io_thread_req *io_req,
1230 unsigned long long offset, int page_offset,
1231 int len, struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232{
1233 struct gendisk *disk = req->rq_disk;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001234 struct ubd *ubd_dev = disk->private_data;
Jeff Dike91acb212005-10-10 23:10:32 -04001235
Jeff Dike62f96cb2007-02-10 01:44:16 -08001236 io_req->req = req;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001237 io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd :
1238 ubd_dev->fd;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001239 io_req->fds[1] = ubd_dev->fd;
Jeff Dike91acb212005-10-10 23:10:32 -04001240 io_req->cow_offset = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 io_req->offset = offset;
1242 io_req->length = len;
1243 io_req->error = 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001244 io_req->sector_mask = 0;
1245
1246 io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247 io_req->offsets[0] = 0;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001248 io_req->offsets[1] = ubd_dev->cow.data_offset;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001249 io_req->buffer = page_address(page) + page_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 io_req->sectorsize = 1 << 9;
1251
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001252 if(ubd_dev->cow.file != NULL)
Jeff Dikea0044bd2007-05-06 14:51:36 -07001253 cowify_req(io_req, ubd_dev->cow.bitmap,
1254 ubd_dev->cow.bitmap_offset, ubd_dev->cow.bitmap_len);
Jeff Dike91acb212005-10-10 23:10:32 -04001255
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256}
1257
Jeff Dike62f96cb2007-02-10 01:44:16 -08001258/* Called with dev->lock held */
Jens Axboe165125e2007-07-24 09:28:11 +02001259static void do_ubd_request(struct request_queue *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260{
Jeff Dike2adcec22007-05-06 14:51:37 -07001261 struct io_thread_req *io_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 struct request *req;
Tejun Heof81f2f72009-04-28 13:06:10 +09001263 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264
Jeff Dikea0044bd2007-05-06 14:51:36 -07001265 while(1){
Jeff Dike2a9529a2007-03-29 01:20:27 -07001266 struct ubd *dev = q->queuedata;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001267 if(dev->end_sg == 0){
Tejun Heo9934c8c2009-05-08 11:54:16 +09001268 struct request *req = blk_fetch_request(q);
Jeff Dikea0044bd2007-05-06 14:51:36 -07001269 if(req == NULL)
1270 return;
1271
1272 dev->request = req;
Tejun Heo47526902010-10-15 12:56:21 +02001273 dev->rq_pos = blk_rq_pos(req);
Jeff Dikea0044bd2007-05-06 14:51:36 -07001274 dev->start_sg = 0;
1275 dev->end_sg = blk_rq_map_sg(q, req, dev->sg);
Jeff Dike91acb212005-10-10 23:10:32 -04001276 }
Jeff Dikea0044bd2007-05-06 14:51:36 -07001277
1278 req = dev->request;
1279 while(dev->start_sg < dev->end_sg){
1280 struct scatterlist *sg = &dev->sg[dev->start_sg];
1281
Jeff Dike2adcec22007-05-06 14:51:37 -07001282 io_req = kmalloc(sizeof(struct io_thread_req),
Peter Zijlstra990c5582007-05-06 14:51:38 -07001283 GFP_ATOMIC);
Jeff Dike2adcec22007-05-06 14:51:37 -07001284 if(io_req == NULL){
1285 if(list_empty(&dev->restart))
1286 list_add(&dev->restart, &restart);
1287 return;
1288 }
1289 prepare_request(req, io_req,
Tejun Heo47526902010-10-15 12:56:21 +02001290 (unsigned long long)dev->rq_pos << 9,
Jens Axboe45711f12007-10-22 21:19:53 +02001291 sg->offset, sg->length, sg_page(sg));
Jeff Dikea0044bd2007-05-06 14:51:36 -07001292
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001293 n = os_write_file(thread_fd, &io_req,
1294 sizeof(struct io_thread_req *));
Jeff Dike2adcec22007-05-06 14:51:37 -07001295 if(n != sizeof(struct io_thread_req *)){
Jeff Dikea0044bd2007-05-06 14:51:36 -07001296 if(n != -EAGAIN)
1297 printk("write to io thread failed, "
1298 "errno = %d\n", -n);
1299 else if(list_empty(&dev->restart))
1300 list_add(&dev->restart, &restart);
Miklos Szeredi12429bf2007-11-28 16:21:52 -08001301 kfree(io_req);
Jeff Dikea0044bd2007-05-06 14:51:36 -07001302 return;
1303 }
1304
Tejun Heo47526902010-10-15 12:56:21 +02001305 dev->rq_pos += sg->length >> 9;
Jeff Dikea0044bd2007-05-06 14:51:36 -07001306 dev->start_sg++;
1307 }
1308 dev->end_sg = 0;
1309 dev->request = NULL;
Jeff Dike91acb212005-10-10 23:10:32 -04001310 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311}
1312
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001313static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
1314{
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001315 struct ubd *ubd_dev = bdev->bd_disk->private_data;
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001316
1317 geo->heads = 128;
1318 geo->sectors = 32;
Paolo 'Blaisorblade' Giarrusso7d314e32006-10-30 22:07:05 -08001319 geo->cylinders = ubd_dev->size / (128 * 32 * 512);
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001320 return 0;
1321}
1322
Al Viroa625c992008-03-02 09:16:26 -05001323static int ubd_ioctl(struct block_device *bdev, fmode_t mode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 unsigned int cmd, unsigned long arg)
1325{
Al Viroa625c992008-03-02 09:16:26 -05001326 struct ubd *ubd_dev = bdev->bd_disk->private_data;
Bartlomiej Zolnierkiewicz73855e12009-04-01 21:42:21 +02001327 u16 ubd_id[ATA_ID_WORDS];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328
1329 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 struct cdrom_volctrl volume;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331 case HDIO_GET_IDENTITY:
Bartlomiej Zolnierkiewicz73855e12009-04-01 21:42:21 +02001332 memset(&ubd_id, 0, ATA_ID_WORDS * 2);
1333 ubd_id[ATA_ID_CYLS] = ubd_dev->size / (128 * 32 * 512);
1334 ubd_id[ATA_ID_HEADS] = 128;
1335 ubd_id[ATA_ID_SECTORS] = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 if(copy_to_user((char __user *) arg, (char *) &ubd_id,
1337 sizeof(ubd_id)))
Jeff Dikedc764e52007-05-06 14:51:41 -07001338 return -EFAULT;
1339 return 0;
Jeff Dikeb8831a12007-02-10 01:44:17 -08001340
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 case CDROMVOLREAD:
1342 if(copy_from_user(&volume, (char __user *) arg, sizeof(volume)))
Jeff Dikedc764e52007-05-06 14:51:41 -07001343 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 volume.channel0 = 255;
1345 volume.channel1 = 255;
1346 volume.channel2 = 255;
1347 volume.channel3 = 255;
1348 if(copy_to_user((char __user *) arg, &volume, sizeof(volume)))
Jeff Dikedc764e52007-05-06 14:51:41 -07001349 return -EFAULT;
1350 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 }
Jeff Dikedc764e52007-05-06 14:51:41 -07001352 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353}
1354
Jeff Dike91acb212005-10-10 23:10:32 -04001355static int update_bitmap(struct io_thread_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356{
Jeff Dike91acb212005-10-10 23:10:32 -04001357 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358
Jeff Dike91acb212005-10-10 23:10:32 -04001359 if(req->cow_offset == -1)
Jeff Dikedc764e52007-05-06 14:51:41 -07001360 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361
Jeff Dike91acb212005-10-10 23:10:32 -04001362 n = os_seek_file(req->fds[1], req->cow_offset);
1363 if(n < 0){
1364 printk("do_io - bitmap lseek failed : err = %d\n", -n);
Jeff Dikedc764e52007-05-06 14:51:41 -07001365 return 1;
Jeff Dike91acb212005-10-10 23:10:32 -04001366 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001368 n = os_write_file(req->fds[1], &req->bitmap_words,
1369 sizeof(req->bitmap_words));
Jeff Dike91acb212005-10-10 23:10:32 -04001370 if(n != sizeof(req->bitmap_words)){
1371 printk("do_io - bitmap update failed, err = %d fd = %d\n", -n,
1372 req->fds[1]);
Jeff Dikedc764e52007-05-06 14:51:41 -07001373 return 1;
Jeff Dike91acb212005-10-10 23:10:32 -04001374 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375
Jeff Dikedc764e52007-05-06 14:51:41 -07001376 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377}
Jeff Dike91acb212005-10-10 23:10:32 -04001378
WANG Cong5dc62b12008-04-28 02:13:58 -07001379static void do_io(struct io_thread_req *req)
Jeff Dike91acb212005-10-10 23:10:32 -04001380{
1381 char *buf;
1382 unsigned long len;
1383 int n, nsectors, start, end, bit;
1384 int err;
1385 __u64 off;
1386
1387 nsectors = req->length / req->sectorsize;
1388 start = 0;
1389 do {
1390 bit = ubd_test_bit(start, (unsigned char *) &req->sector_mask);
1391 end = start;
1392 while((end < nsectors) &&
1393 (ubd_test_bit(end, (unsigned char *)
1394 &req->sector_mask) == bit))
1395 end++;
1396
1397 off = req->offset + req->offsets[bit] +
1398 start * req->sectorsize;
1399 len = (end - start) * req->sectorsize;
1400 buf = &req->buffer[start * req->sectorsize];
1401
1402 err = os_seek_file(req->fds[bit], off);
1403 if(err < 0){
1404 printk("do_io - lseek failed : err = %d\n", -err);
1405 req->error = 1;
1406 return;
1407 }
1408 if(req->op == UBD_READ){
1409 n = 0;
1410 do {
1411 buf = &buf[n];
1412 len -= n;
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001413 n = os_read_file(req->fds[bit], buf, len);
Jeff Dike91acb212005-10-10 23:10:32 -04001414 if (n < 0) {
1415 printk("do_io - read failed, err = %d "
1416 "fd = %d\n", -n, req->fds[bit]);
1417 req->error = 1;
1418 return;
1419 }
1420 } while((n < len) && (n != 0));
1421 if (n < len) memset(&buf[n], 0, len - n);
1422 } else {
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001423 n = os_write_file(req->fds[bit], buf, len);
Jeff Dike91acb212005-10-10 23:10:32 -04001424 if(n != len){
1425 printk("do_io - write failed err = %d "
1426 "fd = %d\n", -n, req->fds[bit]);
1427 req->error = 1;
1428 return;
1429 }
1430 }
1431
1432 start = end;
1433 } while(start < nsectors);
1434
1435 req->error = update_bitmap(req);
1436}
1437
1438/* Changed in start_io_thread, which is serialized by being called only
1439 * from ubd_init, which is an initcall.
1440 */
1441int kernel_fd = -1;
1442
Paolo 'Blaisorblade' Giarrussod8d7c282006-10-30 22:07:12 -08001443/* Only changed by the io thread. XXX: currently unused. */
1444static int io_count = 0;
Jeff Dike91acb212005-10-10 23:10:32 -04001445
1446int io_thread(void *arg)
1447{
Jeff Dike2adcec22007-05-06 14:51:37 -07001448 struct io_thread_req *req;
Jeff Dike91acb212005-10-10 23:10:32 -04001449 int n;
1450
1451 ignore_sigwinch_sig();
1452 while(1){
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001453 n = os_read_file(kernel_fd, &req,
Jeff Dike2adcec22007-05-06 14:51:37 -07001454 sizeof(struct io_thread_req *));
1455 if(n != sizeof(struct io_thread_req *)){
Jeff Dike91acb212005-10-10 23:10:32 -04001456 if(n < 0)
1457 printk("io_thread - read failed, fd = %d, "
1458 "err = %d\n", kernel_fd, -n);
1459 else {
1460 printk("io_thread - short read, fd = %d, "
1461 "length = %d\n", kernel_fd, n);
1462 }
1463 continue;
1464 }
1465 io_count++;
Jeff Dike2adcec22007-05-06 14:51:37 -07001466 do_io(req);
Jeff Dikea6ea4cc2007-05-06 14:51:43 -07001467 n = os_write_file(kernel_fd, &req,
Jeff Dike2adcec22007-05-06 14:51:37 -07001468 sizeof(struct io_thread_req *));
1469 if(n != sizeof(struct io_thread_req *))
Jeff Dike91acb212005-10-10 23:10:32 -04001470 printk("io_thread - write failed, fd = %d, err = %d\n",
1471 kernel_fd, -n);
1472 }
Jeff Dike91acb212005-10-10 23:10:32 -04001473
Jeff Dike1b57e9c2006-01-06 00:18:49 -08001474 return 0;
1475}