aboutsummaryrefslogtreecommitdiff
path: root/arch/um/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'arch/um/drivers')
-rw-r--r--arch/um/drivers/Makefile2
-rw-r--r--arch/um/drivers/chan_kern.c60
-rw-r--r--arch/um/drivers/cow.h39
-rw-r--r--arch/um/drivers/cow_user.c1
-rw-r--r--arch/um/drivers/mcast_user.c12
-rw-r--r--arch/um/drivers/mconsole_kern.c52
-rw-r--r--arch/um/drivers/mconsole_user.c7
-rw-r--r--arch/um/drivers/port_kern.c1
-rw-r--r--arch/um/drivers/pty.c3
-rw-r--r--arch/um/drivers/ubd_kern.c556
-rw-r--r--arch/um/drivers/xterm.c6
11 files changed, 456 insertions, 283 deletions
diff --git a/arch/um/drivers/Makefile b/arch/um/drivers/Makefile
index 783e18cae09..de17d4c6e02 100644
--- a/arch/um/drivers/Makefile
+++ b/arch/um/drivers/Makefile
@@ -13,7 +13,7 @@ mcast-objs := mcast_kern.o mcast_user.o
net-objs := net_kern.o net_user.o
mconsole-objs := mconsole_kern.o mconsole_user.o
hostaudio-objs := hostaudio_kern.o
-ubd-objs := ubd_kern.o
+ubd-objs := ubd_kern.o ubd_user.o
port-objs := port_kern.o port_user.o
harddog-objs := harddog_kern.o harddog_user.o
diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c
index 14a12d6b3df..16e7dc89f61 100644
--- a/arch/um/drivers/chan_kern.c
+++ b/arch/um/drivers/chan_kern.c
@@ -19,18 +19,44 @@
#include "line.h"
#include "os.h"
-#ifdef CONFIG_NOCONFIG_CHAN
+/* XXX: could well be moved to somewhere else, if needed. */
+static int my_printf(const char * fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
+
+static int my_printf(const char * fmt, ...)
+{
+ /* Yes, can be called on atomic context.*/
+ char *buf = kmalloc(4096, GFP_ATOMIC);
+ va_list args;
+ int r;
+
+ if (!buf) {
+ /* We print directly fmt.
+ * Yes, yes, yes, feel free to complain. */
+ r = strlen(fmt);
+ } else {
+ va_start(args, fmt);
+ r = vsprintf(buf, fmt, args);
+ va_end(args);
+ fmt = buf;
+ }
-/* The printk's here are wrong because we are complaining that there is no
- * output device, but printk is printing to that output device. The user will
- * never see the error. printf would be better, except it can't run on a
- * kernel stack because it will overflow it.
- * Use printk for now since that will avoid crashing.
- */
+ if (r)
+ r = os_write_file(1, fmt, r);
+ return r;
+
+}
+
+#ifdef CONFIG_NOCONFIG_CHAN
+/* Despite its name, there's no added trailing newline. */
+static int my_puts(const char * buf)
+{
+ return os_write_file(1, buf, strlen(buf));
+}
static void *not_configged_init(char *str, int device, struct chan_opts *opts)
{
- printk(KERN_ERR "Using a channel type which is configured out of "
+ my_puts("Using a channel type which is configured out of "
"UML\n");
return(NULL);
}
@@ -38,27 +64,27 @@ static void *not_configged_init(char *str, int device, struct chan_opts *opts)
static int not_configged_open(int input, int output, int primary, void *data,
char **dev_out)
{
- printk(KERN_ERR "Using a channel type which is configured out of "
+ my_puts("Using a channel type which is configured out of "
"UML\n");
return(-ENODEV);
}
static void not_configged_close(int fd, void *data)
{
- printk(KERN_ERR "Using a channel type which is configured out of "
+ my_puts("Using a channel type which is configured out of "
"UML\n");
}
static int not_configged_read(int fd, char *c_out, void *data)
{
- printk(KERN_ERR "Using a channel type which is configured out of "
+ my_puts("Using a channel type which is configured out of "
"UML\n");
return(-EIO);
}
static int not_configged_write(int fd, const char *buf, int len, void *data)
{
- printk(KERN_ERR "Using a channel type which is configured out of "
+ my_puts("Using a channel type which is configured out of "
"UML\n");
return(-EIO);
}
@@ -66,7 +92,7 @@ static int not_configged_write(int fd, const char *buf, int len, void *data)
static int not_configged_console_write(int fd, const char *buf, int len,
void *data)
{
- printk(KERN_ERR "Using a channel type which is configured out of "
+ my_puts("Using a channel type which is configured out of "
"UML\n");
return(-EIO);
}
@@ -74,14 +100,14 @@ static int not_configged_console_write(int fd, const char *buf, int len,
static int not_configged_window_size(int fd, void *data, unsigned short *rows,
unsigned short *cols)
{
- printk(KERN_ERR "Using a channel type which is configured out of "
+ my_puts("Using a channel type which is configured out of "
"UML\n");
return(-ENODEV);
}
static void not_configged_free(void *data)
{
- printf(KERN_ERR "Using a channel type which is configured out of "
+ my_puts("Using a channel type which is configured out of "
"UML\n");
}
@@ -457,7 +483,7 @@ static struct chan *parse_chan(char *str, int pri, int device,
}
}
if(ops == NULL){
- printk(KERN_ERR "parse_chan couldn't parse \"%s\"\n",
+ my_printf("parse_chan couldn't parse \"%s\"\n",
str);
return(NULL);
}
@@ -465,7 +491,7 @@ static struct chan *parse_chan(char *str, int pri, int device,
data = (*ops->init)(str, device, opts);
if(data == NULL) return(NULL);
- chan = kmalloc(sizeof(*chan), GFP_KERNEL);
+ chan = kmalloc(sizeof(*chan), GFP_ATOMIC);
if(chan == NULL) return(NULL);
*chan = ((struct chan) { .list = LIST_HEAD_INIT(chan->list),
.primary = 1,
diff --git a/arch/um/drivers/cow.h b/arch/um/drivers/cow.h
index 4fcf3a8d13f..dc36b222100 100644
--- a/arch/um/drivers/cow.h
+++ b/arch/um/drivers/cow.h
@@ -3,15 +3,40 @@
#include <asm/types.h>
-#if defined(__BIG_ENDIAN)
-# define ntohll(x) (x)
-# define htonll(x) (x)
-#elif defined(__LITTLE_ENDIAN)
-# define ntohll(x) bswap_64(x)
-# define htonll(x) bswap_64(x)
+#if defined(__KERNEL__)
+
+# include <asm/byteorder.h>
+
+# if defined(__BIG_ENDIAN)
+# define ntohll(x) (x)
+# define htonll(x) (x)
+# elif defined(__LITTLE_ENDIAN)
+# define ntohll(x) be64_to_cpu(x)
+# define htonll(x) cpu_to_be64(x)
+# else
+# error "Could not determine byte order"
+# endif
+
#else
-#error "__BYTE_ORDER not defined"
+/* For the definition of ntohl, htonl and __BYTE_ORDER */
+#include <endian.h>
+#include <netinet/in.h>
+#if defined(__BYTE_ORDER)
+
+# if __BYTE_ORDER == __BIG_ENDIAN
+# define ntohll(x) (x)
+# define htonll(x) (x)
+# elif __BYTE_ORDER == __LITTLE_ENDIAN
+# define ntohll(x) bswap_64(x)
+# define htonll(x) bswap_64(x)
+# else
+# error "Could not determine byte order: __BYTE_ORDER uncorrectly defined"
+# endif
+
+#else /* ! defined(__BYTE_ORDER) */
+# error "Could not determine byte order: __BYTE_ORDER not defined"
#endif
+#endif /* ! defined(__KERNEL__) */
extern int init_cow_file(int fd, char *cow_file, char *backing_file,
int sectorsize, int alignment, int *bitmap_offset_out,
diff --git a/arch/um/drivers/cow_user.c b/arch/um/drivers/cow_user.c
index a8ce6fc3ef2..fbe2217db5d 100644
--- a/arch/um/drivers/cow_user.c
+++ b/arch/um/drivers/cow_user.c
@@ -9,7 +9,6 @@
#include <sys/time.h>
#include <sys/param.h>
#include <sys/user.h>
-#include <netinet/in.h>
#include "os.h"
diff --git a/arch/um/drivers/mcast_user.c b/arch/um/drivers/mcast_user.c
index 7a0d115b29d..5db136e2651 100644
--- a/arch/um/drivers/mcast_user.c
+++ b/arch/um/drivers/mcast_user.c
@@ -13,7 +13,6 @@
#include <errno.h>
#include <unistd.h>
-#include <linux/inet.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/time.h>
@@ -55,7 +54,7 @@ static int mcast_open(void *data)
struct mcast_data *pri = data;
struct sockaddr_in *sin = pri->mcast_addr;
struct ip_mreq mreq;
- int fd = -EINVAL, yes = 1, err = -EINVAL;;
+ int fd, yes = 1, err = 0;
if ((sin->sin_addr.s_addr == 0) || (sin->sin_port == 0))
@@ -66,13 +65,14 @@ static int mcast_open(void *data)
if (fd < 0){
printk("mcast_open : data socket failed, errno = %d\n",
errno);
- fd = -errno;
+ err = -errno;
goto out;
}
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
printk("mcast_open: SO_REUSEADDR failed, errno = %d\n",
errno);
+ err = -errno;
goto out_close;
}
@@ -81,6 +81,7 @@ static int mcast_open(void *data)
sizeof(pri->ttl)) < 0) {
printk("mcast_open: IP_MULTICAST_TTL failed, error = %d\n",
errno);
+ err = -errno;
goto out_close;
}
@@ -88,12 +89,14 @@ static int mcast_open(void *data)
if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) {
printk("mcast_open: IP_MULTICAST_LOOP failed, error = %d\n",
errno);
+ err = -errno;
goto out_close;
}
/* bind socket to mcast address */
if (bind(fd, (struct sockaddr *) sin, sizeof(*sin)) < 0) {
printk("mcast_open : data bind failed, errno = %d\n", errno);
+ err = -errno;
goto out_close;
}
@@ -108,14 +111,15 @@ static int mcast_open(void *data)
"interface on the host.\n");
printk("eth0 should be configured in order to use the "
"multicast transport.\n");
+ err = -errno;
goto out_close;
}
- out:
return fd;
out_close:
os_close_file(fd);
+ out:
return err;
}
diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c
index c190c241419..12c95368124 100644
--- a/arch/um/drivers/mconsole_kern.c
+++ b/arch/um/drivers/mconsole_kern.c
@@ -32,6 +32,7 @@
#include "os.h"
#include "umid.h"
#include "irq_kern.h"
+#include "choose-mode.h"
static int do_unlink_socket(struct notifier_block *notifier,
unsigned long what, void *data)
@@ -276,6 +277,7 @@ void mconsole_proc(struct mc_request *req)
go - continue the UML after a 'stop' \n\
log <string> - make UML enter <string> into the kernel log\n\
proc <file> - returns the contents of the UML's /proc/<file>\n\
+ stack <pid> - returns the stack of the specified pid\n\
"
void mconsole_help(struct mc_request *req)
@@ -479,6 +481,56 @@ void mconsole_sysrq(struct mc_request *req)
}
#endif
+/* Mconsole stack trace
+ * Added by Allan Graves, Jeff Dike
+ * Dumps a stacks registers to the linux console.
+ * Usage stack <pid>.
+ */
+void do_stack(struct mc_request *req)
+{
+ char *ptr = req->request.data;
+ int pid_requested= -1;
+ struct task_struct *from = NULL;
+ struct task_struct *to = NULL;
+
+ /* Would be nice:
+ * 1) Send showregs output to mconsole.
+ * 2) Add a way to stack dump all pids.
+ */
+
+ ptr += strlen("stack");
+ while(isspace(*ptr)) ptr++;
+
+ /* Should really check for multiple pids or reject bad args here */
+ /* What do the arguments in mconsole_reply mean? */
+ if(sscanf(ptr, "%d", &pid_requested) == 0){
+ mconsole_reply(req, "Please specify a pid", 1, 0);
+ return;
+ }
+
+ from = current;
+ to = find_task_by_pid(pid_requested);
+
+ if((to == NULL) || (pid_requested == 0)) {
+ mconsole_reply(req, "Couldn't find that pid", 1, 0);
+ return;
+ }
+ to->thread.saved_task = current;
+
+ switch_to(from, to, from);
+ mconsole_reply(req, "Stack Dumped to console and message log", 0, 0);
+}
+
+void mconsole_stack(struct mc_request *req)
+{
+ /* This command doesn't work in TT mode, so let's check and then
+ * get out of here
+ */
+ CHOOSE_MODE(mconsole_reply(req, "Sorry, this doesn't work in TT mode",
+ 1, 0),
+ do_stack(req));
+}
+
/* Changed by mconsole_setup, which is __setup, and called before SMP is
* active.
*/
diff --git a/arch/um/drivers/mconsole_user.c b/arch/um/drivers/mconsole_user.c
index fe5afb13252..310c1f823f2 100644
--- a/arch/um/drivers/mconsole_user.c
+++ b/arch/um/drivers/mconsole_user.c
@@ -30,6 +30,7 @@ static struct mconsole_command commands[] = {
{ "go", mconsole_go, MCONSOLE_INTR },
{ "log", mconsole_log, MCONSOLE_INTR },
{ "proc", mconsole_proc, MCONSOLE_PROC },
+ { "stack", mconsole_stack, MCONSOLE_INTR },
};
/* Initialized in mconsole_init, which is an initcall */
@@ -172,9 +173,9 @@ int mconsole_notify(char *sock_name, int type, const void *data, int len)
if(notify_sock < 0){
notify_sock = socket(PF_UNIX, SOCK_DGRAM, 0);
if(notify_sock < 0){
- printk("mconsole_notify - socket failed, errno = %d\n",
- errno);
err = -errno;
+ printk("mconsole_notify - socket failed, errno = %d\n",
+ err);
}
}
unlock_notify();
@@ -197,8 +198,8 @@ int mconsole_notify(char *sock_name, int type, const void *data, int len)
n = sendto(notify_sock, &packet, len, 0, (struct sockaddr *) &target,
sizeof(target));
if(n < 0){
- printk("mconsole_notify - sendto failed, errno = %d\n", errno);
err = -errno;
+ printk("mconsole_notify - sendto failed, errno = %d\n", errno);
}
return(err);
}
diff --git a/arch/um/drivers/port_kern.c b/arch/um/drivers/port_kern.c
index c41efd207fc..189839e4f1d 100644
--- a/arch/um/drivers/port_kern.c
+++ b/arch/um/drivers/port_kern.c
@@ -7,7 +7,6 @@
#include "linux/sched.h"
#include "linux/slab.h"
#include "linux/interrupt.h"
-#include "linux/irq.h"
#include "linux/spinlock.h"
#include "linux/errno.h"
#include "asm/atomic.h"
diff --git a/arch/um/drivers/pty.c b/arch/um/drivers/pty.c
index ed84d01df6c..0306a1b215b 100644
--- a/arch/um/drivers/pty.c
+++ b/arch/um/drivers/pty.c
@@ -43,8 +43,9 @@ static int pts_open(int input, int output, int primary, void *d,
fd = get_pty();
if(fd < 0){
+ err = -errno;
printk("open_pts : Failed to open pts\n");
- return(-errno);
+ return err;
}
if(data->raw){
CATCH_EINTR(err = tcgetattr(fd, &data->tt));
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c
index e77a38da435..f73134333f6 100644
--- a/arch/um/drivers/ubd_kern.c
+++ b/arch/um/drivers/ubd_kern.c
@@ -35,7 +35,6 @@
#include "linux/blkpg.h"
#include "linux/genhd.h"
#include "linux/spinlock.h"
-#include "asm/atomic.h"
#include "asm/segment.h"
#include "asm/uaccess.h"
#include "asm/irq.h"
@@ -54,21 +53,20 @@
#include "mem.h"
#include "mem_kern.h"
#include "cow.h"
-#include "aio.h"
enum ubd_req { UBD_READ, UBD_WRITE };
struct io_thread_req {
- enum aio_type op;
+ enum ubd_req op;
int fds[2];
unsigned long offsets[2];
unsigned long long offset;
unsigned long length;
char *buffer;
int sectorsize;
- int bitmap_offset;
- long bitmap_start;
- long bitmap_end;
+ unsigned long sector_mask;
+ unsigned long long cow_offset;
+ unsigned long bitmap_words[2];
int error;
};
@@ -82,31 +80,28 @@ extern int create_cow_file(char *cow_file, char *backing_file,
unsigned long *bitmap_len_out,
int *data_offset_out);
extern int read_cow_bitmap(int fd, void *buf, int offset, int len);
-extern void do_io(struct io_thread_req *req, struct request *r,
- unsigned long *bitmap);
+extern void do_io(struct io_thread_req *req);
-static inline int ubd_test_bit(__u64 bit, void *data)
+static inline int ubd_test_bit(__u64 bit, unsigned char *data)
{
- unsigned char *buffer = data;
__u64 n;
int bits, off;
- bits = sizeof(buffer[0]) * 8;
+ bits = sizeof(data[0]) * 8;
n = bit / bits;
off = bit % bits;
- return((buffer[n] & (1 << off)) != 0);
+ return((data[n] & (1 << off)) != 0);
}
-static inline void ubd_set_bit(__u64 bit, void *data)
+static inline void ubd_set_bit(__u64 bit, unsigned char *data)
{
- unsigned char *buffer = data;
__u64 n;
int bits, off;
- bits = sizeof(buffer[0]) * 8;
+ bits = sizeof(data[0]) * 8;
n = bit / bits;
off = bit % bits;
- buffer[n] |= (1 << off);
+ data[n] |= (1 << off);
}
/*End stuff from ubd_user.h*/
@@ -115,6 +110,8 @@ static inline void ubd_set_bit(__u64 bit, void *data)
static DEFINE_SPINLOCK(ubd_io_lock);
static DEFINE_SPINLOCK(ubd_lock);
+static void (*do_ubd)(void);
+
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,
@@ -161,8 +158,6 @@ struct cow {
int data_offset;
};
-#define MAX_SG 64
-
struct ubd {
char *file;
int count;
@@ -173,7 +168,6 @@ struct ubd {
int no_cow;
struct cow cow;
struct platform_device pdev;
- struct scatterlist sg[MAX_SG];
};
#define DEFAULT_COW { \
@@ -466,114 +460,81 @@ __uml_help(fakehd,
);
static void do_ubd_request(request_queue_t * q);
-static int in_ubd;
+
+/* Only changed by ubd_init, which is an initcall. */
+int thread_fd = -1;
/* Changed by ubd_handler, which is serialized because interrupts only
* happen on CPU 0.
*/
int intr_count = 0;
-static void ubd_end_request(struct request *req, int bytes, int uptodate)
+/* call ubd_finish if you need to serialize */
+static void __ubd_finish(struct request *req, int error)
{
- if (!end_that_request_first(req, uptodate, bytes >> 9)) {
- add_disk_randomness(req->rq_disk);
- end_that_request_last(req);
+ int nsect;
+
+ if(error){
+ end_request(req, 0);
+ return;
}
+ nsect = req->current_nr_sectors;
+ req->sector += nsect;
+ req->buffer += nsect << 9;
+ req->errors = 0;
+ req->nr_sectors -= nsect;
+ req->current_nr_sectors = 0;
+ end_request(req, 1);
}
-/* call ubd_finish if you need to serialize */
-static void __ubd_finish(struct request *req, int bytes)
+static inline void ubd_finish(struct request *req, int error)
{
- if(bytes < 0){
- ubd_end_request(req, 0, 0);
- return;
- }
-
- ubd_end_request(req, bytes, 1);
+ spin_lock(&ubd_io_lock);
+ __ubd_finish(req, error);
+ spin_unlock(&ubd_io_lock);
}
-static inline void ubd_finish(struct request *req, int bytes)
+/* Called without ubd_io_lock held */
+static void ubd_handler(void)
{
- spin_lock(&ubd_io_lock);
- __ubd_finish(req, bytes);
- spin_unlock(&ubd_io_lock);
+ struct io_thread_req req;
+ struct request *rq = elv_next_request(ubd_queue);
+ int n;
+
+ do_ubd = NULL;
+ intr_count++;
+ n = os_read_file(thread_fd, &req, sizeof(req));
+ if(n != sizeof(req)){
+ printk(KERN_ERR "Pid %d - spurious interrupt in ubd_handler, "
+ "err = %d\n", os_getpid(), -n);
+ spin_lock(&ubd_io_lock);
+ end_request(rq, 0);
+ spin_unlock(&ubd_io_lock);
+ return;
+ }
+
+ ubd_finish(rq, req.error);
+ reactivate_fd(thread_fd, UBD_IRQ);
+ do_ubd_request(ubd_queue);
}
-struct bitmap_io {
- atomic_t count;
- struct aio_context aio;
-};
-
-struct ubd_aio {
- struct aio_context aio;
- struct request *req;
- int len;
- struct bitmap_io *bitmap;
- void *bitmap_buf;
-};
-
-static int ubd_reply_fd = -1;
-
static irqreturn_t ubd_intr(int irq, void *dev, struct pt_regs *unused)
{
- struct aio_thread_reply reply;
- struct ubd_aio *aio;
- struct request *req;
- int err, n, fd = (int) (long) dev;
-
- while(1){
- err = os_read_file(fd, &reply, sizeof(reply));
- if(err == -EAGAIN)
- break;
- if(err < 0){
- printk("ubd_aio_handler - read returned err %d\n",
- -err);
- break;
- }
-
- aio = container_of(reply.data, struct ubd_aio, aio);
- n = reply.err;
-
- if(n == 0){
- req = aio->req;
- req->nr_sectors -= aio->len >> 9;
-
- if((aio->bitmap != NULL) &&
- (atomic_dec_and_test(&aio->bitmap->count))){
- aio->aio = aio->bitmap->aio;
- aio->len = 0;
- kfree(aio->bitmap);
- aio->bitmap = NULL;
- submit_aio(&aio->aio);
- }
- else {
- if((req->nr_sectors == 0) &&
- (aio->bitmap == NULL)){
- int len = req->hard_nr_sectors << 9;
- ubd_finish(req, len);
- }
-
- if(aio->bitmap_buf != NULL)
- kfree(aio->bitmap_buf);
- kfree(aio);
- }
- }
- else if(n < 0){
- ubd_finish(aio->req, n);
- if(aio->bitmap != NULL)
- kfree(aio->bitmap);
- if(aio->bitmap_buf != NULL)
- kfree(aio->bitmap_buf);
- kfree(aio);
- }
- }
- reactivate_fd(fd, UBD_IRQ);
+ ubd_handler();
+ return(IRQ_HANDLED);
+}
- do_ubd_request(ubd_queue);
+/* Only changed by ubd_init, which is an initcall. */
+static int io_pid = -1;
- return(IRQ_HANDLED);
+void kill_io_thread(void)
+{
+ if(io_pid != -1)
+ os_kill_process(io_pid, 1);
}
+__uml_exitcall(kill_io_thread);
+
static int ubd_file_size(struct ubd *dev, __u64 *size_out)
{
char *file;
@@ -608,7 +569,7 @@ static int ubd_open_dev(struct ubd *dev)
&dev->cow.data_offset, create_ptr);
if((dev->fd == -ENOENT) && create_cow){
- dev->fd = create_cow_file(dev->file, dev->cow.file,
+ dev->fd = create_cow_file(dev->file, dev->cow.file,
dev->openflags, 1 << 9, PAGE_SIZE,
&dev->cow.bitmap_offset,
&dev->cow.bitmap_len,
@@ -870,10 +831,6 @@ int ubd_init(void)
{
int i;
- ubd_reply_fd = init_aio_irq(UBD_IRQ, "ubd", ubd_intr);
- if(ubd_reply_fd < 0)
- printk("Setting up ubd AIO failed, err = %d\n", ubd_reply_fd);
-
devfs_mk_dir("ubd");
if (register_blkdev(MAJOR_NR, "ubd"))
return -1;
@@ -884,7 +841,6 @@ int ubd_init(void)
return -1;
}
- blk_queue_max_hw_segments(ubd_queue, MAX_SG);
if (fake_major != MAJOR_NR) {
char name[sizeof("ubd_nnn\0")];
@@ -896,12 +852,40 @@ int ubd_init(void)
driver_register(&ubd_driver);
for (i = 0; i < MAX_DEV; i++)
ubd_add(i);
-
return 0;
}
late_initcall(ubd_init);
+int ubd_driver_init(void){
+ unsigned long stack;
+ int err;
+
+ /* Set by CONFIG_BLK_DEV_UBD_SYNC or ubd=sync.*/
+ if(global_openflags.s){
+ printk(KERN_INFO "ubd: Synchronous mode\n");
+ /* Letting ubd=sync be like using ubd#s= instead of ubd#= is
+ * enough. So use anyway the io thread. */
+ }
+ stack = alloc_stack(0, 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);
+ io_pid = -1;
+ 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);
+}
+
+device_initcall(ubd_driver_init);
+
static int ubd_open(struct inode *inode, struct file *filp)
{
struct gendisk *disk = inode->i_bdev->bd_disk;
@@ -939,55 +923,105 @@ static int ubd_release(struct inode * inode, struct file * file)
return(0);
}
-static void cowify_bitmap(struct io_thread_req *req, unsigned long *bitmap)
+static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask,
+ __u64 *cow_offset, unsigned long *bitmap,
+ __u64 bitmap_offset, unsigned long *bitmap_words,
+ __u64 bitmap_len)
{
- __u64 sector = req->offset / req->sectorsize;
- int i;
+ __u64 sector = io_offset >> 9;
+ int i, update_bitmap = 0;
+
+ for(i = 0; i < length >> 9; i++){
+ if(cow_mask != NULL)
+ ubd_set_bit(i, (unsigned char *) cow_mask);
+ if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
+ continue;
- for(i = 0; i < req->length / req->sectorsize; i++){
- if(ubd_test_bit(sector + i, bitmap))
- continue;
+ update_bitmap = 1;
+ ubd_set_bit(sector + i, (unsigned char *) bitmap);
+ }
+
+ if(!update_bitmap)
+ return;
- if(req->bitmap_start == -1)
- req->bitmap_start = sector + i;
- req->bitmap_end = sector + i + 1;
+ *cow_offset = sector / (sizeof(unsigned long) * 8);
- ubd_set_bit(sector + i, bitmap);
- }
+ /* This takes care of the case where we're exactly at the end of the
+ * device, and *cow_offset + 1 is off the end. So, just back it up
+ * by one word. Thanks to Lynn Kerby for the fix and James McMechan
+ * for the original diagnosis.
+ */
+ if(*cow_offset == ((bitmap_len + sizeof(unsigned long) - 1) /
+ sizeof(unsigned long) - 1))
+ (*cow_offset)--;
+
+ bitmap_words[0] = bitmap[*cow_offset];
+ bitmap_words[1] = bitmap[*cow_offset + 1];
+
+ *cow_offset *= sizeof(unsigned long);
+ *cow_offset += bitmap_offset;
+}
+
+static void cowify_req(struct io_thread_req *req, unsigned long *bitmap,
+ __u64 bitmap_offset, __u64 bitmap_len)
+{
+ __u64 sector = req->offset >> 9;
+ int i;
+
+ 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 *) bitmap))
+ ubd_set_bit(i, (unsigned char *)
+ &req->sector_mask);
+ }
+ }
+ else cowify_bitmap(req->offset, req->length, &req->sector_mask,
+ &req->cow_offset, bitmap, bitmap_offset,
+ req->bitmap_words, bitmap_len);
}
/* Called with ubd_io_lock held */
-static int prepare_request(struct request *req, struct io_thread_req *io_req,
- unsigned long long offset, int page_offset,
- int len, struct page *page)
+static int prepare_request(struct request *req, struct io_thread_req *io_req)
{
struct gendisk *disk = req->rq_disk;
struct ubd *dev = disk->private_data;
+ __u64 offset;
+ int len;
+
+ if(req->rq_status == RQ_INACTIVE) return(1);
/* This should be impossible now */
if((rq_data_dir(req) == WRITE) && !dev->openflags.w){
printk("Write attempted on readonly ubd device %s\n",
disk->disk_name);
- ubd_end_request(req, 0, 0);
+ end_request(req, 0);
return(1);
}
+ offset = ((__u64) req->sector) << 9;
+ len = req->current_nr_sectors << 9;
+
io_req->fds[0] = (dev->cow.file != NULL) ? dev->cow.fd : dev->fd;
io_req->fds[1] = dev->fd;
+ io_req->cow_offset = -1;
io_req->offset = offset;
io_req->length = len;
io_req->error = 0;
- io_req->op = (rq_data_dir(req) == READ) ? AIO_READ : AIO_WRITE;
+ io_req->sector_mask = 0;
+
+ io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE;
io_req->offsets[0] = 0;
io_req->offsets[1] = dev->cow.data_offset;
- io_req->buffer = page_address(page) + page_offset;
+ io_req->buffer = req->buffer;
io_req->sectorsize = 1 << 9;
- io_req->bitmap_offset = dev->cow.bitmap_offset;
- io_req->bitmap_start = -1;
- io_req->bitmap_end = -1;
- if((dev->cow.file != NULL) && (io_req->op == UBD_WRITE))
- cowify_bitmap(io_req, dev->cow.bitmap);
+ if(dev->cow.file != NULL)
+ cowify_req(io_req, dev->cow.bitmap, dev->cow.bitmap_offset,
+ dev->cow.bitmap_len);
+
return(0);
}
@@ -996,36 +1030,30 @@ static void do_ubd_request(request_queue_t *q)
{
struct io_thread_req io_req;
struct request *req;
- __u64 sector;
- int err;
-
- if(in_ubd)
- return;
- in_ubd = 1;
- while((req = elv_next_request(q)) != NULL){
- struct gendisk *disk = req->rq_disk;
- struct ubd *dev = disk->private_data;
- int n, i;
-
- blkdev_dequeue_request(req);
-
- sector = req->sector;
- n = blk_rq_map_sg(q, req, dev->sg);
-
- for(i = 0; i < n; i++){
- struct scatterlist *sg = &dev->sg[i];
-
- err = prepare_request(req, &io_req, sector << 9,
- sg->offset, sg->length,
- sg->page);
- if(err)
- continue;
-
- sector += sg->length >> 9;
- do_io(&io_req, req, dev->cow.bitmap);
+ int err, n;
+
+ if(thread_fd == -1){
+ while((req = elv_next_request(q)) != NULL){
+ err = prepare_request(req, &io_req);
+ if(!err){
+ do_io(&io_req);
+ __ubd_finish(req, io_req.error);
+ }
+ }
+ }
+ else {
+ if(do_ubd || (req = elv_next_request(q)) == NULL)
+ return;
+ err = prepare_request(req, &io_req);
+ if(!err){
+ do_ubd = ubd_handler;
+ n = os_write_file(thread_fd, (char *) &io_req,
+ sizeof(io_req));
+ if(n != sizeof(io_req))
+ printk("write to io thread failed, "
+ "errno = %d\n", -n);
}
}
- in_ubd = 0;
}
static int ubd_ioctl(struct inode * inode, struct file * file,
@@ -1241,95 +1269,131 @@ int create_cow_file(char *cow_file, char *backing_file, struct openflags flags,
return(err);
}
-void do_io(struct io_thread_req *req, struct request *r, unsigned long *bitmap)
+static int update_bitmap(struct io_thread_req *req)
{
- struct ubd_aio *aio;
- struct bitmap_io *bitmap_io = NULL;
- char *buf;
- void *bitmap_buf = NULL;
- unsigned long len, sector;
- int nsectors, start, end, bit, err;
- __u64 off;
-
- if(req->bitmap_start != -1){
- /* Round up to the nearest word */
- int round = sizeof(unsigned long);
- len = (req->bitmap_end - req->bitmap_start +
- round * 8 - 1) / (round * 8);
- len *= round;
-
- off = req->bitmap_start / (8 * round);
- off *= round;
-
- bitmap_io = kmalloc(sizeof(*bitmap_io), GFP_KERNEL);
- if(bitmap_io == NULL){
- printk("Failed to kmalloc bitmap IO\n");
- req->error = 1;
- return;
- }
+ int n;
- bitmap_buf = kmalloc(len, GFP_KERNEL);
- if(bitmap_buf == NULL){
- printk("do_io : kmalloc of bitmap chunk "
- "failed\n");
- kfree(bitmap_io);
- req->error = 1;
- return;
- }
- memcpy(bitmap_buf, &bitmap[off / sizeof(bitmap[0])], len);
-
- *bitmap_io = ((struct bitmap_io)
- { .count = ATOMIC_INIT(0),
- .aio = INIT_AIO(AIO_WRITE, req->fds[1],
- bitmap_buf, len,
- req->bitmap_offset + off,
- ubd_reply_fd) } );
- }
+ if(req->cow_offset == -1)
+ return(0);
- nsectors = req->length / req->sectorsize;
- start = 0;
- end = nsectors;
- bit = 0;
- do {
- if(bitmap != NULL){
- sector = req->offset / req->sectorsize;
- bit = ubd_test_bit(sector + start, bitmap);
- end = start;
- while((end < nsectors) &&
- (ubd_test_bit(sector + end, bitmap) == bit))
- end++;
- }
+ n = os_seek_file(req->fds[1], req->cow_offset);
+ if(n < 0){
+ printk("do_io - bitmap lseek failed : err = %d\n", -n);
+ return(1);
+ }
- off = req->offsets[bit] + req->offset +
- start * req->sectorsize;
- len = (end - start) * req->sectorsize;
- buf = &req->buffer[start * req->sectorsize];
+ n = os_write_file(req->fds[1], &req->bitmap_words,
+ sizeof(req->bitmap_words));
+ if(n != sizeof(req->bitmap_words)){
+ printk("do_io - bitmap update failed, err = %d fd = %d\n", -n,
+ req->fds[1]);
+ return(1);
+ }
- aio = kmalloc(sizeof(*aio), GFP_KERNEL);
- if(aio == NULL){
- req->error = 1;
- return;
- }
+ return(0);
+}
- *aio = ((struct ubd_aio)
- { .aio = INIT_AIO(req->op, req->fds[bit], buf,
- len, off, ubd_reply_fd),
- .len = len,
- .req = r,
- .bitmap = bitmap_io,
- .bitmap_buf = bitmap_buf });
-
- if(aio->bitmap != NULL)
- atomic_inc(&aio->bitmap->count);
-
- err = submit_aio(&aio->aio);
- if(err){
- printk("do_io - submit_aio failed, "
- "err = %d\n", err);
- req->error = 1;
- return;
- }
+void do_io(struct io_thread_req *req)
+{
+ char *buf;
+ unsigned long len;
+ int n, nsectors, start, end, bit;
+ int err;
+ __u64 off;
+
+ nsectors = req->length / req->sectorsize;
+ start = 0;
+ do {
+ bit = ubd_test_bit(start, (unsigned char *) &req->sector_mask);
+ end = start;
+ while((end < nsectors) &&
+ (ubd_test_bit(end, (unsigned char *)
+ &req->sector_mask) == bit))
+ end++;
+
+ off = req->offset + req->offsets[bit] +
+ start * req->sectorsize;
+ len = (end - start) * req->sectorsize;
+ buf = &req->buffer[start * req->sectorsize];
+
+ err = os_seek_file(req->fds[bit], off);
+ if(err < 0){
+ printk("do_io - lseek failed : err = %d\n", -err);
+ req->error = 1;
+ return;
+ }
+ if(req->op == UBD_READ){
+ n = 0;
+ do {
+ buf = &buf[n];
+ len -= n;
+ n = os_read_file(req->fds[bit], buf, len);
+ if (n < 0) {
+ printk("do_io - read failed, err = %d "
+ "fd = %d\n", -n, req->fds[bit]);
+ req->error = 1;
+ return;
+ }
+ } while((n < len) && (n != 0));
+ if (n < len) memset(&buf[n], 0, len - n);
+ } else {
+ n = os_write_file(req->fds[bit], buf, len);
+ if(n != len){
+ printk("do_io - write failed err = %d "
+ "fd = %d\n", -n, req->fds[bit]);
+ req->error = 1;
+ return;
+ }
+ }
+
+ start = end;
+ } while(start < nsectors);
- start = end;
- } while(start < nsectors);
+ req->error = update_bitmap(req);
}
+
+/* Changed in start_io_thread, which is serialized by being called only
+ * from ubd_init, which is an initcall.
+ */
+int kernel_fd = -1;
+
+/* Only changed by the io thread */
+int io_count = 0;
+
+int io_thread(void *arg)
+{
+ struct io_thread_req req;
+ int n;
+
+ ignore_sigwinch_sig();
+ while(1){
+ n = os_read_file(kernel_fd, &req, sizeof(req));
+ if(n != sizeof(req)){
+ if(n < 0)
+ printk("io_thread - read failed, fd = %d, "
+ "err = %d\n", kernel_fd, -n);
+ else {
+ printk("io_thread - short read, fd = %d, "
+ "length = %d\n", kernel_fd, n);
+ }
+ continue;
+ }
+ io_count++;
+ do_io(&req);
+ n = os_write_file(kernel_fd, &req, sizeof(req));
+ if(n != sizeof(req))
+ printk("io_thread - write failed, fd = %d, err = %d\n",
+ kernel_fd, -n);
+ }
+}
+
+/*
+ * 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/xterm.c b/arch/um/drivers/xterm.c
index 93dc1911363..90e0e5ff451 100644
--- a/arch/um/drivers/xterm.c
+++ b/arch/um/drivers/xterm.c
@@ -110,13 +110,15 @@ int xterm_open(int input, int output, int primary, void *d,
fd = mkstemp(file);
if(fd < 0){
+ err = -errno;
printk("xterm_open : mkstemp failed, errno = %d\n", errno);
- return(-errno);
+ return err;
}
if(unlink(file)){
+ err = -errno;
printk("xterm_open : unlink failed, errno = %d\n", errno);
- return(-errno);
+ return err;
}
os_close_file(fd);