Re: [PATCH] fuse: hold i_mutex in fuse_file_fallocate() - v2

2013-06-17 Thread Miklos Szeredi
On Thu, Jun 13, 2013 at 1:46 PM, Brian Foster  wrote:
> On 06/13/2013 04:16 AM, Maxim Patlasov wrote:
>> Changing size of a file on server and local update (fuse_write_update_size)
>> should be always protected by inode->i_mutex. Otherwise a race like this is
>> possible:
>>
>> 1. Process 'A' calls fallocate(2) to extend file (~FALLOC_FL_KEEP_SIZE).
>> fuse_file_fallocate() sends FUSE_FALLOCATE request to the server.
>> 2. Process 'B' calls ftruncate(2) shrinking the file. fuse_do_setattr()
>> sends shrinking FUSE_SETATTR request to the server and updates local i_size
>> by i_size_write(inode, outarg.attr.size).
>> 3. Process 'A' resumes execution of fuse_file_fallocate() and calls
>> fuse_write_update_size(inode, offset + length). But 'offset + length' was
>> obsoleted by ftruncate from previous step.
>>
>> Changed in v2 (thanks Brian and Anand for suggestions):
>>  - made relation between mutex_lock() and fuse_set_nowrite(inode) more
>>explicit and clear.
>>  - updated patch description to use ftruncate(2) in example
>>
>> Signed-off-by: Maxim V. Patlasov 

Thanks, applied.

Miklos
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH] fuse: hold i_mutex in fuse_file_fallocate() - v2

2013-06-17 Thread Miklos Szeredi
On Thu, Jun 13, 2013 at 1:46 PM, Brian Foster bfos...@redhat.com wrote:
 On 06/13/2013 04:16 AM, Maxim Patlasov wrote:
 Changing size of a file on server and local update (fuse_write_update_size)
 should be always protected by inode-i_mutex. Otherwise a race like this is
 possible:

 1. Process 'A' calls fallocate(2) to extend file (~FALLOC_FL_KEEP_SIZE).
 fuse_file_fallocate() sends FUSE_FALLOCATE request to the server.
 2. Process 'B' calls ftruncate(2) shrinking the file. fuse_do_setattr()
 sends shrinking FUSE_SETATTR request to the server and updates local i_size
 by i_size_write(inode, outarg.attr.size).
 3. Process 'A' resumes execution of fuse_file_fallocate() and calls
 fuse_write_update_size(inode, offset + length). But 'offset + length' was
 obsoleted by ftruncate from previous step.

 Changed in v2 (thanks Brian and Anand for suggestions):
  - made relation between mutex_lock() and fuse_set_nowrite(inode) more
explicit and clear.
  - updated patch description to use ftruncate(2) in example

 Signed-off-by: Maxim V. Patlasov mpatla...@parallels.com

Thanks, applied.

Miklos
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH] fuse: hold i_mutex in fuse_file_fallocate() - v2

2013-06-13 Thread Brian Foster
On 06/13/2013 04:16 AM, Maxim Patlasov wrote:
> Changing size of a file on server and local update (fuse_write_update_size)
> should be always protected by inode->i_mutex. Otherwise a race like this is
> possible:
> 
> 1. Process 'A' calls fallocate(2) to extend file (~FALLOC_FL_KEEP_SIZE).
> fuse_file_fallocate() sends FUSE_FALLOCATE request to the server.
> 2. Process 'B' calls ftruncate(2) shrinking the file. fuse_do_setattr()
> sends shrinking FUSE_SETATTR request to the server and updates local i_size
> by i_size_write(inode, outarg.attr.size).
> 3. Process 'A' resumes execution of fuse_file_fallocate() and calls
> fuse_write_update_size(inode, offset + length). But 'offset + length' was
> obsoleted by ftruncate from previous step.
> 
> Changed in v2 (thanks Brian and Anand for suggestions):
>  - made relation between mutex_lock() and fuse_set_nowrite(inode) more
>explicit and clear.
>  - updated patch description to use ftruncate(2) in example
> 
> Signed-off-by: Maxim V. Patlasov 
> ---

Makes more sense and I like the cleanup... thanks.

Reviewed-by: Brian Foster 

