-static int convert_fuse_file_lock(const struct fuse_file_lock *ffl,
- struct file_lock *fl)
-{
- switch (ffl->type) {
- case F_UNLCK:
- break;
-
- case F_RDLCK:
- case F_WRLCK:
- if (ffl->start > OFFSET_MAX || ffl->end > OFFSET_MAX ||
- ffl->end < ffl->start)
- return -EIO;
-
- fl->fl_start = ffl->start;
- fl->fl_end = ffl->end;
- fl->fl_pid = ffl->pid;
- break;
-
- default:
- return -EIO;
- }
- fl->fl_type = ffl->type;
- return 0;
-}
-
-static void fuse_lk_fill(struct fuse_req *req, struct file *file,
- const struct file_lock *fl, int opcode, pid_t pid)
-{
- struct inode *inode = file->f_dentry->d_inode;
- struct fuse_conn *fc = get_fuse_conn(inode);
- struct fuse_file *ff = file->private_data;
- struct fuse_lk_in *arg = &req->misc.lk_in;
-
- arg->fh = ff->fh;
- arg->owner = fuse_lock_owner_id(fc, fl->fl_owner);
- arg->lk.start = fl->fl_start;
- arg->lk.end = fl->fl_end;
- arg->lk.type = fl->fl_type;
- arg->lk.pid = pid;
- req->in.h.opcode = opcode;
- req->in.h.nodeid = get_node_id(inode);
- req->in.numargs = 1;
- req->in.args[0].size = sizeof(*arg);
- req->in.args[0].value = arg;
-}
-
-static int fuse_getlk(struct file *file, struct file_lock *fl)
-{
- struct inode *inode = file->f_dentry->d_inode;
- struct fuse_conn *fc = get_fuse_conn(inode);
- struct fuse_req *req;
- struct fuse_lk_out outarg;
- int err;
-
- req = fuse_get_req(fc);
- if (IS_ERR(req))
- return PTR_ERR(req);
-
- fuse_lk_fill(req, file, fl, FUSE_GETLK, 0);
- req->out.numargs = 1;
- req->out.args[0].size = sizeof(outarg);
- req->out.args[0].value = &outarg;
- request_send(fc, req);
- err = req->out.h.error;
- fuse_put_request(fc, req);
- if (!err)
- err = convert_fuse_file_lock(&outarg.lk, fl);
-
- return err;
-}
-
-static int fuse_setlk(struct file *file, struct file_lock *fl)
-{
- struct inode *inode = file->f_dentry->d_inode;
- struct fuse_conn *fc = get_fuse_conn(inode);
- struct fuse_req *req;
- int opcode = (fl->fl_flags & FL_SLEEP) ? FUSE_SETLKW : FUSE_SETLK;
- pid_t pid = fl->fl_type != F_UNLCK ? current->tgid : 0;
- int err;
-
- /* Unlock on close is handled by the flush method */
- if (fl->fl_flags & FL_CLOSE)
- return 0;
-
- req = fuse_get_req(fc);
- if (IS_ERR(req))
- return PTR_ERR(req);
-
- fuse_lk_fill(req, file, fl, opcode, pid);
- request_send(fc, req);
- err = req->out.h.error;
- /* locking is restartable */
- if (err == -EINTR)
- err = -ERESTARTSYS;
- fuse_put_request(fc, req);
- return err;
-}
-
-static int fuse_file_lock(struct file *file, int cmd, struct file_lock *fl)
-{
- struct inode *inode = file->f_dentry->d_inode;
- struct fuse_conn *fc = get_fuse_conn(inode);
- int err;
-
- if (cmd == F_GETLK) {
- if (fc->no_lock) {
- if (!posix_test_lock(file, fl, fl))
- fl->fl_type = F_UNLCK;
- err = 0;
- } else
- err = fuse_getlk(file, fl);
- } else {
- if (fc->no_lock)
- err = posix_lock_file_wait(file, fl);
- else
- err = fuse_setlk(file, fl);
- }
- return err;
-}
-