fixes
authorMiklos Szeredi <miklos@szeredi.hu>
Mon, 29 Nov 2004 16:53:44 +0000 (16:53 +0000)
committerMiklos Szeredi <miklos@szeredi.hu>
Mon, 29 Nov 2004 16:53:44 +0000 (16:53 +0000)
ChangeLog
kernel/file.c
kernel/fuse_i.h
util/fusermount.c

index 947b4109b0eca1805a3370bc3fe623fb43fafd35..8265a6d26b8d97910e310a3749de1f19718f1b90 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2004-11-29  Miklos Szeredi <miklos@szeredi.hu>
+
+       * kernel: make readpage() uninterruptible
+
+       * kernel: when direct_io is turend on, copy data directly to
+       destination without itermediate buffer.  More efficient and safer,
+       since no allocation is done.
+
+       * fusermount: fix warning if fuse module is not loaded
+       
 2004-11-26  Miklos Szeredi <miklos@szeredi.hu>
 
        * libfuse API change: open, read, write, flush, fsync and release
index c48615b44b253c9440bb3d8a9d5e78185c5fd9d1..bdb379520dcdb3fc8083bc267f6f48164aa8dd02 100644 (file)
@@ -231,10 +231,7 @@ static ssize_t fuse_send_read(struct file *file, struct inode *inode,
        struct fuse_read_in inarg;
        ssize_t res;
        
-       req = fuse_get_request(fc);
-       if (!req)
-               return -ERESTARTSYS;
-       
+       req = fuse_get_request_nonint(fc);
        memset(&inarg, 0, sizeof(inarg));
        inarg.fh = ff->fh;
        inarg.offset = pos;
@@ -510,19 +507,35 @@ static int fuse_read_copyout(struct fuse_req *req, const char __user *buf,
                             size_t nbytes)
 {
        struct fuse_read_in *inarg =  &req->misc.read_in;
+       unsigned count;
+       unsigned page_offset;
        unsigned i;
        if (nbytes > inarg->size) {
                printk("fuse: long read\n");
                return -EPROTO;
        }
        req->out.args[0].size = nbytes;
+       page_offset = req->page_offset;
+       count = min(nbytes, (unsigned) PAGE_SIZE - page_offset);
        for (i = 0; i < req->num_pages && nbytes; i++) {
                struct page *page = req->pages[i];
-               unsigned long offset = i * PAGE_CACHE_SIZE;
-               unsigned count = min((unsigned) PAGE_CACHE_SIZE, nbytes);
-               if (copy_from_user(page_address(page), buf + offset, count))
+               char *buffer = kmap(page);
+               int err = copy_from_user(buffer + page_offset, buf, count);
+               flush_dcache_page(page);
+               kunmap(page);
+#ifdef KERNEL_2_6
+               set_page_dirty_lock(page);
+#else
+               lock_page(page);
+               set_page_dirty(page);
+               unlock_page(page);
+#endif
+               if (err)
                        return -EFAULT;
                nbytes -= count;
+               buf += count;
+               count = min(nbytes, (unsigned) PAGE_SIZE);
+               page_offset = 0;
        }
        return 0;
 }
@@ -555,59 +568,56 @@ static ssize_t fuse_read(struct file *file, char __user *buf, size_t count,
 {
        struct inode *inode = file->f_dentry->d_inode;
        struct fuse_conn *fc = INO_FC(inode);
-       ssize_t res;
        loff_t pos = *ppos;
        struct fuse_req *req;
-       unsigned npages;
-       int i;
-
-       npages = (min(fc->max_read, count) + PAGE_SIZE - 1) >> PAGE_SHIFT;
-       npages = min(npages, (unsigned) FUSE_MAX_PAGES_PER_REQ);
+       ssize_t res;
 
        req = fuse_get_request(fc);
        if (!req)
                return -ERESTARTSYS;
 
-       res = -ENOMEM;
-       for (req->num_pages = 0; req->num_pages < npages; req->num_pages++) {
-               req->pages[req->num_pages] = alloc_page(GFP_KERNEL);
-               if (!req->pages[req->num_pages])
-                       goto out;
-       }
-
        res = 0;
        while (count) {
-               size_t nbytes;
-               size_t nbytes_req = min(req->num_pages * (unsigned) PAGE_SIZE,
-                                       count);
-               int err = fuse_send_read_multi(file, req, nbytes_req, pos);
+               unsigned nbytes = min(count, fc->max_read);
+               unsigned nread;
+               unsigned long user_addr = (unsigned long) buf;
+               unsigned offset = user_addr & ~PAGE_MASK;
+               int npages;
+               int err;
+               int i;
+               
+               nbytes = min(nbytes, (unsigned) (FUSE_MAX_PAGES_PER_REQ * PAGE_SIZE));
+               npages = (nbytes + offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
+               npages = min(npages, FUSE_MAX_PAGES_PER_REQ);
+               npages = get_user_pages(current, current->mm, user_addr,
+                                       npages, 1, 0, req->pages, NULL);
+               if (npages < 0) {
+                       res = npages;
+                       break;
+               }
+               req->num_pages = npages;
+               req->page_offset = offset;
+               nbytes = min(nbytes, (unsigned) (npages * PAGE_SIZE - offset));
+               printk("fusedirect: %i %i %i %i\n", 
+                      count, npages, offset, nbytes);
+
+               err = fuse_send_read_multi(file, req, nbytes, pos);
+               for (i = 0; i < npages; i++)
+                       page_cache_release(req->pages[i]);
                if (err) {
                        if (!res)
                                res = err;
                        break;
                }
-               nbytes = req->out.args[0].size;
-               for (i = 0; i < req->num_pages && nbytes; i++) {
-                       struct page *page = req->pages[i];
-                       unsigned n = min((unsigned) PAGE_SIZE, nbytes);
-                       if (copy_to_user(buf, page_address(page), n)) {
-                               res = -EFAULT;
-                               break;
-                       }
-                       nbytes -= n;
-                       buf += n;
-               }
-               nbytes = req->out.args[0].size;
-               count -= nbytes;
-               res += nbytes;
-               pos += nbytes;
-
-               if (res < 0 || nbytes != nbytes_req)
+               nread = req->out.args[0].size;
+               count -= nread;
+               res += nread;
+               pos += nread;
+               buf += nread;
+               if (nread != nbytes)
                        break;
+               fuse_reset_request(req);
        }
- out:
-       for (i = 0; i < req->num_pages; i++)
-               __free_page(req->pages[i]);
        fuse_put_request(fc, req);
        if (res > 0)
                *ppos += res;
index c5b8e238742ddecaa6c531c24a9014ac29b07635..9dbe3f3690cbad7e587469ec7950d2aa18b2e77a 100644 (file)
@@ -193,6 +193,7 @@ struct fuse_req {
 
        struct page *pages[FUSE_MAX_PAGES_PER_REQ];
        unsigned num_pages;
+       unsigned page_offset;
 };
 
 /**
index a7d26ed8fcf8cf51d720d1b65e28c7db292a1d03..e3d5b295db10d128354e7042e27569ecf8578c36 100644 (file)
@@ -614,7 +614,9 @@ static int try_open(const char *dev, char **devp, int silent)
             close(fd);
             fd = -1;
         }
-    } else if (!silent) {
+    } else if (errno == ENODEV)
+        return -2;
+    else if (!silent) {
         fprintf(stderr, "%s: failed to open %s: %s\n", progname, dev,
                 strerror(errno));
     }
@@ -624,7 +626,7 @@ static int try_open(const char *dev, char **devp, int silent)
 #define FUSE_TMP_DIRNAME "/tmp/.fuse_devXXXXXX"
 #define FUSE_TMP_DEVNAME "/fuse"
 
-static int try_open_new_temp(unsigned devnum, char **devp)
+static int try_open_new_temp(unsigned devnum, char **devp, int silent)
 {
     int res;
     int fd;
@@ -643,7 +645,7 @@ static int try_open_new_temp(unsigned devnum, char **devp)
         rmdir(dirname);
         return -1;
     }
-    fd = try_open(filename, devp, 0);
+    fd = try_open(filename, devp, silent);
     unlink(filename);
     rmdir(dirname);
     return fd;
@@ -662,14 +664,13 @@ static int try_open_new(char **devp, int final)
     if (fd == -1) {
         if (!final)
             return -2;
-        fd = try_open(FUSE_DEV, devp, 0);
-        if (fd != -1)
-            return fd;
-        if (errno == ENODEV)
+        fd = try_open(FUSE_DEV, devp, 1);
+        if (fd == -2)
             return -2;
-        fprintf(stderr, "%s: failed to open %s: %s\n", progname,
-                FUSE_DEV, strerror(errno));
-        return -1;
+        fd = try_open_new_temp(FUSE_MAJOR << 8 | FUSE_MINOR, devp, 1);
+        if (fd == -2)
+            return -2;
+        return try_open(FUSE_DEV, devp, 0);
     }
 
     res = read(fd, buf, sizeof(buf)-1);
@@ -692,7 +693,7 @@ static int try_open_new(char **devp, int final)
     res = stat(dev, &stbuf);
     if (res == -1) {
         if (major == FUSE_MAJOR && minor == FUSE_MINOR)
-            return try_open_new_temp(devnum, devp);
+            return try_open_new_temp(devnum, devp, 0);
         else {
             fprintf(stderr, "%s: failed to open %s: %s\n", progname,
                     dev, strerror(errno));