提交 f3332114 编写于 作者: M Miklos Szeredi 提交者: Linus Torvalds

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: NMiklos Szeredi <mszeredi@suse.cz>
Signed-off-by: NAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: NLinus Torvalds <torvalds@linux-foundation.org>
上级 b25e82e5
...@@ -1108,6 +1108,11 @@ static int fuse_do_setattr(struct dentry *entry, struct iattr *attr, ...@@ -1108,6 +1108,11 @@ static int fuse_do_setattr(struct dentry *entry, struct iattr *attr,
inarg.valid |= FATTR_FH; inarg.valid |= FATTR_FH;
inarg.fh = ff->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.opcode = FUSE_SETATTR;
req->in.h.nodeid = get_node_id(inode); req->in.h.nodeid = get_node_id(inode);
req->in.numargs = 1; req->in.numargs = 1;
......
...@@ -189,7 +189,7 @@ static int fuse_release(struct inode *inode, struct file *file) ...@@ -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 * Scramble the ID space with XTEA, so that the value of the files_struct
* pointer is not exposed to userspace. * 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; u32 *k = fc->scramble_key;
u64 v = (unsigned long) id; u64 v = (unsigned long) id;
...@@ -308,11 +308,19 @@ void fuse_read_fill(struct fuse_req *req, struct fuse_file *ff, ...@@ -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, 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_conn *fc = get_fuse_conn(inode);
struct fuse_file *ff = file->private_data; struct fuse_file *ff = file->private_data;
fuse_read_fill(req, ff, inode, pos, count, FUSE_READ); 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); request_send(fc, req);
return req->out.args[0].size; return req->out.args[0].size;
} }
...@@ -336,7 +344,8 @@ static int fuse_readpage(struct file *file, struct page *page) ...@@ -336,7 +344,8 @@ static int fuse_readpage(struct file *file, struct page *page)
req->out.page_zeroing = 1; req->out.page_zeroing = 1;
req->num_pages = 1; req->num_pages = 1;
req->pages[0] = page; 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; err = req->out.h.error;
fuse_put_request(fc, req); fuse_put_request(fc, req);
if (!err) if (!err)
...@@ -447,6 +456,7 @@ static void fuse_write_fill(struct fuse_req *req, struct fuse_file *ff, ...@@ -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, struct inode *inode, loff_t pos, size_t count,
int writepage) int writepage)
{ {
struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_write_in *inarg = &req->misc.write.in; struct fuse_write_in *inarg = &req->misc.write.in;
struct fuse_write_out *outarg = &req->misc.write.out; 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, ...@@ -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.h.nodeid = get_node_id(inode);
req->in.argpages = 1; req->in.argpages = 1;
req->in.numargs = 2; 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[0].value = inarg;
req->in.args[1].size = count; req->in.args[1].size = count;
req->out.numargs = 1; req->out.numargs = 1;
...@@ -468,10 +481,16 @@ static void fuse_write_fill(struct fuse_req *req, struct fuse_file *ff, ...@@ -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, 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); struct fuse_conn *fc = get_fuse_conn(inode);
fuse_write_fill(req, file->private_data, inode, pos, count, 0); 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); request_send(fc, req);
return req->misc.write.out.size; return req->misc.write.out.size;
} }
...@@ -508,7 +527,7 @@ static int fuse_buffered_write(struct file *file, struct inode *inode, ...@@ -508,7 +527,7 @@ static int fuse_buffered_write(struct file *file, struct inode *inode,
req->num_pages = 1; req->num_pages = 1;
req->pages[0] = page; req->pages[0] = page;
req->page_offset = offset; 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; err = req->out.h.error;
fuse_put_request(fc, req); fuse_put_request(fc, req);
if (!err && !nres) if (!err && !nres)
...@@ -609,9 +628,11 @@ static ssize_t fuse_direct_io(struct file *file, const char __user *buf, ...@@ -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 = (req->num_pages << PAGE_SHIFT) - req->page_offset;
nbytes = min(count, nbytes); nbytes = min(count, nbytes);
if (write) if (write)
nres = fuse_send_write(req, file, inode, pos, nbytes); nres = fuse_send_write(req, file, inode, pos, nbytes,
current->files);
else 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); fuse_release_user_pages(req, !write);
if (req->out.h.error) { if (req->out.h.error) {
if (!res) if (!res)
......
...@@ -591,3 +591,5 @@ int fuse_valid_type(int m); ...@@ -591,3 +591,5 @@ int fuse_valid_type(int m);
* Is task allowed to perform filesystem operation? * Is task allowed to perform filesystem operation?
*/ */
int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task); 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);
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
* 7.9: * 7.9:
* - new fuse_getattr_in input argument of GETATTR * - new fuse_getattr_in input argument of GETATTR
* - add lk_flags in fuse_lk_in * - add lk_flags in fuse_lk_in
* - add lock_owner field to fuse_setattr_in, fuse_read_in and fuse_write_in
*/ */
#include <asm/types.h> #include <asm/types.h>
...@@ -86,6 +87,7 @@ struct fuse_file_lock { ...@@ -86,6 +87,7 @@ struct fuse_file_lock {
#define FATTR_FH (1 << 6) #define FATTR_FH (1 << 6)
#define FATTR_ATIME_NOW (1 << 7) #define FATTR_ATIME_NOW (1 << 7)
#define FATTR_MTIME_NOW (1 << 8) #define FATTR_MTIME_NOW (1 << 8)
#define FATTR_LOCKOWNER (1 << 9)
/** /**
* Flags returned by the OPEN request * Flags returned by the OPEN request
...@@ -123,8 +125,15 @@ struct fuse_file_lock { ...@@ -123,8 +125,15 @@ struct fuse_file_lock {
* WRITE flags * WRITE flags
* *
* FUSE_WRITE_CACHE: delayed write from page cache, file handle is guessed * FUSE_WRITE_CACHE: delayed write from page cache, file handle is guessed
* FUSE_WRITE_LOCKOWNER: lock_owner field is valid
*/ */
#define FUSE_WRITE_CACHE (1 << 0) #define FUSE_WRITE_CACHE (1 << 0)
#define FUSE_WRITE_LOCKOWNER (1 << 1)
/**
* Read flags
*/
#define FUSE_READ_LOCKOWNER (1 << 1)
enum fuse_opcode { enum fuse_opcode {
FUSE_LOOKUP = 1, FUSE_LOOKUP = 1,
...@@ -219,7 +228,7 @@ struct fuse_setattr_in { ...@@ -219,7 +228,7 @@ struct fuse_setattr_in {
__u32 padding; __u32 padding;
__u64 fh; __u64 fh;
__u64 size; __u64 size;
__u64 unused1; __u64 lock_owner;
__u64 atime; __u64 atime;
__u64 mtime; __u64 mtime;
__u64 unused2; __u64 unused2;
...@@ -262,14 +271,18 @@ struct fuse_read_in { ...@@ -262,14 +271,18 @@ struct fuse_read_in {
__u64 fh; __u64 fh;
__u64 offset; __u64 offset;
__u32 size; __u32 size;
__u32 padding; __u32 read_flags;
__u64 lock_owner;
}; };
#define FUSE_COMPAT_WRITE_IN_SIZE 24
struct fuse_write_in { struct fuse_write_in {
__u64 fh; __u64 fh;
__u64 offset; __u64 offset;
__u32 size; __u32 size;
__u32 write_flags; __u32 write_flags;
__u64 lock_owner;
}; };
struct fuse_write_out { struct fuse_write_out {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册