mirror of
https://github.com/openharmony/third_party_libfuse.git
synced 2026-07-19 21:43:34 -04:00
fix
This commit is contained in:
@@ -1,3 +1,12 @@
|
||||
2005-12-06 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
* Use bigger request buffer size. write() did not work on archs
|
||||
with > 4k page size, Bug report by Mark Haney
|
||||
|
||||
* ABI version 7.5:
|
||||
|
||||
* Extend INIT reply with data size limits
|
||||
|
||||
2005-12-02 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
* Fix memory leak in fuse_read_cmd()/fuse_process_cmd(). Bug
|
||||
|
||||
+41
-18
@@ -188,6 +188,37 @@ void fuse_release_background(struct fuse_req *req)
|
||||
spin_unlock(&fuse_lock);
|
||||
}
|
||||
|
||||
static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
|
||||
{
|
||||
int i;
|
||||
struct fuse_init_out *arg = &req->misc.init_out;
|
||||
|
||||
if (arg->major != FUSE_KERNEL_VERSION)
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/* After INIT reply is received other requests can go
|
||||
out. So do (FUSE_MAX_OUTSTANDING - 1) number of
|
||||
up()s on outstanding_sem. The last up() is done in
|
||||
fuse_putback_request() */
|
||||
for (i = 1; i < FUSE_MAX_OUTSTANDING; i++)
|
||||
up(&fc->outstanding_sem);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called when a request is finished. Either a reply
|
||||
* has arrived or it was interrupted (and not yet sent) or some error
|
||||
@@ -212,21 +243,9 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req)
|
||||
up_read(&fc->sbput_sem);
|
||||
}
|
||||
wake_up(&req->waitq);
|
||||
if (req->in.h.opcode == FUSE_INIT) {
|
||||
int i;
|
||||
|
||||
if (req->misc.init_in_out.major != FUSE_KERNEL_VERSION)
|
||||
fc->conn_error = 1;
|
||||
|
||||
fc->minor = req->misc.init_in_out.minor;
|
||||
|
||||
/* After INIT reply is received other requests can go
|
||||
out. So do (FUSE_MAX_OUTSTANDING - 1) number of
|
||||
up()s on outstanding_sem. The last up() is done in
|
||||
fuse_putback_request() */
|
||||
for (i = 1; i < FUSE_MAX_OUTSTANDING; i++)
|
||||
up(&fc->outstanding_sem);
|
||||
} else if (req->in.h.opcode == FUSE_RELEASE && req->inode == NULL) {
|
||||
if (req->in.h.opcode == FUSE_INIT)
|
||||
process_init_reply(fc, req);
|
||||
else if (req->in.h.opcode == FUSE_RELEASE && req->inode == NULL) {
|
||||
/* Special case for failed iget in CREATE */
|
||||
u64 nodeid = req->in.h.nodeid;
|
||||
__fuse_get_request(req);
|
||||
@@ -399,7 +418,7 @@ void fuse_send_init(struct fuse_conn *fc)
|
||||
/* This is called from fuse_read_super() so there's guaranteed
|
||||
to be a request available */
|
||||
struct fuse_req *req = do_get_request(fc);
|
||||
struct fuse_init_in_out *arg = &req->misc.init_in_out;
|
||||
struct fuse_init_in *arg = &req->misc.init_in;
|
||||
arg->major = FUSE_KERNEL_VERSION;
|
||||
arg->minor = FUSE_KERNEL_MINOR_VERSION;
|
||||
req->in.h.opcode = FUSE_INIT;
|
||||
@@ -407,8 +426,12 @@ void fuse_send_init(struct fuse_conn *fc)
|
||||
req->in.args[0].size = sizeof(*arg);
|
||||
req->in.args[0].value = arg;
|
||||
req->out.numargs = 1;
|
||||
req->out.args[0].size = sizeof(*arg);
|
||||
req->out.args[0].value = arg;
|
||||
/* Variable length arguement used for backward compatibility
|
||||
with interface version < 7.5. Rest of init_out is zeroed
|
||||
by do_get_request(), so a short reply is not a problem */
|
||||
req->out.argvar = 1;
|
||||
req->out.args[0].size = sizeof(struct fuse_init_out);
|
||||
req->out.args[0].value = &req->misc.init_out;
|
||||
request_send_background(fc, req);
|
||||
}
|
||||
|
||||
|
||||
+9
-6
@@ -202,7 +202,7 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
|
||||
struct dentry *newent;
|
||||
#endif
|
||||
|
||||
if (entry->d_name.len > FUSE_NAME_MAX)
|
||||
if (entry->d_name.len > fc->name_max)
|
||||
return ERR_PTR(-ENAMETOOLONG);
|
||||
|
||||
req = fuse_get_request(fc);
|
||||
@@ -274,7 +274,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
|
||||
goto out;
|
||||
|
||||
err = -ENAMETOOLONG;
|
||||
if (entry->d_name.len > FUSE_NAME_MAX)
|
||||
if (entry->d_name.len > fc->name_max)
|
||||
goto out;
|
||||
|
||||
err = -EINTR;
|
||||
@@ -455,7 +455,7 @@ static int fuse_symlink(struct inode *dir, struct dentry *entry,
|
||||
unsigned len = strlen(link) + 1;
|
||||
struct fuse_req *req;
|
||||
|
||||
if (len > FUSE_SYMLINK_MAX)
|
||||
if (len > fc->symlink_max)
|
||||
return -ENAMETOOLONG;
|
||||
|
||||
req = fuse_get_request(fc);
|
||||
@@ -561,7 +561,8 @@ static int fuse_rename(struct inode *olddir, struct dentry *oldent,
|
||||
fuse_invalidate_attr(newdir);
|
||||
|
||||
/* newent will end up negative */
|
||||
fuse_invalidate_entry_cache(newent);
|
||||
if (newent->d_inode)
|
||||
fuse_invalidate_entry_cache(newent);
|
||||
} else if (err == -EINTR) {
|
||||
/* If request was interrupted, DEITY only knows if the
|
||||
rename actually took place. If the invalidation
|
||||
@@ -798,11 +799,13 @@ 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 > FUSE_NAME_MAX)
|
||||
if (!dirent->namelen || dirent->namelen > fc->name_max)
|
||||
return -EIO;
|
||||
if (reclen > nbytes)
|
||||
break;
|
||||
@@ -1125,7 +1128,7 @@ static int fuse_setxattr(struct dentry *entry, const char *name,
|
||||
struct fuse_setxattr_in inarg;
|
||||
int err;
|
||||
|
||||
if (size > FUSE_XATTR_SIZE_MAX)
|
||||
if (size > fc->xattr_size_max)
|
||||
return -E2BIG;
|
||||
|
||||
if (fc->no_setxattr)
|
||||
|
||||
+6
-1
@@ -516,7 +516,12 @@ static int fuse_commit_write(struct file *file, struct page *page,
|
||||
struct inode *inode = page->mapping->host;
|
||||
struct fuse_conn *fc = get_fuse_conn(inode);
|
||||
loff_t pos = page_offset(page) + offset;
|
||||
struct fuse_req *req = fuse_get_request(fc);
|
||||
struct fuse_req *req;
|
||||
|
||||
if (count > fc->max_write)
|
||||
return -EIO;
|
||||
|
||||
req = fuse_get_request(fc);
|
||||
if (!req)
|
||||
return -EINTR;
|
||||
|
||||
|
||||
+11
-1
@@ -236,7 +236,8 @@ struct fuse_req {
|
||||
union {
|
||||
struct fuse_forget_in forget_in;
|
||||
struct fuse_release_in release_in;
|
||||
struct fuse_init_in_out init_in_out;
|
||||
struct fuse_init_in init_in;
|
||||
struct fuse_init_out init_out;
|
||||
} misc;
|
||||
|
||||
/** page vector */
|
||||
@@ -284,6 +285,15 @@ 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;
|
||||
|
||||
|
||||
+11
-9
@@ -49,7 +49,7 @@
|
||||
#define FUSE_KERNEL_VERSION 7
|
||||
|
||||
/** Minor version number of this interface */
|
||||
#define FUSE_KERNEL_MINOR_VERSION 4
|
||||
#define FUSE_KERNEL_MINOR_VERSION 5
|
||||
|
||||
/** The node ID of the root inode */
|
||||
#define FUSE_ROOT_ID 1
|
||||
@@ -143,13 +143,6 @@ enum fuse_opcode {
|
||||
FUSE_CREATE = 35
|
||||
};
|
||||
|
||||
/* Conservative buffer size for the client */
|
||||
#define FUSE_MAX_IN 8192
|
||||
|
||||
#define FUSE_NAME_MAX 1024
|
||||
#define FUSE_SYMLINK_MAX 4096
|
||||
#define FUSE_XATTR_SIZE_MAX 4096
|
||||
|
||||
struct fuse_entry_out {
|
||||
__u64 nodeid; /* Inode ID */
|
||||
__u64 generation; /* Inode generation: nodeid:gen must
|
||||
@@ -283,11 +276,20 @@ struct fuse_access_in {
|
||||
__u32 padding;
|
||||
};
|
||||
|
||||
struct fuse_init_in_out {
|
||||
struct fuse_init_in {
|
||||
__u32 major;
|
||||
__u32 minor;
|
||||
};
|
||||
|
||||
struct fuse_init_out {
|
||||
__u32 major;
|
||||
__u32 minor;
|
||||
__u32 name_max;
|
||||
__u32 symlink_max;
|
||||
__u32 xattr_size_max;
|
||||
__u32 max_write;
|
||||
};
|
||||
|
||||
struct fuse_in_header {
|
||||
__u32 len;
|
||||
__u32 opcode;
|
||||
|
||||
@@ -647,7 +647,6 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
|
||||
if (fc->max_read / PAGE_CACHE_SIZE < fc->bdi.ra_pages)
|
||||
fc->bdi.ra_pages = fc->max_read / PAGE_CACHE_SIZE;
|
||||
#endif
|
||||
fc->max_write = FUSE_MAX_IN / 2;
|
||||
|
||||
err = -ENOMEM;
|
||||
root = get_root_inode(sb, d.rootmode);
|
||||
|
||||
@@ -64,6 +64,8 @@ static void fuse_kern_chan_destroy(struct fuse_chan *ch)
|
||||
close(fuse_chan_fd(ch));
|
||||
}
|
||||
|
||||
#define MIN_BUFSIZE 0x21000
|
||||
|
||||
struct fuse_chan *fuse_kern_chan_new(int fd)
|
||||
{
|
||||
struct fuse_chan_ops op = {
|
||||
@@ -71,5 +73,7 @@ struct fuse_chan *fuse_kern_chan_new(int fd)
|
||||
.send = fuse_kern_chan_send,
|
||||
.destroy = fuse_kern_chan_destroy,
|
||||
};
|
||||
return fuse_chan_new(&op, fd, FUSE_MAX_IN, NULL);
|
||||
size_t bufsize = getpagesize() + 0x1000;
|
||||
bufsize = bufsize < MIN_BUFSIZE ? MIN_BUFSIZE : bufsize;
|
||||
return fuse_chan_new(&op, fd, bufsize, NULL);
|
||||
}
|
||||
|
||||
+1
-1
@@ -155,7 +155,7 @@ int fuse_session_loop_mt(struct fuse_session *se)
|
||||
memset(w, 0, sizeof(struct fuse_worker));
|
||||
w->se = se;
|
||||
w->prevch = fuse_session_next_chan(se, NULL);
|
||||
w->ch = fuse_chan_new(&cop, -1, 0, w);
|
||||
w->ch = fuse_chan_new(&cop, -1, fuse_chan_bufsize(w->prevch), w);
|
||||
if (w->ch == NULL) {
|
||||
free(w);
|
||||
return -1;
|
||||
|
||||
+37
-4
@@ -19,6 +19,17 @@
|
||||
|
||||
#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 {
|
||||
unsigned int debug : 1;
|
||||
unsigned int allow_root : 1;
|
||||
@@ -683,10 +694,11 @@ static void do_removexattr(fuse_req_t req, fuse_ino_t nodeid, char *name)
|
||||
fuse_reply_err(req, ENOSYS);
|
||||
}
|
||||
|
||||
static void do_init(fuse_req_t req, struct fuse_init_in_out *arg)
|
||||
static void do_init(fuse_req_t req, struct fuse_init_in *arg)
|
||||
{
|
||||
struct fuse_init_in_out outarg;
|
||||
struct fuse_init_out outarg;
|
||||
struct fuse_ll *f = req->f;
|
||||
size_t bufsize = fuse_chan_bufsize(req->ch);
|
||||
|
||||
if (f->debug) {
|
||||
printf("INIT: %u.%u\n", arg->major, arg->minor);
|
||||
@@ -699,16 +711,37 @@ static void do_init(fuse_req_t req, struct fuse_init_in_out *arg)
|
||||
f->major = FUSE_KERNEL_VERSION;
|
||||
f->minor = arg->minor;
|
||||
|
||||
if (bufsize < MIN_BUFFER_SIZE) {
|
||||
fprintf(stderr, "fuse: warning: buffer size too small: %i\n", bufsize);
|
||||
bufsize = MIN_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (f->debug) {
|
||||
printf(" INIT: %u.%u\n", outarg.major, outarg.minor);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
send_reply_ok(req, &outarg, sizeof(outarg));
|
||||
send_reply_ok(req, &outarg, arg->minor < 5 ? 8 : sizeof(outarg));
|
||||
}
|
||||
|
||||
void *fuse_req_userdata(fuse_req_t req)
|
||||
@@ -759,7 +792,7 @@ static void fuse_ll_process(void *data, const char *buf, size_t len,
|
||||
fuse_reply_err(req, EACCES);
|
||||
} else switch (in->opcode) {
|
||||
case FUSE_INIT:
|
||||
do_init(req, (struct fuse_init_in_out *) inarg);
|
||||
do_init(req, (struct fuse_init_in *) inarg);
|
||||
break;
|
||||
|
||||
case FUSE_LOOKUP:
|
||||
|
||||
Reference in New Issue
Block a user