diff options
author | Miklos Szeredi <miklos@szeredi.hu> | 2001-11-06 12:03:23 +0000 |
---|---|---|
committer | Miklos Szeredi <miklos@szeredi.hu> | 2001-11-06 12:03:23 +0000 |
commit | a181e61ca0119b8c3fd2daa4b8d23add2cda3ed0 (patch) | |
tree | 57176d5ca8f96008180eac92518791ef22add726 /kernel/file.c | |
parent | 5e183482b09cec20f54ccb44e767a7fab51833e9 (diff) | |
download | libfuse-a181e61ca0119b8c3fd2daa4b8d23add2cda3ed0.tar.gz |
bugfixes
Diffstat (limited to 'kernel/file.c')
-rw-r--r-- | kernel/file.c | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/kernel/file.c b/kernel/file.c index df3a863..a677d4c 100644 --- a/kernel/file.c +++ b/kernel/file.c @@ -10,6 +10,7 @@ #include <linux/module.h> #include <linux/kernel.h> #include <linux/pagemap.h> +#include <linux/slab.h> static int fuse_open(struct inode *inode, struct file *file) @@ -25,10 +26,13 @@ static int fuse_open(struct inode *inode, struct file *file) in.argsize = sizeof(arg); in.arg = &arg; request_send(fc, &in, &out); + if(!out.h.error) + invalidate_inode_pages(inode); return out.h.error; } + static int fuse_readpage(struct file *file, struct page *page) { struct inode *inode = page->mapping->host; @@ -65,13 +69,96 @@ static int fuse_readpage(struct file *file, struct page *page) return out.h.error; } +static int write_buffer(struct inode *inode, struct page *page, + unsigned offset, size_t count) +{ + struct fuse_conn *fc = INO_FC(inode); + struct fuse_in in = FUSE_IN_INIT; + struct fuse_out out = FUSE_OUT_INIT; + struct fuse_write_in *arg; + size_t argsize; + char *buffer; + + argsize = offsetof(struct fuse_write_in, buf) + count; + arg = kmalloc(argsize, GFP_KERNEL); + if(!arg) + return -ENOMEM; + + arg->offset = (page->index << PAGE_CACHE_SHIFT) + offset; + arg->size = count; + buffer = kmap(page); + memcpy(arg->buf, buffer + offset, count); + kunmap(page); + + in.h.opcode = FUSE_WRITE; + in.h.ino = inode->i_ino; + in.argsize = argsize; + in.arg = arg; + request_send(fc, &in, &out); + kfree(arg); + + return out.h.error; +} + + +static int fuse_writepage(struct page *page) +{ + struct inode *inode = page->mapping->host; + unsigned count; + unsigned long end_index; + int err; + + end_index = inode->i_size >> PAGE_CACHE_SHIFT; + if(page->index < end_index) + count = PAGE_CACHE_SIZE; + else { + count = inode->i_size & (PAGE_CACHE_SIZE - 1); + err = -EIO; + if(page->index > end_index || count == 0) + goto out; + + } + err = write_buffer(inode, page, 0, count); + out: + UnlockPage(page); + return 0; +} + + +static int fuse_prepare_write(struct file *file, struct page *page, + unsigned offset, unsigned to) +{ + /* No op */ + return 0; +} + +static int fuse_commit_write(struct file *file, struct page *page, + unsigned offset, unsigned to) +{ + int err; + struct inode *inode = page->mapping->host; + + err = write_buffer(inode, page, offset, to - offset); + if(!err) { + loff_t pos = (page->index << PAGE_CACHE_SHIFT) + to; + if(pos > inode->i_size) + inode->i_size = pos; + } + return err; +} + static struct file_operations fuse_file_operations = { open: fuse_open, read: generic_file_read, + write: generic_file_write, + mmap: generic_file_mmap, }; static struct address_space_operations fuse_file_aops = { readpage: fuse_readpage, + writepage: fuse_writepage, + prepare_write: fuse_prepare_write, + commit_write: fuse_commit_write, }; void fuse_init_file_inode(struct inode *inode) |