>  fs/fuse/file.c |   12 
>  1 files changed, 8 insertions(+), 4 deletions(-)
> 
> diff --git a/fs/fuse/file.c b/fs/fuse/file.c
> index e570081..35f2810 100644
> --- a/fs/fuse/file.c
> +++ b/fs/fuse/file.c
> @@ -2470,13 +2470,16 @@ static long fuse_file_fallocate(struct file *file, 
> int mode, loff_t offset,
>   .mode = mode
>   };
>   int err;
> + bool lock_inode = !(mode & FALLOC_FL_KEEP_SIZE) ||
> +(mode & FALLOC_FL_PUNCH_HOLE);
>  
>   if (fc->no_fallocate)
>   return -EOPNOTSUPP;
>  
> - if (mode & FALLOC_FL_PUNCH_HOLE) {
> + if (lock_inode) {
>   mutex_lock(>i_mutex);
> - fuse_set_nowrite(inode);
> + if (mode & FALLOC_FL_PUNCH_HOLE)
> + fuse_set_nowrite(inode);
>   }
>  
>   req = fuse_get_req_nopages(fc);
> @@ -2511,8 +2514,9 @@ static long fuse_file_fallocate(struct file *file, int 
> mode, loff_t offset,
>   fuse_invalidate_attr(inode);
>  
>  out:
> - if (mode & FALLOC_FL_PUNCH_HOLE) {
> - fuse_release_nowrite(inode);
> + if (lock_inode) {
> + if (mode & FALLOC_FL_PUNCH_HOLE)
> + fuse_release_nowrite(inode);
>   mutex_unlock(>i_mutex);
>   }
>  
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH] fuse: hold i_mutex in fuse_file_fallocate()

2013-06-13 Thread Maxim Patlasov

Anand, Brian,

06/12/2013 11:04 PM, Anand Avati пишет:

On 6/11/13 3:59 AM, Maxim Patlasov wrote:


-if (mode & FALLOC_FL_PUNCH_HOLE) {
+if (lock_inode)
  mutex_lock(>i_mutex);



+if (mode & FALLOC_FL_PUNCH_HOLE)
  fuse_set_nowrite(inode);
-}


Just for clarity, can you make the condition to check 
FALLOC_FL_PUNCH_HOLE and call to fuse_set_nowrite() nested within the 
larger if (lock_inode) { .. } block? fuse_set_nowrite() should not be 
called without i_mutex acquired. The current style of calling 
mutex_lock() and fuse_set_nowrite() in separate conditions can 
potentially cause bugs in the future if they were to get re-ordered 
due to some unrelated patch. Nesting them makes the relation more 
explicit and clear.


Thanks a lot for review. I'll post updated patch soon.

Thanks,
Maxim

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH] fuse: hold i_mutex in fuse_file_fallocate()

2013-06-13 Thread Maxim Patlasov

Anand, Brian,

06/12/2013 11:04 PM, Anand Avati пишет:

On 6/11/13 3:59 AM, Maxim Patlasov wrote:


-if (mode  FALLOC_FL_PUNCH_HOLE) {
+if (lock_inode)
  mutex_lock(inode-i_mutex);



+if (mode  FALLOC_FL_PUNCH_HOLE)
  fuse_set_nowrite(inode);
-}


Just for clarity, can you make the condition to check 
FALLOC_FL_PUNCH_HOLE and call to fuse_set_nowrite() nested within the 
larger if (lock_inode) { .. } block? fuse_set_nowrite() should not be 
called without i_mutex acquired. The current style of calling 
mutex_lock() and fuse_set_nowrite() in separate conditions can 
potentially cause bugs in the future if they were to get re-ordered 
due to some unrelated patch. Nesting them makes the relation more 
explicit and clear.


Thanks a lot for review. I'll post updated patch soon.

Thanks,
Maxim

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH] fuse: hold i_mutex in fuse_file_fallocate() - v2

