xfs: refactorings for atomic file content exchanges [v30.3 02/16]

This series applies various cleanups and refactorings to file IO
 handling code ahead of the main series to implement atomic file content
 exchanges.
 
 This has been running on the djcloud for months with no problems.  Enjoy!
 
 Signed-off-by: Darrick J. Wong <djwong@kernel.org>
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQQ2qTKExjcn+O1o2YRKO3ySh0YRpgUCZh23UgAKCRBKO3ySh0YR
 pginAQCcZq5bFYJGYj4UInUOfDDjuq8R9Rl8DGDhnTFb8FxAUAD+Jsol2/wQduII
 Bly/+Hegen2BoayNuf3iZG7RYkJWygo=
 =tHoT
 -----END PGP SIGNATURE-----

Merge tag 'file-exchange-refactorings-6.10_2024-04-15' of https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux into xfs-6.10-mergeA

xfs: refactorings for atomic file content exchanges

This series applies various cleanups and refactorings to file IO
handling code ahead of the main series to implement atomic file content
exchanges.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Chandan Babu R <chandanbabu@kernel.org>

* tag 'file-exchange-refactorings-6.10_2024-04-15' of https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux:
  xfs: constify xfs_bmap_is_written_extent
  xfs: refactor non-power-of-two alignment checks
  xfs: hoist multi-fsb allocation unit detection to a helper
  xfs: create a new helper to return a file's allocation unit
  xfs: declare xfs_file.c symbols in xfs_file.h
  xfs: move xfs_iops.c declarations out of xfs_inode.h
  xfs: move inode lease breaking functions to xfs_inode.c
This commit is contained in:
Chandan Babu R 2024-04-16 11:17:28 +05:30
commit 4ec2e3c167
10 changed files with 121 additions and 93 deletions

View File

