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:
commit
4ec2e3c167
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
15
fs/xfs/xfs_file.h
Normal 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__ */
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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__ */
|
||||
|
@ -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)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user