aboutsummaryrefslogtreecommitdiff
path: root/arch/um/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'arch/um/drivers')
-rw-r--r--arch/um/drivers/daemon_kern.c4
-rw-r--r--arch/um/drivers/daemon_user.c6
-rw-r--r--arch/um/drivers/fd.c1
-rw-r--r--arch/um/drivers/net_kern.c21
-rw-r--r--arch/um/drivers/ubd_kern.c59
5 files changed, 61 insertions, 30 deletions
diff --git a/arch/um/drivers/daemon_kern.c b/arch/um/drivers/daemon_kern.c
index 30d285b266af..507e3cbac9d3 100644
--- a/arch/um/drivers/daemon_kern.c
+++ b/arch/um/drivers/daemon_kern.c
@@ -31,6 +31,10 @@ void daemon_init(struct net_device *dev, void *data)
dpri->fd = -1;
dpri->control = -1;
dpri->dev = dev;
+ /* We will free this pointer. If it contains crap we're burned. */
+ dpri->ctl_addr = NULL;
+ dpri->data_addr = NULL;
+ dpri->local_addr = NULL;
printk("daemon backend (uml_switch version %d) - %s:%s",
SWITCH_VERSION, dpri->sock_type, dpri->ctl_sock);
diff --git a/arch/um/drivers/daemon_user.c b/arch/um/drivers/daemon_user.c
index 1bb085b2824d..c944265955e2 100644
--- a/arch/um/drivers/daemon_user.c
+++ b/arch/um/drivers/daemon_user.c
@@ -158,10 +158,16 @@ static void daemon_remove(void *data)
struct daemon_data *pri = data;
os_close_file(pri->fd);
+ pri->fd = -1;
os_close_file(pri->control);
+ pri->control = -1;
+
kfree(pri->data_addr);
+ pri->data_addr = NULL;
kfree(pri->ctl_addr);
+ pri->ctl_addr = NULL;
kfree(pri->local_addr);
+ pri->local_addr = NULL;
}
int daemon_user_write(int fd, void *buf, int len, struct daemon_data *pri)
diff --git a/arch/um/drivers/fd.c b/arch/um/drivers/fd.c
index 3296e86a03a5..c41f75e4acb5 100644
--- a/arch/um/drivers/fd.c
+++ b/arch/um/drivers/fd.c
@@ -11,6 +11,7 @@
#include "user.h"
#include "user_util.h"
#include "chan_user.h"
+#include "os.h"
struct fd_chan {
int fd;
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c
index fb1f9fb9b871..8ebb2241ad42 100644
--- a/arch/um/drivers/net_kern.c
+++ b/arch/um/drivers/net_kern.c
@@ -68,6 +68,11 @@ static int uml_net_rx(struct net_device *dev)
return pkt_len;
}
+static void uml_dev_close(void* dev)
+{
+ dev_close( (struct net_device *) dev);
+}
+
irqreturn_t uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = dev_id;
@@ -80,15 +85,21 @@ irqreturn_t uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
spin_lock(&lp->lock);
while((err = uml_net_rx(dev)) > 0) ;
if(err < 0) {
+ DECLARE_WORK(close_work, uml_dev_close, dev);
printk(KERN_ERR
"Device '%s' read returned %d, shutting it down\n",
dev->name, err);
- dev_close(dev);
+ /* dev_close can't be called in interrupt context, and takes
+ * again lp->lock.
+ * And dev_close() can be safely called multiple times on the
+ * same device, since it tests for (dev->flags & IFF_UP). So
+ * there's no harm in delaying the device shutdown. */
+ schedule_work(&close_work);
goto out;
}
reactivate_fd(lp->fd, UM_ETH_IRQ);
- out:
+out:
spin_unlock(&lp->lock);
return(IRQ_HANDLED);
}
@@ -317,6 +328,11 @@ static int eth_configure(int n, void *init, char *mac,
return 1;
}
+ lp = dev->priv;
+ /* This points to the transport private data. It's still clear, but we
+ * must memset it to 0 *now*. Let's help the drivers. */
+ memset(lp, 0, size);
+
/* sysfs register */
if (!driver_registered) {
platform_driver_register(&uml_net_driver);
@@ -358,7 +374,6 @@ static int eth_configure(int n, void *init, char *mac,
free_netdev(dev);
return 1;
}
- lp = dev->priv;
/* lp.user is the first four bytes of the transport data, which
* has already been initialized. This structure assignment will
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c
index 7696f8d2d89c..101efd26d467 100644
--- a/arch/um/drivers/ubd_kern.c
+++ b/arch/um/drivers/ubd_kern.c
@@ -1103,31 +1103,33 @@ static int ubd_ioctl(struct inode * inode, struct file * file,
return(-EINVAL);
}
-static int same_backing_files(char *from_cmdline, char *from_cow, char *cow)
+static int path_requires_switch(char *from_cmdline, char *from_cow, char *cow)
{
struct uml_stat buf1, buf2;
int err;
- if(from_cmdline == NULL) return(1);
- if(!strcmp(from_cmdline, from_cow)) return(1);
+ if(from_cmdline == NULL)
+ return 0;
+ if(!strcmp(from_cmdline, from_cow))
+ return 0;
err = os_stat_file(from_cmdline, &buf1);
if(err < 0){
printk("Couldn't stat '%s', err = %d\n", from_cmdline, -err);
- return(1);
+ return 0;
}
err = os_stat_file(from_cow, &buf2);
if(err < 0){
printk("Couldn't stat '%s', err = %d\n", from_cow, -err);
- return(1);
+ return 1;
}
if((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino))
- return(1);
+ return 0;
printk("Backing file mismatch - \"%s\" requested,\n"
"\"%s\" specified in COW header of \"%s\"\n",
from_cmdline, from_cow, cow);
- return(0);
+ return 1;
}
static int backing_file_mismatch(char *file, __u64 size, time_t mtime)
@@ -1189,18 +1191,19 @@ int open_ubd_file(char *file, struct openflags *openflags,
unsigned long long size;
__u32 version, align;
char *backing_file;
- int fd, err, sectorsize, same, mode = 0644;
+ int fd, err, sectorsize, asked_switch, mode = 0644;
fd = os_open_file(file, *openflags, mode);
- if(fd < 0){
- if((fd == -ENOENT) && (create_cow_out != NULL))
+ if (fd < 0) {
+ if ((fd == -ENOENT) && (create_cow_out != NULL))
*create_cow_out = 1;
- if(!openflags->w ||
- ((fd != -EROFS) && (fd != -EACCES))) return(fd);
+ if (!openflags->w ||
+ ((fd != -EROFS) && (fd != -EACCES)))
+ return fd;
openflags->w = 0;
fd = os_open_file(file, *openflags, mode);
- if(fd < 0)
- return(fd);
+ if (fd < 0)
+ return fd;
}
err = os_lock_file(fd, openflags->w);
@@ -1209,7 +1212,9 @@ int open_ubd_file(char *file, struct openflags *openflags,
goto out_close;
}
- if(backing_file_out == NULL) return(fd);
+ /* Succesful return case! */
+ if(backing_file_out == NULL)
+ return(fd);
err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime,
&size, &sectorsize, &align, bitmap_offset_out);
@@ -1218,34 +1223,34 @@ int open_ubd_file(char *file, struct openflags *openflags,
"errno = %d\n", file, -err);
goto out_close;
}
- if(err) return(fd);
-
- if(backing_file_out == NULL) return(fd);
+ if(err)
+ return(fd);
- same = same_backing_files(*backing_file_out, backing_file, file);
+ asked_switch = path_requires_switch(*backing_file_out, backing_file, file);
- if(!same && !backing_file_mismatch(*backing_file_out, size, mtime)){
+ /* Allow switching only if no mismatch. */
+ if (asked_switch && !backing_file_mismatch(*backing_file_out, size, mtime)) {
printk("Switching backing file to '%s'\n", *backing_file_out);
err = write_cow_header(file, fd, *backing_file_out,
sectorsize, align, &size);
- if(err){
+ if (err) {
printk("Switch failed, errno = %d\n", -err);
- return(err);
+ goto out_close;
}
- }
- else {
+ } else {
*backing_file_out = backing_file;
err = backing_file_mismatch(*backing_file_out, size, mtime);
- if(err) goto out_close;
+ if (err)
+ goto out_close;
}
cow_sizes(version, size, sectorsize, align, *bitmap_offset_out,
bitmap_len_out, data_offset_out);
- return(fd);
+ return fd;
out_close:
os_close_file(fd);
- return(err);
+ return err;
}
int create_cow_file(char *cow_file, char *backing_file, struct openflags flags,