various fixes
authorMiklos Szeredi <miklos@szeredi.hu>
Tue, 23 Nov 2004 22:32:16 +0000 (22:32 +0000)
committerMiklos Szeredi <miklos@szeredi.hu>
Tue, 23 Nov 2004 22:32:16 +0000 (22:32 +0000)
ChangeLog
kernel/dev.c
kernel/dir.c
kernel/fuse_i.h
kernel/inode.c
kernel/linux/fuse.h
lib/fuse.c
lib/mount.c
util/fusermount.c

index 61d8293cfe98d5d8e9c7bc4841beb8446ccc9a7b..e8d2cacdb6f8dbd9816645c2ec3a93f0add18ee3 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2004-11-23  Miklos Szeredi <miklos@szeredi.hu>
+
+       * More cleanups in the kernel
+
+       * The 10,229 charater device number has been assigned for FUSE
+
+       * Version file checking fix (reported by Christian Magnusson)
+
+       * fusermount: opening the fuse device now doesn't need /sys.
+
+       * Optimize reading by controlling the maximum readahead based on
+       the 'max_read' mount option
+
+       * fixes for UCLIBC (Christian Magnusson)
+
 2004-11-19  Miklos Szeredi <miklos@szeredi.hu>
 
        * Cleaned up kernel in preparation for merge into mainline:
index 726177097c75ab4e966ed0fe77069cc0fa5417b0..da41e599e55647fd8f3bd2f42bb31646d1d67e67 100644 (file)
@@ -8,6 +8,7 @@
 
 #include "fuse_i.h"
 
+#include <linux/init.h>
 #include <linux/module.h>
 #include <linux/poll.h>
 #ifdef KERNEL_2_6
