diff options
author | cvs-fast-export <cvs-fast-export> | 2002-07-21 22:06:46 +0000 |
---|---|---|
committer | cvs-fast-export <cvs-fast-export> | 2002-07-21 22:06:46 +0000 |
commit | 77fef6c99d083f485c94d757c34a359dee107b18 (patch) | |
tree | 36a7617c7076430a8e5a433b5974ac95573e372d | |
parent | 8ef331c2a7c80ea47f2d4a144e4bbcc9676a68fe (diff) | |
download | uml-history-v_2_4_18_42.tar.gz |
Synthetic commit for tag v_2_4_18_42v_2_4_18_42
-rw-r--r-- | arch/um/drivers/harddog.c | 192 | ||||
-rw-r--r-- | arch/um/drivers/port.c | 190 | ||||
-rw-r--r-- | arch/um/drivers/ubd.c | 924 |
3 files changed, 0 insertions, 1306 deletions
diff --git a/arch/um/drivers/harddog.c b/arch/um/drivers/harddog.c deleted file mode 100644 index e2214e1..0000000 --- a/arch/um/drivers/harddog.c +++ /dev/null @@ -1,192 +0,0 @@ -/* UML hardware watchdog, shamelessly stolen from: - * - * SoftDog 0.05: A Software Watchdog Device - * - * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved. - * http://www.redhat.com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide - * warranty for any of this software. This material is provided - * "AS-IS" and at no charge. - * - * (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk> - * - * Software only watchdog driver. Unlike its big brother the WDT501P - * driver this won't always recover a failed machine. - * - * 03/96: Angelo Haritsis <ah@doc.ic.ac.uk> : - * Modularised. - * Added soft_margin; use upon insmod to change the timer delay. - * NB: uses same minor as wdt (WATCHDOG_MINOR); we could use separate - * minors. - * - * 19980911 Alan Cox - * Made SMP safe for 2.3.x - * - * 20011127 Joel Becker (jlbec@evilplan.org> - * Added soft_noboot; Allows testing the softdog trigger without - * requiring a recompile. - * Added WDIOC_GETTIMEOUT and WDIOC_SETTIMOUT. - */ - -#include <linux/module.h> -#include <linux/config.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/fs.h> -#include <linux/mm.h> -#include <linux/miscdevice.h> -#include <linux/watchdog.h> -#include <linux/reboot.h> -#include <linux/smp_lock.h> -#include <linux/init.h> -#include <asm/uaccess.h> -#include "helper.h" -#include "mconsole.h" - -MODULE_LICENSE("GPL"); - -static int timer_alive; - -static int harddog_in_fd = -1; -static int harddog_out_fd = -1; - -/* - * Allow only one person to hold it open - */ - -extern int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock); - -static int harddog_open(struct inode *inode, struct file *file) -{ - int err; - char *sock = NULL; - - if(timer_alive) - return -EBUSY; -#ifdef CONFIG_HARDDOG_NOWAYOUT - MOD_INC_USE_COUNT; -#endif - -#ifdef CONFIG_MCONSOLE - sock = mconsole_notify_socket(); -#endif - err = start_watchdog(&harddog_in_fd, &harddog_out_fd, sock); - if(err) return(err); - - timer_alive = 1; - return 0; -} - -extern void stop_watchdog(int in_fd, int out_fd); - -static int harddog_release(struct inode *inode, struct file *file) -{ - /* - * Shut off the timer. - */ - lock_kernel(); - - stop_watchdog(harddog_in_fd, harddog_out_fd); - harddog_in_fd = -1; - harddog_out_fd = -1; - - timer_alive=0; - unlock_kernel(); - return 0; -} - -extern int ping_watchdog(int fd); - -static ssize_t harddog_write(struct file *file, const char *data, size_t len, - loff_t *ppos) -{ - /* Can't seek (pwrite) on this device */ - if (ppos != &file->f_pos) - return -ESPIPE; - - /* - * Refresh the timer. - */ - if(len) - return(ping_watchdog(harddog_out_fd)); - return 0; -} - -static int harddog_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - static struct watchdog_info ident = { - WDIOF_SETTIMEOUT, - 0, - "UML Hardware Watchdog" - }; - switch (cmd) { - default: - return -ENOTTY; - case WDIOC_GETSUPPORT: - if(copy_to_user((struct harddog_info *)arg, &ident, - sizeof(ident))) - return -EFAULT; - return 0; - case WDIOC_GETSTATUS: - case WDIOC_GETBOOTSTATUS: - return put_user(0,(int *)arg); - case WDIOC_KEEPALIVE: - return(ping_watchdog(harddog_out_fd)); - } -} - -static struct file_operations harddog_fops = { - owner: THIS_MODULE, - write: harddog_write, - ioctl: harddog_ioctl, - open: harddog_open, - release: harddog_release, -}; - -static struct miscdevice harddog_miscdev = { - minor: WATCHDOG_MINOR, - name: "watchdog", - fops: &harddog_fops, -}; - -static char banner[] __initdata = KERN_INFO "UML Watchdog Timer\n"; - -static int __init harddog_init(void) -{ - int ret; - - ret = misc_register(&harddog_miscdev); - - if (ret) - return ret; - - printk(banner); - - return(0); -} - -static void __exit harddog_exit(void) -{ - misc_deregister(&harddog_miscdev); -} - -module_init(harddog_init); -module_exit(harddog_exit); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/port.c b/arch/um/drivers/port.c deleted file mode 100644 index 556c174..0000000 --- a/arch/um/drivers/port.c +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include <stddef.h> -#include <stdlib.h> -#include <errno.h> -#include <unistd.h> -#include <string.h> -#include <termios.h> -#include <sys/socket.h> -#include <sys/un.h> -#include <netinet/in.h> -#include "user_util.h" -#include "kern_util.h" -#include "user.h" -#include "chan_user.h" -#include "port.h" -#include "helper.h" -#include "os.h" - -struct port_chan { - int raw; - struct termios tt; - void *kernel_data; -}; - -void *port_init(char *str, int device, struct chan_opts *opts) -{ - struct port_chan *data; - void *kern_data; - char *end; - int port; - - if(*str != ':'){ - printk("port_init : channel type 'port' must specify a " - "port number\n"); - return(NULL); - } - str++; - port = strtoul(str, &end, 0); - if(*end != '\0'){ - printk("port_init : couldn't parse port '%s'\n", str); - return(NULL); - } - - if((kern_data = port_data(port)) == NULL) return(NULL); - - if((data = um_kmalloc(sizeof(*data))) == NULL) return(NULL); - *data = ((struct port_chan) { raw : opts->raw, - kernel_data : kern_data }); - - return(data); -} - -int port_open(int input, int output, int primary, void *d) -{ - struct port_chan *data = d; - int fd; - - fd = port_wait(data->kernel_data); - if((fd >= 0) && data->raw){ - tcgetattr(fd, &data->tt); - raw(fd, 0); - } - return(fd); -} - -void port_close(int fd, void *d) -{ - struct port_chan *data = d; - - port_remove_dev(data->kernel_data); - close(fd); -} - -int port_console_write(int fd, const char *buf, int n, void *d) -{ - struct port_chan *data = d; - - return(generic_console_write(fd, buf, n, &data->tt)); -} - -void port_free(void *d) -{ - struct port_chan *data = d; - - port_kern_free(data->kernel_data); - kfree(data); -} - -struct chan_ops port_ops = { - init: port_init, - open: port_open, - close: generic_close, - read: generic_read, - write: generic_write, - console_write: port_console_write, - window_size: generic_window_size, - free: port_free, - winch: 1, -}; - -int port_listen_fd(int port) -{ - struct sockaddr_in addr; - int fd, err; - - fd = socket(PF_INET, SOCK_STREAM, 0); - if(fd == -1) return(-errno); - - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr.s_addr = htonl(INADDR_ANY); - if(bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0){ - err = -errno; - goto out; - } - - if(listen(fd, 1) < 0){ - err = -errno; - goto out; - } - - return(fd); - out: - os_close_file(fd); - return(err); -} - -struct port_pre_exec_data { - int sock_fd; - int pipe_fd; -}; - -void port_pre_exec(void *arg) -{ - struct port_pre_exec_data *data = arg; - - dup2(data->sock_fd, 0); - dup2(data->sock_fd, 1); - dup2(data->sock_fd, 2); - close(data->sock_fd); - dup2(data->pipe_fd, 3); - shutdown(3, SHUT_RD); - close(data->pipe_fd); -} - -int port_connection(int fd, int *socket) -{ - int new, err; - char *argv[] = { "/usr/sbin/in.telnetd", "-L", - "/usr/lib/uml/port-helper", NULL }; - struct port_pre_exec_data data; - - if((new = accept(fd, NULL, 0)) < 0) return(-errno); - - err = os_pipe(socket, 0); - if(err) goto out_close; - - data = ((struct port_pre_exec_data) - { sock_fd : new, - pipe_fd : socket[1] }); - - err = run_helper(port_pre_exec, &data, argv, NULL); - if(err < 0) goto out_shutdown; - - return(new); - - out_shutdown: - shutdown(socket[0], SHUT_RDWR); - close(socket[0]); - shutdown(socket[1], SHUT_RDWR); - close(socket[1]); - out_close: - close(new); - return(err); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/ubd.c b/arch/um/drivers/ubd.c deleted file mode 100644 index 197071d..0000000 --- a/arch/um/drivers/ubd.c +++ /dev/null @@ -1,924 +0,0 @@ -/* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -/* 2001-09-28...2002-04-17 - * Partition stuff by James_McMechan@hotmail.com - * old style ubd by setting UBD_SHIFT to 0 - */ - -#define MAJOR_NR UBD_MAJOR -#define UBD_SHIFT 4 - -#include "linux/config.h" -#include "linux/blk.h" -#include "linux/blkdev.h" -#include "linux/hdreg.h" -#include "linux/init.h" -#include "linux/devfs_fs_kernel.h" -#include "linux/cdrom.h" -#include "linux/proc_fs.h" -#include "linux/ctype.h" -#include "linux/capability.h" -#include "linux/mm.h" -#include "linux/vmalloc.h" -#include "linux/blkpg.h" -#include "linux/genhd.h" -#include "asm/segment.h" -#include "asm/uaccess.h" -#include "asm/irq.h" -#include "asm/types.h" -#include "user_util.h" -#include "mem_user.h" -#include "kern_util.h" -#include "kern.h" -#include "mconsole_kern.h" -#include "init.h" -#include "irq_user.h" -#include "ubd_user.h" -#include "2_5compat.h" -#include "os.h" - -static int ubd_open(struct inode * inode, struct file * filp); -static int ubd_release(struct inode * inode, struct file * file); -static int ubd_ioctl(struct inode * inode, struct file * file, - unsigned int cmd, unsigned long arg); -static int ubd_revalidate(kdev_t rdev); - -#define MAX_DEV (8) -#define MAX_MINOR (MAX_DEV << UBD_SHIFT) - -/* block size in bytes */ -static int blk_sizes[MAX_MINOR] = { [ 0 ... MAX_MINOR - 1 ] = BLOCK_SIZE }; - -/* number of bytes per sector */ -static int hardsect_sizes[MAX_MINOR] = { [ 0 ... MAX_MINOR - 1 ] = 512 }; - -/* device size in KB */ -static int sizes[MAX_MINOR] = { [ 0 ... MAX_MINOR - 1 ] = 0 }; - -static struct block_device_operations ubd_blops = { - open: ubd_open, - release: ubd_release, - ioctl: ubd_ioctl, - revalidate: ubd_revalidate, -}; - -static struct hd_struct ubd_part[MAX_MINOR] = - { [ 0 ... MAX_MINOR - 1 ] = { 0, 0, 0 } }; - -static request_queue_t *ubd_queue; - -static int fake_major = 0; - -#define INIT_GENDISK(maj, name, parts, shift, bsizes, max, blops) \ -{ \ - major : maj, \ - major_name : name, \ - minor_shift : shift, \ - max_p : 1 << shift, \ - part : parts, \ - sizes : bsizes, \ - nr_real : max, \ - real_devices : NULL, \ - next : NULL, \ - fops : blops, \ - de_arr : NULL, \ - flags : 0 \ -} - -static struct gendisk ubd_gendisk = INIT_GENDISK(MAJOR_NR, "ubd", ubd_part, - UBD_SHIFT, sizes, MAX_DEV, - &ubd_blops); -static struct gendisk fake_gendisk = INIT_GENDISK(0, "ubd", ubd_part, - UBD_SHIFT, sizes, MAX_DEV, - &ubd_blops); - -#ifdef CONFIG_BLK_DEV_UBD_SYNC -#define OPEN_FLAGS ((struct openflags) { r : 1, w : 1, s : 1, c : 0 }) -#else -#define OPEN_FLAGS ((struct openflags) { r : 1, w : 1, s : 0, c : 0 }) -#endif - -static struct openflags global_openflags = OPEN_FLAGS; - -struct cow { - char *file; - int fd; - unsigned long *bitmap; - unsigned long bitmap_len; - int bitmap_offset; - int data_offset; -}; - -struct ubd { - char *file; - int is_dir; - int count; - int fd; - __u64 size; - struct openflags boot_openflags; - struct openflags openflags; - devfs_handle_t real; - devfs_handle_t fake; - struct cow cow; -}; - -#define DEFAULT_COW { \ - file: NULL, \ - fd: -1, \ - bitmap: NULL, \ - bitmap_offset: 0, \ - data_offset: 0, \ -} - -#define DEFAULT_UBD { \ - file: NULL, \ - is_dir: 0, \ - count: 0, \ - fd: -1, \ - size: -1, \ - boot_openflags: OPEN_FLAGS, \ - openflags: OPEN_FLAGS, \ - real: NULL, \ - fake: NULL, \ - cow: DEFAULT_COW, \ -} - -struct ubd ubd_dev[MAX_DEV] = { -{ - file: "root_fs", - is_dir: 0, - count: 0, - fd: -1, - size: 0, - boot_openflags: OPEN_FLAGS, - openflags: OPEN_FLAGS, - real: NULL, - fake: NULL, - cow: DEFAULT_COW, -}, -[ 1 ... MAX_DEV - 1 ] = DEFAULT_UBD -}; - -static struct hd_driveid ubd_id = { - cyls: 0, - heads: 128, - sectors: 32, -}; - -static int fake_ide = 0; -static struct proc_dir_entry *proc_ide_root = NULL; -static struct proc_dir_entry *proc_ide = NULL; - -static void make_proc_ide(void) -{ - proc_ide_root = proc_mkdir("ide", 0); - proc_ide = proc_mkdir("ide0", proc_ide_root); -} - -static int proc_ide_read_media(char *page, char **start, off_t off, int count, - int *eof, void *data) -{ - int len; - - strcpy(page, "disk\n"); - len = strlen("disk\n"); - len -= off; - if (len < count){ - *eof = 1; - if (len <= 0) return 0; - } - else len = count; - *start = page + off; - return len; - -} - -static void make_ide_entries(char *dev_name) -{ - struct proc_dir_entry *dir, *ent; - char name[64]; - - if(!fake_ide) return; - if(proc_ide_root == NULL) make_proc_ide(); - dir = proc_mkdir(dev_name, proc_ide); - ent = create_proc_entry("media", S_IFREG|S_IRUGO, dir); - if(!ent) return; - ent->nlink = 1; - ent->data = NULL; - ent->read_proc = proc_ide_read_media; - ent->write_proc = NULL; - sprintf(name,"ide0/%s", dev_name); - proc_symlink(dev_name, proc_ide_root, name); -} - -static int fake_ide_setup(char *str) -{ - fake_ide = 1; - return(1); -} - -__setup("fake_ide", fake_ide_setup); - -__uml_help(fake_ide_setup, -"fake_ide\n" -" Create ide0 entries that map onto ubd devices.\n\n" -); - -static int ubd_setup_common(char *str, int *index_out) -{ - struct openflags flags = global_openflags; - char *backing_file; - int n; - - if(index_out) *index_out = -1; - n = *str++; - if(n == '='){ - char *end; - int major; - - if(!strcmp(str, "sync")){ - global_openflags.s = 1; - return(0); - } - major = simple_strtoul(str, &end, 0); - if(*end != '\0'){ - printk(KERN_ERR - "ubd_setup : didn't parse major number\n"); - return(1); - } - fake_gendisk.major = major; - fake_major = major; - printk(KERN_INFO "Setting extra ubd major number to %d\n", - major); - return(0); - } - - if(n < '0'){ - printk(KERN_ERR "ubd_setup : index out of range\n"); } - - if((n >= '0') && (n <= '9')) n -= '0'; - else if((n >= 'a') && (n <= 'z')) n -= 'a'; - else { - printk(KERN_ERR "ubd_setup : device syntax invalid\n"); - return(1); - } - if(n >= MAX_DEV){ - printk(KERN_ERR "ubd_setup : index out of range " - "(%d devices)\n", MAX_DEV); - return(1); - } - if(index_out) *index_out = n; - - if (*str == 'r'){ - flags.w = 0; - str++; - } - if (*str == 's'){ - flags.s = 1; - str++; - } - if(*str++ != '='){ - printk(KERN_ERR "ubd_setup : Expected '='\n"); - return(1); - } - backing_file = strchr(str, ','); - if(backing_file){ - *backing_file = '\0'; - backing_file++; - } - ubd_dev[n].file = str; - ubd_dev[n].cow.file = backing_file; - ubd_dev[n].boot_openflags = flags; - return(0); -} - -static int ubd_setup(char *str) -{ - ubd_setup_common(str, NULL); - return(1); -} - -__setup("ubd", ubd_setup); -__uml_help(ubd_setup, -"ubd<n>=<filename>\n" -" This is used to associate a device with a file in the underlying\n" -" filesystem. Usually, there is a filesystem in the file, but \n" -" that's not required. Swap devices containing swap files can be\n" -" specified like this. Also, a file which doesn't contain a\n" -" filesystem can have its contents read in the virtual \n" -" machine by running dd on the device. n must be in the range\n" -" 0 to 7. Appending an 'r' to the number will cause that device\n" -" to be mounted read-only. For example ubd1r=./ext_fs. Appending\n" -" an 's' (has to be _after_ 'r', if there is one) will cause data\n" -" to be written to disk on the host immediately.\n\n" -); - -static int fakehd(char *str) -{ - printk(KERN_INFO - "fakehd : Changing ubd_gendisk.major_name to \"hd\".\n"); - ubd_gendisk.major_name = "hd"; - return(1); -} - -__setup("fakehd", fakehd); -__uml_help(fakehd, -"fakehd\n" -" Change the ubd device name to \"hd\".\n\n" -); - -static void do_ubd_request(request_queue_t * q); - -int thread_fd = -1; - -int intr_count = 0; - -static void ubd_finish(int error) -{ - int nsect; - - if(error){ - end_request(0); - return; - } - nsect = CURRENT->current_nr_sectors; - CURRENT->sector += nsect; - CURRENT->buffer += nsect << 9; - CURRENT->errors = 0; - CURRENT->nr_sectors -= nsect; - CURRENT->current_nr_sectors = 0; - end_request(1); -} - -static void ubd_handler(void) -{ - struct io_thread_req req; - int n; - - DEVICE_INTR = NULL; - intr_count++; - n = read_ubd_fs(thread_fd, &req, sizeof(req)); - if(n != sizeof(req)){ - printk(KERN_ERR "Pid %d - spurious interrupt in ubd_handler, " - "errno = %d\n", os_getpid(), -n); - spin_lock(&REQUEST_LOCK); - end_request(0); - spin_unlock(&REQUEST_LOCK); - return; - } - - if((req.offset != ((__u64) (CURRENT->sector)) << 9) || - (req.length != (CURRENT->current_nr_sectors) << 9)) - panic("I/O op mismatch"); - - spin_lock(&REQUEST_LOCK); - ubd_finish(req.error); - reactivate_fd(thread_fd, UBD_IRQ); - do_ubd_request(ubd_queue); - spin_unlock(&REQUEST_LOCK); -} - -static void ubd_intr(int irq, void *dev, struct pt_regs *unused) -{ - ubd_handler(); -} - -static int io_pid = -1; - -void kill_io_thread(void) -{ - if(io_pid != -1) kill(io_pid, SIGKILL); -} - -__uml_exitcall(kill_io_thread); - -int sync = 0; - -devfs_handle_t ubd_dir_handle; -devfs_handle_t ubd_fake_dir_handle; - -static int ubd_add(int n) -{ - char name[sizeof("nnnnnn\0")], dev_name[sizeof("ubd0x")]; - - if(ubd_dev[n].file == NULL) return(-1); - sprintf(name, "%d", n); - ubd_dev[n].real = devfs_register(ubd_dir_handle, name, - DEVFS_FL_REMOVABLE, MAJOR_NR, - n << UBD_SHIFT, - S_IFBLK | S_IRUSR | S_IWUSR | - S_IRGRP |S_IWGRP, - &ubd_blops, NULL); - if(fake_major != 0){ - ubd_dev[n].fake = devfs_register(ubd_fake_dir_handle, name, - DEVFS_FL_REMOVABLE, - fake_major, n << UBD_SHIFT, - S_IFBLK | S_IRUSR | - S_IWUSR | S_IRGRP | S_IWGRP, - &ubd_blops, NULL); - } - if(!strcmp(ubd_gendisk.major_name, "ubd")){ - sprintf(dev_name, "%s%d", ubd_gendisk.major_name, n); - } - else sprintf(dev_name, "%s%c", ubd_gendisk.major_name, - n + 'a'); - make_ide_entries(dev_name); - ubd_revalidate(MKDEV(MAJOR_NR, n << UBD_SHIFT)); - return(0); -} - -static int ubd_config(char *str) -{ - int n, err; - - str = uml_strdup(str); - if(str == NULL){ - printk(KERN_ERR "ubd_config failed to strdup string\n"); - return(1); - } - err = ubd_setup_common(str, &n); - if(err){ - kfree(str); - return(-1); - } - if(n != -1) ubd_add(n); - return(0); -} - -static int ubd_remove(char *str) -{ - struct ubd *dev; - int n; - - if(!isdigit(*str)) return(-1); - n = *str - '0'; - if(n > MAX_DEV) return(-1); - dev = &ubd_dev[n]; - if(dev->file == NULL) return(0); - if(dev->count > 0) return(-1); - if(dev->real != NULL) devfs_unregister(dev->real); - if(dev->fake != NULL) devfs_unregister(dev->fake); - *dev = ((struct ubd) DEFAULT_UBD); - return(0); -} - -static struct mc_device ubd_mc = { - name: "ubd", - config: ubd_config, - remove: ubd_remove, -}; - -int ubd_mc_init(void) -{ - mconsole_register_dev(&ubd_mc); - return(0); -} - -__initcall(ubd_mc_init); - -static request_queue_t *ubd_get_queue(kdev_t device) -{ - return(ubd_queue); -} - -int ubd_init(void) -{ - unsigned long stack; - int i, err; - - ubd_dir_handle = devfs_mk_dir (NULL, "ubd", NULL); - if (devfs_register_blkdev(MAJOR_NR, "ubd", &ubd_blops)) { - printk(KERN_ERR "ubd: unable to get major %d\n", MAJOR_NR); - return -1; - } - ubd_queue = BLK_DEFAULT_QUEUE(MAJOR_NR); - INIT_QUEUE(ubd_queue, DEVICE_REQUEST, &ubd_lock); - INIT_ELV(ubd_queue, &ubd_queue->elevator); - read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read-ahead */ - blksize_size[MAJOR_NR] = blk_sizes; - blk_size[MAJOR_NR] = sizes; - INIT_HARDSECT(hardsect_size, MAJOR_NR, hardsect_sizes); - add_gendisk(&ubd_gendisk); - if (fake_major != 0){ - char name[sizeof("ubd_nnn\0")]; - - snprintf(name, sizeof(name), "ubd_%d", fake_major); - ubd_fake_dir_handle = devfs_mk_dir(NULL, name, NULL); - if(devfs_register_blkdev(fake_major, "ubd", &ubd_blops)) { - printk(KERN_ERR "ubd: unable to get major %d\n", - fake_major); - return -1; - } - blk_dev[fake_major].queue = ubd_get_queue; - read_ahead[fake_major] = 8; /* 8 sector (4kB) read-ahead */ - blksize_size[fake_major] = blk_sizes; - blk_size[fake_major] = sizes; - INIT_HARDSECT(hardsect_size, fake_major, hardsect_sizes); - add_gendisk(&fake_gendisk); - } - for(i=0;i<MAX_DEV;i++) ubd_add(i); - if(sync){ - printk(KERN_INFO "ubd : Synchronous mode\n"); - return(0); - } - stack = alloc_stack(0); - io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *), - &thread_fd); - if(io_pid < 0){ - printk(KERN_ERR - "ubd : Failed to start I/O thread (errno = %d) - " - "falling back to synchronous I/O\n", -io_pid); - return(0); - } - err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr, - SA_INTERRUPT, "ubd", ubd_dev); - if(err != 0) printk(KERN_ERR - "um_request_irq failed - errno = %d\n", -err); - return(err); -} - -__initcall(ubd_init); - -static void ubd_close(struct ubd *dev) -{ - close_fd(dev->fd); - if(dev->cow.file != NULL) { - close_fd(dev->cow.fd); - vfree(dev->cow.bitmap); - dev->cow.bitmap = NULL; - } -} - -static int ubd_open_dev(struct ubd *dev) -{ - struct openflags flags; - int err, n, create_cow, *create_ptr; - - create_cow = 0; - create_ptr = (dev->cow.file != NULL) ? &create_cow : NULL; - dev->fd = open_ubd_file(dev->file, &dev->openflags, &dev->cow.file, - &dev->cow.bitmap_offset, &dev->cow.bitmap_len, - &dev->cow.data_offset, create_ptr); - - if((dev->fd == -ENOENT) && create_cow){ - n = dev - ubd_dev; - dev->fd = create_cow_file(dev->file, dev->cow.file, - dev->openflags, 1 << 9, - &dev->cow.bitmap_offset, - &dev->cow.bitmap_len, - &dev->cow.data_offset); - if(dev->fd >= 0){ - printk(KERN_INFO "Creating \"%s\" as COW file for " - "\"%s\"\n", dev->file, dev->cow.file); - } - } - - if(dev->fd < 0) return(dev->fd); - - if(dev->cow.file != NULL){ - err = -ENOMEM; - dev->cow.bitmap = (void *) vmalloc(dev->cow.bitmap_len); - if(dev->cow.bitmap == NULL) goto error; - flush_tlb_kernel_vm(); - - err = read_cow_bitmap(dev->fd, dev->cow.bitmap, - dev->cow.bitmap_offset, - dev->cow.bitmap_len); - if(err) goto error; - - flags = dev->openflags; - flags.w = 0; - err = open_ubd_file(dev->cow.file, &flags, NULL, NULL, NULL, - NULL, NULL); - if(err < 0) goto error; - dev->cow.fd = err; - } - return(0); - error: - close_fd(dev->fd); - return(err); -} - -static int ubd_file_size(struct ubd *dev, __u64 *size_out) -{ - char *file; - - file = dev->cow.file ? dev->cow.file : dev->file; - return(os_file_size(file, size_out)); -} - -static int ubd_open(struct inode *inode, struct file *filp) -{ - struct ubd *dev; - int n, offset, err; - - n = DEVICE_NR(inode->i_rdev); - dev = &ubd_dev[n]; - if(n > MAX_DEV) - return -ENODEV; - offset = n << UBD_SHIFT; - if(ubd_is_dir(dev->file)){ - dev->is_dir = 1; - return(0); - } - if(dev->count == 0){ - dev->openflags = dev->boot_openflags; - /* XXX This error is wrong when errno isn't stored in - * dev->fd - */ - if(ubd_open_dev(dev) < 0){ - printk(KERN_ERR "ubd%d: Can't open \"%s\": " - "errno = %d\n", n, dev->file, -dev->fd); - } - if(dev->fd < 0) - return -ENODEV; - err = ubd_file_size(dev, &dev->size); - if(err) return(err); - sizes[offset] = dev->size / BLOCK_SIZE; - ubd_part[offset].nr_sects = dev->size / hardsect_sizes[offset]; - } - dev->count++; - if((filp->f_mode & FMODE_WRITE) && !dev->openflags.w){ - if(--dev->count == 0) ubd_close(dev); - return -EROFS; - } - return(0); -} - -static int ubd_release(struct inode * inode, struct file * file) -{ - int n, offset; - - n = DEVICE_NR(inode->i_rdev); - offset = n << UBD_SHIFT; - if(n > MAX_DEV) - return -ENODEV; - if(--ubd_dev[n].count == 0){ - ubd_close(&ubd_dev[n]); - sizes[offset] = 0; - ubd_part[offset].nr_sects = 0; - } - return(0); -} - -int cow_read = 0; -int cow_write = 0; - -void cowify_req(struct io_thread_req *req, struct ubd *dev) -{ - int i, update_bitmap, sector = req->offset >> 9; - - if(req->length > (sizeof(req->sector_mask) * 8) << 9) - panic("Operation too long"); - if(req->op == UBD_READ) { - for(i = 0; i < req->length >> 9; i++){ - if(ubd_test_bit(sector + i, (unsigned char *) - dev->cow.bitmap)){ - ubd_set_bit(i, (unsigned char *) - &req->sector_mask); - cow_read++; - } - } - } - else { - update_bitmap = 0; - for(i = 0; i < req->length >> 9; i++){ - cow_write++; - ubd_set_bit(i, (unsigned char *) - &req->sector_mask); - if(!ubd_test_bit(sector + i, (unsigned char *) - dev->cow.bitmap)) - update_bitmap = 1; - ubd_set_bit(sector + i, (unsigned char *) - dev->cow.bitmap); - } - if(update_bitmap){ - req->cow_offset = sector / (sizeof(unsigned long) * 8); - req->bitmap_words[0] = - dev->cow.bitmap[req->cow_offset]; - req->bitmap_words[1] = - dev->cow.bitmap[req->cow_offset + 1]; - req->cow_offset *= sizeof(unsigned long); - req->cow_offset += dev->cow.bitmap_offset; - } - } -} - -static int prepare_request(struct request *req, struct io_thread_req *io_req) -{ - struct ubd *dev; - __u64 block; - int nsect, minor, n; - - if(req->rq_status == RQ_INACTIVE) return(1); - - minor = MINOR(req->rq_dev); - n = minor >> UBD_SHIFT; - dev = &ubd_dev[n]; - if(dev->is_dir){ - strcpy(req->buffer, "HOSTFS:"); - strcat(req->buffer, dev->file); - end_request(1); - return(1); - } - if(IS_WRITE(req) && !dev->openflags.w){ - printk("Write attempted on readonly ubd device %d\n", n); - end_request(0); - return(1); - } - - req->sector += ubd_part[minor].start_sect; - block = req->sector; - nsect = req->current_nr_sectors; - - io_req->op = (req->cmd == READ) ? UBD_READ : UBD_WRITE; - io_req->fds[0] = (dev->cow.file != NULL) ? dev->cow.fd : dev->fd; - io_req->fds[1] = dev->fd; - io_req->offsets[0] = 0; - io_req->offsets[1] = dev->cow.data_offset; - io_req->offset = ((__u64) block) << 9; - io_req->length = nsect << 9; - io_req->buffer = req->buffer; - io_req->sectorsize = 1 << 9; - io_req->sector_mask = 0; - io_req->cow_offset = -1; - io_req->error = 0; - - if(dev->cow.file != NULL) cowify_req(io_req, dev); - return(0); -} - -static void do_ubd_request(request_queue_t *q) -{ - struct io_thread_req io_req; - struct request *req; - int err, n; - - if(thread_fd == -1){ - while(!list_empty(&q->queue_head)){ - req = blkdev_entry_next_request(&q->queue_head); - err = prepare_request(req, &io_req); - if(!err){ - do_io(&io_req); - ubd_finish(io_req.error); - } - } - } - else { - if(DEVICE_INTR || list_empty(&q->queue_head)) return; - req = blkdev_entry_next_request(&q->queue_head); - err = prepare_request(req, &io_req); - if(!err){ - SET_INTR(ubd_handler); - n = write_ubd_fs(thread_fd, (char *) &io_req, - sizeof(io_req)); - if(n != sizeof(io_req)) - printk("write to io thread failed, " - "errno = %d\n", -n); - } - } -} - -static int ubd_ioctl(struct inode * inode, struct file * file, - unsigned int cmd, unsigned long arg) -{ - struct hd_geometry *loc = (struct hd_geometry *) arg; - struct ubd *dev; - int n, minor, err; - - if(!inode) return(-EINVAL); - minor = MINOR(inode->i_rdev); - n = minor >> UBD_SHIFT; - if(n > MAX_DEV) - return(-EINVAL); - dev = &ubd_dev[n]; - switch (cmd) { - struct hd_geometry g; - struct cdrom_volctrl volume; - case HDIO_GETGEO: - if(!loc) return(-EINVAL); - g.heads = 128; - g.sectors = 32; - g.cylinders = dev->size / (128 * 32 * hardsect_sizes[minor]); - g.start = 2; - return(copy_to_user(loc, &g, sizeof(g)) ? -EFAULT : 0); - case BLKGETSIZE: /* Return device size */ - if(!arg) return(-EINVAL); - err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long)); - if(err) - return(err); - put_user(ubd_part[minor].nr_sects, (long *) arg); - return(0); - case BLKRRPART: /* Re-read partition tables */ - return(ubd_revalidate(inode->i_rdev)); - - case HDIO_SET_UNMASKINTR: - if(!capable(CAP_SYS_ADMIN)) return(-EACCES); - if((arg > 1) || (minor & 0x3F)) return(-EINVAL); - return(0); - - case HDIO_GET_UNMASKINTR: - if(!arg) return(-EINVAL); - err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long)); - if(err) - return(err); - return(0); - - case HDIO_GET_MULTCOUNT: - if(!arg) return(-EINVAL); - err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long)); - if(err) - return(err); - return(0); - - case HDIO_SET_MULTCOUNT: - if(!capable(CAP_SYS_ADMIN)) return(-EACCES); - if(MINOR(inode->i_rdev) & 0x3F) return(-EINVAL); - return(0); - - case HDIO_GET_IDENTITY: - ubd_id.cyls = dev->size / (128 * 32 * hardsect_sizes[minor]); - if(copy_to_user((char *) arg, (char *) &ubd_id, - sizeof(ubd_id))) - return(-EFAULT); - return(0); - - case CDROMVOLREAD: - if(copy_from_user(&volume, (char *) arg, sizeof(volume))) - return(-EFAULT); - volume.channel0 = 255; - volume.channel1 = 255; - volume.channel2 = 255; - volume.channel3 = 255; - if(copy_to_user((char *) arg, &volume, sizeof(volume))) - return(-EFAULT); - return(0); - - default: - return blk_ioctl(inode->i_rdev, cmd, arg); - } -} - -static int ubd_revalidate(kdev_t rdev) -{ - int i, n, offset, err, pcount = 1 << UBD_SHIFT; - struct ubd *dev; - struct hd_struct *part; - - n = DEVICE_NR(rdev); - offset = n << UBD_SHIFT; - dev = &ubd_dev[n]; - part = &ubd_part[offset]; - - /* clear all old partition counts */ - for(i = 1; i < pcount; i++) { - part[i].start_sect = 0; - part[i].nr_sects = 0; - } - - /* If it already has been opened we can check the partitions - * directly - */ - if(dev->count){ - part->start_sect = 0; - register_disk(&ubd_gendisk, MKDEV(MAJOR_NR, offset), pcount, - &ubd_blops, part->nr_sects); - } - else if(dev->file){ - if(ubd_open_dev(dev) < 0){ - printk(KERN_ERR "unable to open %s for validation\n", - dev->file); - return 1; - } - - /* have to recompute sizes since we opened it */ - err = ubd_file_size(dev, &dev->size); - if(err) { - ubd_close(dev); - return 1; - } - part->start_sect = 0; - part->nr_sects = dev->size / hardsect_sizes[offset]; - register_disk(&ubd_gendisk, MKDEV(MAJOR_NR, offset), pcount, - &ubd_blops, part->nr_sects); - - /* we are done so close it */ - ubd_close(dev); - } - else return(1); - return(0); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ |