diff mbox series

[6/6] fs: xfs: Set FMODE_CAN_ATOMIC_WRITE for FS_XFLAG_ATOMICWRITES set

Message ID 20240124142645.9334-7-john.g.garry@oracle.com (mailing list archive)
State Deferred, archived
Headers show
Series block atomic writes for XFS | expand

Commit Message

John Garry Jan. 24, 2024, 2:26 p.m. UTC
For when an inode is enabled for atomic writes, set FMODE_CAN_ATOMIC_WRITE
flag.

Signed-off-by: John Garry <john.g.garry@oracle.com>
---
 fs/xfs/xfs_file.c | 2 ++
 1 file changed, 2 insertions(+)

Comments

Darrick J. Wong Feb. 2, 2024, 6:06 p.m. UTC | #1
On Wed, Jan 24, 2024 at 02:26:45PM +0000, John Garry wrote:
> For when an inode is enabled for atomic writes, set FMODE_CAN_ATOMIC_WRITE
> flag.
> 
> Signed-off-by: John Garry <john.g.garry@oracle.com>
> ---
>  fs/xfs/xfs_file.c | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
> index e33e5e13b95f..1375d0089806 100644
> --- a/fs/xfs/xfs_file.c
> +++ b/fs/xfs/xfs_file.c
> @@ -1232,6 +1232,8 @@ xfs_file_open(
>  		return -EIO;
>  	file->f_mode |= FMODE_NOWAIT | FMODE_BUF_RASYNC | FMODE_BUF_WASYNC |
>  			FMODE_DIO_PARALLEL_WRITE | FMODE_CAN_ODIRECT;
> +	if (xfs_inode_atomicwrites(XFS_I(inode)))

Shouldn't we check that the device supports AWU at all before turning on
the FMODE flag?

--D

> +		file->f_mode |= FMODE_CAN_ATOMIC_WRITE;
>  	return generic_file_open(inode, file);
>  }
>  
> -- 
> 2.31.1
> 
>
John Garry Feb. 5, 2024, 10:26 a.m. UTC | #2
On 02/02/2024 18:06, Darrick J. Wong wrote:
> On Wed, Jan 24, 2024 at 02:26:45PM +0000, John Garry wrote:
>> For when an inode is enabled for atomic writes, set FMODE_CAN_ATOMIC_WRITE
>> flag.
>>
>> Signed-off-by: John Garry <john.g.garry@oracle.com>
>> ---
>>   fs/xfs/xfs_file.c | 2 ++
>>   1 file changed, 2 insertions(+)
>>
>> diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
>> index e33e5e13b95f..1375d0089806 100644
>> --- a/fs/xfs/xfs_file.c
>> +++ b/fs/xfs/xfs_file.c
>> @@ -1232,6 +1232,8 @@ xfs_file_open(
>>   		return -EIO;
>>   	file->f_mode |= FMODE_NOWAIT | FMODE_BUF_RASYNC | FMODE_BUF_WASYNC |
>>   			FMODE_DIO_PARALLEL_WRITE | FMODE_CAN_ODIRECT;
>> +	if (xfs_inode_atomicwrites(XFS_I(inode)))

Note to self: This should also check if O_DIRECT is set

> 
> Shouldn't we check that the device supports AWU at all before turning on
> the FMODE flag?

Can we easily get this sort of bdev info here?

Currently if we do try to issue an atomic write and AWU for the bdev is 
zero, then XFS iomap code will reject it.

Thanks,
John

> 
> --D
> 
>> +		file->f_mode |= FMODE_CAN_ATOMIC_WRITE;
>>   	return generic_file_open(inode, file);
>>   }
>>   
>> -- 
>> 2.31.1
>>
>>
Darrick J. Wong Feb. 13, 2024, 5:59 p.m. UTC | #3
On Mon, Feb 05, 2024 at 10:26:43AM +0000, John Garry wrote:
> On 02/02/2024 18:06, Darrick J. Wong wrote:
> > On Wed, Jan 24, 2024 at 02:26:45PM +0000, John Garry wrote:
> > > For when an inode is enabled for atomic writes, set FMODE_CAN_ATOMIC_WRITE
> > > flag.
> > > 
> > > Signed-off-by: John Garry <john.g.garry@oracle.com>
> > > ---
> > >   fs/xfs/xfs_file.c | 2 ++
> > >   1 file changed, 2 insertions(+)
> > > 
> > > diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
> > > index e33e5e13b95f..1375d0089806 100644
> > > --- a/fs/xfs/xfs_file.c
> > > +++ b/fs/xfs/xfs_file.c
> > > @@ -1232,6 +1232,8 @@ xfs_file_open(
> > >   		return -EIO;
> > >   	file->f_mode |= FMODE_NOWAIT | FMODE_BUF_RASYNC | FMODE_BUF_WASYNC |
> > >   			FMODE_DIO_PARALLEL_WRITE | FMODE_CAN_ODIRECT;
> > > +	if (xfs_inode_atomicwrites(XFS_I(inode)))
> 
> Note to self: This should also check if O_DIRECT is set
> 
> > 
> > Shouldn't we check that the device supports AWU at all before turning on
> > the FMODE flag?
> 
> Can we easily get this sort of bdev info here?
> 
> Currently if we do try to issue an atomic write and AWU for the bdev is
> zero, then XFS iomap code will reject it.

Hmm.  Well, if we move towards pushing all the hardware checks out of
xfs/iomap and into whatever goes on underneath submit_bio then I guess
we don't need to check device support here at all.

--D

> Thanks,
> John
> 
> > 
> > --D
> > 
> > > +		file->f_mode |= FMODE_CAN_ATOMIC_WRITE;
> > >   	return generic_file_open(inode, file);
> > >   }
> > > -- 
> > > 2.31.1
> > > 
> > > 
> 
>
John Garry Feb. 14, 2024, 12:36 p.m. UTC | #4
On 13/02/2024 17:59, Darrick J. Wong wrote:
>>> Shouldn't we check that the device supports AWU at all before turning on
>>> the FMODE flag?
>> Can we easily get this sort of bdev info here?
>>
>> Currently if we do try to issue an atomic write and AWU for the bdev is
>> zero, then XFS iomap code will reject it.
> Hmm.  Well, if we move towards pushing all the hardware checks out of
> xfs/iomap and into whatever goes on underneath submit_bio then I guess
> we don't need to check device support here at all.

