diff mbox series

[RFCv2,2/8] libfs: Add __generic_file_fsync_nolock implementation

Message ID 6fad2ec25bccbbb9b3effbd18c2d6d6965b9a33c.1681188927.git.ritesh.list@gmail.com
State Not Applicable
Headers show
Series ext2: DIO to use iomap | expand

Commit Message

Ritesh Harjani (IBM) April 11, 2023, 5:21 a.m. UTC
Some of the higher layers like iomap takes inode_lock() when calling
generic_write_sync().
Also writeback already happens from other paths without inode lock,
so it's difficult to say that we really need sync_mapping_buffers() to
take any inode locking here. Having said that, let's add a _nolock
variant of this function in libfs for now so that filesystems like
ext2 and ext4's nojournal mode can use it.

Ext4 when got converted to iomap for direct-io already copied it's own
variant of __generic_file_fsync() without lock. Hence let's add a helper
API and use it both in ext2 and ext4.

Later we can review other filesystems as well to see if we can make
_nolock as the default path if inode_lock() is not necessary here.

Signed-off-by: Ritesh Harjani (IBM) <ritesh.list@gmail.com>
---
 fs/libfs.c         | 43 +++++++++++++++++++++++++++++++++++++++++++
 include/linux/fs.h |  1 +
 2 files changed, 44 insertions(+)

Comments

