From 05033041285858d581b05617900e2921502bf434 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Tue, 13 Nov 2001 16:11:35 +0000 Subject: [PATCH] fix vfsmount leak bug in fuse_follow_link --- include/fuse.h | 5 +++++ include/linux/fuse.h | 2 +- kernel/dir.c | 40 +++++++++++++++++----------------------- kernel/inode.c | 5 +++-- lib/fuse.c | 1 - 5 files changed, 26 insertions(+), 27 deletions(-) diff --git a/include/fuse.h b/include/fuse.h index a117211..60cd378 100644 --- a/include/fuse.h +++ b/include/fuse.h @@ -30,6 +30,11 @@ typedef int (*fuse_dirfil_t) (fuse_dirh_t, const char *, int type); * - All operations should return the negated error value (-errno) on * error. * + * - Getattr() doesn't need to fill in the following fields: + * st_ino + * st_dev + * st_blksize + * * - readlink() should fill the buffer with a null terminated string. The * buffer size argument includes the space for the terminating null * character. If the linkname is too long to fit in the buffer, it should diff --git a/include/linux/fuse.h b/include/linux/fuse.h index d41a957..0cd9e5c 100644 --- a/include/linux/fuse.h +++ b/include/linux/fuse.h @@ -42,7 +42,7 @@ struct fuse_attr { unsigned int gid; unsigned int rdev; unsigned long long size; - unsigned long blksize; + unsigned long _dummy; unsigned long blocks; unsigned long atime; unsigned long mtime; diff --git a/kernel/dir.c b/kernel/dir.c index cd6394a..8c60afa 100644 --- a/kernel/dir.c +++ b/kernel/dir.c @@ -8,6 +8,7 @@ #include "fuse_i.h" +#include #include #include @@ -32,7 +33,7 @@ static void change_attributes(struct inode *inode, struct fuse_attr *attr) inode->i_uid = attr->uid; inode->i_gid = attr->gid; inode->i_size = attr->size; - inode->i_blksize = attr->blksize; + inode->i_blksize = PAGE_CACHE_SIZE; inode->i_blocks = attr->blocks; inode->i_atime = attr->atime; inode->i_mtime = attr->mtime; @@ -385,37 +386,37 @@ static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) return ret; } -static int read_link(struct dentry *dentry, char **bufp) +static char *read_link(struct dentry *dentry) { struct inode *inode = dentry->d_inode; struct fuse_conn *fc = INO_FC(inode); struct fuse_in in = FUSE_IN_INIT; struct fuse_out out = FUSE_OUT_INIT; - unsigned long page; + char *link; - page = __get_free_page(GFP_KERNEL); - if(!page) - return -ENOMEM; + link = (char *) __get_free_page(GFP_KERNEL); + if(!link) + return ERR_PTR(-ENOMEM); in.h.opcode = FUSE_READLINK; in.h.ino = inode->i_ino; - out.arg = (void *) page; + out.arg = link; out.argsize = PAGE_SIZE - 1; out.argvar = 1; request_send(fc, &in, &out); if(out.h.error) { - free_page(page); - return out.h.error; + free_page((unsigned long) link); + return ERR_PTR(out.h.error); } - *bufp = (char *) page; - (*bufp)[out.argsize] = '\0'; - return 0; + link[out.argsize] = '\0'; + return link; } static void free_link(char *link) { - free_page((unsigned long) link); + if(!IS_ERR(link)) + free_page((unsigned long) link); } static int fuse_readlink(struct dentry *dentry, char *buffer, int buflen) @@ -423,10 +424,7 @@ static int fuse_readlink(struct dentry *dentry, char *buffer, int buflen) int ret; char *link; - ret = read_link(dentry, &link); - if(ret) - return ret; - + link = read_link(dentry); ret = vfs_readlink(dentry, buffer, buflen, link); free_link(link); return ret; @@ -437,10 +435,7 @@ static int fuse_follow_link(struct dentry *dentry, struct nameidata *nd) int ret; char *link; - ret = read_link(dentry, &link); - if(ret) - return ret; - + link = read_link(dentry); ret = vfs_follow_link(nd, link); free_link(link); return ret; @@ -550,8 +545,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, int flags) { if(!entry->d_inode) return 0; - else if(!(flags & LOOKUP_CONTINUE) && - time_after(jiffies, entry->d_time + FUSE_REVALIDATE_TIME)) + else if(!(flags & LOOKUP_CONTINUE)) return 0; else return 1; diff --git a/kernel/inode.c b/kernel/inode.c index 3a78040..36819b7 100644 --- a/kernel/inode.c +++ b/kernel/inode.c @@ -8,6 +8,7 @@ #include "fuse_i.h" +#include #include #include #include @@ -104,8 +105,8 @@ static struct super_block *fuse_read_super(struct super_block *sb, struct inode *root; struct fuse_mount_data *d = data; - sb->s_blocksize = 1024; - sb->s_blocksize_bits = 10; + sb->s_blocksize = PAGE_CACHE_SIZE; + sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->s_magic = FUSE_SUPER_MAGIC; sb->s_op = &fuse_super_operations; diff --git a/lib/fuse.c b/lib/fuse.c index 3f8a46b..e042c4a 100644 --- a/lib/fuse.c +++ b/lib/fuse.c @@ -297,7 +297,6 @@ static void convert_stat(struct stat *stbuf, struct fuse_attr *attr) attr->gid = stbuf->st_gid; attr->rdev = stbuf->st_rdev; attr->size = stbuf->st_size; - attr->blksize = stbuf->st_blksize; attr->blocks = stbuf->st_blocks; attr->atime = stbuf->st_atime; attr->mtime = stbuf->st_mtime;