2013-06-13 Thread Brian Foster
On 06/13/2013 04:16 AM, Maxim Patlasov wrote:
 Changing size of a file on server and local update (fuse_write_update_size)
 should be always protected by inode-i_mutex. Otherwise a race like this is
 possible:
 
 1. Process 'A' calls fallocate(2) to extend file (~FALLOC_FL_KEEP_SIZE).
 fuse_file_fallocate() sends FUSE_FALLOCATE request to the server.
 2. Process 'B' calls ftruncate(2) shrinking the file. fuse_do_setattr()
 sends shrinking FUSE_SETATTR request to the server and updates local i_size
 by i_size_write(inode, outarg.attr.size).
 3. Process 'A' resumes execution of fuse_file_fallocate() and calls
 fuse_write_update_size(inode, offset + length). But 'offset + length' was
 obsoleted by ftruncate from previous step.
 
 Changed in v2 (thanks Brian and Anand for suggestions):
  - made relation between mutex_lock() and fuse_set_nowrite(inode) more
explicit and clear.
  - updated patch description to use ftruncate(2) in example
 
 Signed-off-by: Maxim V. Patlasov mpatla...@parallels.com
 ---

Makes more sense and I like the cleanup... thanks.

Reviewed-by: Brian Foster bfos...@redhat.com

  fs/fuse/file.c |   12 
  1 files changed, 8 insertions(+), 4 deletions(-)
 
 diff --git a/fs/fuse/file.c b/fs/fuse/file.c
 index e570081..35f2810 100644
 --- a/fs/fuse/file.c
 +++ b/fs/fuse/file.c
 @@ -2470,13 +2470,16 @@ static long fuse_file_fallocate(struct file *file, 
 int mode, loff_t offset,
   .mode = mode
   };
   int err;
 + bool lock_inode = !(mode  FALLOC_FL_KEEP_SIZE) ||
 +(mode  FALLOC_FL_PUNCH_HOLE);
  
   if (fc-no_fallocate)
   return -EOPNOTSUPP;
  
 - if (mode  FALLOC_FL_PUNCH_HOLE) {
 + if (lock_inode) {
   mutex_lock(inode-i_mutex);
 - fuse_set_nowrite(inode);
 + if (mode  FALLOC_FL_PUNCH_HOLE)
 + fuse_set_nowrite(inode);
   }
  
   req = fuse_get_req_nopages(fc);
 @@ -2511,8 +2514,9 @@ static long fuse_file_fallocate(struct file *file, int 
 mode, loff_t offset,
   fuse_invalidate_attr(inode);
  
  out:
 - if (mode  FALLOC_FL_PUNCH_HOLE) {
 - fuse_release_nowrite(inode);
 + if (lock_inode) {
 + if (mode  FALLOC_FL_PUNCH_HOLE)
 + fuse_release_nowrite(inode);
   mutex_unlock(inode-i_mutex);
   }
  
 

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH] fuse: hold i_mutex in fuse_file_fallocate()

2013-06-12 Thread Anand Avati

On 6/11/13 3:59 AM, Maxim Patlasov wrote:


-   if (mode & FALLOC_FL_PUNCH_HOLE) {
+   if (lock_inode)
mutex_lock(>i_mutex);



+   if (mode & FALLOC_FL_PUNCH_HOLE)
fuse_set_nowrite(inode);
-   }


Just for clarity, can you make the condition to check 
FALLOC_FL_PUNCH_HOLE and call to fuse_set_nowrite() nested within the 
larger if (lock_inode) { .. } block? fuse_set_nowrite() should not be 
called without i_mutex acquired. The current style of calling 
mutex_lock() and fuse_set_nowrite() in separate conditions can 
potentially cause bugs in the future if they were to get re-ordered due 
to some unrelated patch. Nesting them makes the relation more explicit 
and clear.


Thanks,
Avati

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH] fuse: hold i_mutex in fuse_file_fallocate()

2013-06-12 Thread Anand Avati

On 6/12/13 4:40 AM, Brian Foster wrote:

On 06/11/2013 06:59 AM, Maxim Patlasov wrote:

Changing size of a file on server and local update (fuse_write_update_size)
should be always protected by inode->i_mutex. Otherwise a race like this is
possible:

1. Process 'A' calls fallocate(2) to extend file (~FALLOC_FL_KEEP_SIZE).
fuse_file_fallocate() sends FUSE_FALLOCATE request to the server.
2. Process 'B' performs ordinary buffered write(2) with a length big enough
to extend the file beyond "offset + length" of fallocate call.
3. Process 'A' resumes execution of fuse_file_fallocate() and calls
fuse_write_update_size(inode, offset + length). But 'offset + length' was
obsoleted by write from previous step.



Hi Maxim,

Doesn't fuse_write_update_size() already handle this particular case by
only ever extending the size?




As you say, fuse_write_update_size() does seem to protect against the 
case Maxim writes in the commit log.


However, there is still an issue with with truncate(shrinking_offset) 
and fallocate(growing_offset,~FALLOC_FL_KEEP_SIZE) racing, and changing 
inode size in opposing order between file server and in core ->i_size. 
Therefore, grabbing i_mutex is making fallocate and truncate atomic 
against each other.


I guess we just need an updated commit log, and same code change?

Avati


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH] fuse: hold i_mutex in fuse_file_fallocate()

