diff options
-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 | ||||
-rw-r--r-- | include/linux/fuse.h | 17 |
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 | */ |
192 | static u64 fuse_lock_owner_id(struct fuse_conn *fc, fl_owner_t id) | 192 | u64 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 | ||
310 | static size_t fuse_send_read(struct fuse_req *req, struct file *file, | 310 | static 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 | ||
470 | static size_t fuse_send_write(struct fuse_req *req, struct file *file, | 483 | static 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 | */ |
593 | int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task); | 593 | int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task); |
594 | |||
595 | u64 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 | ||
129 | enum fuse_opcode { | 138 | enum 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 | |||
268 | struct fuse_write_in { | 280 | struct 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 | ||
275 | struct fuse_write_out { | 288 | struct fuse_write_out { |