Christoph Hellwig April 11, 2023, 5:27 a.m. UTC | #1
On Tue, Apr 11, 2023 at 10:51:50AM +0530, Ritesh Harjani (IBM) wrote:
> +/**
> + * __generic_file_fsync_nolock - generic fsync implementation for simple
> + * filesystems with no inode lock

No reallz need for the __ prefix in the name.

> +extern int __generic_file_fsync_nolock(struct file *, loff_t, loff_t, int);

No need for the extern.  And at least I personally prefer to spell out
the parameter names to make the prototype much more readable.
Matthew Wilcox April 11, 2023, 12:33 p.m. UTC | #2
On Mon, Apr 10, 2023 at 10:27:10PM -0700, Christoph Hellwig wrote:
> On Tue, Apr 11, 2023 at 10:51:50AM +0530, Ritesh Harjani (IBM) wrote:
> > +/**
> > + * __generic_file_fsync_nolock - generic fsync implementation for simple
> > + * filesystems with no inode lock
> 
> No reallz need for the __ prefix in the name.

It kind of makes sense though.

generic_file_fsync does the flush
__generic_file_fsync doesn't do the flush
__generic_file_fsync_nolock doesn't do the flush and doesn't lock/unlock

> > +extern int __generic_file_fsync_nolock(struct file *, loff_t, loff_t, int);
> 
> No need for the extern.  And at least I personally prefer to spell out
> the parameter names to make the prototype much more readable.

Agreed, although I make an exception for the 'struct file *'.  Naming that
parameter adds no value, but a plain int is just obscene.

int __generic_file_fsync_nolock(struct file *, loff_t start, loff_t end,
		bool datasync);

(yes, the other variants don't use a bool for datasync, but they should)
Ritesh Harjani (IBM) April 11, 2023, 3:12 p.m. UTC | #3
Matthew Wilcox <willy@infradead.org> writes:

> On Mon, Apr 10, 2023 at 10:27:10PM -0700, Christoph Hellwig wrote:
>> On Tue, Apr 11, 2023 at 10:51:50AM +0530, Ritesh Harjani (IBM) wrote:
>> > +/**
>> > + * __generic_file_fsync_nolock - generic fsync implementation for simple
>> > + * filesystems with no inode lock
>>
>> No reallz need for the __ prefix in the name.
>
> It kind of makes sense though.
>
> generic_file_fsync does the flush
> __generic_file_fsync doesn't do the flush
> __generic_file_fsync_nolock doesn't do the flush and doesn't lock/unlock

Yes.

>
>> > +extern int __generic_file_fsync_nolock(struct file *, loff_t, loff_t, int);
>>
>> No need for the extern.  And at least I personally prefer to spell out
>> the parameter names to make the prototype much more readable.
>
> Agreed, although I make an exception for the 'struct file *'.  Naming that
> parameter adds no value, but a plain int is just obscene.
>
> int __generic_file_fsync_nolock(struct file *, loff_t start, loff_t end,
> 		bool datasync);
>
> (yes, the other variants don't use a bool for datasync, but they should)

Sure. Will make the change.

-ritesh
Christoph Hellwig April 12, 2023, 11:43 a.m. UTC | #4
On Tue, Apr 11, 2023 at 01:33:17PM +0100, Matthew Wilcox wrote:
> On Mon, Apr 10, 2023 at 10:27:10PM -0700, Christoph Hellwig wrote:
> > On Tue, Apr 11, 2023 at 10:51:50AM +0530, Ritesh Harjani (IBM) wrote:
> > > +/**
> > > + * __generic_file_fsync_nolock - generic fsync implementation for simple
> > > + * filesystems with no inode lock
> > 
> > No reallz need for the __ prefix in the name.
> 
> It kind of makes sense though.
> 
> generic_file_fsync does the flush
> __generic_file_fsync doesn't do the flush
> __generic_file_fsync_nolock doesn't do the flush and doesn't lock/unlock

Indeed.  Part of it is that the naming is a bit horrible.
Maybe it should move to buffer.c and be called generic_buffer_fsync,
or generic_block_fsync which still wouldn't be perfect but match the
buffer.c naming scheme.

> 
> > > +extern int __generic_file_fsync_nolock(struct file *, loff_t, loff_t, int);
> > 
> > No need for the extern.  And at least I personally prefer to spell out
> > the parameter names to make the prototype much more readable.
> 
> Agreed, although I make an exception for the 'struct file *'.  Naming that
> parameter adds no value, but a plain int is just obscene.
> 
> int __generic_file_fsync_nolock(struct file *, loff_t start, loff_t end,
> 		bool datasync);

While I agree that it's not needed for the file, leaving it out is a bit
silly.

> (yes, the other variants don't use a bool for datasync, but they should)

.. including the ->fsync prototype to make it work ..
Ritesh Harjani (IBM) April 12, 2023, 2:02 p.m. UTC | #5
Christoph Hellwig <hch@infradead.org> writes:

> On Tue, Apr 11, 2023 at 01:33:17PM +0100, Matthew Wilcox wrote:
>> On Mon, Apr 10, 2023 at 10:27:10PM -0700, Christoph Hellwig wrote:
>> > On Tue, Apr 11, 2023 at 10:51:50AM +0530, Ritesh Harjani (IBM) wrote:
>> > > +/**
>> > > + * __generic_file_fsync_nolock - generic fsync implementation for simple
>> > > + * filesystems with no inode lock
>> >
>> > No reallz need for the __ prefix in the name.
>>
>> It kind of makes sense though.
>>
>> generic_file_fsync does the flush
>> __generic_file_fsync doesn't do the flush
>> __generic_file_fsync_nolock doesn't do the flush and doesn't lock/unlock
>
> Indeed.  Part of it is that the naming is a bit horrible.
> Maybe it should move to buffer.c and be called generic_buffer_fsync,
> or generic_block_fsync which still wouldn't be perfect but match the
> buffer.c naming scheme.
>

Eventually it anyways needs some work to see if we can kill the lock
variant all together. I didn't do that in this series which is
focused on ext2 conversion of iomap.
So, if it's not that bad, I would like to keep both function
definitions at one place so that it can be worked out later.

>>
>> > > +extern int __generic_file_fsync_nolock(struct file *, loff_t, loff_t, int);
>> >
>> > No need for the extern.  And at least I personally prefer to spell out
>> > the parameter names to make the prototype much more readable.
>>
>> Agreed, although I make an exception for the 'struct file *'.  Naming that
>> parameter adds no value, but a plain int is just obscene.
>>
>> int __generic_file_fsync_nolock(struct file *, loff_t start, loff_t end,
>> 		bool datasync);
>
> While I agree that it's not needed for the file, leaving it out is a bit
> silly.
>

Sure. Will fix it.

>> (yes, the other variants don't use a bool for datasync, but they should)
>
> .. including the ->fsync prototype to make it work ..

Sure, this work should go as a seperate series.

-ritesh
Christian Brauner April 13, 2023, 9:51 a.m. UTC | #6
On Wed, Apr 12, 2023 at 04:43:03AM -0700, Christoph Hellwig wrote:
> On Tue, Apr 11, 2023 at 01:33:17PM +0100, Matthew Wilcox wrote:
> > On Mon, Apr 10, 2023 at 10:27:10PM -0700, Christoph Hellwig wrote:
> > > On Tue, Apr 11, 2023 at 10:51:50AM +0530, Ritesh Harjani (IBM) wrote:
> > > > +/**
> > > > + * __generic_file_fsync_nolock - generic fsync implementation for simple
> > > > + * filesystems with no inode lock
> > > 
> > > No reallz need for the __ prefix in the name.
> > 
> > It kind of makes sense though.
> > 
> > generic_file_fsync does the flush
> > __generic_file_fsync doesn't do the flush
> > __generic_file_fsync_nolock doesn't do the flush and doesn't lock/unlock
> 
> Indeed.  Part of it is that the naming is a bit horrible.
> Maybe it should move to buffer.c and be called generic_buffer_fsync,
> or generic_block_fsync which still wouldn't be perfect but match the
> buffer.c naming scheme.
> 
> > 
> > > > +extern int __generic_file_fsync_nolock(struct file *, loff_t, loff_t, int);
> > > 
> > > No need for the extern.  And at least I personally prefer to spell out
> > > the parameter names to make the prototype much more readable.
> > 
> > Agreed, although I make an exception for the 'struct file *'.  Naming that
> > parameter adds no value, but a plain int is just obscene.
> > 
> > int __generic_file_fsync_nolock(struct file *, loff_t start, loff_t end,
> > 		bool datasync);
> 
> While I agree that it's not needed for the file, leaving it out is a bit
> silly.

I think we should just be consistent and try to enforce that the
parameter name is added in new patches. It's often easier for grepping
and there's really not a lot of value in leaving it out in general.
diff mbox series

Patch

diff --git a/fs/libfs.c b/fs/libfs.c
index 4eda519c3002..d2dfb72e3cf8 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -1110,6 +1110,49 @@  struct dentry *generic_fh_to_parent(struct super_block *sb, struct fid *fid,
 }
 EXPORT_SYMBOL_GPL(generic_fh_to_parent);
 
+/**
+ * __generic_file_fsync_nolock - generic fsync implementation for simple
+ * filesystems with no inode lock
+ *
+ * @file:	file to synchronize
+ * @start:	start offset in bytes
+ * @end:	end offset in bytes (inclusive)
+ * @datasync:	only synchronize essential metadata if true
+ *
+ * This is a generic implementation of the fsync method for simple
+ * filesystems which track all non-inode metadata in the buffers list
+ * hanging off the address_space structure.
+ */
+int __generic_file_fsync_nolock(struct file *file, loff_t start, loff_t end,
+				 int datasync)
+{
+	struct inode *inode = file->f_mapping->host;
+	int err;
+	int ret;
+
+	err = file_write_and_wait_range(file, start, end);
+	if (err)
+		return err;
+
+	ret = sync_mapping_buffers(inode->i_mapping);
+	if (!(inode->i_state & I_DIRTY_ALL))
+		goto out;
+	if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
+		goto out;
+
+	err = sync_inode_metadata(inode, 1);
+	if (ret == 0)
+		ret = err;
+
+out:
+	/* check and advance again to catch errors after syncing out buffers */
+	err = file_check_and_advance_wb_err(file);
+	if (ret == 0)
+		ret = err;
+	return ret;
+}
+EXPORT_SYMBOL(__generic_file_fsync_nolock);
+
 /**
  * __generic_file_fsync - generic fsync implementation for simple filesystems
  *
diff --git a/include/linux/fs.h b/include/linux/fs.h
index c85916e9f7db..21d2b5670308 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2935,6 +2935,7 @@  extern ssize_t simple_read_from_buffer(void __user *to, size_t count,
 extern ssize_t simple_write_to_buffer(void *to, size_t available, loff_t *ppos,
 		const void __user *from, size_t count);
 
+extern int __generic_file_fsync_nolock(struct file *, loff_t, loff_t, int);
 extern int __generic_file_fsync(struct file *, loff_t, loff_t, int);
 extern int generic_file_fsync(struct file *, loff_t, loff_t, int);