diff options
author | Miklos Szeredi <miklos@szeredi.hu> | 2005-12-15 16:41:20 +0000 |
---|---|---|
committer | Miklos Szeredi <miklos@szeredi.hu> | 2005-12-15 16:41:20 +0000 |
commit | 154ffe2c27e84a29eafedc5327f663a313f2721a (patch) | |
tree | 42d3497095b2eb452cbe3a504733112f0c44ad8d /kernel | |
parent | 4e8290961d24105834fed054afbf1f7749553e47 (diff) | |
download | libfuse-154ffe2c27e84a29eafedc5327f663a313f2721a.tar.gz |
fix
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/dev.c | 39 | ||||
-rw-r--r-- | kernel/dir.c | 24 | ||||
-rw-r--r-- | kernel/file.c | 10 | ||||
-rw-r--r-- | kernel/fuse_i.h | 15 | ||||
-rw-r--r-- | kernel/fuse_kernel.h | 7 |
5 files changed, 32 insertions, 63 deletions
diff --git a/kernel/dev.c b/kernel/dev.c index 4f1e8c0..f7ccb7b 100644 --- a/kernel/dev.c +++ b/kernel/dev.c @@ -197,18 +197,7 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) fc->conn_error = 1; else { fc->minor = arg->minor; - if (fc->minor >= 5) { - fc->name_max = arg->name_max; - fc->symlink_max = arg->symlink_max; - fc->xattr_size_max = arg->xattr_size_max; - fc->max_write = arg->max_write; - } else { - /* Old fix values */ - fc->name_max = 1024; - fc->symlink_max = 4096; - fc->xattr_size_max = 4096; - fc->max_write = 4096; - } + fc->max_write = arg->minor < 5 ? 4096 : arg->max_write; } /* After INIT reply is received other requests can go @@ -691,6 +680,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; @@ -706,20 +696,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) diff --git a/kernel/dir.c b/kernel/dir.c index b1bf3aa..fa4857f 100644 --- a/kernel/dir.c +++ b/kernel/dir.c @@ -202,13 +202,13 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, int err; struct fuse_entry_out outarg; struct inode *inode = NULL; - struct fuse_conn *fc = get_fuse_conn(dir); - struct fuse_req *req; #if !defined(FUSE_MAINLINE) && defined(KERNEL_2_6) struct dentry *newent; #endif + struct fuse_conn *fc = get_fuse_conn(dir); + struct fuse_req *req; - if (entry->d_name.len > fc->name_max) + if (entry->d_name.len > FUSE_NAME_MAX) return ERR_PTR(-ENAMETOOLONG); req = fuse_get_request(fc); @@ -280,10 +280,6 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, if (fc->no_create) goto out; - err = -ENAMETOOLONG; - if (entry->d_name.len > fc->name_max) - goto out; - err = -EINTR; req = fuse_get_request(fc); if (!req) @@ -466,12 +462,7 @@ static int fuse_symlink(struct inode *dir, struct dentry *entry, { struct fuse_conn *fc = get_fuse_conn(dir); unsigned len = strlen(link) + 1; - struct fuse_req *req; - - if (len > fc->symlink_max) - return -ENAMETOOLONG; - - req = fuse_get_request(fc); + struct fuse_req *req = fuse_get_request(fc); if (!req) return -EINTR; @@ -812,13 +803,11 @@ static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) static int parse_dirfile(char *buf, size_t nbytes, struct file *file, void *dstbuf, filldir_t filldir) { - struct fuse_conn *fc = get_fuse_conn(file->f_dentry->d_inode); - while (nbytes >= FUSE_NAME_OFFSET) { struct fuse_dirent *dirent = (struct fuse_dirent *) buf; size_t reclen = FUSE_DIRENT_SIZE(dirent); int over; - if (!dirent->namelen || dirent->namelen > fc->name_max) + if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX) return -EIO; if (reclen > nbytes) break; @@ -1146,9 +1135,6 @@ static int fuse_setxattr(struct dentry *entry, const char *name, struct fuse_setxattr_in inarg; int err; - if (size > fc->xattr_size_max) - return -E2BIG; - if (fc->no_setxattr) return -EOPNOTSUPP; diff --git a/kernel/file.c b/kernel/file.c index 0a625a2..2d34e01 100644 --- a/kernel/file.c +++ b/kernel/file.c @@ -538,9 +538,6 @@ static int fuse_commit_write(struct file *file, struct page *page, if (is_bad_inode(inode)) return -EIO; - if (count > fc->max_write) - return -EIO; - req = fuse_get_request(fc); if (!req) return -EINTR; @@ -592,7 +589,7 @@ static int fuse_get_user_pages(struct fuse_req *req, const char __user *buf, nbytes = min(nbytes, (unsigned) FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT); npages = (nbytes + offset + PAGE_SIZE - 1) >> PAGE_SHIFT; - npages = min(npages, FUSE_MAX_PAGES_PER_REQ); + npages = min(max(npages, 1), FUSE_MAX_PAGES_PER_REQ); down_read(¤t->mm->mmap_sem); npages = get_user_pages(current, current->mm, user_addr, npages, write, 0, req->pages, NULL); @@ -623,7 +620,6 @@ static ssize_t fuse_direct_io(struct file *file, const char __user *buf, return -EINTR; while (count) { - size_t tmp; size_t nres; size_t nbytes = min(count, nmax); int err = fuse_get_user_pages(req, buf, nbytes, !write); @@ -631,8 +627,8 @@ static ssize_t fuse_direct_io(struct file *file, const char __user *buf, res = err; break; } - tmp = (req->num_pages << PAGE_SHIFT) - req->page_offset; - nbytes = min(nbytes, tmp); + nbytes = (req->num_pages << PAGE_SHIFT) - req->page_offset; + nbytes = min(count, nbytes); if (write) nres = fuse_send_write(req, file, inode, pos, nbytes); else diff --git a/kernel/fuse_i.h b/kernel/fuse_i.h index 7f26b65..4bf9a32 100644 --- a/kernel/fuse_i.h +++ b/kernel/fuse_i.h @@ -93,6 +93,9 @@ static inline void set_page_dirty_lock(struct page *page) /** If more requests are outstanding, then the operation will block */ #define FUSE_MAX_OUTSTANDING 10 +/** 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 module will check permissions based on the file mode. Otherwise no permission checking is done in the kernel */ @@ -185,9 +188,6 @@ struct fuse_out { struct fuse_arg args[3]; }; -struct fuse_req; -struct fuse_conn; - /** * A request to the client */ @@ -285,15 +285,6 @@ struct fuse_conn { /** Maximum write size */ unsigned max_write; - /** Maximum path segment length */ - unsigned name_max; - - /** Maximum symbolic link size */ - unsigned symlink_max; - - /** Maximum size of xattr data */ - unsigned xattr_size_max; - /** Readers of the connection are waiting on this */ wait_queue_head_t waitq; diff --git a/kernel/fuse_kernel.h b/kernel/fuse_kernel.h index 26fff13..f494aff 100644 --- a/kernel/fuse_kernel.h +++ b/kernel/fuse_kernel.h @@ -143,6 +143,9 @@ enum fuse_opcode { FUSE_CREATE = 35 }; +/* The read buffer is required to be at least 8k, but may be much larger */ +#define FUSE_MIN_READ_BUFFER 8192 + struct fuse_entry_out { __u64 nodeid; /* Inode ID */ __u64 generation; /* Inode generation: nodeid:gen must @@ -284,9 +287,7 @@ struct fuse_init_in { struct fuse_init_out { __u32 major; __u32 minor; - __u32 name_max; - __u32 symlink_max; - __u32 xattr_size_max; + __u32 unused[3]; __u32 max_write; }; |