[PATCH] fuse: clean up request size limit checking
Change the way a too large request is handled. Until now in this case the device read returned -EINVAL and the operation returned -EIO. Make it more flexibible by not returning -EINVAL from the read, but restarting it instead. Also remove the fixed limit on setxattr data and let the filesystem provide as large a read buffer as it needs to handle the extended attribute data. The symbolic link length is already checked by VFS to be less than PATH_MAX, so the extra check against FUSE_SYMLINK_MAX is not needed. The check in fuse_create_open() against FUSE_NAME_MAX is not needed, since the dentry has already been looked up, and hence the name already checked. Signed-off-by: Miklos Szeredi <miklos@szeredi.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
committed by
Linus Torvalds
parent
248d86e87d
commit
1d3d752b47
@ -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)
|
||||
|
Reference in New Issue
Block a user