2013-06-12 Thread Brian Foster
On 06/11/2013 06:59 AM, Maxim Patlasov wrote:
> Changing size of a file on server and local update (fuse_write_update_size)
> should be always protected by inode->i_mutex. Otherwise a race like this is
> possible:
> 
> 1. Process 'A' calls fallocate(2) to extend file (~FALLOC_FL_KEEP_SIZE).
> fuse_file_fallocate() sends FUSE_FALLOCATE request to the server.
> 2. Process 'B' performs ordinary buffered write(2) with a length big enough
> to extend the file beyond "offset + length" of fallocate call.
> 3. Process 'A' resumes execution of fuse_file_fallocate() and calls
> fuse_write_update_size(inode, offset + length). But 'offset + length' was
> obsoleted by write from previous step.
> 

Hi Maxim,

Doesn't fuse_write_update_size() already handle this particular case by
only ever extending the size?

Brian

> Signed-off-by: Maxim V. Patlasov 
> ---
>  fs/fuse/file.c |   10 ++
>  1 files changed, 6 insertions(+), 4 deletions(-)
> 
> diff --git a/fs/fuse/file.c b/fs/fuse/file.c
> index e570081..8dfbf7d 100644
> --- a/fs/fuse/file.c
> +++ b/fs/fuse/file.c
> @@ -2470,14 +2470,16 @@ static long fuse_file_fallocate(struct file *file, 
> int mode, loff_t offset,
>   .mode = mode
>   };
>   int err;
> + bool lock_inode = !(mode & FALLOC_FL_KEEP_SIZE) ||
> +(mode & FALLOC_FL_PUNCH_HOLE);
>  
>   if (fc->no_fallocate)
>   return -EOPNOTSUPP;
>  
> - if (mode & FALLOC_FL_PUNCH_HOLE) {
> + if (lock_inode)
>   mutex_lock(>i_mutex);
> + if (mode & FALLOC_FL_PUNCH_HOLE)
>   fuse_set_nowrite(inode);
> - }
>  
>   req = fuse_get_req_nopages(fc);
>   if (IS_ERR(req)) {
> @@ -2511,10 +2513,10 @@ static long fuse_file_fallocate(struct file *file, 
> int mode, loff_t offset,
>   fuse_invalidate_attr(inode);
>  
>  out:
> - if (mode & FALLOC_FL_PUNCH_HOLE) {
> + if (mode & FALLOC_FL_PUNCH_HOLE)
>   fuse_release_nowrite(inode);
> + if (lock_inode)
>   mutex_unlock(>i_mutex);
> - }
>  
>   return err;
>  }
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH] fuse: hold i_mutex in fuse_file_fallocate()

2013-06-12 Thread Brian Foster
On 06/11/2013 06:59 AM, Maxim Patlasov wrote:
 Changing size of a file on server and local update (fuse_write_update_size)
 should be always protected by inode-i_mutex. Otherwise a race like this is
 possible:
 
 1. Process 'A' calls fallocate(2) to extend file (~FALLOC_FL_KEEP_SIZE).
 fuse_file_fallocate() sends FUSE_FALLOCATE request to the server.
 2. Process 'B' performs ordinary buffered write(2) with a length big enough
 to extend the file beyond offset + length of fallocate call.
 3. Process 'A' resumes execution of fuse_file_fallocate() and calls
 fuse_write_update_size(inode, offset + length). But 'offset + length' was
 obsoleted by write from previous step.
 

