public inbox for linux-fsdevel@vger.kernel.org
 help / color / mirror / Atom feed
* [patch 0/5] fuse updates
@ 2008-04-25 17:55 Miklos Szeredi
  2008-04-25 17:55 ` [patch 1/5] fuse: fix max i/o size calculation Miklos Szeredi
                   ` (5 more replies)
  0 siblings, 6 replies; 12+ messages in thread
From: Miklos Szeredi @ 2008-04-25 17:55 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, linux-fsdevel

These are fuse fixes for 2.6.26.  Please apply.

Thanks,
Miklos

--

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [patch 1/5] fuse: fix max i/o size calculation
  2008-04-25 17:55 [patch 0/5] fuse updates Miklos Szeredi
@ 2008-04-25 17:55 ` Miklos Szeredi
  2008-04-25 17:55 ` [patch 2/5] fuse: fix node ID type Miklos Szeredi
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 12+ messages in thread
From: Miklos Szeredi @ 2008-04-25 17:55 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, linux-fsdevel

[-- Attachment #1: fuse_max_write_fix.patch --]
[-- Type: text/plain, Size: 2109 bytes --]

From: Miklos Szeredi <mszeredi@suse.cz>

Fix a bug that Werner Baumann reported: fuse can send a bigger write
request than the maximum specified.  This only affected direct_io
operation.

In addition set a sane minimum for the max_read and max_write
tunables, so I/O always makes some progress.

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
---
 fs/fuse/file.c  |    7 ++++---
 fs/fuse/inode.c |    3 ++-
 2 files changed, 6 insertions(+), 4 deletions(-)

Index: linux/fs/fuse/file.c
===================================================================
--- linux.orig/fs/fuse/file.c	2008-04-25 18:48:08.000000000 +0200
+++ linux/fs/fuse/file.c	2008-04-25 19:38:05.000000000 +0200
@@ -960,14 +960,15 @@ static ssize_t fuse_direct_io(struct fil
 
 	while (count) {
 		size_t nres;
-		size_t nbytes = min(count, nmax);
-		int err = fuse_get_user_pages(req, buf, nbytes, !write);
+		size_t nbytes_limit = min(count, nmax);
+		size_t nbytes;
+		int err = fuse_get_user_pages(req, buf, nbytes_limit, !write);
 		if (err) {
 			res = err;
 			break;
 		}
 		nbytes = (req->num_pages << PAGE_SHIFT) - req->page_offset;
-		nbytes = min(count, nbytes);
+		nbytes = min(nbytes_limit, nbytes);
 		if (write)
 			nres = fuse_send_write(req, file, inode, pos, nbytes,
 					       current->files);
Index: linux/fs/fuse/inode.c
===================================================================
--- linux.orig/fs/fuse/inode.c	2008-04-25 19:07:27.000000000 +0200
+++ linux/fs/fuse/inode.c	2008-04-25 19:38:05.000000000 +0200
@@ -585,6 +585,7 @@ static void process_init_reply(struct fu
 		fc->bdi.ra_pages = min(fc->bdi.ra_pages, ra_pages);
 		fc->minor = arg->minor;
 		fc->max_write = arg->minor < 5 ? 4096 : arg->max_write;
+		fc->max_write = min_t(unsigned, 4096, fc->max_write);
 		fc->conn_init = 1;
 	}
 	fuse_put_request(fc, req);
@@ -659,7 +660,7 @@ static int fuse_fill_super(struct super_
 	fc->flags = d.flags;
 	fc->user_id = d.user_id;
 	fc->group_id = d.group_id;
-	fc->max_read = d.max_read;
+	fc->max_read = min_t(unsigned, 4096, d.max_read);
 
 	/* Used by get_root_inode() */
 	sb->s_fs_info = fc;

--

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [patch 2/5] fuse: fix node ID type
  2008-04-25 17:55 [patch 0/5] fuse updates Miklos Szeredi
  2008-04-25 17:55 ` [patch 1/5] fuse: fix max i/o size calculation Miklos Szeredi
@ 2008-04-25 17:55 ` Miklos Szeredi
  2008-04-25 17:55 ` [patch 3/5] fuse: fix race in llseek Miklos Szeredi
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 12+ messages in thread
From: Miklos Szeredi @ 2008-04-25 17:55 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, linux-fsdevel

[-- Attachment #1: fuse_64bit_nodeid.patch --]
[-- Type: text/plain, Size: 2470 bytes --]

From: Miklos Szeredi <mszeredi@suse.cz>

Node ID is 64bit but it is passed as unsigned long to some functions.
This breakage wasn't noticed, because libfuse uses unsigned long too.

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
---
 fs/fuse/fuse_i.h |    4 ++--
 fs/fuse/inode.c  |    8 ++++----
 2 files changed, 6 insertions(+), 6 deletions(-)

Index: linux/fs/fuse/fuse_i.h
===================================================================
--- linux.orig/fs/fuse/fuse_i.h	2008-04-09 13:17:45.000000000 +0200
+++ linux/fs/fuse/fuse_i.h	2008-04-09 13:17:59.000000000 +0200
@@ -461,7 +461,7 @@ extern const struct file_operations fuse
 /**
  * Get a filled in inode
  */
-struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
+struct inode *fuse_iget(struct super_block *sb, u64 nodeid,
 			int generation, struct fuse_attr *attr,
 			u64 attr_valid, u64 attr_version);
 
@@ -469,7 +469,7 @@ struct inode *fuse_iget(struct super_blo
  * Send FORGET command
  */
 void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req,
-		      unsigned long nodeid, u64 nlookup);
+		      u64 nodeid, u64 nlookup);
 
 /**
  * Initialize READ or READDIR request
Index: linux/fs/fuse/inode.c
===================================================================
--- linux.orig/fs/fuse/inode.c	2008-04-09 13:17:45.000000000 +0200
+++ linux/fs/fuse/inode.c	2008-04-09 13:17:59.000000000 +0200
@@ -84,7 +84,7 @@ static void fuse_destroy_inode(struct in
 }
 
 void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req,
-		      unsigned long nodeid, u64 nlookup)
+		      u64 nodeid, u64 nlookup)
 {
 	struct fuse_forget_in *inarg = &req->misc.forget_in;
 	inarg->nlookup = nlookup;
@@ -207,7 +207,7 @@ static void fuse_init_inode(struct inode
 
 static int fuse_inode_eq(struct inode *inode, void *_nodeidp)
 {
-	unsigned long nodeid = *(unsigned long *) _nodeidp;
+	u64 nodeid = *(u64 *) _nodeidp;
 	if (get_node_id(inode) == nodeid)
 		return 1;
 	else
@@ -216,12 +216,12 @@ static int fuse_inode_eq(struct inode *i
 
 static int fuse_inode_set(struct inode *inode, void *_nodeidp)
 {
-	unsigned long nodeid = *(unsigned long *) _nodeidp;
+	u64 nodeid = *(u64 *) _nodeidp;
 	get_fuse_inode(inode)->nodeid = nodeid;
 	return 0;
 }
 
-struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
+struct inode *fuse_iget(struct super_block *sb, u64 nodeid,
 			int generation, struct fuse_attr *attr,
 			u64 attr_valid, u64 attr_version)
 {

--

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [patch 3/5] fuse: fix race in llseek
  2008-04-25 17:55 [patch 0/5] fuse updates Miklos Szeredi
  2008-04-25 17:55 ` [patch 1/5] fuse: fix max i/o size calculation Miklos Szeredi
  2008-04-25 17:55 ` [patch 2/5] fuse: fix node ID type Miklos Szeredi
@ 2008-04-25 17:55 ` Miklos Szeredi
  2008-04-28  2:26   ` Andrew Morton
  2008-04-28  8:34   ` Jan Blunck
  2008-04-25 17:55 ` [patch 4/5] fuse: fix truncation on short read Miklos Szeredi
                   ` (2 subsequent siblings)
  5 siblings, 2 replies; 12+ messages in thread
From: Miklos Szeredi @ 2008-04-25 17:55 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, linux-fsdevel

[-- Attachment #1: fuse_llseek.patch --]
[-- Type: text/plain, Size: 1781 bytes --]

From: Miklos Szeredi <mszeredi@suse.cz>

Fuse doesn't use i_mutex to protect setting i_size, and so
generic_file_llseek() can be racy: it doesn't use i_size_read().

So do a fuse specific llseek method, which does use i_size_read().

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
---
 fs/fuse/file.c |   29 +++++++++++++++++++++++++++--
 1 file changed, 27 insertions(+), 2 deletions(-)

Index: linux/fs/fuse/file.c
===================================================================
--- linux.orig/fs/fuse/file.c	2008-04-25 19:38:10.000000000 +0200
+++ linux/fs/fuse/file.c	2008-04-25 19:40:11.000000000 +0200
@@ -1425,8 +1425,33 @@ static sector_t fuse_bmap(struct address
 	return err ? 0 : outarg.block;
 }
 
+static loff_t fuse_file_llseek(struct file *file, loff_t offset, int origin)
+{
+	long long retval;
+	struct inode *inode = file->f_path.dentry->d_inode;
+
+	mutex_lock(&inode->i_mutex);
+	switch (origin) {
+	case SEEK_END:
+		offset += i_size_read(inode);
+		break;
+	case SEEK_CUR:
+		offset += file->f_pos;
+	}
+	retval = -EINVAL;
+	if (offset >= 0 && offset <= inode->i_sb->s_maxbytes) {
+		if (offset != file->f_pos) {
+			file->f_pos = offset;
+			file->f_version = 0;
+		}
+		retval = offset;
+	}
+	mutex_unlock(&inode->i_mutex);
+	return retval;
+}
+
 static const struct file_operations fuse_file_operations = {
-	.llseek		= generic_file_llseek,
+	.llseek		= fuse_file_llseek,
 	.read		= do_sync_read,
 	.aio_read	= fuse_file_aio_read,
 	.write		= do_sync_write,
@@ -1442,7 +1467,7 @@ static const struct file_operations fuse
 };
 
 static const struct file_operations fuse_direct_io_file_operations = {
-	.llseek		= generic_file_llseek,
+	.llseek		= fuse_file_llseek,
 	.read		= fuse_direct_read,
 	.write		= fuse_direct_write,
 	.open		= fuse_open,

--

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [patch 4/5] fuse: fix truncation on short read
  2008-04-25 17:55 [patch 0/5] fuse updates Miklos Szeredi
                   ` (2 preceding siblings ...)
  2008-04-25 17:55 ` [patch 3/5] fuse: fix race in llseek Miklos Szeredi
@ 2008-04-25 17:55 ` Miklos Szeredi
  2008-04-25 17:55 ` [patch 5/5] fuse: fix sparse warnings Miklos Szeredi
  2008-04-28  2:20 ` [patch 0/5] fuse updates Andrew Morton
  5 siblings, 0 replies; 12+ messages in thread
From: Miklos Szeredi @ 2008-04-25 17:55 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, linux-fsdevel

[-- Attachment #1: fuse_truncate_file_on_short_read_fix.patch --]
[-- Type: text/plain, Size: 4925 bytes --]

From: Miklos Szeredi <mszeredi@suse.cz>

fuse-update-file-size-on-short-read.patch introduced a bug, where a
read could truncate off the part recently extended by a parallel
write.

Fix by using the attribute versioning already used by getattr().

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
---
 fs/fuse/dir.c    |    2 +-
 fs/fuse/file.c   |   22 ++++++++++++++--------
 fs/fuse/fuse_i.h |    7 ++++++-
 3 files changed, 21 insertions(+), 10 deletions(-)

Index: linux/fs/fuse/dir.c
===================================================================
--- linux.orig/fs/fuse/dir.c	2008-04-25 17:10:02.000000000 +0200
+++ linux/fs/fuse/dir.c	2008-04-25 17:11:02.000000000 +0200
@@ -132,7 +132,7 @@ static void fuse_lookup_init(struct fuse
 	req->out.args[0].value = outarg;
 }
 
-static u64 fuse_get_attr_version(struct fuse_conn *fc)
+u64 fuse_get_attr_version(struct fuse_conn *fc)
 {
 	u64 curr_version;
 
Index: linux/fs/fuse/file.c
===================================================================
--- linux.orig/fs/fuse/file.c	2008-04-25 17:10:47.000000000 +0200
+++ linux/fs/fuse/file.c	2008-04-25 17:11:02.000000000 +0200
@@ -363,7 +363,7 @@ static int fuse_fsync(struct file *file,
 void fuse_read_fill(struct fuse_req *req, struct file *file,
 		    struct inode *inode, loff_t pos, size_t count, int opcode)
 {
-	struct fuse_read_in *inarg = &req->misc.read_in;
+	struct fuse_read_in *inarg = &req->misc.read.in;
 	struct fuse_file *ff = file->private_data;
 
 	inarg->fh = ff->fh;
@@ -389,7 +389,7 @@ static size_t fuse_send_read(struct fuse
 
 	fuse_read_fill(req, file, inode, pos, count, FUSE_READ);
 	if (owner != NULL) {
-		struct fuse_read_in *inarg = &req->misc.read_in;
+		struct fuse_read_in *inarg = &req->misc.read.in;
 
 		inarg->read_flags |= FUSE_READ_LOCKOWNER;
 		inarg->lock_owner = fuse_lock_owner_id(fc, owner);
@@ -398,15 +398,17 @@ static size_t fuse_send_read(struct fuse
 	return req->out.args[0].size;
 }
 
-static void fuse_read_update_size(struct inode *inode, loff_t size)
+static void fuse_read_update_size(struct inode *inode, loff_t size,
+				  u64 attr_ver)
 {
 	struct fuse_conn *fc = get_fuse_conn(inode);
 	struct fuse_inode *fi = get_fuse_inode(inode);
 
 	spin_lock(&fc->lock);
-	fi->attr_version = ++fc->attr_version;
-	if (size < inode->i_size)
+	if (attr_ver == fi->attr_version && size < inode->i_size) {
+		fi->attr_version = ++fc->attr_version;
 		i_size_write(inode, size);
+	}
 	spin_unlock(&fc->lock);
 }
 
@@ -418,6 +420,7 @@ static int fuse_readpage(struct file *fi
 	size_t num_read;
 	loff_t pos = page_offset(page);
 	size_t count = PAGE_CACHE_SIZE;
+	u64 attr_ver;
 	int err;
 
 	err = -EIO;
@@ -436,6 +439,8 @@ static int fuse_readpage(struct file *fi
 	if (IS_ERR(req))
 		goto out;
 
+	attr_ver = fuse_get_attr_version(fc);
+
 	req->out.page_zeroing = 1;
 	req->num_pages = 1;
 	req->pages[0] = page;
@@ -448,7 +453,7 @@ static int fuse_readpage(struct file *fi
 		 * Short read means EOF.  If file size is larger, truncate it
 		 */
 		if (num_read < count)
-			fuse_read_update_size(inode, pos + num_read);
+			fuse_read_update_size(inode, pos + num_read, attr_ver);
 
 		SetPageUptodate(page);
 	}
@@ -462,7 +467,7 @@ static int fuse_readpage(struct file *fi
 static void fuse_readpages_end(struct fuse_conn *fc, struct fuse_req *req)
 {
 	int i;
-	size_t count = req->misc.read_in.size;
+	size_t count = req->misc.read.in.size;
 	size_t num_read = req->out.args[0].size;
 	struct inode *inode = req->pages[0]->mapping->host;
 
@@ -471,7 +476,7 @@ static void fuse_readpages_end(struct fu
 	 */
 	if (!req->out.h.error && num_read < count) {
 		loff_t pos = page_offset(req->pages[0]) + num_read;
-		fuse_read_update_size(inode, pos);
+		fuse_read_update_size(inode, pos, req->misc.read.attr_ver);
 	}
 
 	fuse_invalidate_attr(inode); /* atime changed */
@@ -497,6 +502,7 @@ static void fuse_send_readpages(struct f
 	size_t count = req->num_pages << PAGE_CACHE_SHIFT;
 	req->out.page_zeroing = 1;
 	fuse_read_fill(req, file, inode, pos, count, FUSE_READ);
+	req->misc.read.attr_ver = fuse_get_attr_version(fc);
 	if (fc->async_read) {
 		struct fuse_file *ff = file->private_data;
 		req->ff = fuse_file_get(ff);
Index: linux/fs/fuse/fuse_i.h
===================================================================
--- linux.orig/fs/fuse/fuse_i.h	2008-04-25 17:09:29.000000000 +0200
+++ linux/fs/fuse/fuse_i.h	2008-04-25 17:11:02.000000000 +0200
@@ -239,7 +239,10 @@ struct fuse_req {
 		} release;
 		struct fuse_init_in init_in;
 		struct fuse_init_out init_out;
-		struct fuse_read_in read_in;
+		struct {
+			struct fuse_read_in in;
+			u64 attr_ver;
+		} read;
 		struct {
 			struct fuse_write_in in;
 			struct fuse_write_out out;
@@ -637,3 +640,5 @@ void fuse_flush_writepages(struct inode 
 
 void fuse_set_nowrite(struct inode *inode);
 void fuse_release_nowrite(struct inode *inode);
+
+u64 fuse_get_attr_version(struct fuse_conn *fc);

--

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [patch 5/5] fuse: fix sparse warnings
  2008-04-25 17:55 [patch 0/5] fuse updates Miklos Szeredi
                   ` (3 preceding siblings ...)
  2008-04-25 17:55 ` [patch 4/5] fuse: fix truncation on short read Miklos Szeredi
@ 2008-04-25 17:55 ` Miklos Szeredi
  2008-04-28  2:20 ` [patch 0/5] fuse updates Andrew Morton
  5 siblings, 0 replies; 12+ messages in thread
From: Miklos Szeredi @ 2008-04-25 17:55 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, linux-fsdevel

[-- Attachment #1: fuse_sparse_fixes.patch --]
[-- Type: text/plain, Size: 1528 bytes --]

From: Miklos Szeredi <mszeredi@suse.cz>

fs/fuse/dev.c:306:2: warning: context imbalance in 'wait_answer_interruptible' - unexpected unlock
fs/fuse/dev.c:361:2: warning: context imbalance in 'request_wait_answer' - unexpected unlock
fs/fuse/dev.c:1002:4: warning: context imbalance in 'end_io_requests' - unexpected unlock

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
---
 fs/fuse/dev.c |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

Index: linux/fs/fuse/dev.c
===================================================================
--- linux.orig/fs/fuse/dev.c	2008-04-25 18:48:08.000000000 +0200
+++ linux/fs/fuse/dev.c	2008-04-25 18:48:28.000000000 +0200
@@ -299,6 +299,7 @@ static void request_end(struct fuse_conn
 
 static void wait_answer_interruptible(struct fuse_conn *fc,
 				      struct fuse_req *req)
+	__releases(fc->lock) __acquires(fc->lock)
 {
 	if (signal_pending(current))
 		return;
@@ -315,8 +316,8 @@ static void queue_interrupt(struct fuse_
 	kill_fasync(&fc->fasync, SIGIO, POLL_IN);
 }
 
-/* Called with fc->lock held.  Releases, and then reacquires it. */
 static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
+	__releases(fc->lock) __acquires(fc->lock)
 {
 	if (!fc->no_interrupt) {
 		/* Any signal may interrupt this */
@@ -987,6 +988,7 @@ static void end_requests(struct fuse_con
  * locked).
  */
 static void end_io_requests(struct fuse_conn *fc)
+	__releases(fc->lock) __acquires(fc->lock)
 {
 	while (!list_empty(&fc->io)) {
 		struct fuse_req *req =

--

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [patch 0/5] fuse updates
  2008-04-25 17:55 [patch 0/5] fuse updates Miklos Szeredi
                   ` (4 preceding siblings ...)
  2008-04-25 17:55 ` [patch 5/5] fuse: fix sparse warnings Miklos Szeredi
@ 2008-04-28  2:20 ` Andrew Morton
  2008-04-28  7:46   ` Miklos Szeredi
  5 siblings, 1 reply; 12+ messages in thread
From: Andrew Morton @ 2008-04-28  2:20 UTC (permalink / raw)
  To: Miklos Szeredi; +Cc: linux-kernel, linux-fsdevel

On Fri, 25 Apr 2008 19:55:20 +0200 Miklos Szeredi <miklos@szeredi.hu> wrote:

> These are fuse fixes for 2.6.26.  Please apply.
> 

Are none of them needed in 2.6.25.x?

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [patch 3/5] fuse: fix race in llseek
  2008-04-25 17:55 ` [patch 3/5] fuse: fix race in llseek Miklos Szeredi
@ 2008-04-28  2:26   ` Andrew Morton
  2008-04-28  7:51     ` Miklos Szeredi
  2008-04-28  8:34   ` Jan Blunck
  1 sibling, 1 reply; 12+ messages in thread
From: Andrew Morton @ 2008-04-28  2:26 UTC (permalink / raw)
  To: Miklos Szeredi; +Cc: linux-kernel, linux-fsdevel

On Fri, 25 Apr 2008 19:55:23 +0200 Miklos Szeredi <miklos@szeredi.hu> wrote:

> +static loff_t fuse_file_llseek(struct file *file, loff_t offset, int origin)
> +{
> +	long long retval;

I switched this to have a type of loff_t.

> +	struct inode *inode = file->f_path.dentry->d_inode;
> +
> +	mutex_lock(&inode->i_mutex);
> +	switch (origin) {
> +	case SEEK_END:
> +		offset += i_size_read(inode);

As we hold i_mutex we could directly read inode->i_size here, save a few
cycles.

> +		break;
> +	case SEEK_CUR:
> +		offset += file->f_pos;
> +	}
> +	retval = -EINVAL;
> +	if (offset >= 0 && offset <= inode->i_sb->s_maxbytes) {
> +		if (offset != file->f_pos) {
> +			file->f_pos = offset;
> +			file->f_version = 0;
> +		}
> +		retval = offset;
> +	}
> +	mutex_unlock(&inode->i_mutex);
> +	return retval;
> +}

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [patch 0/5] fuse updates
  2008-04-28  2:20 ` [patch 0/5] fuse updates Andrew Morton
@ 2008-04-28  7:46   ` Miklos Szeredi
  0 siblings, 0 replies; 12+ messages in thread
From: Miklos Szeredi @ 2008-04-28  7:46 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, linux-fsdevel

> > These are fuse fixes for 2.6.26.  Please apply.
> > 
> 
> Are none of them needed in 2.6.25.x?

Not really.  All of them are minor issues, and some of them fix
regressions by the fuse patches already in -mm.

Thanks,
Miklos

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [patch 3/5] fuse: fix race in llseek
  2008-04-28  2:26   ` Andrew Morton
@ 2008-04-28  7:51     ` Miklos Szeredi
  0 siblings, 0 replies; 12+ messages in thread
From: Miklos Szeredi @ 2008-04-28  7:51 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, linux-fsdevel

> > +static loff_t fuse_file_llseek(struct file *file, loff_t offset, int origin)
> > +{
> > +	long long retval;
> 
> I switched this to have a type of loff_t.

Ugh, right.  I wonder where that long long came from.  I probably
copied the generic_file_llseek() from some earlier kernel...

> 
> > +	struct inode *inode = file->f_path.dentry->d_inode;
> > +
> > +	mutex_lock(&inode->i_mutex);
> > +	switch (origin) {
> > +	case SEEK_END:
> > +		offset += i_size_read(inode);
> 
> As we hold i_mutex we could directly read inode->i_size here, save a few
> cycles.

No, that's the whole point of the fuse specific function: fuse doesn't
use i_mutex to protect writing i_size, instead it uses a per
filesystem spinlock.

This is probably worth a comment though, so I'll do that.

Thanks,
Miklos

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [patch 3/5] fuse: fix race in llseek
  2008-04-25 17:55 ` [patch 3/5] fuse: fix race in llseek Miklos Szeredi
  2008-04-28  2:26   ` Andrew Morton
@ 2008-04-28  8:34   ` Jan Blunck
  2008-04-28 15:12     ` Miklos Szeredi
  1 sibling, 1 reply; 12+ messages in thread
From: Jan Blunck @ 2008-04-28  8:34 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: linux-kernel

On Fri, 25 Apr 2008 19:55:23 +0200, Miklos Szeredi wrote:

> From: Miklos Szeredi <mszeredi@suse.cz>
> 
> Fuse doesn't use i_mutex to protect setting i_size, and so
> generic_file_llseek() can be racy: it doesn't use i_size_read().
> 
> So do a fuse specific llseek method, which does use i_size_read().
> 

Is there any specific reason why we don't use i_size_read() in 
generic_file_llseek()? If no, why don't you fix it instead?

Regards,
	Jan

-- 
Jan Blunck <jblunck@suse.de>


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [patch 3/5] fuse: fix race in llseek
  2008-04-28  8:34   ` Jan Blunck
@ 2008-04-28 15:12     ` Miklos Szeredi
  0 siblings, 0 replies; 12+ messages in thread
From: Miklos Szeredi @ 2008-04-28 15:12 UTC (permalink / raw)
  To: jblunck; +Cc: linux-fsdevel, linux-kernel

> > From: Miklos Szeredi <mszeredi@suse.cz>
> > 
> > Fuse doesn't use i_mutex to protect setting i_size, and so
> > generic_file_llseek() can be racy: it doesn't use i_size_read().
> > 
> > So do a fuse specific llseek method, which does use i_size_read().
> > 
> 
> Is there any specific reason why we don't use i_size_read() in 
> generic_file_llseek()?

Just to save some cycles on 32bit archs.  Considering that
lseek(SEEK_END) isn't a very performance sensitive operation...

> If no, why don't you fix it instead?

...we could do that.  Does anybody object?

Miklos
----


Some filesystems (e.g. fuse) don't use i_mutex to protect setting
i_size, and so generic_file_llseek() can be racy.

Since lseek(SEEK_END) isn't a very performance sensitive operation, do
this in generic_file_llseek(), instead of requiring such filesystems
to duplicate this function.

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
---
 fs/read_write.c |    6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

Index: linux/fs/read_write.c
===================================================================
--- linux.orig/fs/read_write.c	2008-04-17 04:49:44.000000000 +0200
+++ linux/fs/read_write.c	2008-04-28 17:08:25.000000000 +0200
@@ -39,7 +39,11 @@ loff_t generic_file_llseek(struct file *
 	mutex_lock(&inode->i_mutex);
 	switch (origin) {
 		case SEEK_END:
-			offset += inode->i_size;
+			/*
+			 * Some filesystems use a different lock as i_mutex
+			 * to protect writing i_size
+			 */
+			offset += i_size_read(inode);
 			break;
 		case SEEK_CUR:
 			offset += file->f_pos;

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2008-04-28 15:12 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-04-25 17:55 [patch 0/5] fuse updates Miklos Szeredi
2008-04-25 17:55 ` [patch 1/5] fuse: fix max i/o size calculation Miklos Szeredi
2008-04-25 17:55 ` [patch 2/5] fuse: fix node ID type Miklos Szeredi
2008-04-25 17:55 ` [patch 3/5] fuse: fix race in llseek Miklos Szeredi
2008-04-28  2:26   ` Andrew Morton
2008-04-28  7:51     ` Miklos Szeredi
2008-04-28  8:34   ` Jan Blunck
2008-04-28 15:12     ` Miklos Szeredi
2008-04-25 17:55 ` [patch 4/5] fuse: fix truncation on short read Miklos Szeredi
2008-04-25 17:55 ` [patch 5/5] fuse: fix sparse warnings Miklos Szeredi
2008-04-28  2:20 ` [patch 0/5] fuse updates Andrew Morton
2008-04-28  7:46   ` Miklos Szeredi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox