aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@suse.cz>2007-10-18 06:07:04 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-18 17:37:31 -0400
commitf33321141b273d60cbb3a8f56a5489baad82ba5e (patch)
treeb6443b674600dcdb8c33aa6d44b7a673edc255b4
parentb25e82e5673c750116e8b01a4fc7d09be7809f8c (diff)
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>
-rw-r--r--fs/fuse/dir.c5
-rw-r--r--fs/fuse/file.c37
-rw-r--r--fs/fuse/fuse_i.h2
-rw-r--r--include/linux/fuse.h17
4 files changed, 51 insertions, 10 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 052327bd6c9d..6c83ed052026 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,
1108 inarg.valid |= FATTR_FH; 1108 inarg.valid |= FATTR_FH;
1109 inarg.fh = ff->fh; 1109 inarg.fh = ff->fh;
1110 } 1110 }
1111 if (attr->ia_valid & ATTR_SIZE) {
1112 /* For mandatory locking in truncate */
1113 inarg.valid |= FATTR_LOCKOWNER;
1114 inarg.lock_owner = fuse_lock_owner_id(fc, current->files);
1115 }
1111 req->in.h.opcode = FUSE_SETATTR; 1116 req->in.h.opcode = FUSE_SETATTR;
1112 req->in.h.nodeid = get_node_id(inode); 1117 req->in.h.nodeid = get_node_id(inode);
1113 req->in.numargs = 1; 1118 req->in.numargs = 1;
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 2b589de044e8..0fcdba9d47c0 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)
189 * Scramble the ID space with XTEA, so that the value of the files_struct 189 * Scramble the ID space with XTEA, so that the value of the files_struct
190 * pointer is not exposed to userspace. 190 * pointer is not exposed to userspace.
191 */ 191 */
192static u64 fuse_lock_owner_id(struct fuse_conn *fc, fl_owner_t id) 192u64 fuse_lock_owner_id(struct fuse_conn *fc, fl_owner_t id)
193{ 193{
194 u32 *k = fc->scramble_key; 194 u32 *k = fc->scramble_key;
195 u64 v = (unsigned long) id; 195 u64 v = (unsigned long) id;
@@ -308,11 +308,19 @@ void fuse_read_fill(struct fuse_req *req, struct fuse_file *ff,
308} 308}
309 309
310static size_t fuse_send_read(struct fuse_req *req, struct file *file, 310static size_t fuse_send_read(struct fuse_req *req, struct file *file,
311 struct inode *inode, loff_t pos, size_t count) 311 struct inode *inode, loff_t pos, size_t count,
312 fl_owner_t owner)
312{ 313{
313 struct fuse_conn *fc = get_fuse_conn(inode); 314 struct fuse_conn *fc = get_fuse_conn(inode);
314 struct fuse_file *ff = file->private_data; 315 struct fuse_file *ff = file->private_data;
316
315 fuse_read_fill(req, ff, inode, pos, count, FUSE_READ); 317 fuse_read_fill(req, ff, inode, pos, count, FUSE_READ);
318 if (owner != NULL) {
319 struct fuse_read_in *inarg = &req->misc.read_in;
320
321 inarg->read_flags |= FUSE_READ_LOCKOWNER;
322 inarg->lock_owner = fuse_lock_owner_id(fc, owner);
323 }
316 request_send(fc, req); 324 request_send(fc, req);
317 return req->out.args[0].size; 325 return req->out.args[0].size;
318} 326}
@@ -336,7 +344,8 @@ static int fuse_readpage(struct file *file, struct page *page)
336 req->out.page_zeroing = 1; 344 req->out.page_zeroing = 1;
337 req->num_pages = 1; 345 req->num_pages = 1;
338 req->pages[0] = page; 346 req->pages[0] = page;
339 fuse_send_read(req, file, inode, page_offset(page), PAGE_CACHE_SIZE); 347 fuse_send_read(req, file, inode, page_offset(page), PAGE_CACHE_SIZE,
348 NULL);
340 err = req->out.h.error; 349 err = req->out.h.error;
341 fuse_put_request(fc, req); 350 fuse_put_request(fc, req);
342 if (!err) 351 if (!err)
@@ -447,6 +456,7 @@ static void fuse_write_fill(struct fuse_req *req, struct fuse_file *ff,
447 struct inode *inode, loff_t pos, size_t count, 456 struct inode *inode, loff_t pos, size_t count,
448 int writepage) 457 int writepage)
449{ 458{
459 struct fuse_conn *fc = get_fuse_conn(inode);
450 struct fuse_write_in *inarg = &req->misc.write.in; 460 struct fuse_write_in *inarg = &req->misc.write.in;
451 struct fuse_write_out *outarg = &req->misc.write.out; 461 struct fuse_write_out *outarg = &req->misc.write.out;
452 462
@@ -459,7 +469,10 @@ static void fuse_write_fill(struct fuse_req *req, struct fuse_file *ff,
459 req->in.h.nodeid = get_node_id(inode); 469 req->in.h.nodeid = get_node_id(inode);
460 req->in.argpages = 1; 470 req->in.argpages = 1;
461 req->in.numargs = 2; 471 req->in.numargs = 2;
462 req->in.args[0].size = sizeof(struct fuse_write_in); 472 if (fc->minor < 9)
473 req->in.args[0].size = FUSE_COMPAT_WRITE_IN_SIZE;
474 else
475 req->in.args[0].size = sizeof(struct fuse_write_in);
463 req->in.args[0].value = inarg; 476 req->in.args[0].value = inarg;
464 req->in.args[1].size = count; 477 req->in.args[1].size = count;
465 req->out.numargs = 1; 478 req->out.numargs = 1;
@@ -468,10 +481,16 @@ static void fuse_write_fill(struct fuse_req *req, struct fuse_file *ff,
468} 481}
469 482
470static size_t fuse_send_write(struct fuse_req *req, struct file *file, 483static size_t fuse_send_write(struct fuse_req *req, struct file *file,
471 struct inode *inode, loff_t pos, size_t count) 484 struct inode *inode, loff_t pos, size_t count,
485 fl_owner_t owner)
472{ 486{
473 struct fuse_conn *fc = get_fuse_conn(inode); 487 struct fuse_conn *fc = get_fuse_conn(inode);
474 fuse_write_fill(req, file->private_data, inode, pos, count, 0); 488 fuse_write_fill(req, file->private_data, inode, pos, count, 0);
489 if (owner != NULL) {
490 struct fuse_write_in *inarg = &req->misc.write.in;
491 inarg->write_flags |= FUSE_WRITE_LOCKOWNER;
492 inarg->lock_owner = fuse_lock_owner_id(fc, owner);
493 }
475 request_send(fc, req); 494 request_send(fc, req);
476 return req->misc.write.out.size; 495 return req->misc.write.out.size;
477} 496}
@@ -508,7 +527,7 @@ static int fuse_buffered_write(struct file *file, struct inode *inode,
508 req->num_pages = 1; 527 req->num_pages = 1;
509 req->pages[0] = page; 528 req->pages[0] = page;
510 req->page_offset = offset; 529 req->page_offset = offset;
511 nres = fuse_send_write(req, file, inode, pos, count); 530 nres = fuse_send_write(req, file, inode, pos, count, NULL);
512 err = req->out.h.error; 531 err = req->out.h.error;
513 fuse_put_request(fc, req); 532 fuse_put_request(fc, req);
514 if (!err && !nres) 533 if (!err && !nres)
@@ -609,9 +628,11 @@ static ssize_t fuse_direct_io(struct file *file, const char __user *buf,
609 nbytes = (req->num_pages << PAGE_SHIFT) - req->page_offset; 628 nbytes = (req->num_pages << PAGE_SHIFT) - req->page_offset;
610 nbytes = min(count, nbytes); 629 nbytes = min(count, nbytes);
611 if (write) 630 if (write)
612 nres = fuse_send_write(req, file, inode, pos, nbytes); 631 nres = fuse_send_write(req, file, inode, pos, nbytes,
632 current->files);
613 else 633 else
614 nres = fuse_send_read(req, file, inode, pos, nbytes); 634 nres = fuse_send_read(req, file, inode, pos, nbytes,
635 current->files);
615 fuse_release_user_pages(req, !write); 636 fuse_release_user_pages(req, !write);
616 if (req->out.h.error) { 637 if (req->out.h.error) {
617 if (!res) 638 if (!res)
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 8b64a630e758..6c5461de1a5f 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -591,3 +591,5 @@ int fuse_valid_type(int m);
591 * Is task allowed to perform filesystem operation? 591 * Is task allowed to perform filesystem operation?
592 */ 592 */
593int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task); 593int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task);
594
595u64 fuse_lock_owner_id(struct fuse_conn *fc, fl_owner_t id);
diff --git a/include/linux/fuse.h b/include/linux/fuse.h
index 6f4a31266cd5..7d4fa5b25b87 100644
--- a/include/linux/fuse.h
+++ b/include/linux/fuse.h
@@ -14,6 +14,7 @@
14 * 7.9: 14 * 7.9:
15 * - new fuse_getattr_in input argument of GETATTR 15 * - new fuse_getattr_in input argument of GETATTR
16 * - add lk_flags in fuse_lk_in 16 * - add lk_flags in fuse_lk_in
17 * - add lock_owner field to fuse_setattr_in, fuse_read_in and fuse_write_in
17 */ 18 */
18 19
19#include <asm/types.h> 20#include <asm/types.h>
@@ -86,6 +87,7 @@ struct fuse_file_lock {
86#define FATTR_FH (1 << 6) 87#define FATTR_FH (1 << 6)
87#define FATTR_ATIME_NOW (1 << 7) 88#define FATTR_ATIME_NOW (1 << 7)
88#define FATTR_MTIME_NOW (1 << 8) 89#define FATTR_MTIME_NOW (1 << 8)
90#define FATTR_LOCKOWNER (1 << 9)
89 91
90/** 92/**
91 * Flags returned by the OPEN request 93 * Flags returned by the OPEN request
@@ -123,8 +125,15 @@ struct fuse_file_lock {
123 * WRITE flags 125 * WRITE flags
124 * 126 *
125 * FUSE_WRITE_CACHE: delayed write from page cache, file handle is guessed 127 * FUSE_WRITE_CACHE: delayed write from page cache, file handle is guessed
128 * FUSE_WRITE_LOCKOWNER: lock_owner field is valid
126 */ 129 */
127#define FUSE_WRITE_CACHE (1 << 0) 130#define FUSE_WRITE_CACHE (1 << 0)
131#define FUSE_WRITE_LOCKOWNER (1 << 1)
132
133/**
134 * Read flags
135 */
136#define FUSE_READ_LOCKOWNER (1 << 1)
128 137
129enum fuse_opcode { 138enum fuse_opcode {
130 FUSE_LOOKUP = 1, 139 FUSE_LOOKUP = 1,
@@ -219,7 +228,7 @@ struct fuse_setattr_in {
219 __u32 padding; 228 __u32 padding;
220 __u64 fh; 229 __u64 fh;
221 __u64 size; 230 __u64 size;
222 __u64 unused1; 231 __u64 lock_owner;
223 __u64 atime; 232 __u64 atime;
224 __u64 mtime; 233 __u64 mtime;
225 __u64 unused2; 234 __u64 unused2;
@@ -262,14 +271,18 @@ struct fuse_read_in {
262 __u64 fh; 271 __u64 fh;
263 __u64 offset; 272 __u64 offset;
264 __u32 size; 273 __u32 size;
265 __u32 padding; 274 __u32 read_flags;
275 __u64 lock_owner;
266}; 276};
267 277
278#define FUSE_COMPAT_WRITE_IN_SIZE 24
279
268struct fuse_write_in { 280struct fuse_write_in {
269 __u64 fh; 281 __u64 fh;
270 __u64 offset; 282 __u64 offset;
271 __u32 size; 283 __u32 size;
272 __u32 write_flags; 284 __u32 write_flags;
285 __u64 lock_owner;
273}; 286};
274 287
275struct fuse_write_out { 288struct fuse_write_out {