aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiklos Szeredi <miklos@szeredi.hu>2006-01-06 03:19:40 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-06 11:33:56 -0500
commit1d3d752b471d2a3a1d5e4fe177e5e7d52abb4e4c (patch)
tree05c6c99ca02118e2c80199c36f4f6263cdf7986b
parent248d86e87d12da19eee602075f05a49a5215288b (diff)
[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>
-rw-r--r--fs/fuse/dev.c26
-rw-r--r--fs/fuse/dir.c14
-rw-r--r--fs/fuse/fuse_i.h9
-rw-r--r--fs/fuse/inode.c2
-rw-r--r--include/linux/fuse.h8
5 files changed, 26 insertions, 33 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)
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 9a6075de961f..f156392d019e 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -236,10 +236,6 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
236 if (fc->no_create) 236 if (fc->no_create)
237 goto out; 237 goto out;
238 238
239 err = -ENAMETOOLONG;
240 if (entry->d_name.len > FUSE_NAME_MAX)
241 goto out;
242
243 err = -EINTR; 239 err = -EINTR;
244 req = fuse_get_request(fc); 240 req = fuse_get_request(fc);
245 if (!req) 241 if (!req)
@@ -413,12 +409,7 @@ static int fuse_symlink(struct inode *dir, struct dentry *entry,
413{ 409{
414 struct fuse_conn *fc = get_fuse_conn(dir); 410 struct fuse_conn *fc = get_fuse_conn(dir);
415 unsigned len = strlen(link) + 1; 411 unsigned len = strlen(link) + 1;
416 struct fuse_req *req; 412 struct fuse_req *req = fuse_get_request(fc);
417
418 if (len > FUSE_SYMLINK_MAX)
419 return -ENAMETOOLONG;
420
421 req = fuse_get_request(fc);
422 if (!req) 413 if (!req)
423 return -EINTR; 414 return -EINTR;
424 415
@@ -988,9 +979,6 @@ static int fuse_setxattr(struct dentry *entry, const char *name,
988 struct fuse_setxattr_in inarg; 979 struct fuse_setxattr_in inarg;
989 int err; 980 int err;
990 981
991 if (size > FUSE_XATTR_SIZE_MAX)
992 return -E2BIG;
993
994 if (fc->no_setxattr) 982 if (fc->no_setxattr)
995 return -EOPNOTSUPP; 983 return -EOPNOTSUPP;
996 984
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 2d4835e54c90..17fd368559cd 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -21,6 +21,12 @@
21/** If more requests are outstanding, then the operation will block */ 21/** If more requests are outstanding, then the operation will block */
22#define FUSE_MAX_OUTSTANDING 10 22#define FUSE_MAX_OUTSTANDING 10
23 23
24/** Maximum size of data in a write request */
25#define FUSE_MAX_WRITE 4096
26
27/** It could be as large as PATH_MAX, but would that have any uses? */
28#define FUSE_NAME_MAX 1024
29
24/** If the FUSE_DEFAULT_PERMISSIONS flag is given, the filesystem 30/** If the FUSE_DEFAULT_PERMISSIONS flag is given, the filesystem
25 module will check permissions based on the file mode. Otherwise no 31 module will check permissions based on the file mode. Otherwise no
26 permission checking is done in the kernel */ 32 permission checking is done in the kernel */
@@ -108,9 +114,6 @@ struct fuse_out {
108 struct fuse_arg args[3]; 114 struct fuse_arg args[3];
109}; 115};
110 116
111struct fuse_req;
112struct fuse_conn;
113
114/** 117/**
115 * A request to the client 118 * A request to the client
116 */ 119 */
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 3b928a02af04..3580b9e12345 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -485,7 +485,7 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
485 fc->max_read = d.max_read; 485 fc->max_read = d.max_read;
486 if (fc->max_read / PAGE_CACHE_SIZE < fc->bdi.ra_pages) 486 if (fc->max_read / PAGE_CACHE_SIZE < fc->bdi.ra_pages)
487 fc->bdi.ra_pages = fc->max_read / PAGE_CACHE_SIZE; 487 fc->bdi.ra_pages = fc->max_read / PAGE_CACHE_SIZE;
488 fc->max_write = FUSE_MAX_IN / 2; 488 fc->max_write = FUSE_MAX_WRITE;
489 489
490 err = -ENOMEM; 490 err = -ENOMEM;
491 root = get_root_inode(sb, d.rootmode); 491 root = get_root_inode(sb, d.rootmode);
diff --git a/include/linux/fuse.h b/include/linux/fuse.h
index 9d5177c356cc..8f64cc2205b0 100644
--- a/include/linux/fuse.h
+++ b/include/linux/fuse.h
@@ -108,12 +108,8 @@ enum fuse_opcode {
108 FUSE_CREATE = 35 108 FUSE_CREATE = 35
109}; 109};
110 110
111/* Conservative buffer size for the client */ 111/* The read buffer is required to be at least 8k, but may be much larger */
112#define FUSE_MAX_IN 8192 112#define FUSE_MIN_READ_BUFFER 8192
113
114#define FUSE_NAME_MAX 1024
115#define FUSE_SYMLINK_MAX 4096
116#define FUSE_XATTR_SIZE_MAX 4096
117 113
118struct fuse_entry_out { 114struct fuse_entry_out {
119 __u64 nodeid; /* Inode ID */ 115 __u64 nodeid; /* Inode ID */