Commit 20e029d7 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml

Pull UML updates from Richard Weinberger:
 "This pile contains mostly fixes and improvements for issues identified
  by Richard W M Jones while adding UML as backend to libguestfs"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml:
  um: Add irq chip um/mask handlers
  um: prctl: Do not include linux/ptrace.h
  um: Run UML in it's own session.
  um: Cleanup SIGTERM handling
  um: ubd: Introduce submit_request()
  um: ubd: Add REQ_FLUSH suppport
  um: Implement probe_kernel_read()
  um: hostfs: Fix writeback
parents e5c832d5 81bab4c3
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
#ifndef __UM_UBD_USER_H #ifndef __UM_UBD_USER_H
#define __UM_UBD_USER_H #define __UM_UBD_USER_H
extern void ignore_sigwinch_sig(void);
extern int start_io_thread(unsigned long sp, int *fds_out); extern int start_io_thread(unsigned long sp, int *fds_out);
extern int io_thread(void *arg); extern int io_thread(void *arg);
extern int kernel_fd; extern int kernel_fd;
......
...@@ -41,7 +41,7 @@ ...@@ -41,7 +41,7 @@
#include <os.h> #include <os.h>
#include "cow.h" #include "cow.h"
enum ubd_req { UBD_READ, UBD_WRITE }; enum ubd_req { UBD_READ, UBD_WRITE, UBD_FLUSH };
struct io_thread_req { struct io_thread_req {
struct request *req; struct request *req;
...@@ -866,6 +866,7 @@ static int ubd_add(int n, char **error_out) ...@@ -866,6 +866,7 @@ static int ubd_add(int n, char **error_out)
goto out; goto out;
} }
ubd_dev->queue->queuedata = ubd_dev; ubd_dev->queue->queuedata = ubd_dev;
blk_queue_flush(ubd_dev->queue, REQ_FLUSH);
blk_queue_max_segments(ubd_dev->queue, MAX_SG); blk_queue_max_segments(ubd_dev->queue, MAX_SG);
err = ubd_disk_register(UBD_MAJOR, ubd_dev->size, n, &ubd_gendisk[n]); err = ubd_disk_register(UBD_MAJOR, ubd_dev->size, n, &ubd_gendisk[n]);
...@@ -1238,12 +1239,41 @@ static void prepare_request(struct request *req, struct io_thread_req *io_req, ...@@ -1238,12 +1239,41 @@ static void prepare_request(struct request *req, struct io_thread_req *io_req,
} }
/* Called with dev->lock held */
static void prepare_flush_request(struct request *req,
struct io_thread_req *io_req)
{
struct gendisk *disk = req->rq_disk;
struct ubd *ubd_dev = disk->private_data;
io_req->req = req;
io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd :
ubd_dev->fd;
io_req->op = UBD_FLUSH;
}
static bool submit_request(struct io_thread_req *io_req, struct ubd *dev)
{
int n = os_write_file(thread_fd, &io_req,
sizeof(io_req));
if (n != sizeof(io_req)) {
if (n != -EAGAIN)
printk("write to io thread failed, "
"errno = %d\n", -n);
else if (list_empty(&dev->restart))
list_add(&dev->restart, &restart);
kfree(io_req);
return false;
}
return true;
}
/* Called with dev->lock held */ /* Called with dev->lock held */
static void do_ubd_request(struct request_queue *q) static void do_ubd_request(struct request_queue *q)
{ {
struct io_thread_req *io_req; struct io_thread_req *io_req;
struct request *req; struct request *req;
int n;
while(1){ while(1){
struct ubd *dev = q->queuedata; struct ubd *dev = q->queuedata;
...@@ -1259,6 +1289,19 @@ static void do_ubd_request(struct request_queue *q) ...@@ -1259,6 +1289,19 @@ static void do_ubd_request(struct request_queue *q)
} }
req = dev->request; req = dev->request;
if (req->cmd_flags & REQ_FLUSH) {
io_req = kmalloc(sizeof(struct io_thread_req),
GFP_ATOMIC);
if (io_req == NULL) {
if (list_empty(&dev->restart))
list_add(&dev->restart, &restart);
return;
}
prepare_flush_request(req, io_req);
submit_request(io_req, dev);
}
while(dev->start_sg < dev->end_sg){ while(dev->start_sg < dev->end_sg){
struct scatterlist *sg = &dev->sg[dev->start_sg]; struct scatterlist *sg = &dev->sg[dev->start_sg];
...@@ -1273,17 +1316,8 @@ static void do_ubd_request(struct request_queue *q) ...@@ -1273,17 +1316,8 @@ static void do_ubd_request(struct request_queue *q)
(unsigned long long)dev->rq_pos << 9, (unsigned long long)dev->rq_pos << 9,
sg->offset, sg->length, sg_page(sg)); sg->offset, sg->length, sg_page(sg));
n = os_write_file(thread_fd, &io_req, if (submit_request(io_req, dev) == false)
sizeof(struct io_thread_req *));
if(n != sizeof(struct io_thread_req *)){
if(n != -EAGAIN)
printk("write to io thread failed, "
"errno = %d\n", -n);
else if(list_empty(&dev->restart))
list_add(&dev->restart, &restart);
kfree(io_req);
return; return;
}
dev->rq_pos += sg->length >> 9; dev->rq_pos += sg->length >> 9;
dev->start_sg++; dev->start_sg++;
...@@ -1367,6 +1401,17 @@ static void do_io(struct io_thread_req *req) ...@@ -1367,6 +1401,17 @@ static void do_io(struct io_thread_req *req)
int err; int err;
__u64 off; __u64 off;
if (req->op == UBD_FLUSH) {
/* fds[0] is always either the rw image or our cow file */
n = os_sync_file(req->fds[0]);
if (n != 0) {
printk("do_io - sync failed err = %d "
"fd = %d\n", -n, req->fds[0]);
req->error = 1;
}
return;
}
nsectors = req->length / req->sectorsize; nsectors = req->length / req->sectorsize;
start = 0; start = 0;
do { do {
...@@ -1431,7 +1476,8 @@ int io_thread(void *arg) ...@@ -1431,7 +1476,8 @@ int io_thread(void *arg)
struct io_thread_req *req; struct io_thread_req *req;
int n; int n;
ignore_sigwinch_sig(); os_fix_helper_signals();
while(1){ while(1){
n = os_read_file(kernel_fd, &req, n = os_read_file(kernel_fd, &req,
sizeof(struct io_thread_req *)); sizeof(struct io_thread_req *));
......
...@@ -21,11 +21,6 @@ ...@@ -21,11 +21,6 @@
#include "ubd.h" #include "ubd.h"
#include <os.h> #include <os.h>
void ignore_sigwinch_sig(void)
{
signal(SIGWINCH, SIG_IGN);
}
int start_io_thread(unsigned long sp, int *fd_out) int start_io_thread(unsigned long sp, int *fd_out)
{ {
int pid, fds[2], err; int pid, fds[2], err;
......
...@@ -141,6 +141,7 @@ extern int os_seek_file(int fd, unsigned long long offset); ...@@ -141,6 +141,7 @@ extern int os_seek_file(int fd, unsigned long long offset);
extern int os_open_file(const char *file, struct openflags flags, int mode); extern int os_open_file(const char *file, struct openflags flags, int mode);
extern int os_read_file(int fd, void *buf, int len); extern int os_read_file(int fd, void *buf, int len);
extern int os_write_file(int fd, const void *buf, int count); extern int os_write_file(int fd, const void *buf, int count);
extern int os_sync_file(int fd);
extern int os_file_size(const char *file, unsigned long long *size_out); extern int os_file_size(const char *file, unsigned long long *size_out);
extern int os_file_modtime(const char *file, unsigned long *modtime); extern int os_file_modtime(const char *file, unsigned long *modtime);
extern int os_pipe(int *fd, int stream, int close_on_exec); extern int os_pipe(int *fd, int stream, int close_on_exec);
...@@ -200,6 +201,7 @@ extern int os_unmap_memory(void *addr, int len); ...@@ -200,6 +201,7 @@ extern int os_unmap_memory(void *addr, int len);
extern int os_drop_memory(void *addr, int length); extern int os_drop_memory(void *addr, int length);
extern int can_drop_memory(void); extern int can_drop_memory(void);
extern void os_flush_stdout(void); extern void os_flush_stdout(void);
extern int os_mincore(void *addr, unsigned long len);
/* execvp.c */ /* execvp.c */
extern int execvp_noalloc(char *buf, const char *file, char *const argv[]); extern int execvp_noalloc(char *buf, const char *file, char *const argv[]);
...@@ -233,6 +235,7 @@ extern void setup_machinename(char *machine_out); ...@@ -233,6 +235,7 @@ extern void setup_machinename(char *machine_out);
extern void setup_hostinfo(char *buf, int len); extern void setup_hostinfo(char *buf, int len);
extern void os_dump_core(void) __attribute__ ((noreturn)); extern void os_dump_core(void) __attribute__ ((noreturn));
extern void um_early_printk(const char *s, unsigned int n); extern void um_early_printk(const char *s, unsigned int n);
extern void os_fix_helper_signals(void);
/* time.c */ /* time.c */
extern void idle_sleep(unsigned long long nsecs); extern void idle_sleep(unsigned long long nsecs);
......
...@@ -13,7 +13,7 @@ clean-files := ...@@ -13,7 +13,7 @@ clean-files :=
obj-y = config.o exec.o exitcode.o irq.o ksyms.o mem.o \ obj-y = config.o exec.o exitcode.o irq.o ksyms.o mem.o \
physmem.o process.o ptrace.o reboot.o sigio.o \ physmem.o process.o ptrace.o reboot.o sigio.o \
signal.o smp.o syscall.o sysrq.o time.o tlb.o trap.o \ signal.o smp.o syscall.o sysrq.o time.o tlb.o trap.o \
um_arch.o umid.o skas/ um_arch.o umid.o maccess.o skas/
obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o
obj-$(CONFIG_GPROF) += gprof_syms.o obj-$(CONFIG_GPROF) += gprof_syms.o
......
...@@ -337,6 +337,8 @@ static struct irq_chip normal_irq_type = { ...@@ -337,6 +337,8 @@ static struct irq_chip normal_irq_type = {
.irq_disable = dummy, .irq_disable = dummy,
.irq_enable = dummy, .irq_enable = dummy,
.irq_ack = dummy, .irq_ack = dummy,
.irq_mask = dummy,
.irq_unmask = dummy,
}; };
static struct irq_chip SIGVTALRM_irq_type = { static struct irq_chip SIGVTALRM_irq_type = {
...@@ -344,6 +346,8 @@ static struct irq_chip SIGVTALRM_irq_type = { ...@@ -344,6 +346,8 @@ static struct irq_chip SIGVTALRM_irq_type = {
.irq_disable = dummy, .irq_disable = dummy,
.irq_enable = dummy, .irq_enable = dummy,
.irq_ack = dummy, .irq_ack = dummy,
.irq_mask = dummy,
.irq_unmask = dummy,
}; };
void __init init_IRQ(void) void __init init_IRQ(void)
......
/*
* Copyright (C) 2013 Richard Weinberger <richrd@nod.at>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/uaccess.h>
#include <linux/kernel.h>
#include <os.h>
long probe_kernel_read(void *dst, const void *src, size_t size)
{
void *psrc = (void *)rounddown((unsigned long)src, PAGE_SIZE);
if ((unsigned long)src < PAGE_SIZE || size <= 0)
return -EFAULT;
if (os_mincore(psrc, size + src - psrc) <= 0)
return -EFAULT;
return __probe_kernel_read(dst, src, size);
}
...@@ -104,8 +104,7 @@ static int aio_thread(void *arg) ...@@ -104,8 +104,7 @@ static int aio_thread(void *arg)
struct io_event event; struct io_event event;
int err, n, reply_fd; int err, n, reply_fd;
signal(SIGWINCH, SIG_IGN); os_fix_helper_signals();
while (1) { while (1) {
n = io_getevents(ctx, 1, 1, &event, NULL); n = io_getevents(ctx, 1, 1, &event, NULL);
if (n < 0) { if (n < 0) {
...@@ -173,7 +172,7 @@ static int not_aio_thread(void *arg) ...@@ -173,7 +172,7 @@ static int not_aio_thread(void *arg)
struct aio_thread_reply reply; struct aio_thread_reply reply;
int err; int err;
signal(SIGWINCH, SIG_IGN); os_fix_helper_signals();
while (1) { while (1) {
err = read(aio_req_fd_r, &req, sizeof(req)); err = read(aio_req_fd_r, &req, sizeof(req));
if (err != sizeof(req)) { if (err != sizeof(req)) {
......
...@@ -266,6 +266,15 @@ int os_write_file(int fd, const void *buf, int len) ...@@ -266,6 +266,15 @@ int os_write_file(int fd, const void *buf, int len)
return n; return n;
} }
int os_sync_file(int fd)
{
int n = fsync(fd);
if (n < 0)
return -errno;
return n;
}
int os_file_size(const char *file, unsigned long long *size_out) int os_file_size(const char *file, unsigned long long *size_out)
{ {
struct uml_stat buf; struct uml_stat buf;
......
...@@ -123,6 +123,8 @@ int __init main(int argc, char **argv, char **envp) ...@@ -123,6 +123,8 @@ int __init main(int argc, char **argv, char **envp)
setup_env_path(); setup_env_path();
setsid();
new_argv = malloc((argc + 1) * sizeof(char *)); new_argv = malloc((argc + 1) * sizeof(char *));
if (new_argv == NULL) { if (new_argv == NULL) {
perror("Mallocing argv"); perror("Mallocing argv");
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
*/ */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <errno.h> #include <errno.h>
#include <signal.h> #include <signal.h>
...@@ -232,6 +233,57 @@ int __init can_drop_memory(void) ...@@ -232,6 +233,57 @@ int __init can_drop_memory(void)
return ok; return ok;
} }
static int os_page_mincore(void *addr)
{
char vec[2];
int ret;
ret = mincore(addr, UM_KERN_PAGE_SIZE, vec);
if (ret < 0) {
if (errno == ENOMEM || errno == EINVAL)
return 0;
else
return -errno;
}
return vec[0] & 1;
}
int os_mincore(void *addr, unsigned long len)
{
char *vec;
int ret, i;
if (len <= UM_KERN_PAGE_SIZE)
return os_page_mincore(addr);
vec = calloc(1, (len + UM_KERN_PAGE_SIZE - 1) / UM_KERN_PAGE_SIZE);
if (!vec)
return -ENOMEM;
ret = mincore(addr, UM_KERN_PAGE_SIZE, vec);
if (ret < 0) {
if (errno == ENOMEM || errno == EINVAL)
ret = 0;
else
ret = -errno;
goto out;
}
for (i = 0; i < ((len + UM_KERN_PAGE_SIZE - 1) / UM_KERN_PAGE_SIZE); i++) {
if (!(vec[i] & 1)) {
ret = 0;
goto out;
}
}
ret = 1;
out:
free(vec);
return ret;
}
void init_new_thread_signals(void) void init_new_thread_signals(void)
{ {
set_handler(SIGSEGV); set_handler(SIGSEGV);
...@@ -242,5 +294,4 @@ void init_new_thread_signals(void) ...@@ -242,5 +294,4 @@ void init_new_thread_signals(void)
signal(SIGHUP, SIG_IGN); signal(SIGHUP, SIG_IGN);
set_handler(SIGIO); set_handler(SIGIO);
signal(SIGWINCH, SIG_IGN); signal(SIGWINCH, SIG_IGN);
signal(SIGTERM, SIG_DFL);
} }
...@@ -55,7 +55,7 @@ static int write_sigio_thread(void *unused) ...@@ -55,7 +55,7 @@ static int write_sigio_thread(void *unused)
int i, n, respond_fd; int i, n, respond_fd;
char c; char c;
signal(SIGWINCH, SIG_IGN); os_fix_helper_signals();
fds = &current_poll; fds = &current_poll;
while (1) { while (1) {
n = poll(fds->poll, fds->used, -1); n = poll(fds->poll, fds->used, -1);
......
...@@ -94,6 +94,16 @@ static inline void __attribute__ ((noreturn)) uml_abort(void) ...@@ -94,6 +94,16 @@ static inline void __attribute__ ((noreturn)) uml_abort(void)
exit(127); exit(127);
} }
/*
* UML helper threads must not handle SIGWINCH/INT/TERM
*/
void os_fix_helper_signals(void)
{
signal(SIGWINCH, SIG_IGN);
signal(SIGINT, SIG_DFL);
signal(SIGTERM, SIG_DFL);
}
void os_dump_core(void) void os_dump_core(void)
{ {
int pid; int pid;
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
*/ */
#include <sys/ptrace.h> #include <sys/ptrace.h>
#include <linux/ptrace.h> #include <asm/ptrace.h>
int os_arch_prctl(int pid, int code, unsigned long *addr) int os_arch_prctl(int pid, int code, unsigned long *addr)
{ {
......
...@@ -361,6 +361,13 @@ int hostfs_file_open(struct inode *ino, struct file *file) ...@@ -361,6 +361,13 @@ int hostfs_file_open(struct inode *ino, struct file *file)
return 0; return 0;
} }
static int hostfs_file_release(struct inode *inode, struct file *file)
{
filemap_write_and_wait(inode->i_mapping);
return 0;
}
int hostfs_fsync(struct file *file, loff_t start, loff_t end, int datasync) int hostfs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
{ {
struct inode *inode = file->f_mapping->host; struct inode *inode = file->f_mapping->host;
...@@ -386,7 +393,7 @@ static const struct file_operations hostfs_file_fops = { ...@@ -386,7 +393,7 @@ static const struct file_operations hostfs_file_fops = {
.write = do_sync_write, .write = do_sync_write,
.mmap = generic_file_mmap, .mmap = generic_file_mmap,
.open = hostfs_file_open, .open = hostfs_file_open,
.release = NULL, .release = hostfs_file_release,
.fsync = hostfs_fsync, .fsync = hostfs_fsync,
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment