extern char *read_dir(void *stream, unsigned long long *pos,
                      unsigned long long *ino_out, int *len_out);
 extern void close_file(void *stream);
+extern int replace_file(int oldfd, int fd);
 extern void close_dir(void *stream);
 extern int read_file(int fd, unsigned long long *offset, char *buf, int len);
 extern int write_file(int fd, unsigned long long *offset, const char *buf,
 
 
 int hostfs_file_open(struct inode *ino, struct file *file)
 {
+       static DEFINE_MUTEX(open_mutex);
        char *name;
        fmode_t mode = 0;
+       int err;
        int r = 0, w = 0, fd;
 
        mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
        if ((mode & HOSTFS_I(ino)->mode) == mode)
                return 0;
 
-       /*
-        * The file may already have been opened, but with the wrong access,
-        * so this resets things and reopens the file with the new access.
-        */
-       if (HOSTFS_I(ino)->fd != -1) {
-               close_file(&HOSTFS_I(ino)->fd);
-               HOSTFS_I(ino)->fd = -1;
-       }
+       mode |= HOSTFS_I(ino)->mode;
 
-       HOSTFS_I(ino)->mode |= mode;
-       if (HOSTFS_I(ino)->mode & FMODE_READ)
+retry:
+       if (mode & FMODE_READ)
                r = 1;
-       if (HOSTFS_I(ino)->mode & FMODE_WRITE)
+       if (mode & FMODE_WRITE)
                w = 1;
        if (w)
                r = 1;
        __putname(name);
        if (fd < 0)
                return fd;
-       FILE_HOSTFS_I(file)->fd = fd;
+
+       mutex_lock(&open_mutex);
+       /* somebody else had handled it first? */
+       if ((mode & HOSTFS_I(ino)->mode) == mode) {
+               mutex_unlock(&open_mutex);
+               return 0;
+       }
+       if ((mode | HOSTFS_I(ino)->mode) != mode) {
+               mode |= HOSTFS_I(ino)->mode;
+               mutex_unlock(&open_mutex);
+               close_file(&fd);
+               goto retry;
+       }
+       if (HOSTFS_I(ino)->fd == -1) {
+               HOSTFS_I(ino)->fd = fd;
+       } else {
+               err = replace_file(fd, HOSTFS_I(ino)->fd);
+               close_file(&fd);
+               if (err < 0) {
+                       mutex_unlock(&open_mutex);
+                       return err;
+               }
+       }
+       HOSTFS_I(ino)->mode = mode;
+       mutex_unlock(&open_mutex);
 
        return 0;
 }