aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fuse/file.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/fuse/file.c')
-rw-r--r--fs/fuse/file.c132
1 files changed, 132 insertions, 0 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