Hi Maxim,

Doesn't fuse_write_update_size() already handle this particular case by
only ever extending the size?

Brian

 Signed-off-by: Maxim V. Patlasov mpatla...@parallels.com
 ---
  fs/fuse/file.c |   10 ++
  1 files changed, 6 insertions(+), 4 deletions(-)
 
 diff --git a/fs/fuse/file.c b/fs/fuse/file.c
 index e570081..8dfbf7d 100644
 --- a/fs/fuse/file.c
 +++ b/fs/fuse/file.c
 @@ -2470,14 +2470,16 @@ static long fuse_file_fallocate(struct file *file, 
 int mode, loff_t offset,
   .mode = mode
   };
   int err;
 + bool lock_inode = !(mode  FALLOC_FL_KEEP_SIZE) ||
 +(mode  FALLOC_FL_PUNCH_HOLE);
  
   if (fc-no_fallocate)
   return -EOPNOTSUPP;
  
 - if (mode  FALLOC_FL_PUNCH_HOLE) {
 + if (lock_inode)
   mutex_lock(inode-i_mutex);
 + if (mode  FALLOC_FL_PUNCH_HOLE)
   fuse_set_nowrite(inode);
 - }
  
   req = fuse_get_req_nopages(fc);
   if (IS_ERR(req)) {
 @@ -2511,10 +2513,10 @@ static long fuse_file_fallocate(struct file *file, 
 int mode, loff_t offset,
   fuse_invalidate_attr(inode);
  
  out:
 - if (mode  FALLOC_FL_PUNCH_HOLE) {
 + if (mode  FALLOC_FL_PUNCH_HOLE)
   fuse_release_nowrite(inode);
 + if (lock_inode)
   mutex_unlock(inode-i_mutex);
 - }
  
   return err;
  }
 

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH] fuse: hold i_mutex in fuse_file_fallocate()

2013-06-12 Thread Anand Avati

On 6/12/13 4:40 AM, Brian Foster wrote:

On 06/11/2013 06:59 AM, Maxim Patlasov wrote:

Changing size of a file on server and local update (fuse_write_update_size)
should be always protected by inode-i_mutex. Otherwise a race like this is
possible:

1. Process 'A' calls fallocate(2) to extend file (~FALLOC_FL_KEEP_SIZE).
fuse_file_fallocate() sends FUSE_FALLOCATE request to the server.
2. Process 'B' performs ordinary buffered write(2) with a length big enough
to extend the file beyond offset + length of fallocate call.
3. Process 'A' resumes execution of fuse_file_fallocate() and calls
fuse_write_update_size(inode, offset + length). But 'offset + length' was
obsoleted by write from previous step.



Hi Maxim,

Doesn't fuse_write_update_size() already handle this particular case by
only ever extending the size?




As you say, fuse_write_update_size() does seem to protect against the 
case Maxim writes in the commit log.


However, there is still an issue with with truncate(shrinking_offset) 
and fallocate(growing_offset,~FALLOC_FL_KEEP_SIZE) racing, and changing 
inode size in opposing order between file server and in core -i_size. 
Therefore, grabbing i_mutex is making fallocate and truncate atomic 
against each other.


I guess we just need an updated commit log, and same code change?

Avati


--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH] fuse: hold i_mutex in fuse_file_fallocate()

2013-06-12 Thread Anand Avati

On 6/11/13 3:59 AM, Maxim Patlasov wrote:


-   if (mode  FALLOC_FL_PUNCH_HOLE) {
+   if (lock_inode)
mutex_lock(inode-i_mutex);



+   if (mode  FALLOC_FL_PUNCH_HOLE)
fuse_set_nowrite(inode);
-   }


Just for clarity, can you make the condition to check 
FALLOC_FL_PUNCH_HOLE and call to fuse_set_nowrite() nested within the 
larger if (lock_inode) { .. } block? fuse_set_nowrite() should not be 
called without i_mutex acquired. The current style of calling 
mutex_lock() and fuse_set_nowrite() in separate conditions can 
potentially cause bugs in the future if they were to get re-ordered due 
to some unrelated patch. Nesting them makes the relation more explicit 
and clear.


Thanks,
Avati

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/