Yeah, I have been thinking about this. But I was still planning on 
putting a "bdev on atomic write" check here, as you mentioned.

But is this a proper method to access the bdev for an xfs inode:

STATIC bool
xfs_file_can_atomic_write(
struct xfs_inode *inode)
{
	struct xfs_buftarg *target = xfs_inode_buftarg(inode);
	struct block_device *bdev = target->bt_bdev;

	if (!xfs_inode_atomicwrites(inode))
		return false;

	return bdev_can_atomic_write(bdev);
}

I do notice the dax check in xfs_bmbt_to_iomap() when assigning 
iomap->bdev, which is creating some doubt?

Thanks,
John
Darrick J. Wong Feb. 21, 2024, 5 p.m. UTC | #5
On Wed, Feb 14, 2024 at 12:36:40PM +0000, John Garry wrote:
> On 13/02/2024 17:59, Darrick J. Wong wrote:
> > > > Shouldn't we check that the device supports AWU at all before turning on
> > > > the FMODE flag?
> > > Can we easily get this sort of bdev info here?
> > > 
> > > Currently if we do try to issue an atomic write and AWU for the bdev is
> > > zero, then XFS iomap code will reject it.
> > Hmm.  Well, if we move towards pushing all the hardware checks out of
> > xfs/iomap and into whatever goes on underneath submit_bio then I guess
> > we don't need to check device support here at all.
> 
> Yeah, I have been thinking about this. But I was still planning on putting a
> "bdev on atomic write" check here, as you mentioned.
> 
> But is this a proper method to access the bdev for an xfs inode:
> 
> STATIC bool
> xfs_file_can_atomic_write(
> struct xfs_inode *inode)
> {
> 	struct xfs_buftarg *target = xfs_inode_buftarg(inode);
> 	struct block_device *bdev = target->bt_bdev;
> 
> 	if (!xfs_inode_atomicwrites(inode))
> 		return false;
> 
> 	return bdev_can_atomic_write(bdev);
> }

There's still a TOCTOU race problem if the bdev gets reconfigured
between xfs_file_can_atomic_write and submit_bio.

However, if you're only using this to advertise the capability via statx
then I suppose that's fine -- userspace has to have some means of
discovering the ability at all.  Userspace is also inherently racy.

> I do notice the dax check in xfs_bmbt_to_iomap() when assigning iomap->bdev,
> which is creating some doubt?

Do you mean this?

	if (mapping_flags & IOMAP_DAX)
		iomap->dax_dev = target->bt_daxdev;
	else
		iomap->bdev = target->bt_bdev;

The dax path wants dax_dev set so that it can do the glorified memcpy
operation, and it doesn't need (or want) a block device.

--D

