|
@@ -617,6 +617,7 @@ static ssize_t fuse_dev_readv(struct file *file, const struct iovec *iov,
|
|
|
struct fuse_copy_state cs;
|
|
|
unsigned reqsize;
|
|
|
|
|
|
+ restart:
|
|
|
spin_lock(&fuse_lock);
|
|
|
fc = file->private_data;
|
|
|
err = -EPERM;
|
|
@@ -632,20 +633,25 @@ static ssize_t fuse_dev_readv(struct file *file, const struct iovec *iov,
|
|
|
|
|
|
req = list_entry(fc->pending.next, struct fuse_req, list);
|
|
|
list_del_init(&req->list);
|
|
|
- spin_unlock(&fuse_lock);
|
|
|
|
|
|
in = &req->in;
|
|
|
- reqsize = req->in.h.len;
|
|
|
- fuse_copy_init(&cs, 1, req, iov, nr_segs);
|
|
|
- err = -EINVAL;
|
|
|
- if (iov_length(iov, nr_segs) >= reqsize) {
|
|
|
- err = fuse_copy_one(&cs, &in->h, sizeof(in->h));
|
|
|
- if (!err)
|
|
|
- err = fuse_copy_args(&cs, in->numargs, in->argpages,
|
|
|
- (struct fuse_arg *) in->args, 0);
|
|
|
+ reqsize = in->h.len;
|
|
|
+ /* If request is too large, reply with an error and restart the read */
|
|
|
+ if (iov_length(iov, nr_segs) < reqsize) {
|
|
|
+ req->out.h.error = -EIO;
|
|
|
+ /* SETXATTR is special, since it may contain too large data */
|
|
|
+ if (in->h.opcode == FUSE_SETXATTR)
|
|
|
+ req->out.h.error = -E2BIG;
|
|
|
+ request_end(fc, req);
|
|
|
+ goto restart;
|
|
|
}
|
|
|
+ spin_unlock(&fuse_lock);
|
|
|
+ fuse_copy_init(&cs, 1, req, iov, nr_segs);
|
|
|
+ err = fuse_copy_one(&cs, &in->h, sizeof(in->h));
|
|
|
+ if (!err)
|
|
|
+ err = fuse_copy_args(&cs, in->numargs, in->argpages,
|
|
|
+ (struct fuse_arg *) in->args, 0);
|
|
|
fuse_copy_finish(&cs);
|
|
|
-
|
|
|
spin_lock(&fuse_lock);
|
|
|
req->locked = 0;
|
|
|
if (!err && req->interrupted)
|