From 2defe5eadb46dd64ee40ced067e9da235218e2db Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Mon, 29 Nov 2004 16:53:44 +0000 Subject: [PATCH] fixes --- ChangeLog | 10 +++++ kernel/file.c | 98 ++++++++++++++++++++++++++--------------------- kernel/fuse_i.h | 1 + util/fusermount.c | 23 +++++------ 4 files changed, 77 insertions(+), 55 deletions(-) diff --git a/ChangeLog b/ChangeLog index 947b410..8265a6d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2004-11-29 Miklos Szeredi + + * 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 * libfuse API change: open, read, write, flush, fsync and release diff --git a/kernel/file.c b/kernel/file.c index c48615b..bdb3795 100644 --- a/kernel/file.c +++ b/kernel/file.c @@ -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; diff --git a/kernel/fuse_i.h b/kernel/fuse_i.h index c5b8e23..9dbe3f3 100644 --- a/kernel/fuse_i.h +++ b/kernel/fuse_i.h @@ -193,6 +193,7 @@ struct fuse_req { struct page *pages[FUSE_MAX_PAGES_PER_REQ]; unsigned num_pages; + unsigned page_offset; }; /** diff --git a/util/fusermount.c b/util/fusermount.c index a7d26ed..e3d5b29 100644 --- a/util/fusermount.c +++ b/util/fusermount.c @@ -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)); -- 2.30.2