forked from Minki/linux
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
This commit is contained in:
commit
20e029d791
@ -7,7 +7,6 @@
|
||||
#ifndef __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 io_thread(void *arg);
|
||||
extern int kernel_fd;
|
||||
|
@ -41,7 +41,7 @@
|
||||
#include <os.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 request *req;
|
||||
@ -866,6 +866,7 @@ static int ubd_add(int n, char **error_out)
|
||||
goto out;
|
||||
}
|
||||
ubd_dev->queue->queuedata = ubd_dev;
|
||||
blk_queue_flush(ubd_dev->queue, REQ_FLUSH);
|
||||
|
||||
blk_queue_max_segments(ubd_dev->queue, MAX_SG);
|
||||
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,
|
||||
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
static void do_ubd_request(struct request_queue *q)
|
||||
{
|
||||
struct io_thread_req *io_req;
|
||||
struct request *req;
|
||||
int n;
|
||||
|
||||
while(1){
|
||||
struct ubd *dev = q->queuedata;
|
||||
@ -1259,6 +1289,19 @@ static void do_ubd_request(struct request_queue *q)
|
||||
}
|
||||
|
||||
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){
|
||||
struct scatterlist *sg = &dev->sg[dev->start_sg];
|
||||
|
||||
@ -1273,17 +1316,8 @@ static void do_ubd_request(struct request_queue *q)
|
||||
(unsigned long long)dev->rq_pos << 9,
|
||||
sg->offset, sg->length, sg_page(sg));
|
||||
|
||||
n = os_write_file(thread_fd, &io_req,
|
||||
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);
|
||||
if (submit_request(io_req, dev) == false)
|
||||
return;
|
||||
}
|
||||
|
||||
dev->rq_pos += sg->length >> 9;
|
||||
dev->start_sg++;
|
||||
@ -1367,6 +1401,17 @@ static void do_io(struct io_thread_req *req)
|
||||
int err;
|
||||
__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;
|
||||
start = 0;
|
||||
do {
|
||||
@ -1431,7 +1476,8 @@ int io_thread(void *arg)
|
||||
struct io_thread_req *req;
|
||||
int n;
|
||||
|
||||
ignore_sigwinch_sig();
|
||||
os_fix_helper_signals();
|
||||
|
||||
while(1){
|
||||
n = os_read_file(kernel_fd, &req,
|
||||
sizeof(struct io_thread_req *));
|
||||
|
@ -21,11 +21,6 @@
|
||||
#include "ubd.h"
|
||||
#include <os.h>
|
||||
|
||||
void ignore_sigwinch_sig(void)
|
||||
{
|
||||
signal(SIGWINCH, SIG_IGN);
|
||||
}
|
||||
|
||||
int start_io_thread(unsigned long sp, int *fd_out)
|
||||
{
|
||||
int pid, fds[2], err;
|
||||
|
@ -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_read_file(int fd, void *buf, int len);
|
||||
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_modtime(const char *file, unsigned long *modtime);
|
||||
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);
|
||||
extern int os_drop_memory(void *addr, int length);
|
||||
extern int can_drop_memory(void);
|
||||
extern void os_flush_stdout(void);
|
||||
extern int os_mincore(void *addr, unsigned long len);
|
||||
|
||||
/* execvp.c */
|
||||
extern int execvp_noalloc(char *buf, const char *file, char *const argv[]);
|
||||
@ -233,6 +235,7 @@ extern void setup_machinename(char *machine_out);
|
||||
extern void setup_hostinfo(char *buf, int len);
|
||||
extern void os_dump_core(void) __attribute__ ((noreturn));
|
||||
extern void um_early_printk(const char *s, unsigned int n);
|
||||
extern void os_fix_helper_signals(void);
|
||||
|
||||
/* time.c */
|
||||
extern void idle_sleep(unsigned long long nsecs);
|
||||
|
@ -13,7 +13,7 @@ clean-files :=
|
||||
obj-y = config.o exec.o exitcode.o irq.o ksyms.o mem.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 \
|
||||
um_arch.o umid.o skas/
|
||||
um_arch.o umid.o maccess.o skas/
|
||||
|
||||
obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o
|
||||
obj-$(CONFIG_GPROF) += gprof_syms.o
|
||||
|
@ -337,6 +337,8 @@ static struct irq_chip normal_irq_type = {
|
||||
.irq_disable = dummy,
|
||||
.irq_enable = dummy,
|
||||
.irq_ack = dummy,
|
||||
.irq_mask = dummy,
|
||||
.irq_unmask = dummy,
|
||||
};
|
||||
|
||||
static struct irq_chip SIGVTALRM_irq_type = {
|
||||
@ -344,6 +346,8 @@ static struct irq_chip SIGVTALRM_irq_type = {
|
||||
.irq_disable = dummy,
|
||||
.irq_enable = dummy,
|
||||
.irq_ack = dummy,
|
||||
.irq_mask = dummy,
|
||||
.irq_unmask = dummy,
|
||||
};
|
||||
|
||||
void __init init_IRQ(void)
|
||||
|
24
arch/um/kernel/maccess.c
Normal file
24
arch/um/kernel/maccess.c
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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)
|
||||
struct io_event event;
|
||||
int err, n, reply_fd;
|
||||
|
||||
signal(SIGWINCH, SIG_IGN);
|
||||
|
||||
os_fix_helper_signals();
|
||||
while (1) {
|
||||
n = io_getevents(ctx, 1, 1, &event, NULL);
|
||||
if (n < 0) {
|
||||
@ -173,7 +172,7 @@ static int not_aio_thread(void *arg)
|
||||
struct aio_thread_reply reply;
|
||||
int err;
|
||||
|
||||
signal(SIGWINCH, SIG_IGN);
|
||||
os_fix_helper_signals();
|
||||
while (1) {
|
||||
err = read(aio_req_fd_r, &req, sizeof(req));
|
||||
if (err != sizeof(req)) {
|
||||
|
@ -266,6 +266,15 @@ int os_write_file(int fd, const void *buf, int len)
|
||||
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)
|
||||
{
|
||||
struct uml_stat buf;
|
||||
|
@ -123,6 +123,8 @@ int __init main(int argc, char **argv, char **envp)
|
||||
|
||||
setup_env_path();
|
||||
|
||||
setsid();
|
||||
|
||||
new_argv = malloc((argc + 1) * sizeof(char *));
|
||||
if (new_argv == NULL) {
|
||||
perror("Mallocing argv");
|
||||
|
@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
@ -232,6 +233,57 @@ out:
|
||||
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)
|
||||
{
|
||||
set_handler(SIGSEGV);
|
||||
@ -242,5 +294,4 @@ void init_new_thread_signals(void)
|
||||
signal(SIGHUP, SIG_IGN);
|
||||
set_handler(SIGIO);
|
||||
signal(SIGWINCH, SIG_IGN);
|
||||
signal(SIGTERM, SIG_DFL);
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ static int write_sigio_thread(void *unused)
|
||||
int i, n, respond_fd;
|
||||
char c;
|
||||
|
||||
signal(SIGWINCH, SIG_IGN);
|
||||
os_fix_helper_signals();
|
||||
fds = ¤t_poll;
|
||||
while (1) {
|
||||
n = poll(fds->poll, fds->used, -1);
|
||||
|
@ -94,6 +94,16 @@ static inline void __attribute__ ((noreturn)) uml_abort(void)
|
||||
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)
|
||||
{
|
||||
int pid;
|
||||
|
@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/ptrace.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <asm/ptrace.h>
|
||||
|
||||
int os_arch_prctl(int pid, int code, unsigned long *addr)
|
||||
{
|
||||
|
@ -361,6 +361,13 @@ retry:
|
||||
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)
|
||||
{
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
@ -386,7 +393,7 @@ static const struct file_operations hostfs_file_fops = {
|
||||
.write = do_sync_write,
|
||||
.mmap = generic_file_mmap,
|
||||
.open = hostfs_file_open,
|
||||
.release = NULL,
|
||||
.release = hostfs_file_release,
|
||||
.fsync = hostfs_fsync,
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user