> Thanks,
> John
>
John Garry Feb. 21, 2024, 5:38 p.m. UTC | #6
On 21/02/2024 17:00, Darrick J. Wong wrote:
>>> Hmm.  Well, if we move towards pushing all the hardware checks out of
>>> xfs/iomap and into whatever goes on underneath submit_bio then I guess
>>> we don't need to check device support here at all.
>> Yeah, I have been thinking about this. But I was still planning on putting a
>> "bdev on atomic write" check here, as you mentioned.
>>
>> But is this a proper method to access the bdev for an xfs inode:
>>
>> STATIC bool
>> xfs_file_can_atomic_write(
>> struct xfs_inode *inode)
>> {
>> 	struct xfs_buftarg *target = xfs_inode_buftarg(inode);
>> 	struct block_device *bdev = target->bt_bdev;
>>
>> 	if (!xfs_inode_atomicwrites(inode))
>> 		return false;
>>
>> 	return bdev_can_atomic_write(bdev);
>> }
> There's still a TOCTOU race problem if the bdev gets reconfigured
> between xfs_file_can_atomic_write and submit_bio.

If that is the case then a check in the bio submit path is required to 
catch any such reconfigure problems - and we effectively have that in 
this series.

I am looking at change some of these XFS bdev_can_atomic_write() checks, 
but would still have a check in the bio submit path.

> 
> However, if you're only using this to advertise the capability via statx
> then I suppose that's fine -- userspace has to have some means of
> discovering the ability at all.  Userspace is also inherently racy.
> 
>> I do notice the dax check in xfs_bmbt_to_iomap() when assigning iomap->bdev,
>> which is creating some doubt?
> Do you mean this?
> 
> 	if (mapping_flags & IOMAP_DAX)
> 		iomap->dax_dev = target->bt_daxdev;
> 	else
> 		iomap->bdev = target->bt_bdev;
> 
> The dax path wants dax_dev set so that it can do the glorified memcpy
> operation, and it doesn't need (or want) a block device.

Yes, so proper to use target->bt_bdev for checks for bdev atomic write 
capability, right?

Thanks,
John
Darrick J. Wong Feb. 24, 2024, 4:18 a.m. UTC | #7
On Wed, Feb 21, 2024 at 05:38:39PM +0000, John Garry wrote:
> On 21/02/2024 17:00, Darrick J. Wong wrote:
> > > > Hmm.  Well, if we move towards pushing all the hardware checks out of
> > > > xfs/iomap and into whatever goes on underneath submit_bio then I guess
> > > > we don't need to check device support here at all.
> > > Yeah, I have been thinking about this. But I was still planning on putting a
> > > "bdev on atomic write" check here, as you mentioned.
> > > 
> > > But is this a proper method to access the bdev for an xfs inode:
> > > 
> > > STATIC bool
> > > xfs_file_can_atomic_write(
> > > struct xfs_inode *inode)
> > > {
> > > 	struct xfs_buftarg *target = xfs_inode_buftarg(inode);
> > > 	struct block_device *bdev = target->bt_bdev;
> > > 
> > > 	if (!xfs_inode_atomicwrites(inode))
> > > 		return false;
> > > 
> > > 	return bdev_can_atomic_write(bdev);
> > > }
> > There's still a TOCTOU race problem if the bdev gets reconfigured
> > between xfs_file_can_atomic_write and submit_bio.
> 
> If that is the case then a check in the bio submit path is required to catch
> any such reconfigure problems - and we effectively have that in this series.
> 
> I am looking at change some of these XFS bdev_can_atomic_write() checks, but
> would still have a check in the bio submit path.

<nod> "check in the bio submit path" sounds good to me.  Adding in
redundant checks which are eventually gated on whatever submit_bio does
sounds like excessive overhead and layering violations.

> > 
> > However, if you're only using this to advertise the capability via statx
> > then I suppose that's fine -- userspace has to have some means of
> > discovering the ability at all.  Userspace is also inherently racy.
> > 
> > > I do notice the dax check in xfs_bmbt_to_iomap() when assigning iomap->bdev,
> > > which is creating some doubt?
> > Do you mean this?
> > 
> > 	if (mapping_flags & IOMAP_DAX)
> > 		iomap->dax_dev = target->bt_daxdev;
> > 	else
> > 		iomap->bdev = target->bt_bdev;
> > 
> > The dax path wants dax_dev set so that it can do the glorified memcpy
> > operation, and it doesn't need (or want) a block device.
> 
> Yes, so proper to use target->bt_bdev for checks for bdev atomic write
> capability, right?

Right.  fsdax doesn't support atomic memcpy to pmem.

--D

> 
> Thanks,
> John
> 
>
diff mbox series

Patch

diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index e33e5e13b95f..1375d0089806 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -1232,6 +1232,8 @@  xfs_file_open(
 		return -EIO;
 	file->f_mode |= FMODE_NOWAIT | FMODE_BUF_RASYNC | FMODE_BUF_WASYNC |
 			FMODE_DIO_PARALLEL_WRITE | FMODE_CAN_ODIRECT;
+	if (xfs_inode_atomicwrites(XFS_I(inode)))
+		file->f_mode |= FMODE_CAN_ATOMIC_WRITE;
 	return generic_file_open(inode, file);
 }