* fusermount: check if /mnt/mtab is a symlink and don't modify it
in that case
+ * kernel: simplify request size limiting. INIT only contains
+ maximum write size, maximum path component size remains fixed at
+ 1024 bytes, and maximum xattr size depends on read buffer.
+
2005-12-14 Miklos Szeredi <miklos@szeredi.hu>
* Fix readdir() failure on x86_64, of 32bit programs compiled
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
struct fuse_copy_state cs;
unsigned reqsize;
+ restart:
spin_lock(&fuse_lock);
fc = file->private_data;
err = -EPERM;
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)
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);
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)
{
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;
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;
struct fuse_setxattr_in inarg;
int err;
- if (size > fc->xattr_size_max)
- return -E2BIG;
-
if (fc->no_setxattr)
return -EOPNOTSUPP;
if (is_bad_inode(inode))
return -EIO;
- if (count > fc->max_write)
- return -EIO;
-
req = fuse_get_request(fc);
if (!req)
return -EINTR;
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);
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);
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
/** 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 */
struct fuse_arg args[3];
};
-struct fuse_req;
-struct fuse_conn;
-
/**
* A request to the client
*/
/** 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;
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
struct fuse_init_out {
__u32 major;
__u32 minor;
- __u32 name_max;
- __u32 symlink_max;
- __u32 xattr_size_max;
+ __u32 unused[3];
__u32 max_write;
};
#define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg)))
-/* PATH_MAX is 4k on Linux, but I don't dare to define it to PATH_MAX,
- because it may be much larger on other systems */
-#define MIN_SYMLINK 0x1000
-
-/* Generous 4k overhead for headers, includes room for xattr name
- (XATTR_NAME_MAX = 255) */
-#define HEADER_OVERHEAD 0x1000
-
-/* 8k, the same as the old FUSE_MAX_IN constant */
-#define MIN_BUFFER_SIZE (MIN_SYMLINK + HEADER_OVERHEAD)
-
struct fuse_ll {
int debug;
int allow_root;
f->major = FUSE_KERNEL_VERSION;
f->minor = arg->minor;
- if (bufsize < MIN_BUFFER_SIZE) {
+ if (bufsize < FUSE_MIN_READ_BUFFER) {
fprintf(stderr, "fuse: warning: buffer size too small: %i\n", bufsize);
- bufsize = MIN_BUFFER_SIZE;
+ bufsize = FUSE_MIN_READ_BUFFER;
}
- bufsize -= HEADER_OVERHEAD;
-
memset(&outarg, 0, sizeof(outarg));
outarg.major = f->major;
outarg.minor = FUSE_KERNEL_MINOR_VERSION;
-
- /* The calculated limits may be oversized, but because of the
- limits in VFS names and symlinks are never larger than PATH_MAX - 1
- and xattr values never larger than XATTR_SIZE_MAX */
-
- /* Max two names per request */
- outarg.symlink_max = outarg.name_max = bufsize / 2;
- /* But if buffer is small, give more room to link name */
- if (outarg.symlink_max < MIN_SYMLINK) {
- outarg.symlink_max = MIN_SYMLINK;
- /* Borrow from header overhead for the SYMLINK operation */
- outarg.name_max = HEADER_OVERHEAD / 4;
- }
- outarg.xattr_size_max = outarg.max_write = bufsize;
+ outarg.max_write = bufsize - 4096;
if (f->debug) {
printf(" INIT: %u.%u\n", outarg.major, outarg.minor);