diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/fuse/dir.c | 5 | ||||
-rw-r--r-- | fs/fuse/file.c | 37 | ||||
-rw-r--r-- | fs/fuse/fuse_i.h | 2 |
3 files changed, 36 insertions, 8 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 052327bd6c9..6c83ed05202 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -1108,6 +1108,11 @@ static int fuse_do_setattr(struct dentry *entry, struct iattr *attr, inarg.valid |= FATTR_FH; inarg.fh = ff->fh; } + if (attr->ia_valid & ATTR_SIZE) { + /* For mandatory locking in truncate */ + inarg.valid |= FATTR_LOCKOWNER; + inarg.lock_owner = fuse_lock_owner_id(fc, current->files); + } req->in.h.opcode = FUSE_SETATTR; req->in.h.nodeid = get_node_id(inode); req->in.numargs = 1; diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 2b589de044e..0fcdba9d47c 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -189,7 +189,7 @@ static int fuse_release(struct inode *inode, struct file *file) * Scramble the ID space with XTEA, so that the value of the files_struct * pointer is not exposed to userspace. */ -static u64 fuse_lock_owner_id(struct fuse_conn *fc, fl_owner_t id) +u64 fuse_lock_owner_id(struct fuse_conn *fc, fl_owner_t id) { u32 *k = fc->scramble_key; u64 v = (unsigned long) id; @@ -308,11 +308,19 @@ void fuse_read_fill(struct fuse_req *req, struct fuse_file *ff, } static size_t fuse_send_read(struct fuse_req *req, struct file *file, - struct inode *inode, loff_t pos, size_t count) + struct inode *inode, loff_t pos, size_t count, + fl_owner_t owner) { struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_file *ff = file->private_data; + fuse_read_fill(req, ff, inode, pos, count, FUSE_READ); + if (owner != NULL) { + struct fuse_read_in *inarg = &req->misc.read_in; + + inarg->read_flags |= FUSE_READ_LOCKOWNER; + inarg->lock_owner = fuse_lock_owner_id(fc, owner); + } request_send(fc, req); return req->out.args[0].size; } @@ -336,7 +344,8 @@ static int fuse_readpage(struct file *file, struct page *page) req->out.page_zeroing = 1; req->num_pages = 1; req->pages[0] = page; - fuse_send_read(req, file, inode, page_offset(page), PAGE_CACHE_SIZE); + fuse_send_read(req, file, inode, page_offset(page), PAGE_CACHE_SIZE, + NULL); err = req->out.h.error; fuse_put_request(fc, req); if (!err) @@ -447,6 +456,7 @@ static void fuse_write_fill(struct fuse_req *req, struct fuse_file *ff, struct inode *inode, loff_t pos, size_t count, int writepage) { + struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_write_in *inarg = &req->misc.write.in; struct fuse_write_out *outarg = &req->misc.write.out; @@ -459,7 +469,10 @@ static void fuse_write_fill(struct fuse_req *req, struct fuse_file *ff, req->in.h.nodeid = get_node_id(inode); req->in.argpages = 1; req->in.numargs = 2; - req->in.args[0].size = sizeof(struct fuse_write_in); + if (fc->minor < 9) + req->in.args[0].size = FUSE_COMPAT_WRITE_IN_SIZE; + else + req->in.args[0].size = sizeof(struct fuse_write_in); req->in.args[0].value = inarg; req->in.args[1].size = count; req->out.numargs = 1; @@ -468,10 +481,16 @@ static void fuse_write_fill(struct fuse_req *req, struct fuse_file *ff, } static size_t fuse_send_write(struct fuse_req *req, struct file *file, - struct inode *inode, loff_t pos, size_t count) + struct inode *inode, loff_t pos, size_t count, + fl_owner_t owner) { struct fuse_conn *fc = get_fuse_conn(inode); fuse_write_fill(req, file->private_data, inode, pos, count, 0); + if (owner != NULL) { + struct fuse_write_in *inarg = &req->misc.write.in; + inarg->write_flags |= FUSE_WRITE_LOCKOWNER; + inarg->lock_owner = fuse_lock_owner_id(fc, owner); + } request_send(fc, req); return req->misc.write.out.size; } @@ -508,7 +527,7 @@ static int fuse_buffered_write(struct file *file, struct inode *inode, req->num_pages = 1; req->pages[0] = page; req->page_offset = offset; - nres = fuse_send_write(req, file, inode, pos, count); + nres = fuse_send_write(req, file, inode, pos, count, NULL); err = req->out.h.error; fuse_put_request(fc, req); if (!err && !nres) @@ -609,9 +628,11 @@ static ssize_t fuse_direct_io(struct file *file, const char __user *buf, nbytes = (req->num_pages << PAGE_SHIFT) - req->page_offset; nbytes = min(count, nbytes); if (write) - nres = fuse_send_write(req, file, inode, pos, nbytes); + nres = fuse_send_write(req, file, inode, pos, nbytes, + current->files); else - nres = fuse_send_read(req, file, inode, pos, nbytes); + nres = fuse_send_read(req, file, inode, pos, nbytes, + current->files); fuse_release_user_pages(req, !write); if (req->out.h.error) { if (!res) diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 8b64a630e75..6c5461de1a5 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -591,3 +591,5 @@ int fuse_valid_type(int m); * Is task allowed to perform filesystem operation? */ int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task); + +u64 fuse_lock_owner_id(struct fuse_conn *fc, fl_owner_t id); |