diff options
Diffstat (limited to 'fs/fuse/file.c')
-rw-r--r-- | fs/fuse/file.c | 76 |
1 files changed, 58 insertions, 18 deletions
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 183626868eea..1387749201b3 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -141,8 +141,8 @@ int fuse_release_common(struct inode *inode, struct file *file, int isdir) isdir ? FUSE_RELEASEDIR : FUSE_RELEASE); /* Hold vfsmount and dentry until release is finished */ - req->vfsmount = mntget(file->f_vfsmnt); - req->dentry = dget(file->f_dentry); + req->vfsmount = mntget(file->f_path.mnt); + req->dentry = dget(file->f_path.dentry); request_send_background(fc, req); } @@ -184,7 +184,7 @@ static u64 fuse_lock_owner_id(struct fuse_conn *fc, fl_owner_t id) static int fuse_flush(struct file *file, fl_owner_t id) { - struct inode *inode = file->f_dentry->d_inode; + struct inode *inode = file->f_path.dentry->d_inode; struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_file *ff = file->private_data; struct fuse_req *req; @@ -397,14 +397,14 @@ static int fuse_readpages(struct file *file, struct address_space *mapping, err = -EIO; if (is_bad_inode(inode)) - goto clean_pages_up; + goto out; data.file = file; data.inode = inode; data.req = fuse_get_req(fc); err = PTR_ERR(data.req); if (IS_ERR(data.req)) - goto clean_pages_up; + goto out; err = read_cache_pages(mapping, pages, fuse_readpages_fill, &data); if (!err) { @@ -413,10 +413,7 @@ static int fuse_readpages(struct file *file, struct address_space *mapping, else fuse_put_request(fc, data.req); } - return err; - -clean_pages_up: - put_pages_list(pages); +out: return err; } @@ -481,8 +478,10 @@ static int fuse_commit_write(struct file *file, struct page *page, err = -EIO; if (!err) { pos += count; - if (pos > i_size_read(inode)) + spin_lock(&fc->lock); + if (pos > inode->i_size) i_size_write(inode, pos); + spin_unlock(&fc->lock); if (offset == 0 && to == PAGE_CACHE_SIZE) { clear_page_dirty(page); @@ -534,7 +533,7 @@ static int fuse_get_user_pages(struct fuse_req *req, const char __user *buf, static ssize_t fuse_direct_io(struct file *file, const char __user *buf, size_t count, loff_t *ppos, int write) { - struct inode *inode = file->f_dentry->d_inode; + struct inode *inode = file->f_path.dentry->d_inode; struct fuse_conn *fc = get_fuse_conn(inode); size_t nmax = write ? fc->max_write : fc->max_read; loff_t pos = *ppos; @@ -586,8 +585,12 @@ static ssize_t fuse_direct_io(struct file *file, const char __user *buf, } fuse_put_request(fc, req); if (res > 0) { - if (write && pos > i_size_read(inode)) - i_size_write(inode, pos); + if (write) { + spin_lock(&fc->lock); + if (pos > inode->i_size) + i_size_write(inode, pos); + spin_unlock(&fc->lock); + } *ppos = pos; } fuse_invalidate_attr(inode); @@ -604,7 +607,7 @@ static ssize_t fuse_direct_read(struct file *file, char __user *buf, static ssize_t fuse_direct_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { - struct inode *inode = file->f_dentry->d_inode; + struct inode *inode = file->f_path.dentry->d_inode; ssize_t res; /* Don't allow parallel writes to the same file */ mutex_lock(&inode->i_mutex); @@ -659,7 +662,7 @@ static int convert_fuse_file_lock(const struct fuse_file_lock *ffl, static void fuse_lk_fill(struct fuse_req *req, struct file *file, const struct file_lock *fl, int opcode, pid_t pid) { - struct inode *inode = file->f_dentry->d_inode; + struct inode *inode = file->f_path.dentry->d_inode; struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_file *ff = file->private_data; struct fuse_lk_in *arg = &req->misc.lk_in; @@ -679,7 +682,7 @@ static void fuse_lk_fill(struct fuse_req *req, struct file *file, static int fuse_getlk(struct file *file, struct file_lock *fl) { - struct inode *inode = file->f_dentry->d_inode; + struct inode *inode = file->f_path.dentry->d_inode; struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_req *req; struct fuse_lk_out outarg; @@ -704,7 +707,7 @@ static int fuse_getlk(struct file *file, struct file_lock *fl) static int fuse_setlk(struct file *file, struct file_lock *fl) { - struct inode *inode = file->f_dentry->d_inode; + struct inode *inode = file->f_path.dentry->d_inode; struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_req *req; int opcode = (fl->fl_flags & FL_SLEEP) ? FUSE_SETLKW : FUSE_SETLK; @@ -731,7 +734,7 @@ static int fuse_setlk(struct file *file, struct file_lock *fl) static int fuse_file_lock(struct file *file, int cmd, struct file_lock *fl) { - struct inode *inode = file->f_dentry->d_inode; + struct inode *inode = file->f_path.dentry->d_inode; struct fuse_conn *fc = get_fuse_conn(inode); int err; @@ -751,6 +754,42 @@ static int fuse_file_lock(struct file *file, int cmd, struct file_lock *fl) return err; } +static sector_t fuse_bmap(struct address_space *mapping, sector_t block) +{ + struct inode *inode = mapping->host; + struct fuse_conn *fc = get_fuse_conn(inode); + struct fuse_req *req; + struct fuse_bmap_in inarg; + struct fuse_bmap_out outarg; + int err; + + if (!inode->i_sb->s_bdev || fc->no_bmap) + return 0; + + req = fuse_get_req(fc); + if (IS_ERR(req)) + return 0; + + memset(&inarg, 0, sizeof(inarg)); + inarg.block = block; + inarg.blocksize = inode->i_sb->s_blocksize; + req->in.h.opcode = FUSE_BMAP; + req->in.h.nodeid = get_node_id(inode); + req->in.numargs = 1; + req->in.args[0].size = sizeof(inarg); + req->in.args[0].value = &inarg; + req->out.numargs = 1; + req->out.args[0].size = sizeof(outarg); + req->out.args[0].value = &outarg; + request_send(fc, req); + err = req->out.h.error; + fuse_put_request(fc, req); + if (err == -ENOSYS) + fc->no_bmap = 1; + + return err ? 0 : outarg.block; +} + static const struct file_operations fuse_file_operations = { .llseek = generic_file_llseek, .read = do_sync_read, @@ -784,6 +823,7 @@ static const struct address_space_operations fuse_file_aops = { .commit_write = fuse_commit_write, .readpages = fuse_readpages, .set_page_dirty = fuse_set_page_dirty, + .bmap = fuse_bmap, }; void fuse_init_file_inode(struct inode *inode) |