@@ -261,7 +262,6 @@ static ssize_t fuse_dev_read(struct file *file, char __user *buf,
        else if (!list_empty(&fc->pending)) {
                req = list_entry(fc->pending.next, struct fuse_req, list);
                list_del_init(&req->list);
-               req->locked = 1;
        }
        spin_unlock(&fuse_lock);
        if (!fc)
@@ -275,12 +275,9 @@ static ssize_t fuse_dev_read(struct file *file, char __user *buf,
                if (ret < 0) {
                        req->out.h.error = -EPROTO;
                        req->finished = 1;
-               } else {
+               } else
                        list_add_tail(&req->list, &fc->processing);
-                       req->sent = 1;
-               }
-               req->locked = 0;
-               if (ret < 0 || req->interrupted)
+               if (ret < 0)
                        /* Unlocks fuse_lock: */
                        request_end(fc, req);
                else
@@ -471,10 +468,8 @@ static ssize_t fuse_dev_write(struct file *file, const char __user *buf,
 
        spin_lock(&fuse_lock);
        req = request_find(fc, oh.unique);
-       if (req != NULL) {
+       if (req != NULL)
                list_del_init(&req->list);
-               req->locked = 1;
-       }
        spin_unlock(&fuse_lock);
        if (!req)
                return -ENOENT;
@@ -491,7 +486,6 @@ static ssize_t fuse_dev_write(struct file *file, const char __user *buf,
                        process_getdir(req);
        }       
        req->finished = 1;
-       req->locked = 0;
        /* Unlocks fuse_lock: */
        request_end(fc, req);
 
@@ -565,7 +559,6 @@ struct file_operations fuse_dev_operations = {
 };
 
 #ifdef KERNEL_2_6
-#define FUSE_MINOR MISC_DYNAMIC_MINOR
 
 #ifndef FUSE_MAINLINE
 static decl_subsys(fs, NULL, NULL);
index 124bf867e46087bb8c2c93338c8e0c470b409ee0..fe8e803ed2d9237656ae951023a402ccf5c2a2f2 100644 (file)
@@ -111,6 +111,7 @@ struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
                        int generation, struct fuse_attr *attr, int version)
 {
        struct inode *inode;
+       struct fuse_conn *fc = SB_FC(sb);
 
        inode = iget5_locked(sb, nodeid, fuse_inode_eq, fuse_inode_set, &nodeid);
        if (!inode)
@@ -118,6 +119,7 @@ struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
 
        if ((inode->i_state & I_NEW)) {
                inode->i_generation = generation;
+               inode->i_data.backing_dev_info = &fc->bdi;
                fuse_init_inode(inode, attr);
                unlock_new_inode(inode);
        } else if (inode->i_generation != generation)
index e454fd0447e0caaea327aacd01213e6ff82391a2..c5b8e238742ddecaa6c531c24a9014ac29b07635 100644 (file)
 #include <linux/wait.h>
 #include <linux/list.h>
 #include <linux/spinlock.h>
+#ifdef KERNEL_2_6
+#include <linux/mm.h>
+#include <linux/backing-dev.h>
+#endif
 #include <asm/semaphore.h>
 
 #ifndef BUG_ON
@@ -152,15 +156,6 @@ struct fuse_req {
        /** True if the request has reply */
        unsigned int isreply:1;
 
-       /** The request is locked */
-       unsigned int locked:1;
-
-       /** The request has been interrupted while it was locked */
-       unsigned int interrupted:1;
-
-       /* The request has been sent to the client */
-       unsigned int sent:1;
-
        /* The request is preallocated */
        unsigned int preallocated:1;
 
@@ -264,6 +259,11 @@ struct fuse_conn {
 
        /** Is removexattr not implemented by fs? */
        unsigned int no_removexattr : 1;
+
+#ifdef KERNEL_2_6
+       /** Backing dev info */
+       struct backing_dev_info bdi;
+#endif
 };
 
 struct fuse_getdir_out_i {
@@ -283,7 +283,16 @@ struct fuse_getdir_out_i {
 extern struct file_operations fuse_dev_operations;
 
 /**
- * The lock to protect fuses structures
+ * This is the single global spinlock which protects FUSE's structures
+ *
+ * The following data is protected by this lock:
+ * 
+ *  - the private_data field of the device file
+ *  - the s_fs_info field of the super block
+ *  - unused_list, pending, processing lists in fuse_conn
+ *  - the unique request ID counter reqctr in fuse_conn
+ *  - the sb (super_block) field in fuse_conn
+ *  - the file (device file) field in fuse_conn
  */
 extern spinlock_t fuse_lock;
 
@@ -336,7 +345,6 @@ int fuse_fs_init(void);
  */
 void fuse_fs_cleanup(void);
 
-
 /** 
  * Allocate a request
  */
index 55a283b1e3fff896f22c1be3ec6cc79394abbb33..8cae834961c689397697001c0642963defe79408 100644 (file)
@@ -178,7 +178,9 @@ enum {
        OPT_ALLOW_OTHER,
        OPT_ALLOW_ROOT,
        OPT_KERNEL_CACHE,
+#ifndef FUSE_MAINLINE
        OPT_LARGE_READ,
+#endif
        OPT_DIRECT_IO,
        OPT_MAX_READ,
        OPT_ERR 
@@ -192,7 +194,9 @@ static match_table_t tokens = {
        {OPT_ALLOW_OTHER,               "allow_other"},
        {OPT_ALLOW_ROOT,                "allow_root"},
        {OPT_KERNEL_CACHE,              "kernel_cache"},
+#ifndef FUSE_MAINLINE
        {OPT_LARGE_READ,                "large_read"},
+#endif
        {OPT_DIRECT_IO,                 "direct_io"},
        {OPT_MAX_READ,                  "max_read=%u"},
        {OPT_ERR,                       NULL}
@@ -247,7 +251,8 @@ static int parse_fuse_opt(char *opt, struct fuse_mount_data *d)
                case OPT_KERNEL_CACHE:
                        d->flags |= FUSE_KERNEL_CACHE;
                        break;
-                       
+
+#ifndef FUSE_MAINLINE                  
                case OPT_LARGE_READ:
 #ifndef KERNEL_2_6
                        d->flags |= FUSE_LARGE_READ;
@@ -261,7 +266,7 @@ static int parse_fuse_opt(char *opt, struct fuse_mount_data *d)
                        }
 #endif
                        break;
-                       
+#endif                 
                case OPT_DIRECT_IO:
                        d->flags |= FUSE_DIRECT_IO;
                        break;
@@ -351,6 +356,10 @@ static struct fuse_conn *new_conn(void)
                        req->preallocated = 1;
                        list_add(&req->list, &fc->unused_list);
                }
+#ifdef KERNEL_2_6
+               fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
+               fc->bdi.unplug_io_fn = default_unplug_io_fn;
+#endif
                fc->reqctr = 1;
        }
        return fc;
@@ -502,6 +511,10 @@ static int fuse_read_super(struct super_block *sb, void *data, int silent)
        fc->flags = d.flags;
        fc->uid = d.uid;
        fc->max_read = d.max_read;
+#ifdef KERNEL_2_6
+       if (fc->max_read / PAGE_CACHE_SIZE < fc->bdi.ra_pages)
+               fc->bdi.ra_pages = fc->max_read / PAGE_CACHE_SIZE;
+#endif
        fc->max_write = FUSE_MAX_IN / 2;
        
        SB_FC(sb) = fc;
index f5f7405be244848cb0ab5648e67cbe43233f859f..ea640e982de281851b2d33e99b4f65163399b7a9 100644 (file)
 /** The node ID of the root inode */
 #define FUSE_ROOT_ID 1
 
+/** The major number of the fuse character device */
+#define FUSE_MAJOR 10
+
+/** The minor number of the fuse character device */
+#define FUSE_MINOR 229
+
 /** Opening this will yield a new control file */
 #define FUSE_DEV "/dev/fuse"
 
index b29db9d2f7d326736092bee358e476d3f8ddfb70..59f8b453b26d6b6dd3dc643a4ef161bd57a99a0c 100644 (file)
@@ -17,6 +17,9 @@
 #include <errno.h>
 #include <sys/param.h>
 
+#define FUSE_VERSION_FILE_OLD "/proc/fs/fuse/version"
+#define FUSE_DEV_OLD "/proc/fs/fuse/dev"
+
 #define FUSE_MAX_PATH 4096
 #define PARAM(inarg) (((char *)(inarg)) + sizeof(*inarg))
 
@@ -1722,12 +1725,18 @@ static int check_version(struct fuse *f)
     const char *version_file = FUSE_VERSION_FILE;
     FILE *vf = fopen(version_file, "r");
     if (vf == NULL) {
-        version_file = "/sys/fs/fuse/version";
+        version_file = FUSE_VERSION_FILE_OLD;
         vf = fopen(version_file, "r");
         if (vf == NULL) {
-            fprintf(stderr, "fuse: kernel interface too old, need >= %i.%i\n",
-                    FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
-            return -1;
+            struct stat tmp;
+            if (stat(FUSE_DEV_OLD, &tmp) != -1) {
+                fprintf(stderr, "fuse: kernel interface too old, need >= %i.%i\n",
+                        FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
+                return -1;
+            } else {
+                fprintf(stderr, "fuse: warning: version of kernel interface unknown\n");
+                return 0;
+            }
         }
     }
     res = fscanf(vf, "%i.%i", &f->majorver, &f->minorver);
@@ -1817,7 +1826,17 @@ struct fuse *fuse_new(int fd, const char *opts, const struct fuse_operations *op
     if (f->id_table == NULL)
         goto out_free_name_table;
 
-    pthread_mutex_init(&f->lock, NULL);
+#ifndef USE_UCLIBC
+     pthread_mutex_init(&f->lock, NULL);
+#else
+     {
+         pthread_mutexattr_t attr;
+         pthread_mutexattr_init(&attr);
+         pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
+         pthread_mutex_init(&f->lock, &attr);
+         pthread_mutexattr_destroy(&attr);
+     }
+#endif
     f->numworker = 0;
     f->numavail = 0;
     f->op = *op;
index 05dcb59db0a99134e16e78d26d8a663248fac34c..a84dbee47f158bfb3aa3d21483da01343e3ee977 100644 (file)
@@ -91,7 +91,11 @@ int fuse_mount(const char *mountpoint, const char *opts)
         return -1;
     }
 
+#ifndef USE_UCLIBC
     pid = fork();
+#else
+    pid = vfork();
+#endif
     if(pid == -1) {
         perror("fuse: fork() failed");
         close(fds[0]);
index 98a705b448ef2015532985ce2dd2cad19bf3c3a6..a7d26ed8fcf8cf51d720d1b65e28c7db292a1d03 100644 (file)
@@ -38,8 +38,8 @@
 #define FUSE_COMMFD_ENV         "_FUSE_COMMFD"
 
 #define FUSE_DEV_OLD "/proc/fs/fuse/dev"
-#define FUSE_DEV_NEW "/dev/fuse"
 #define FUSE_SYS_DEV "/sys/class/misc/fuse/dev"
+#define FUSE_VERSION_FILE_OLD "/proc/fs/fuse/version"
 
 const char *progname;
 
@@ -54,66 +54,7 @@ static const char *get_user_name()
     }
 }
 
-/* use a lock file so that multiple fusermount processes don't try and
-   modify the mtab file at once! */
-static int lock_mtab()
-{
-    const char *mtab_lock = _PATH_MOUNTED ".fuselock";
-    int mtablock;
-    int res;
-
-    mtablock = open(mtab_lock, O_RDWR | O_CREAT, 0600);
-    if (mtablock >= 0) {
-        res = lockf(mtablock, F_LOCK, 0);
-        if (res < 0)
-            perror("error getting lock");
-    } else
-        fprintf(stderr, "unable to open fuse lock file, continuing anyway\n");
-
-    return mtablock;
-}
-
-static void unlock_mtab(int mtablock)
-{
-    if (mtablock >= 0) {
-       lockf(mtablock, F_ULOCK, 0);
-       close(mtablock);
-    }
-}
-
-static int add_mount(const char *fsname, const char *mnt, const char *type,
-                     const char *opts)
-{
-    int res;
-    const char *mtab = _PATH_MOUNTED;
-    struct mntent ent;
-    FILE *fp;
-
-    fp = setmntent(mtab, "a");
-    if (fp == NULL) {
-       fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab,
-               strerror(errno));
-       return -1;
-    }
-    
-    ent.mnt_fsname = (char *) fsname;
-    ent.mnt_dir = (char *) mnt;
-    ent.mnt_type = (char *) type;
-    ent.mnt_opts = (char *) opts;
-    ent.mnt_freq = 0;
-    ent.mnt_passno = 0;
-    res = addmntent(fp, &ent);
-    if (res != 0) {
-        fprintf(stderr, "%s: failed to add entry to %s: %s\n", progname,
-                mtab, strerror(errno));
-        return -1;
-    }
-    
-    endmntent(fp);
-    return 0;
-}
-
-
+#ifndef USE_UCLIBC
 /* Until there is a nice interface for capabilities in _libc_, this will
 remain here.  I don't think it is fair to expect users to compile libcap
 for this program.  And anyway what's all this fuss about versioning the
@@ -140,7 +81,7 @@ static uid_t oldfsuid;
 static gid_t oldfsgid;
 static struct __user_cap_data_struct oldcaps;
 
-static int drop_privs()
+static int drop_privs(void)
 {
     int res;
     struct __user_cap_header_struct head;
@@ -174,7 +115,7 @@ static int drop_privs()
     return 0;
 }
 
-static void restore_privs()
+static void restore_privs(void)
 {
     struct __user_cap_header_struct head;
     int res;
@@ -189,12 +130,81 @@ static void restore_privs()
     setfsuid(oldfsuid);
     setfsgid(oldfsgid);
 }
+#else /* USE_UCLIBC */
+static int drop_privs(void)
+{
+    return 0;
+}
+static void restore_privs(void)
+{
+}
+#endif /* USE_UCLIBC */
+
+
+#ifndef USE_UCLIBC
+/* use a lock file so that multiple fusermount processes don't try and
+   modify the mtab file at once! */
+static int lock_mtab()
+{
+    const char *mtab_lock = _PATH_MOUNTED ".fuselock";
+    int mtablock;
+    int res;
+
+    mtablock = open(mtab_lock, O_RDWR | O_CREAT, 0600);
+    if (mtablock >= 0) {
+        res = lockf(mtablock, F_LOCK, 0);
+        if (res < 0)
+            perror("error getting lock");
+    } else
+        fprintf(stderr, "unable to open fuse lock file, continuing anyway\n");
+
+    return mtablock;
+}
+
+static void unlock_mtab(int mtablock)
+{
+    if (mtablock >= 0) {
+       lockf(mtablock, F_ULOCK, 0);
+       close(mtablock);
+    }
+}
 
-static int remove_mount(const char *mnt, int quiet, int lazy)
+static int add_mount(const char *fsname, const char *mnt, const char *type,
+                     const char *opts)
 {
     int res;
     const char *mtab = _PATH_MOUNTED;
-    const char *mtab_new = _PATH_MOUNTED "~fuse~";
+    struct mntent ent;
+    FILE *fp;
+
+    fp = setmntent(mtab, "a");
+    if (fp == NULL) {
+       fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab,
+               strerror(errno));
+       return -1;
+    }
+    
+    ent.mnt_fsname = (char *) fsname;
+    ent.mnt_dir = (char *) mnt;
+    ent.mnt_type = (char *) type;
+    ent.mnt_opts = (char *) opts;
+    ent.mnt_freq = 0;
+    ent.mnt_passno = 0;
+    res = addmntent(fp, &ent);
+    if (res != 0) {
+        fprintf(stderr, "%s: failed to add entry to %s: %s\n", progname,
+                mtab, strerror(errno));
+        return -1;
+    }
+    
+    endmntent(fp);
+    return 0;
+}
+
+static int remove_mount(const char *mnt, int quiet, const char *mtab,
+                        const char *mtab_new)
+{
+    int res;
     struct mntent *entp;
     FILE *fp;
     FILE *newfp;
@@ -248,46 +258,67 @@ static int remove_mount(const char *mnt, int quiet, int lazy)
     
     endmntent(fp);
     endmntent(newfp);
-    
-    if (found) {
-        if (getuid() != 0) {
-            res = drop_privs();
-            if (res == -1) {
-                unlink(mtab_new);
-                return -1;
-            }
-        }
 
-        res = umount2(mnt, lazy ? 2 : 0);
-        if (res == -1) {
-            if (!quiet)
-                fprintf(stderr, "%s: failed to unmount %s: %s\n",
-                        progname, mnt,strerror(errno));
-            found = -1;
-        }
-        if (getuid() != 0)
-            restore_privs();
+    if (!found) {
+        if (!quiet)
+            fprintf(stderr, "%s: entry for %s not found in %s\n", progname,
+                    mnt, mtab);
+        unlink(mtab_new);
+        return -1;
     }
 
-    if (found == 1) {
-        res = rename(mtab_new, mtab);
-        if (res == -1) {
-            fprintf(stderr, "%s: failed to rename %s to %s: %s\n", progname,
-                    mtab_new, mtab, strerror(errno));
+    return 0;
+}
+
+
+static int do_unmount(const char *mnt, int quiet, int lazy, const char *mtab,
+                      const char *mtab_new)
+{
+    int res;
+
+    if (getuid() != 0) {
+        res = drop_privs();
+        if (res == -1)
             return -1;
-        }
     }
-    else {
-        if (!found && !quiet)
-            fprintf(stderr, "%s: entry for %s not found in %s\n", progname,
-                    mnt, mtab);
-        unlink(mtab_new);
+    res = umount2(mnt, lazy ? 2 : 0);
+    if (res == -1) {
+        if (!quiet)
+            fprintf(stderr, "%s: failed to unmount %s: %s\n",
+                    progname, mnt, strerror(errno));
         return -1;
     }
+    if (getuid() != 0)
+        restore_privs();
 
+    res = rename(mtab_new, mtab);
+    if (res == -1) {
+        fprintf(stderr, "%s: failed to rename %s to %s: %s\n", progname,
+                mtab_new, mtab, strerror(errno));
+        return -1;
+    }
     return 0;
 }
 
+static int unmount_fuse(const char *mnt, int quiet, int lazy)
+{
+    int res;
+    const char *mtab = _PATH_MOUNTED;
+    const char *mtab_new = _PATH_MOUNTED "~fuse~";
+    
+    res = remove_mount(mnt, quiet, mtab, mtab_new);
+    if (res == -1)
+        return -1;
+
+    res = do_unmount(mnt, quiet, lazy, mtab, mtab_new);
+    if (res == -1) {
+        unlink(mtab_new);
+        return -1;
+    }
+    return 0;
+}
+#endif /* USE_UCLIBC */    
+
 static int begins_with(const char *s, const char *beg)
 {
     if (strncmp(s, beg, strlen(beg)) == 0)
@@ -475,20 +506,32 @@ static int do_mount(const char *mnt, const char *type, mode_t rootmode,
     return res;
 }
 
-static int check_version(void)
+static int check_version(const char *dev)
 {
     int res;
     int majorver;
     int minorver;
-    const char *version_file = FUSE_VERSION_FILE;
-    FILE *vf = fopen(version_file, "r");
+    const char *version_file;
+    int isold = 0;
+    FILE *vf;
+
+    if (strcmp(dev, FUSE_DEV_OLD) == 0)
+        isold = 1;
+
+    if (isold)
+        version_file = FUSE_VERSION_FILE_OLD;
+    else
+        version_file = FUSE_VERSION_FILE;
+
+    vf = fopen(version_file, "r");
     if (vf == NULL) {
-        version_file = "/sys/fs/fuse/version";
-        vf = fopen(version_file, "r");
-        if (vf == NULL) {
+        if (isold) {
             fprintf(stderr, "%s: kernel interface too old\n", progname);
             return -1;
-        }
+        } else
+            /* If /sys/fs/fuse/version doesn't exist, just skip
+               version checking */
+            return 0;
     }
     res = fscanf(vf, "%i.%i", &majorver, &minorver);
     fclose(vf);
@@ -606,7 +649,7 @@ static int try_open_new_temp(unsigned devnum, char **devp)
     return fd;
 }
 
-static int try_open_new(char **devp)
+static int try_open_new(char **devp, int final)
 {
     const char *dev;
     unsigned minor;
@@ -616,8 +659,18 @@ static int try_open_new(char **devp)
     unsigned devnum;
     char buf[256];
     int fd = open(FUSE_SYS_DEV, O_RDONLY);
-    if (fd == -1)
-        return -2;
+    if (fd == -1) {
+        if (!final)
+            return -2;
+        fd = try_open(FUSE_DEV, devp, 0);
+        if (fd != -1)
+            return fd;
+        if (errno == ENODEV)
+            return -2;
+        fprintf(stderr, "%s: failed to open %s: %s\n", progname,
+                FUSE_DEV, strerror(errno));
+        return -1;
+    }
 
     res = read(fd, buf, sizeof(buf)-1);
     close(fd);
@@ -635,10 +688,17 @@ static int try_open_new(char **devp)
     }
 
     devnum = (major << 8) + (minor & 0xff) + ((minor & 0xff00) << 12);
-    dev = FUSE_DEV_NEW;
+    dev = FUSE_DEV;
     res = stat(dev, &stbuf);
-    if (res == -1)
-        return try_open_new_temp(devnum, devp);
+    if (res == -1) {
+        if (major == FUSE_MAJOR && minor == FUSE_MINOR)
+            return try_open_new_temp(devnum, devp);
+        else {
+            fprintf(stderr, "%s: failed to open %s: %s\n", progname,
+                    dev, strerror(errno));
+            return -1;
+        }
+    }
     
     if ((stbuf.st_mode & S_IFMT) != S_IFCHR || stbuf.st_rdev != devnum) {
         fprintf(stderr, "%s: %s exists but has wrong attributes\n", progname,
@@ -652,21 +712,27 @@ static int open_fuse_device(char **devp)
 {
     int fd;
 
-    fd = try_open_new(devp);
-    if (fd != -2)
-        return fd;
-
-    fd = try_open(FUSE_DEV_OLD, devp, 1);
-    if (fd != -1)
-        return fd;
-
     if (1
 #ifndef AUTO_MODPROBE
         && getuid() == 0
 #endif
         ) {
         int status;
-        pid_t pid = fork();
+        pid_t pid;
+
+        fd = try_open(FUSE_DEV_OLD, devp, 1);
+        if (fd != -1)
+            return fd;
+
+        fd = try_open_new(devp, 0);
+        if (fd != -2)
+            return fd;
+
+#ifndef USE_UCLIBC
+        pid = fork();
+#else
+        pid = vfork();
+#endif
         if (pid == 0) {
             setuid(0);
             execl("/sbin/modprobe", "/sbin/modprobe", "fuse", NULL);
@@ -674,16 +740,15 @@ static int open_fuse_device(char **devp)
         }
         if (pid != -1)
             waitpid(pid, &status, 0);
+    }
 
-        fd = try_open_new(devp);
-        if (fd != -2)
-            return fd;
+    fd = try_open(FUSE_DEV_OLD, devp, 1);
+    if (fd != -1)
+        return fd;
 
-        fd = try_open(FUSE_DEV_OLD, devp, 1);
-        if (fd != -1)
-            return fd;
-        
-    }
+    fd = try_open_new(devp, 1);
+    if (fd != -2)
+        return fd;        
 
     fprintf(stderr, "fuse device not found, try 'modprobe fuse' first\n");
     return -1;
@@ -697,7 +762,6 @@ static int mount_fuse(const char *mnt, const char *opts)
     char *dev;
     const char *type = "fuse";
     struct stat stbuf;
-    int mtablock;
     char *fsname;
     char *mnt_opts;
     const char *real_mnt = mnt;
@@ -713,7 +777,7 @@ static int mount_fuse(const char *mnt, const char *opts)
             return -1;
     }
 
-    res = check_version();
+    res = check_version(dev);
     if (res != -1) {
         res = check_perm(&real_mnt, &stbuf, &currdir_fd);
         if (res != -1)
@@ -731,9 +795,10 @@ static int mount_fuse(const char *mnt, const char *opts)
         fchdir(currdir_fd);
         close(currdir_fd);
     }
-
+    
+#ifndef USE_UCLIBC
     if (geteuid() == 0) {
-        mtablock = lock_mtab();
+        int mtablock = lock_mtab();
         res = add_mount(fsname, mnt, type, mnt_opts);
         unlock_mtab(mtablock);
         if (res == -1) {
@@ -741,6 +806,8 @@ static int mount_fuse(const char *mnt, const char *opts)
             return -1;
         }
     }
+#endif
+
     free(fsname);
     free(mnt_opts);
     free(dev);
@@ -928,11 +995,14 @@ int main(int argc, char *argv[])
         restore_privs();
     
     if (unmount) {
+#ifndef USE_UCLIBC
         if (geteuid() == 0) {
             int mtablock = lock_mtab();
-            res = remove_mount(mnt, quiet, lazy);
+            res = unmount_fuse(mnt, quiet, lazy);
             unlock_mtab(mtablock);
-        } else {
+        } else 
+#endif
+        {
             res = umount2(mnt, lazy ? 2 : 0);
             if (res == -1) {
                 if (!quiet)