aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/fuse/file.c132
-rw-r--r--fs/fuse/fuse_i.h4
-rw-r--r--fs/fuse/inode.c20
-rw-r--r--include/linux/fuse.h26
4 files changed, 178 insertions, 4 deletions
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 1d59af306b28..d9a8289297c0 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -160,6 +160,18 @@ static int fuse_release(struct inode *inode, struct file *file)
160 return fuse_release_common(inode, file, 0); 160 return fuse_release_common(inode, file, 0);
161} 161}
162 162
163/*
164 * It would be nice to scramble the ID space, so that the value of the
165 * files_struct pointer is not exposed to userspace. Symmetric crypto
166 * functions are overkill, since the inverse function doesn't need to
167 * be implemented (though it does have to exist). Is there something
168 * simpler?
169 */
170static inline u64 fuse_lock_owner_id(fl_owner_t id)
171{
172 return (unsigned long) id;
173}
174
163static int fuse_flush(struct file *file, fl_owner_t id) 175static int fuse_flush(struct file *file, fl_owner_t id)
164{ 176{
165 struct inode *inode = file->f_dentry->d_inode; 177 struct inode *inode = file->f_dentry->d_inode;
@@ -181,11 +193,13 @@ static int fuse_flush(struct file *file, fl_owner_t id)
181 193
182 memset(&inarg, 0, sizeof(inarg)); 194 memset(&inarg, 0, sizeof(inarg));
183 inarg.fh = ff->fh; 195 inarg.fh = ff->fh;
196 inarg.lock_owner = fuse_lock_owner_id(id);
184 req->in.h.opcode = FUSE_FLUSH; 197 req->in.h.opcode = FUSE_FLUSH;
185 req->in.h.nodeid = get_node_id(inode); 198 req->in.h.nodeid = get_node_id(inode);
186 req->in.numargs = 1; 199 req->in.numargs = 1;
187 req->in.args[0].size = sizeof(inarg); 200 req->in.args[0].size = sizeof(inarg);
188 req->in.args[0].value = &inarg; 201 req->in.args[0].value = &inarg;
202 req->force = 1;
189 request_send(fc, req); 203 request_send(fc, req);
190 err = req->out.h.error; 204 err = req->out.h.error;
191 fuse_put_request(fc, req); 205 fuse_put_request(fc, req);
@@ -604,6 +618,122 @@ static int fuse_set_page_dirty(struct page *page)
604 return 0; 618 return 0;
605} 619}
606 620
621static int convert_fuse_file_lock(const struct fuse_file_lock *ffl,
622 struct file_lock *fl)
623{
624 switch (ffl->type) {
625 case F_UNLCK:
626 break;
627
628 case F_RDLCK:
629 case F_WRLCK:
630 if (ffl->start > OFFSET_MAX || ffl->end > OFFSET_MAX ||
631 ffl->end < ffl->start)
632 return -EIO;
633
634 fl->fl_start = ffl->start;
635 fl->fl_end = ffl->end;
636 fl->fl_pid = ffl->pid;
637 break;
638
639 default:
640 return -EIO;
641 }
642 fl->fl_type = ffl->type;
643 return 0;
644}
645
646static void fuse_lk_fill(struct fuse_req *req, struct file *file,
647 const struct file_lock *fl, int opcode, pid_t pid)
648{
649 struct inode *inode = file->f_dentry->d_inode;
650 struct fuse_file *ff = file->private_data;
651 struct fuse_lk_in *arg = &req->misc.lk_in;
652
653 arg->fh = ff->fh;
654 arg->owner = fuse_lock_owner_id(fl->fl_owner);
655 arg->lk.start = fl->fl_start;
656 arg->lk.end = fl->fl_end;
657 arg->lk.type = fl->fl_type;
658 arg->lk.pid = pid;
659 req->in.h.opcode = opcode;
660 req->in.h.nodeid = get_node_id(inode);
661 req->in.numargs = 1;
662 req->in.args[0].size = sizeof(*arg);
663 req->in.args[0].value = arg;
664}
665
666static int fuse_getlk(struct file *file, struct file_lock *fl)
667{
668 struct inode *inode = file->f_dentry->d_inode;
669 struct fuse_conn *fc = get_fuse_conn(inode);
670 struct fuse_req *req;
671 struct fuse_lk_out outarg;
672 int err;
673
674 req = fuse_get_req(fc);
675 if (IS_ERR(req))
676 return PTR_ERR(req);
677
678 fuse_lk_fill(req, file, fl, FUSE_GETLK, 0);
679 req->out.numargs = 1;
680 req->out.args[0].size = sizeof(outarg);
681 req->out.args[0].value = &outarg;
682 request_send(fc, req);
683 err = req->out.h.error;
684 fuse_put_request(fc, req);
685 if (!err)
686 err = convert_fuse_file_lock(&outarg.lk, fl);
687
688 return err;
689}
690
691static int fuse_setlk(struct file *file, struct file_lock *fl)
692{
693 struct inode *inode = file->f_dentry->d_inode;
694 struct fuse_conn *fc = get_fuse_conn(inode);
695 struct fuse_req *req;
696 int opcode = (fl->fl_flags & FL_SLEEP) ? FUSE_SETLKW : FUSE_SETLK;
697 pid_t pid = fl->fl_type != F_UNLCK ? current->tgid : 0;
698 int err;
699
700 /* Unlock on close is handled by the flush method */
701 if (fl->fl_flags & FL_CLOSE)
702 return 0;
703
704 req = fuse_get_req(fc);
705 if (IS_ERR(req))
706 return PTR_ERR(req);
707
708 fuse_lk_fill(req, file, fl, opcode, pid);
709 request_send(fc, req);
710 err = req->out.h.error;
711 fuse_put_request(fc, req);
712 return err;
713}
714
715static int fuse_file_lock(struct file *file, int cmd, struct file_lock *fl)
716{
717 struct inode *inode = file->f_dentry->d_inode;
718 struct fuse_conn *fc = get_fuse_conn(inode);
719 int err;
720
721 if (cmd == F_GETLK) {
722 if (fc->no_lock) {
723 if (!posix_test_lock(file, fl, fl))
724 fl->fl_type = F_UNLCK;
725 err = 0;
726 } else
727 err = fuse_getlk(file, fl);
728 } else {
729 if (fc->no_lock)
730 err = posix_lock_file_wait(file, fl);
731 else
732 err = fuse_setlk(file, fl);
733 }
734 return err;
735}
736
607static const struct file_operations fuse_file_operations = { 737static const struct file_operations fuse_file_operations = {
608 .llseek = generic_file_llseek, 738 .llseek = generic_file_llseek,
609 .read = generic_file_read, 739 .read = generic_file_read,
@@ -613,6 +743,7 @@ static const struct file_operations fuse_file_operations = {
613 .flush = fuse_flush, 743 .flush = fuse_flush,
614 .release = fuse_release, 744 .release = fuse_release,
615 .fsync = fuse_fsync, 745 .fsync = fuse_fsync,
746 .lock = fuse_file_lock,
616 .sendfile = generic_file_sendfile, 747 .sendfile = generic_file_sendfile,
617}; 748};
618 749
@@ -624,6 +755,7 @@ static const struct file_operations fuse_direct_io_file_operations = {
624 .flush = fuse_flush, 755 .flush = fuse_flush,
625 .release = fuse_release, 756 .release = fuse_release,
626 .fsync = fuse_fsync, 757 .fsync = fuse_fsync,
758 .lock = fuse_file_lock,
627 /* no mmap and sendfile */ 759 /* no mmap and sendfile */
628}; 760};
629 761
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index ac12b01f4446..eb3166625ca9 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -190,6 +190,7 @@ struct fuse_req {
190 struct fuse_init_in init_in; 190 struct fuse_init_in init_in;
191 struct fuse_init_out init_out; 191 struct fuse_init_out init_out;
192 struct fuse_read_in read_in; 192 struct fuse_read_in read_in;
193 struct fuse_lk_in lk_in;
193 } misc; 194 } misc;
194 195
195 /** page vector */ 196 /** page vector */
@@ -307,6 +308,9 @@ struct fuse_conn {
307 /** Is removexattr not implemented by fs? */ 308 /** Is removexattr not implemented by fs? */
308 unsigned no_removexattr : 1; 309 unsigned no_removexattr : 1;
309 310
311 /** Are file locking primitives not implemented by fs? */
312 unsigned no_lock : 1;
313
310 /** Is access not implemented by fs? */ 314 /** Is access not implemented by fs? */
311 unsigned no_access : 1; 315 unsigned no_access : 1;
312 316
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 13a7e8ab7a78..412892905838 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -98,6 +98,14 @@ static void fuse_clear_inode(struct inode *inode)
98 } 98 }
99} 99}
100 100
101static int fuse_remount_fs(struct super_block *sb, int *flags, char *data)
102{
103 if (*flags & MS_MANDLOCK)
104 return -EINVAL;
105
106 return 0;
107}
108
101void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr) 109void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr)
102{ 110{
103 if (S_ISREG(inode->i_mode) && i_size_read(inode) != attr->size) 111 if (S_ISREG(inode->i_mode) && i_size_read(inode) != attr->size)
@@ -409,6 +417,7 @@ static struct super_operations fuse_super_operations = {
409 .destroy_inode = fuse_destroy_inode, 417 .destroy_inode = fuse_destroy_inode,
410 .read_inode = fuse_read_inode, 418 .read_inode = fuse_read_inode,
411 .clear_inode = fuse_clear_inode, 419 .clear_inode = fuse_clear_inode,
420 .remount_fs = fuse_remount_fs,
412 .put_super = fuse_put_super, 421 .put_super = fuse_put_super,
413 .umount_begin = fuse_umount_begin, 422 .umount_begin = fuse_umount_begin,
414 .statfs = fuse_statfs, 423 .statfs = fuse_statfs,
@@ -428,8 +437,12 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
428 ra_pages = arg->max_readahead / PAGE_CACHE_SIZE; 437 ra_pages = arg->max_readahead / PAGE_CACHE_SIZE;
429 if (arg->flags & FUSE_ASYNC_READ) 438 if (arg->flags & FUSE_ASYNC_READ)
430 fc->async_read = 1; 439 fc->async_read = 1;
431 } else 440 if (!(arg->flags & FUSE_POSIX_LOCKS))
441 fc->no_lock = 1;
442 } else {
432 ra_pages = fc->max_read / PAGE_CACHE_SIZE; 443 ra_pages = fc->max_read / PAGE_CACHE_SIZE;
444 fc->no_lock = 1;
445 }
433 446
434 fc->bdi.ra_pages = min(fc->bdi.ra_pages, ra_pages); 447 fc->bdi.ra_pages = min(fc->bdi.ra_pages, ra_pages);
435 fc->minor = arg->minor; 448 fc->minor = arg->minor;
@@ -447,7 +460,7 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req)
447 arg->major = FUSE_KERNEL_VERSION; 460 arg->major = FUSE_KERNEL_VERSION;
448 arg->minor = FUSE_KERNEL_MINOR_VERSION; 461 arg->minor = FUSE_KERNEL_MINOR_VERSION;
449 arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE; 462 arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE;
450 arg->flags |= FUSE_ASYNC_READ; 463 arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS;
451 req->in.h.opcode = FUSE_INIT; 464 req->in.h.opcode = FUSE_INIT;
452 req->in.numargs = 1; 465 req->in.numargs = 1;
453 req->in.args[0].size = sizeof(*arg); 466 req->in.args[0].size = sizeof(*arg);
@@ -479,6 +492,9 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
479 struct fuse_req *init_req; 492 struct fuse_req *init_req;
480 int err; 493 int err;
481 494
495 if (sb->s_flags & MS_MANDLOCK)
496 return -EINVAL;
497
482 if (!parse_fuse_opt((char *) data, &d)) 498 if (!parse_fuse_opt((char *) data, &d))
483 return -EINVAL; 499 return -EINVAL;
484 500
diff --git a/include/linux/fuse.h b/include/linux/fuse.h
index 8e4319614bef..e7a76ec0f05c 100644
--- a/include/linux/fuse.h
+++ b/include/linux/fuse.h
@@ -1,6 +1,6 @@
1/* 1/*
2 FUSE: Filesystem in Userspace 2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu> 3 Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu>
4 4
5 This program can be distributed under the terms of the GNU GPL. 5 This program can be distributed under the terms of the GNU GPL.
6 See the file COPYING. 6 See the file COPYING.
@@ -15,7 +15,7 @@
15#define FUSE_KERNEL_VERSION 7 15#define FUSE_KERNEL_VERSION 7
16 16
17/** Minor version number of this interface */ 17/** Minor version number of this interface */
18#define FUSE_KERNEL_MINOR_VERSION 6 18#define FUSE_KERNEL_MINOR_VERSION 7
19 19
20/** The node ID of the root inode */ 20/** The node ID of the root inode */
21#define FUSE_ROOT_ID 1 21#define FUSE_ROOT_ID 1
@@ -59,6 +59,13 @@ struct fuse_kstatfs {
59 __u32 spare[6]; 59 __u32 spare[6];
60}; 60};
61 61
62struct fuse_file_lock {
63 __u64 start;
64 __u64 end;
65 __u32 type;
66 __u32 pid; /* tgid */
67};
68
62/** 69/**
63 * Bitmasks for fuse_setattr_in.valid 70 * Bitmasks for fuse_setattr_in.valid
64 */ 71 */
@@ -83,6 +90,7 @@ struct fuse_kstatfs {
83 * INIT request/reply flags 90 * INIT request/reply flags
84 */ 91 */
85#define FUSE_ASYNC_READ (1 << 0) 92#define FUSE_ASYNC_READ (1 << 0)
93#define FUSE_POSIX_LOCKS (1 << 1)
86 94
87enum fuse_opcode { 95enum fuse_opcode {
88 FUSE_LOOKUP = 1, 96 FUSE_LOOKUP = 1,
@@ -113,6 +121,9 @@ enum fuse_opcode {
113 FUSE_READDIR = 28, 121 FUSE_READDIR = 28,
114 FUSE_RELEASEDIR = 29, 122 FUSE_RELEASEDIR = 29,
115 FUSE_FSYNCDIR = 30, 123 FUSE_FSYNCDIR = 30,
124 FUSE_GETLK = 31,
125 FUSE_SETLK = 32,
126 FUSE_SETLKW = 33,
116 FUSE_ACCESS = 34, 127 FUSE_ACCESS = 34,
117 FUSE_CREATE = 35 128 FUSE_CREATE = 35
118}; 129};
@@ -200,6 +211,7 @@ struct fuse_flush_in {
200 __u64 fh; 211 __u64 fh;
201 __u32 flush_flags; 212 __u32 flush_flags;
202 __u32 padding; 213 __u32 padding;
214 __u64 lock_owner;
203}; 215};
204 216
205struct fuse_read_in { 217struct fuse_read_in {
@@ -248,6 +260,16 @@ struct fuse_getxattr_out {
248 __u32 padding; 260 __u32 padding;
249}; 261};
250 262
263struct fuse_lk_in {
264 __u64 fh;
265 __u64 owner;
266 struct fuse_file_lock lk;
267};
268
269struct fuse_lk_out {
270 struct fuse_file_lock lk;
271};
272
251struct fuse_access_in { 273struct fuse_access_in {
252 __u32 mask; 274 __u32 mask;
253 __u32 padding; 275 __u32 padding;