From 48706d0a91583d08c56e7ef2a7602d99c8d4133f Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Tue, 13 Dec 2011 10:36:59 +0100 Subject: fuse: fix fuse_retrieve Fix two bugs in fuse_retrieve(): - retrieving more than one page would yield repeated instances of the first page - if more than FUSE_MAX_PAGES_PER_REQ pages were requested than the request page array would overflow fuse_retrieve() was added in 2.6.36 and these bugs had been there since the beginning. Signed-off-by: Miklos Szeredi CC: stable@vger.kernel.org --- fs/fuse/dev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'fs/fuse') diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 5cb8614508c3..2aaf3eaaf13d 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -1512,7 +1512,7 @@ static int fuse_retrieve(struct fuse_conn *fc, struct inode *inode, else if (outarg->offset + num > file_size) num = file_size - outarg->offset; - while (num) { + while (num && req->num_pages < FUSE_MAX_PAGES_PER_REQ) { struct page *page; unsigned int this_num; @@ -1526,6 +1526,7 @@ static int fuse_retrieve(struct fuse_conn *fc, struct inode *inode, num -= this_num; total_len += this_num; + index++; } req->misc.retrieve_in.offset = outarg->offset; req->misc.retrieve_in.size = total_len; -- cgit v1.2.3 From b48c6af2086ab2ba8a9c9b6ce9ecb34592ce500c Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Tue, 13 Dec 2011 10:37:00 +0100 Subject: fuse: fix llseek bug The test in fuse_file_llseek() "not SEEK_CUR or not SEEK_SET" always evaluates to true. This was introduced in 3.1 by commit 06222e49 (fs: handle SEEK_HOLE/SEEK_DATA properly in all fs's that define their own llseek) and changed the behavior of SEEK_CUR and SEEK_SET to always retrieve the file attributes. This is a performance regression. Fix the test so that it makes sense. Signed-off-by: Miklos Szeredi CC: stable@vger.kernel.org CC: Josef Bacik CC: Al Viro --- fs/fuse/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/fuse') diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 594f07a81c28..19029e97ca2f 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -1556,7 +1556,7 @@ static loff_t fuse_file_llseek(struct file *file, loff_t offset, int origin) struct inode *inode = file->f_path.dentry->d_inode; mutex_lock(&inode->i_mutex); - if (origin != SEEK_CUR || origin != SEEK_SET) { + if (origin != SEEK_CUR && origin != SEEK_SET) { retval = fuse_update_attributes(inode, NULL, file, NULL); if (retval) goto exit; -- cgit v1.2.3 From 73104b6e37f75f822e3dcf016147c322d1f6dad9 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Tue, 13 Dec 2011 11:40:59 +0100 Subject: fuse: llseek fix race Fix race between lseek(fd, 0, SEEK_CUR) and read/write. This was fixed in generic code by commit 5b6f1eb97d (vfs: lseek(fd, 0, SEEK_CUR) race condition). Signed-off-by: Miklos Szeredi --- fs/fuse/file.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'fs/fuse') diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 19029e97ca2f..0c84100acd44 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -1567,6 +1567,10 @@ static loff_t fuse_file_llseek(struct file *file, loff_t offset, int origin) offset += i_size_read(inode); break; case SEEK_CUR: + if (offset == 0) { + retval = file->f_pos; + goto exit; + } offset += file->f_pos; break; case SEEK_DATA: -- cgit v1.2.3