@ -158,7 +158,7 @@ static inline bool xfs_bmap_is_real_extent(const struct xfs_bmbt_irec *irec)
* Return true if the extent is a real, allocated extent, or false if it is a
* delayed allocation, and unwritten extent or a hole.
*/
static inline bool xfs_bmap_is_written_extent(struct xfs_bmbt_irec *irec)
static inline bool xfs_bmap_is_written_extent(const struct xfs_bmbt_irec *irec)
{
return xfs_bmap_is_real_extent(irec) &&
irec->br_state != XFS_EXT_UNWRITTEN;

View File

@ -542,7 +542,7 @@ xfs_can_free_eofblocks(
* forever.
*/
end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_ISIZE(ip));
if (XFS_IS_REALTIME_INODE(ip) && mp->m_sb.sb_rextsize > 1)
if (xfs_inode_has_bigrtalloc(ip))
end_fsb = xfs_rtb_roundup_rtx(mp, end_fsb);
last_fsb = XFS_B_TO_FSB(mp, mp->m_super->s_maxbytes);
if (last_fsb <= end_fsb)
@ -843,7 +843,7 @@ xfs_free_file_space(
endoffset_fsb = XFS_B_TO_FSBT(mp, offset + len);
/* We can only free complete realtime extents. */
if (XFS_IS_REALTIME_INODE(ip) && mp->m_sb.sb_rextsize > 1) {
if (xfs_inode_has_bigrtalloc(ip)) {
startoffset_fsb = xfs_rtb_roundup_rtx(mp, startoffset_fsb);
endoffset_fsb = xfs_rtb_rounddown_rtx(mp, endoffset_fsb);
}

View File

@ -24,6 +24,7 @@
#include "xfs_pnfs.h"
#include "xfs_iomap.h"
#include "xfs_reflink.h"
#include "xfs_file.h"
#include <linux/dax.h>
#include <linux/falloc.h>
@ -38,33 +39,19 @@ static const struct vm_operations_struct xfs_file_vm_ops;
* Decide if the given file range is aligned to the size of the fundamental
* allocation unit for the file.
*/
static bool
bool
xfs_is_falloc_aligned(
struct xfs_inode *ip,
loff_t pos,
long long int len)
{
struct xfs_mount *mp = ip->i_mount;
uint64_t mask;
unsigned int alloc_unit = xfs_inode_alloc_unitsize(ip);
if (XFS_IS_REALTIME_INODE(ip)) {
if (!is_power_of_2(mp->m_sb.sb_rextsize)) {
u64 rextbytes;
u32 mod;
if (!is_power_of_2(alloc_unit))
return isaligned_64(pos, alloc_unit) &&
isaligned_64(len, alloc_unit);
rextbytes = XFS_FSB_TO_B(mp, mp->m_sb.sb_rextsize);
div_u64_rem(pos, rextbytes, &mod);
if (mod)
return false;
div_u64_rem(len, rextbytes, &mod);
return mod == 0;
}
mask = XFS_FSB_TO_B(mp, mp->m_sb.sb_rextsize) - 1;
} else {
mask = mp->m_sb.sb_blocksize - 1;
}
return !((pos | len) & mask);
return !((pos | len) & (alloc_unit - 1));
}
/*
@ -861,67 +848,6 @@ xfs_file_write_iter(
return xfs_file_buffered_write(iocb, from);
}
static void
xfs_wait_dax_page(
struct inode *inode)
{
struct xfs_inode *ip = XFS_I(inode);
xfs_iunlock(ip, XFS_MMAPLOCK_EXCL);
schedule();
xfs_ilock(ip, XFS_MMAPLOCK_EXCL);
}
int
xfs_break_dax_layouts(
struct inode *inode,
bool *retry)
{
struct page *page;
xfs_assert_ilocked(XFS_I(inode), XFS_MMAPLOCK_EXCL);
page = dax_layout_busy_page(inode->i_mapping);
if (!page)
return 0;
*retry = true;
return ___wait_var_event(&page->_refcount,
atomic_read(&page->_refcount) == 1, TASK_INTERRUPTIBLE,
0, 0, xfs_wait_dax_page(inode));
}
int
xfs_break_layouts(
struct inode *inode,
uint *iolock,
enum layout_break_reason reason)
{
bool retry;
int error;
xfs_assert_ilocked(XFS_I(inode), XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL);
do {
retry = false;
switch (reason) {
case BREAK_UNMAP:
error = xfs_break_dax_layouts(inode, &retry);
if (error || retry)
break;
fallthrough;
case BREAK_WRITE:
error = xfs_break_leased_layouts(inode, iolock, &retry);
break;
default:
WARN_ON_ONCE(1);
error = -EINVAL;
}
} while (error == 0 && retry);
return error;
}
/* Does this file, inode, or mount want synchronous writes? */
static inline bool xfs_file_sync_writes(struct file *filp)
{

15
fs/xfs/xfs_file.h Normal file
View File

@ -0,0 +1,15 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2000-2005 Silicon Graphics, Inc.
* All Rights Reserved.
*/
#ifndef __XFS_FILE_H__
#define __XFS_FILE_H__
extern const struct file_operations xfs_file_operations;
extern const struct file_operations xfs_dir_file_operations;
bool xfs_is_falloc_aligned(struct xfs_inode *ip, loff_t pos,
long long int len);
#endif /* __XFS_FILE_H__ */

View File

@ -38,6 +38,7 @@
#include "xfs_ag.h"
#include "xfs_log_priv.h"
#include "xfs_health.h"
#include "xfs_pnfs.h"
struct kmem_cache *xfs_inode_cache;
@ -3946,3 +3947,77 @@ xfs_inode_count_blocks(
xfs_bmap_count_leaves(ifp, rblocks);
*dblocks = ip->i_nblocks - *rblocks;
}
static void
xfs_wait_dax_page(
struct inode *inode)
{
struct xfs_inode *ip = XFS_I(inode);
xfs_iunlock(ip, XFS_MMAPLOCK_EXCL);
schedule();
xfs_ilock(ip, XFS_MMAPLOCK_EXCL);
}
int
xfs_break_dax_layouts(
struct inode *inode,
bool *retry)
{
struct page *page;
xfs_assert_ilocked(XFS_I(inode), XFS_MMAPLOCK_EXCL);
page = dax_layout_busy_page(inode->i_mapping);
if (!page)
return 0;
*retry = true;
return ___wait_var_event(&page->_refcount,
atomic_read(&page->_refcount) == 1, TASK_INTERRUPTIBLE,
0, 0, xfs_wait_dax_page(inode));
}
int
xfs_break_layouts(
struct inode *inode,
uint *iolock,
enum layout_break_reason reason)
{
bool retry;
int error;
xfs_assert_ilocked(XFS_I(inode), XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL);
do {
retry = false;
switch (reason) {
case BREAK_UNMAP:
error = xfs_break_dax_layouts(inode, &retry);
if (error || retry)
break;
fallthrough;
case BREAK_WRITE:
error = xfs_break_leased_layouts(inode, iolock, &retry);
break;
default:
WARN_ON_ONCE(1);
error = -EINVAL;
}
} while (error == 0 && retry);
return error;
}
/* Returns the size of fundamental allocation unit for a file, in bytes. */
unsigned int
xfs_inode_alloc_unitsize(
struct xfs_inode *ip)
{
unsigned int blocks = 1;
if (XFS_IS_REALTIME_INODE(ip))
blocks = ip->i_mount->m_sb.sb_rextsize;
return XFS_FSB_TO_B(ip->i_mount, blocks);
}

View File

@ -311,6 +311,15 @@ static inline bool xfs_inode_has_large_extent_counts(struct xfs_inode *ip)
return ip->i_diflags2 & XFS_DIFLAG2_NREXT64;
}
/*
* Decide if this file is a realtime file whose data allocation unit is larger
* than a single filesystem block.
*/
static inline bool xfs_inode_has_bigrtalloc(struct xfs_inode *ip)
{
return XFS_IS_REALTIME_INODE(ip) && ip->i_mount->m_sb.sb_rextsize > 1;
}
/*
* Return the buftarg used for data allocations on a given inode.
*/
@ -565,16 +574,10 @@ xfs_itruncate_extents(
return xfs_itruncate_extents_flags(tpp, ip, whichfork, new_size, 0);
}
/* from xfs_file.c */
int xfs_break_dax_layouts(struct inode *inode, bool *retry);
int xfs_break_layouts(struct inode *inode, uint *iolock,
enum layout_break_reason reason);
/* from xfs_iops.c */
extern void xfs_setup_inode(struct xfs_inode *ip);
extern void xfs_setup_iops(struct xfs_inode *ip);
extern void xfs_diflags_to_iflags(struct xfs_inode *ip, bool init);
static inline void xfs_update_stable_writes(struct xfs_inode *ip)
{
if (bdev_stable_writes(xfs_inode_buftarg(ip)->bt_bdev))
@ -631,6 +634,7 @@ int xfs_inode_reload_unlinked(struct xfs_inode *ip);
bool xfs_ifork_zapped(const struct xfs_inode *ip, int whichfork);
void xfs_inode_count_blocks(struct xfs_trans *tp, struct xfs_inode *ip,
xfs_filblks_t *dblocks, xfs_filblks_t *rblocks);
unsigned int xfs_inode_alloc_unitsize(struct xfs_inode *ip);
struct xfs_dir_update_params {
const struct xfs_inode *dp;

View File

@ -39,6 +39,7 @@
#include "xfs_ioctl.h"
#include "xfs_xattr.h"
#include "xfs_rtbitmap.h"
#include "xfs_file.h"
#include <linux/mount.h>
#include <linux/namei.h>

View File

@ -25,6 +25,7 @@
#include "xfs_error.h"
#include "xfs_ioctl.h"
#include "xfs_xattr.h"
#include "xfs_file.h"
#include <linux/posix_acl.h>
#include <linux/security.h>

View File

@ -8,9 +8,6 @@
struct xfs_inode;
extern const struct file_operations xfs_file_operations;
extern const struct file_operations xfs_dir_file_operations;
extern ssize_t xfs_vn_listxattr(struct dentry *, char *data, size_t size);
int xfs_vn_setattr_size(struct mnt_idmap *idmap,
@ -19,4 +16,8 @@ int xfs_vn_setattr_size(struct mnt_idmap *idmap,
int xfs_inode_init_security(struct inode *inode, struct inode *dir,
const struct qstr *qstr);
extern void xfs_setup_inode(struct xfs_inode *ip);
extern void xfs_setup_iops(struct xfs_inode *ip);
extern void xfs_diflags_to_iflags(struct xfs_inode *ip, bool init);
#endif /* __XFS_IOPS_H__ */

View File

@ -198,6 +198,11 @@ static inline uint64_t howmany_64(uint64_t x, uint32_t y)
return x;
}
static inline bool isaligned_64(uint64_t x, uint32_t y)
{
return do_div(x, y) == 0;
}
/* If @b is a power of 2, return log2(b). Else return -1. */
static inline int8_t log2_if_power2(unsigned long b)
{