fuse: add support for mandatory locking
For mandatory locking the userspace filesystem needs to know the lock
ownership for read, write and truncate operations.
This patch adds the necessary fields to the protocol.
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 2b589de..0fcdba9 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -189,7 +189,7 @@
* 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 @@
}
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 @@
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 @@
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 @@
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 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 @@
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 @@
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)