diff options
Diffstat (limited to 'fs/fuse/dev.c')
-rw-r--r-- | fs/fuse/dev.c | 26 |
1 files changed, 16 insertions, 10 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index e5bc3f8eebd0..1afdffdf80db 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c | |||
@@ -617,6 +617,7 @@ static ssize_t fuse_dev_readv(struct file *file, const struct iovec *iov, | |||
617 | struct fuse_copy_state cs; | 617 | struct fuse_copy_state cs; |
618 | unsigned reqsize; | 618 | unsigned reqsize; |
619 | 619 | ||
620 | restart: | ||
620 | spin_lock(&fuse_lock); | 621 | spin_lock(&fuse_lock); |
621 | fc = file->private_data; | 622 | fc = file->private_data; |
622 | err = -EPERM; | 623 | err = -EPERM; |
@@ -632,20 +633,25 @@ static ssize_t fuse_dev_readv(struct file *file, const struct iovec *iov, | |||
632 | 633 | ||
633 | req = list_entry(fc->pending.next, struct fuse_req, list); | 634 | req = list_entry(fc->pending.next, struct fuse_req, list); |
634 | list_del_init(&req->list); | 635 | list_del_init(&req->list); |
635 | spin_unlock(&fuse_lock); | ||
636 | 636 | ||
637 | in = &req->in; | 637 | in = &req->in; |
638 | reqsize = req->in.h.len; | 638 | reqsize = in->h.len; |
639 | fuse_copy_init(&cs, 1, req, iov, nr_segs); | 639 | /* If request is too large, reply with an error and restart the read */ |
640 | err = -EINVAL; | 640 | if (iov_length(iov, nr_segs) < reqsize) { |
641 | if (iov_length(iov, nr_segs) >= reqsize) { | 641 | req->out.h.error = -EIO; |
642 | err = fuse_copy_one(&cs, &in->h, sizeof(in->h)); | 642 | /* SETXATTR is special, since it may contain too large data */ |
643 | if (!err) | 643 | if (in->h.opcode == FUSE_SETXATTR) |
644 | err = fuse_copy_args(&cs, in->numargs, in->argpages, | 644 | req->out.h.error = -E2BIG; |
645 | (struct fuse_arg *) in->args, 0); | 645 | request_end(fc, req); |
646 | goto restart; | ||
646 | } | 647 | } |
648 | spin_unlock(&fuse_lock); | ||
649 | fuse_copy_init(&cs, 1, req, iov, nr_segs); | ||
650 | err = fuse_copy_one(&cs, &in->h, sizeof(in->h)); | ||
651 | if (!err) | ||
652 | err = fuse_copy_args(&cs, in->numargs, in->argpages, | ||
653 | (struct fuse_arg *) in->args, 0); | ||
647 | fuse_copy_finish(&cs); | 654 | fuse_copy_finish(&cs); |
648 | |||
649 | spin_lock(&fuse_lock); | 655 | spin_lock(&fuse_lock); |
650 | req->locked = 0; | 656 | req->locked = 0; |
651 | if (!err && req->interrupted) | 657 | if (!err && req->interrupted) |