diff options
| author | Miklos Szeredi <miklos@szeredi.hu> | 2006-01-06 03:19:40 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-06 11:33:56 -0500 |
| commit | 1d3d752b471d2a3a1d5e4fe177e5e7d52abb4e4c (patch) | |
| tree | 05c6c99ca02118e2c80199c36f4f6263cdf7986b /fs/fuse | |
| parent | 248d86e87d12da19eee602075f05a49a5215288b (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>
Diffstat (limited to 'fs/fuse')
| -rw-r--r-- | fs/fuse/dev.c | 26 | ||||
| -rw-r--r-- | fs/fuse/dir.c | 14 | ||||
| -rw-r--r-- | fs/fuse/fuse_i.h | 9 | ||||
| -rw-r--r-- | fs/fuse/inode.c | 2 |
4 files changed, 24 insertions, 27 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 | ||
| 111 | struct fuse_req; | ||
| 112 | struct 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); |
