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:
Linus Torvalds 2013-09-09 09:03:46 -07:00
commit 20e029d791
15 changed files with 176 additions and 27 deletions

View File

@ -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;

View File

@ -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 *));

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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
View 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);
}

View File

@ -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)) {

View File

@ -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;

View File

@ -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");

View File

@ -4,6 +4,7 @@
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
@ -232,6 +233,57 @@ int __init can_drop_memory(void)
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);
}

View File

@ -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 = &current_poll;
while (1) {
n = poll(fds->poll, fds->used, -1);

View File

@ -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;

View File

@ -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)
{

View File

@ -361,6 +361,13 @@ int hostfs_file_open(struct inode *ino, struct file *file)
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,
};