aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fuse/file.c
diff options
context:
space:
mode:
authorMiklos Szeredi <miklos@szeredi.hu>2006-06-25 08:48:52 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-25 13:01:19 -0400
commit7142125937e1482ad3ae4366594c6586153dfc86 (patch)
tree8d85908a36485df0c80de2032e7fcfa493621fe4 /fs/fuse/file.c
parentbafa96541b250a7051e3fbc5de6e8369daf8ffec (diff)
[PATCH] fuse: add POSIX file locking support
This patch adds POSIX file locking support to the fuse interface. This implementation doesn't keep any locking state in kernel. Unlocking on close() is handled by the FLUSH message, which now contains the lock owner id. Mandatory locking is not supported. The filesystem may enfoce mandatory locking in userspace if needed. Signed-off-by: Miklos Szeredi <miklos@szeredi.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
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