[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:
Miklos Szeredi 2006-01-06 00:19:40 -08:00 committed by Linus Torvalds
parent 248d86e87d
commit 1d3d752b47
5 changed files with 26 additions and 33 deletions

View file

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

View file

@ -236,10 +236,6 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
if (fc->no_create) if (fc->no_create)
goto out; goto out;
err = -ENAMETOOLONG;
if (entry->d_name.len > FUSE_NAME_MAX)
goto out;
err = -EINTR; err = -EINTR;
req = fuse_get_request(fc); req = fuse_get_request(fc);
if (!req) if (!req)
@ -413,12 +409,7 @@ static int fuse_symlink(struct inode *dir, struct dentry *entry,
{ {
struct fuse_conn *fc = get_fuse_conn(dir); struct fuse_conn *fc = get_fuse_conn(dir);
unsigned len = strlen(link) + 1; unsigned len = strlen(link) + 1;
struct fuse_req *req; struct fuse_req *req = fuse_get_request(fc);
if (len > FUSE_SYMLINK_MAX)
return -ENAMETOOLONG;
req = fuse_get_request(fc);
if (!req) if (!req)
return -EINTR; return -EINTR;
@ -988,9 +979,6 @@ static int fuse_setxattr(struct dentry *entry, const char *name,
struct fuse_setxattr_in inarg; struct fuse_setxattr_in inarg;
int err; int err;
if (size > FUSE_XATTR_SIZE_MAX)
return -E2BIG;
if (fc->no_setxattr) if (fc->no_setxattr)
return -EOPNOTSUPP; return -EOPNOTSUPP;

View file

@ -21,6 +21,12 @@
/** If more requests are outstanding, then the operation will block */ /** If more requests are outstanding, then the operation will block */
#define FUSE_MAX_OUTSTANDING 10 #define FUSE_MAX_OUTSTANDING 10
/** Maximum size of data in a write request */
#define FUSE_MAX_WRITE 4096
/** It could be as large as PATH_MAX, but would that have any uses? */
#define FUSE_NAME_MAX 1024
/** If the FUSE_DEFAULT_PERMISSIONS flag is given, the filesystem /** If the FUSE_DEFAULT_PERMISSIONS flag is given, the filesystem
module will check permissions based on the file mode. Otherwise no module will check permissions based on the file mode. Otherwise no
permission checking is done in the kernel */ permission checking is done in the kernel */
@ -108,9 +114,6 @@ struct fuse_out {
struct fuse_arg args[3]; struct fuse_arg args[3];
}; };
struct fuse_req;
struct fuse_conn;
/** /**
* A request to the client * A request to the client
*/ */

View file

@ -485,7 +485,7 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
fc->max_read = d.max_read; fc->max_read = d.max_read;
if (fc->max_read / PAGE_CACHE_SIZE < fc->bdi.ra_pages) if (fc->max_read / PAGE_CACHE_SIZE < fc->bdi.ra_pages)
fc->bdi.ra_pages = fc->max_read / PAGE_CACHE_SIZE; fc->bdi.ra_pages = fc->max_read / PAGE_CACHE_SIZE;
fc->max_write = FUSE_MAX_IN / 2; fc->max_write = FUSE_MAX_WRITE;
err = -ENOMEM; err = -ENOMEM;
root = get_root_inode(sb, d.rootmode); root = get_root_inode(sb, d.rootmode);

View file

@ -108,12 +108,8 @@ enum fuse_opcode {
FUSE_CREATE = 35 FUSE_CREATE = 35
}; };
/* Conservative buffer size for the client */ /* The read buffer is required to be at least 8k, but may be much larger */
#define FUSE_MAX_IN 8192 #define FUSE_MIN_READ_BUFFER 8192
#define FUSE_NAME_MAX 1024
#define FUSE_SYMLINK_MAX 4096
#define FUSE_XATTR_SIZE_MAX 4096
struct fuse_entry_out { struct fuse_entry_out {
__u64 nodeid; /* Inode ID */ __u64 nodeid; /* Inode ID */