diff mbox series

[v2,2/5] fuse: Create helper function if DIO write needs exclusive lock

Message ID 20240131230827.207552-3-bschubert@ddn.com (mailing list archive)
State New
Headers show
Series fuse: inode IO modes and mmap | expand

Commit Message

Bernd Schubert Jan. 31, 2024, 11:08 p.m. UTC
This makes the code a bit easier to read and allows to more
easily add more conditions when an exclusive lock is needed.

Signed-off-by: Bernd Schubert <bschubert@ddn.com>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
---
 fs/fuse/file.c | 64 +++++++++++++++++++++++++++++++++++---------------
 1 file changed, 45 insertions(+), 19 deletions(-)

Comments

Jingbo Xu Feb. 6, 2024, 9:20 a.m. UTC | #1
On 2/1/24 7:08 AM, Bernd Schubert wrote:
> @@ -1591,10 +1616,10 @@ static ssize_t fuse_direct_write_iter(struct kiocb *iocb, struct iov_iter *from)
>  	else {
>  		inode_lock_shared(inode);
>  
> -		/* A race with truncate might have come up as the decision for
> -		 * the lock type was done without holding the lock, check again.
> +		/*
> +		 * Previous check was without any lock and might have raced.
>  		 */
> -		if (fuse_direct_write_extending_i_size(iocb, from)) {
> +		if (fuse_dio_wr_exclusive_lock(iocb, from)) {
			^

The overall is good.  Maybe fuse_io_past_eof() is better to make it a
solely cleanup or refactoring.  Actually it's already changed back to
fuse_io_past_eof() in patch 3/5.
Bernd Schubert Feb. 7, 2024, 1:38 p.m. UTC | #2
On 2/6/24 10:20, Jingbo Xu wrote:
> 
> 
> On 2/1/24 7:08 AM, Bernd Schubert wrote:
>> @@ -1591,10 +1616,10 @@ static ssize_t fuse_direct_write_iter(struct kiocb *iocb, struct iov_iter *from)
>>  	else {
>>  		inode_lock_shared(inode);
>>  
>> -		/* A race with truncate might have come up as the decision for
>> -		 * the lock type was done without holding the lock, check again.
>> +		/*
>> +		 * Previous check was without any lock and might have raced.
>>  		 */
>> -		if (fuse_direct_write_extending_i_size(iocb, from)) {
>> +		if (fuse_dio_wr_exclusive_lock(iocb, from)) {
> 			^
> 
> The overall is good.  Maybe fuse_io_past_eof() is better to make it a
> solely cleanup or refactoring.  Actually it's already changed back to
> fuse_io_past_eof() in patch 3/5.

So I'm bit confused what you would like to see improved. Patch 2/5
renames "fuse_direct_write_extending_i_size" to "fuse_io_past_eof" and
also moves it up in the file. (The latter is a preparation for my
direct-write consolidation patches.). It also creates the helper
function fuse_dio_wr_exclusive_lock(). None of that is changed in 3/5,
which just moves the locking/unlocking from fuse_cache_write_iter() into
the functions fuse_dio_lock/fuse_dio_unlock.


Thanks,
Bernd
Jingbo Xu Feb. 7, 2024, 1:44 p.m. UTC | #3
On 2/7/24 9:38 PM, Bernd Schubert wrote:
> 
> 
> On 2/6/24 10:20, Jingbo Xu wrote:
>>
>>
>> On 2/1/24 7:08 AM, Bernd Schubert wrote:
>>> @@ -1591,10 +1616,10 @@ static ssize_t fuse_direct_write_iter(struct kiocb *iocb, struct iov_iter *from)
>>>  	else {
>>>  		inode_lock_shared(inode);
>>>  
>>> -		/* A race with truncate might have come up as the decision for
>>> -		 * the lock type was done without holding the lock, check again.
>>> +		/*
>>> +		 * Previous check was without any lock and might have raced.
>>>  		 */


>>> -		if (fuse_direct_write_extending_i_size(iocb, from)) {
>>> +		if (fuse_dio_wr_exclusive_lock(iocb, from)) {
>> 			^

I mean, in patch 2/5

> -		if (fuse_direct_write_extending_i_size(iocb, from)) {
> +		if (fuse_io_past_eof(iocb, from)) {

is better, otherwise it's not an equivalent change.


Thanks,
Jingbo
Bernd Schubert Feb. 7, 2024, 2:13 p.m. UTC | #4
On 2/7/24 14:44, Jingbo Xu wrote:
> 
> 
> On 2/7/24 9:38 PM, Bernd Schubert wrote:
>>
>>
>> On 2/6/24 10:20, Jingbo Xu wrote:
>>>
>>>
>>> On 2/1/24 7:08 AM, Bernd Schubert wrote:
>>>> @@ -1591,10 +1616,10 @@ static ssize_t fuse_direct_write_iter(struct kiocb *iocb, struct iov_iter *from)
>>>>  	else {
>>>>  		inode_lock_shared(inode);
>>>>  
>>>> -		/* A race with truncate might have come up as the decision for
>>>> -		 * the lock type was done without holding the lock, check again.
>>>> +		/*
>>>> +		 * Previous check was without any lock and might have raced.
>>>>  		 */
> 
> 
>>>> -		if (fuse_direct_write_extending_i_size(iocb, from)) {
>>>> +		if (fuse_dio_wr_exclusive_lock(iocb, from)) {
>>> 			^
> 
> I mean, in patch 2/5
> 
>> -		if (fuse_direct_write_extending_i_size(iocb, from)) {
>> +		if (fuse_io_past_eof(iocb, from)) {
> 
> is better, otherwise it's not an equivalent change.

Ah thanks, good catch! Now I see what you mean. Yeah, we can switch to
fuse_io_past_eof() here. And yeah, 3/5 changes it back.
Fortunately there is actually not much harm, as
fuse_dio_wr_exclusive_lock also calls into fuse_io_past_eof.


Thanks,
Bernd
Jingbo Xu Feb. 8, 2024, 12:04 a.m. UTC | #5
On 2/7/24 10:13 PM, Bernd Schubert wrote:
> 
> 
> On 2/7/24 14:44, Jingbo Xu wrote:
>>
>>
>> On 2/7/24 9:38 PM, Bernd Schubert wrote:
>>>
>>>
>>> On 2/6/24 10:20, Jingbo Xu wrote:
>>>>
>>>>
>>>> On 2/1/24 7:08 AM, Bernd Schubert wrote:
>>>>> @@ -1591,10 +1616,10 @@ static ssize_t fuse_direct_write_iter(struct kiocb *iocb, struct iov_iter *from)
>>>>>  	else {
>>>>>  		inode_lock_shared(inode);
>>>>>  
>>>>> -		/* A race with truncate might have come up as the decision for
>>>>> -		 * the lock type was done without holding the lock, check again.
>>>>> +		/*
>>>>> +		 * Previous check was without any lock and might have raced.
>>>>>  		 */
>>
>>
>>>>> -		if (fuse_direct_write_extending_i_size(iocb, from)) {
>>>>> +		if (fuse_dio_wr_exclusive_lock(iocb, from)) {
>>>> 			^
>>
>> I mean, in patch 2/5
>>
>>> -		if (fuse_direct_write_extending_i_size(iocb, from)) {
>>> +		if (fuse_io_past_eof(iocb, from)) {
>>
>> is better, otherwise it's not an equivalent change.
> 
> Ah thanks, good catch! Now I see what you mean. Yeah, we can switch to
> fuse_io_past_eof() here. And yeah, 3/5 changes it back.
> Fortunately there is actually not much harm, as
> fuse_dio_wr_exclusive_lock also calls into fuse_io_past_eof.
> 

Yeah fortunately we needn't retest it as patch 3/5 changes it back.

The whole series is good.  The comment is just from per-patch basis.

Thanks,
Jingbo
diff mbox series

Patch

diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 243f469cac07..0c4d93293eac 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -1299,6 +1299,45 @@  static ssize_t fuse_perform_write(struct kiocb *iocb, struct iov_iter *ii)
 	return res;
 }
 
+static bool fuse_io_past_eof(struct kiocb *iocb, struct iov_iter *iter)
+{
+	struct inode *inode = file_inode(iocb->ki_filp);
+
+	return iocb->ki_pos + iov_iter_count(iter) > i_size_read(inode);
+}
+
+/*
+ * @return true if an exclusive lock for direct IO writes is needed
+ */
+static bool fuse_dio_wr_exclusive_lock(struct kiocb *iocb, struct iov_iter *from)
+{
+	struct file *file = iocb->ki_filp;
+	struct fuse_file *ff = file->private_data;
+	struct inode *inode = file_inode(iocb->ki_filp);
+
+	/* server side has to advise that it supports parallel dio writes */
+	if (!(ff->open_flags & FOPEN_PARALLEL_DIRECT_WRITES))
+		return true;
+
+	/* append will need to know the eventual eof - always needs an
+	 * exclusive lock
+	 */
+	if (iocb->ki_flags & IOCB_APPEND)
+		return true;
+
+	/* combination opf page access and direct-io difficult, shared
+	 * locks actually introduce a conflict.
+	 */
+	if (get_fuse_conn(inode)->direct_io_allow_mmap)
+		return true;
+
+	/* parallel dio beyond eof is at least for now not supported */
+	if (fuse_io_past_eof(iocb, from))
+		return true;
+
+	return false;
+}
+
 static ssize_t fuse_cache_write_iter(struct kiocb *iocb, struct iov_iter *from)
 {
 	struct file *file = iocb->ki_filp;
@@ -1558,26 +1597,12 @@  static ssize_t fuse_direct_read_iter(struct kiocb *iocb, struct iov_iter *to)
 	return res;
 }
 
-static bool fuse_direct_write_extending_i_size(struct kiocb *iocb,
-					       struct iov_iter *iter)
-{
-	struct inode *inode = file_inode(iocb->ki_filp);
-
-	return iocb->ki_pos + iov_iter_count(iter) > i_size_read(inode);
-}
-
 static ssize_t fuse_direct_write_iter(struct kiocb *iocb, struct iov_iter *from)
 {
 	struct inode *inode = file_inode(iocb->ki_filp);
-	struct file *file = iocb->ki_filp;
-	struct fuse_file *ff = file->private_data;
 	struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(iocb);
 	ssize_t res;
-	bool exclusive_lock =
-		!(ff->open_flags & FOPEN_PARALLEL_DIRECT_WRITES) ||
-		get_fuse_conn(inode)->direct_io_allow_mmap ||
-		iocb->ki_flags & IOCB_APPEND ||
-		fuse_direct_write_extending_i_size(iocb, from);
+	bool exclusive_lock = fuse_dio_wr_exclusive_lock(iocb, from);
 
 	/*
 	 * Take exclusive lock if
@@ -1591,10 +1616,10 @@  static ssize_t fuse_direct_write_iter(struct kiocb *iocb, struct iov_iter *from)
 	else {
 		inode_lock_shared(inode);
 
-		/* A race with truncate might have come up as the decision for
-		 * the lock type was done without holding the lock, check again.
+		/*
+		 * Previous check was without any lock and might have raced.
 		 */
-		if (fuse_direct_write_extending_i_size(iocb, from)) {
+		if (fuse_dio_wr_exclusive_lock(iocb, from)) {
 			inode_unlock_shared(inode);
 			inode_lock(inode);
 			exclusive_lock = true;
@@ -2468,7 +2493,8 @@  static int fuse_file_mmap(struct file *file, struct vm_area_struct *vma)
 		return fuse_dax_mmap(file, vma);
 
 	if (ff->open_flags & FOPEN_DIRECT_IO) {
-		/* Can't provide the coherency needed for MAP_SHARED
+		/*
+		 * Can't provide the coherency needed for MAP_SHARED
 		 * if FUSE_DIRECT_IO_ALLOW_MMAP isn't set.
 		 */
 		if ((vma->vm_flags & VM_MAYSHARE) && !fc->direct_io_allow_mmap)