mirror of
https://github.com/libfuse/libfuse.git
synced 2024-11-24 04:34:13 +08:00
optimize reading
This commit is contained in:
parent
84ba0f45c2
commit
588653700e
@ -1,6 +1,7 @@
|
||||
Makefile.in
|
||||
Makefile
|
||||
aclocal.m4
|
||||
*.m4
|
||||
ltmain.sh
|
||||
configure
|
||||
install-sh
|
||||
mkinstalldirs
|
||||
|
@ -1,3 +1,8 @@
|
||||
2004-07-20 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
* Optimize reading under 2.6 kernels by issuing multiple page
|
||||
asynchronous read requests
|
||||
|
||||
2004-07-18 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
* Only use redirty_page_for_writepage() for kernels >= 2.6.6
|
||||
|
33
kernel/dev.c
33
kernel/dev.c
@ -364,9 +364,10 @@ static inline int copy_out_one(struct fuse_out_arg *arg, const char **srcp,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int copy_out_args(struct fuse_out *out, const char *buf,
|
||||
static inline int copy_out_args(struct fuse_req *req, const char *buf,
|
||||
size_t nbytes)
|
||||
{
|
||||
struct fuse_out *out = &req->out;
|
||||
int err;
|
||||
int i;
|
||||
|
||||
@ -374,18 +375,22 @@ static inline int copy_out_args(struct fuse_out *out, const char *buf,
|
||||
nbytes -= sizeof(struct fuse_out_header);
|
||||
|
||||
if (!out->h.error) {
|
||||
for (i = 0; i < out->numargs; i++) {
|
||||
struct fuse_out_arg *arg = &out->args[i];
|
||||
int allowvar;
|
||||
|
||||
if (out->argvar && i == out->numargs - 1)
|
||||
allowvar = 1;
|
||||
else
|
||||
allowvar = 0;
|
||||
|
||||
err = copy_out_one(arg, &buf, &nbytes, allowvar);
|
||||
if (err)
|
||||
return err;
|
||||
if (req->copy_out)
|
||||
return req->copy_out(req, buf, nbytes);
|
||||
else {
|
||||
for (i = 0; i < out->numargs; i++) {
|
||||
struct fuse_out_arg *arg = &out->args[i];
|
||||
int allowvar;
|
||||
|
||||
if (out->argvar && i == out->numargs - 1)
|
||||
allowvar = 1;
|
||||
else
|
||||
allowvar = 0;
|
||||
|
||||
err = copy_out_one(arg, &buf, &nbytes, allowvar);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -499,7 +504,7 @@ static ssize_t fuse_dev_write(struct file *file, const char *buf,
|
||||
return -ENOENT;
|
||||
|
||||
req->out.h = oh;
|
||||
err = copy_out_args(&req->out, buf, nbytes);
|
||||
err = copy_out_args(req, buf, nbytes);
|
||||
|
||||
spin_lock(&fuse_lock);
|
||||
if (err)
|
||||
|
120
kernel/file.c
120
kernel/file.c
@ -220,7 +220,7 @@ static int fuse_readpage(struct file *file, struct page *page)
|
||||
ssize_t res;
|
||||
loff_t pos;
|
||||
|
||||
pos = (unsigned long long) page->index << PAGE_CACHE_SHIFT;
|
||||
pos = (loff_t) page->index << PAGE_CACHE_SHIFT;
|
||||
buffer = kmap(page);
|
||||
res = fuse_send_read(inode, buffer, pos, PAGE_CACHE_SIZE);
|
||||
if (res >= 0) {
|
||||
@ -235,6 +235,115 @@ static int fuse_readpage(struct file *file, struct page *page)
|
||||
return res;
|
||||
}
|
||||
|
||||
#ifdef KERNEL_2_6
|
||||
|
||||
static int read_pages_copyout(struct fuse_req *req, const char *buf,
|
||||
size_t nbytes)
|
||||
{
|
||||
unsigned i;
|
||||
unsigned long base_index = req->pages[0]->index;
|
||||
for (i = 0; i < req->num_pages; i++) {
|
||||
struct page *page = req->pages[i];
|
||||
unsigned long offset;
|
||||
unsigned count;
|
||||
char *tmpbuf;
|
||||
int err;
|
||||
|
||||
offset = (page->index - base_index) * PAGE_CACHE_SIZE;
|
||||
if (offset >= nbytes)
|
||||
count = 0;
|
||||
else if (offset + PAGE_CACHE_SIZE <= nbytes)
|
||||
count = PAGE_CACHE_SIZE;
|
||||
else
|
||||
count = nbytes - offset;
|
||||
|
||||
tmpbuf = kmap(page);
|
||||
err = 0;
|
||||
if (count)
|
||||
err = copy_from_user(tmpbuf, buf + offset, count);
|
||||
if (count < PAGE_CACHE_SIZE)
|
||||
memset(tmpbuf + count, 0, PAGE_CACHE_SIZE - count);
|
||||
kunmap(page);
|
||||
if (err)
|
||||
return -EFAULT;
|
||||
|
||||
flush_dcache_page(page);
|
||||
SetPageUptodate(page);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void read_pages_end(struct fuse_conn *fc, struct fuse_req *req)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < req->num_pages; i++)
|
||||
unlock_page(req->pages[i]);
|
||||
|
||||
fuse_put_request(fc, req);
|
||||
}
|
||||
|
||||
static void fuse_send_readpages(struct fuse_req *req, struct inode *inode)
|
||||
{
|
||||
struct fuse_conn *fc = INO_FC(inode);
|
||||
struct fuse_read_in *inarg;
|
||||
loff_t pos;
|
||||
unsigned numpages;
|
||||
|
||||
pos = (loff_t) req->pages[0]->index << PAGE_CACHE_SHIFT;
|
||||
/* Allow for holes between the pages */
|
||||
numpages = req->pages[req->num_pages - 1]->index + 1
|
||||
- req->pages[0]->index;
|
||||
|
||||
inarg = &req->misc.read_in;
|
||||
inarg->offset = pos;
|
||||
inarg->size = numpages * PAGE_CACHE_SIZE;
|
||||
req->in.h.opcode = FUSE_READ;
|
||||
req->in.h.ino = inode->i_ino;
|
||||
req->in.numargs = 1;
|
||||
req->in.args[0].size = sizeof(struct fuse_read_in);
|
||||
req->in.args[0].value = inarg;
|
||||
req->copy_out = read_pages_copyout;
|
||||
request_send_nonblock(fc, req, read_pages_end, NULL);
|
||||
}
|
||||
|
||||
static int fuse_readpages_fill(void *_reqp, struct page *page)
|
||||
{
|
||||
struct inode *inode = page->mapping->host;
|
||||
struct fuse_conn *fc = INO_FC(inode);
|
||||
struct fuse_req **reqp = (struct fuse_req **) _reqp;
|
||||
struct fuse_req *req = *reqp;
|
||||
|
||||
if (req->num_pages &&
|
||||
(req->num_pages == FUSE_MAX_PAGES_PER_REQ ||
|
||||
(req->num_pages + 1) * PAGE_CACHE_SIZE > fc->max_read ||
|
||||
req->pages[req->num_pages - 1]->index + 1 != page->index)) {
|
||||
struct fuse_conn *fc = INO_FC(page->mapping->host);
|
||||
fuse_send_readpages(req, inode);
|
||||
*reqp = req = fuse_get_request(fc);
|
||||
}
|
||||
req->pages[req->num_pages] = page;
|
||||
req->num_pages ++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fuse_readpages(struct file *file, struct address_space *mapping,
|
||||
struct list_head *pages, unsigned nr_pages)
|
||||
{
|
||||
struct inode *inode = mapping->host;
|
||||
struct fuse_conn *fc = INO_FC(inode);
|
||||
struct fuse_req *req = fuse_get_request(fc);
|
||||
|
||||
read_cache_pages(mapping, pages, fuse_readpages_fill, &req);
|
||||
if (req->num_pages)
|
||||
fuse_send_readpages(req, inode);
|
||||
else
|
||||
fuse_put_request(fc, req);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int fuse_is_block_uptodate(struct inode *inode, size_t bl_index)
|
||||
{
|
||||
size_t index = bl_index << FUSE_BLOCK_PAGE_SHIFT;
|
||||
@ -305,7 +414,7 @@ static int fuse_file_read_block(struct inode *inode, char *bl_buf,
|
||||
ssize_t res;
|
||||
loff_t offset;
|
||||
|
||||
offset = (unsigned long long) bl_index << FUSE_BLOCK_SHIFT;
|
||||
offset = (loff_t) bl_index << FUSE_BLOCK_SHIFT;
|
||||
res = fuse_send_read(inode, bl_buf, offset, FUSE_BLOCK_SIZE);
|
||||
if (res >= 0) {
|
||||
if (res < FUSE_BLOCK_SIZE)
|
||||
@ -451,7 +560,7 @@ static int write_buffer(struct inode *inode, struct page *page,
|
||||
if (!req)
|
||||
return -ERESTARTSYS;
|
||||
|
||||
pos = ((unsigned long long) page->index << PAGE_CACHE_SHIFT) + offset;
|
||||
pos = ((loff_t) page->index << PAGE_CACHE_SHIFT) + offset;
|
||||
buffer = kmap(page);
|
||||
res = fuse_send_write(req, inode, buffer + offset, pos, count);
|
||||
fuse_put_request(fc, req);
|
||||
@ -504,7 +613,7 @@ static int write_page_block(struct inode *inode, struct page *page)
|
||||
count = get_write_count(inode, page);
|
||||
res = 0;
|
||||
if (count) {
|
||||
pos = ((unsigned long long) page->index << PAGE_CACHE_SHIFT);
|
||||
pos = ((loff_t) page->index << PAGE_CACHE_SHIFT);
|
||||
buffer = kmap(page);
|
||||
res = fuse_send_write(req, inode, buffer, pos, count);
|
||||
if (res >= 0) {
|
||||
@ -561,7 +670,7 @@ static void send_write_nonblock(struct fuse_req *req, struct inode *inode,
|
||||
|
||||
inarg = &req->misc.write.in;
|
||||
buffer = kmap(page);
|
||||
inarg->offset = ((unsigned long long) page->index << PAGE_CACHE_SHIFT);
|
||||
inarg->offset = ((loff_t) page->index << PAGE_CACHE_SHIFT);
|
||||
inarg->size = count;
|
||||
req->in.h.opcode = FUSE_WRITE;
|
||||
req->in.h.ino = inode->i_ino;
|
||||
@ -762,6 +871,7 @@ static struct address_space_operations fuse_file_aops = {
|
||||
.prepare_write = fuse_prepare_write,
|
||||
.commit_write = fuse_commit_write,
|
||||
#ifdef KERNEL_2_6
|
||||
.readpages = fuse_readpages,
|
||||
.set_page_dirty = __set_page_dirty_nobuffers,
|
||||
#endif
|
||||
};
|
||||
|
@ -43,6 +43,8 @@
|
||||
|
||||
#define FUSE_BLOCK_PAGE_SHIFT (FUSE_BLOCK_SHIFT - PAGE_CACHE_SHIFT)
|
||||
|
||||
#define FUSE_MAX_PAGES_PER_REQ 32
|
||||
|
||||
/** If the FUSE_DEFAULT_PERMISSIONS flag is given, the filesystem
|
||||
module will check permissions based on the file mode. Otherwise no
|
||||
permission checking is done in the kernel */
|
||||
@ -103,6 +105,7 @@ struct fuse_req;
|
||||
struct fuse_conn;
|
||||
|
||||
typedef void (*fuse_reqend_t)(struct fuse_conn *, struct fuse_req *);
|
||||
typedef int (*fuse_copyout_t)(struct fuse_req *, const char *, size_t);
|
||||
|
||||
/**
|
||||
* A request to the client
|
||||
@ -141,6 +144,9 @@ struct fuse_req {
|
||||
/** Request completion callback */
|
||||
fuse_reqend_t end;
|
||||
|
||||
/** Request copy out function */
|
||||
fuse_copyout_t copy_out;
|
||||
|
||||
/** User data */
|
||||
void *data;
|
||||
|
||||
@ -151,9 +157,13 @@ struct fuse_req {
|
||||
struct fuse_write_out out;
|
||||
|
||||
} write;
|
||||
struct fuse_read_in read_in;
|
||||
struct fuse_open_in open_in;
|
||||
struct fuse_forget_in forget_in;
|
||||
} misc;
|
||||
|
||||
struct page *pages[FUSE_MAX_PAGES_PER_REQ];
|
||||
unsigned num_pages;
|
||||
};
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user