mirror of
https://github.com/torvalds/linux.git
synced 2024-11-21 19:41:42 +00:00
Bug fixes for 6.10-rc6:
* Always free only post-EOF delayed allocations for files with the XFS_DIFLAG_PREALLOC or APPEND flags set. * Do not align cow fork delalloc to cowextsz hint when running low on space. * Allow zero-size symlinks and directories as long as the link count is zero. * Change XFS_IOC_EXCHANGE_RANGE to be a _IOW only ioctl. This was ioctl was introduced during v6.10 developement cycle. * xfs_init_new_inode() now creates an attribute fork on a newly created inode even if ATTR feature flag is not enabled. Signed-off-by: Chandan Babu R <chandanbabu@kernel.org> -----BEGIN PGP SIGNATURE----- iHUEABYIAB0WIQQjMC4mbgVeU7MxEIYH7y4RirJu9AUCZnvYdwAKCRAH7y4RirJu 9DRmAP9VwmSgBrVGZ459K6LluP12FoIpzUljEYSiQiyjhxuQJgD/fou/8G+/TTQH 3TtdmC8Xo7SWRMq9+wPpH5OywbsvZQM= =fV8d -----END PGP SIGNATURE----- Merge tag 'xfs-6.10-fixes-5' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux Pull xfs fixes from Chandan Babu: - Always free only post-EOF delayed allocations for files with the XFS_DIFLAG_PREALLOC or APPEND flags set. - Do not align cow fork delalloc to cowextsz hint when running low on space. - Allow zero-size symlinks and directories as long as the link count is zero. - Change XFS_IOC_EXCHANGE_RANGE to be a _IOW only ioctl. This was ioctl was introduced during v6.10 developement cycle. - xfs_init_new_inode() now creates an attribute fork on a newly created inode even if ATTR feature flag is not enabled. * tag 'xfs-6.10-fixes-5' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux: xfs: honor init_xattrs in xfs_init_new_inode for !ATTR fs xfs: fix direction in XFS_IOC_EXCHANGE_RANGE xfs: allow unlinked symlinks and dirs with zero size xfs: restrict when we try to align cow fork delalloc to cowextsz hints xfs: fix freeing speculative preallocations for preallocated files
This commit is contained in:
commit
27b31deb90
@ -4058,20 +4058,32 @@ xfs_bmapi_reserve_delalloc(
|
||||
xfs_extlen_t indlen;
|
||||
uint64_t fdblocks;
|
||||
int error;
|
||||
xfs_fileoff_t aoff = off;
|
||||
xfs_fileoff_t aoff;
|
||||
bool use_cowextszhint =
|
||||
whichfork == XFS_COW_FORK && !prealloc;
|
||||
|
||||
retry:
|
||||
/*
|
||||
* Cap the alloc length. Keep track of prealloc so we know whether to
|
||||
* tag the inode before we return.
|
||||
*/
|
||||
aoff = off;
|
||||
alen = XFS_FILBLKS_MIN(len + prealloc, XFS_MAX_BMBT_EXTLEN);
|
||||
if (!eof)
|
||||
alen = XFS_FILBLKS_MIN(alen, got->br_startoff - aoff);
|
||||
if (prealloc && alen >= len)
|
||||
prealloc = alen - len;
|
||||
|
||||
/* Figure out the extent size, adjust alen */
|
||||
if (whichfork == XFS_COW_FORK) {
|
||||
/*
|
||||
* If we're targetting the COW fork but aren't creating a speculative
|
||||
* posteof preallocation, try to expand the reservation to align with
|
||||
* the COW extent size hint if there's sufficient free space.
|
||||
*
|
||||
* Unlike the data fork, the CoW cancellation functions will free all
|
||||
* the reservations at inactivation, so we don't require that every
|
||||
* delalloc reservation have a dirty pagecache.
|
||||
*/
|
||||
if (use_cowextszhint) {
|
||||
struct xfs_bmbt_irec prev;
|
||||
xfs_extlen_t extsz = xfs_get_cowextsz_hint(ip);
|
||||
|
||||
@ -4090,7 +4102,7 @@ xfs_bmapi_reserve_delalloc(
|
||||
*/
|
||||
error = xfs_quota_reserve_blkres(ip, alen);
|
||||
if (error)
|
||||
return error;
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Split changing sb for alen and indlen since they could be coming
|
||||
@ -4140,6 +4152,17 @@ out_unreserve_frextents:
|
||||
out_unreserve_quota:
|
||||
if (XFS_IS_QUOTA_ON(mp))
|
||||
xfs_quota_unreserve_blkres(ip, alen);
|
||||
out:
|
||||
if (error == -ENOSPC || error == -EDQUOT) {
|
||||
trace_xfs_delalloc_enospc(ip, off, len);
|
||||
|
||||
if (prealloc || use_cowextszhint) {
|
||||
/* retry without any preallocation */
|
||||
use_cowextszhint = false;
|
||||
prealloc = 0;
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -996,7 +996,7 @@ struct xfs_getparents_by_handle {
|
||||
#define XFS_IOC_FSGEOMETRY _IOR ('X', 126, struct xfs_fsop_geom)
|
||||
#define XFS_IOC_BULKSTAT _IOR ('X', 127, struct xfs_bulkstat_req)
|
||||
#define XFS_IOC_INUMBERS _IOR ('X', 128, struct xfs_inumbers_req)
|
||||
#define XFS_IOC_EXCHANGE_RANGE _IOWR('X', 129, struct xfs_exchange_range)
|
||||
#define XFS_IOC_EXCHANGE_RANGE _IOW ('X', 129, struct xfs_exchange_range)
|
||||
/* XFS_IOC_GETFSUUID ---------- deprecated 140 */
|
||||
|
||||
|
||||
|
@ -379,10 +379,13 @@ xfs_dinode_verify_fork(
|
||||
/*
|
||||
* A directory small enough to fit in the inode must be stored
|
||||
* in local format. The directory sf <-> extents conversion
|
||||
* code updates the directory size accordingly.
|
||||
* code updates the directory size accordingly. Directories
|
||||
* being truncated have zero size and are not subject to this
|
||||
* check.
|
||||
*/
|
||||
if (S_ISDIR(mode)) {
|
||||
if (be64_to_cpu(dip->di_size) <= fork_size &&
|
||||
if (dip->di_size &&
|
||||
be64_to_cpu(dip->di_size) <= fork_size &&
|
||||
fork_format != XFS_DINODE_FMT_LOCAL)
|
||||
return __this_address;
|
||||
}
|
||||
@ -528,9 +531,19 @@ xfs_dinode_verify(
|
||||
if (mode && xfs_mode_to_ftype(mode) == XFS_DIR3_FT_UNKNOWN)
|
||||
return __this_address;
|
||||
|
||||
/* No zero-length symlinks/dirs. */
|
||||
if ((S_ISLNK(mode) || S_ISDIR(mode)) && di_size == 0)
|
||||
return __this_address;
|
||||
/*
|
||||
* No zero-length symlinks/dirs unless they're unlinked and hence being
|
||||
* inactivated.
|
||||
*/
|
||||
if ((S_ISLNK(mode) || S_ISDIR(mode)) && di_size == 0) {
|
||||
if (dip->di_version > 1) {
|
||||
if (dip->di_nlink)
|
||||
return __this_address;
|
||||
} else {
|
||||
if (dip->di_onlink)
|
||||
return __this_address;
|
||||
}
|
||||
}
|
||||
|
||||
fa = xfs_dinode_verify_nrext64(mp, dip);
|
||||
if (fa)
|
||||
|
@ -486,13 +486,11 @@ out_unlock:
|
||||
|
||||
/*
|
||||
* Test whether it is appropriate to check an inode for and free post EOF
|
||||
* blocks. The 'force' parameter determines whether we should also consider
|
||||
* regular files that are marked preallocated or append-only.
|
||||
* blocks.
|
||||
*/
|
||||
bool
|
||||
xfs_can_free_eofblocks(
|
||||
struct xfs_inode *ip,
|
||||
bool force)
|
||||
struct xfs_inode *ip)
|
||||
{
|
||||
struct xfs_bmbt_irec imap;
|
||||
struct xfs_mount *mp = ip->i_mount;
|
||||
@ -526,11 +524,11 @@ xfs_can_free_eofblocks(
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Do not free real preallocated or append-only files unless the file
|
||||
* has delalloc blocks and we are forced to remove them.
|
||||
* Only free real extents for inodes with persistent preallocations or
|
||||
* the append-only flag.
|
||||
*/
|
||||
if (ip->i_diflags & (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND))
|
||||
if (!force || ip->i_delayed_blks == 0)
|
||||
if (ip->i_delayed_blks == 0)
|
||||
return false;
|
||||
|
||||
/*
|
||||
@ -584,6 +582,22 @@ xfs_free_eofblocks(
|
||||
/* Wait on dio to ensure i_size has settled. */
|
||||
inode_dio_wait(VFS_I(ip));
|
||||
|
||||
/*
|
||||
* For preallocated files only free delayed allocations.
|
||||
*
|
||||
* Note that this means we also leave speculative preallocations in
|
||||
* place for preallocated files.
|
||||
*/
|
||||
if (ip->i_diflags & (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)) {
|
||||
if (ip->i_delayed_blks) {
|
||||
xfs_bmap_punch_delalloc_range(ip,
|
||||
round_up(XFS_ISIZE(ip), mp->m_sb.sb_blocksize),
|
||||
LLONG_MAX);
|
||||
}
|
||||
xfs_inode_clear_eofblocks_tag(ip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp);
|
||||
if (error) {
|
||||
ASSERT(xfs_is_shutdown(mp));
|
||||
@ -891,7 +905,7 @@ xfs_prepare_shift(
|
||||
* Trim eofblocks to avoid shifting uninitialized post-eof preallocation
|
||||
* into the accessible region of the file.
|
||||
*/
|
||||
if (xfs_can_free_eofblocks(ip, true)) {
|
||||
if (xfs_can_free_eofblocks(ip)) {
|
||||
error = xfs_free_eofblocks(ip);
|
||||
if (error)
|
||||
return error;
|
||||
|
@ -63,7 +63,7 @@ int xfs_insert_file_space(struct xfs_inode *, xfs_off_t offset,
|
||||
xfs_off_t len);
|
||||
|
||||
/* EOF block manipulation functions */
|
||||
bool xfs_can_free_eofblocks(struct xfs_inode *ip, bool force);
|
||||
bool xfs_can_free_eofblocks(struct xfs_inode *ip);
|
||||
int xfs_free_eofblocks(struct xfs_inode *ip);
|
||||
|
||||
int xfs_swap_extents(struct xfs_inode *ip, struct xfs_inode *tip,
|
||||
|
@ -1155,7 +1155,7 @@ xfs_inode_free_eofblocks(
|
||||
}
|
||||
*lockflags |= XFS_IOLOCK_EXCL;
|
||||
|
||||
if (xfs_can_free_eofblocks(ip, false))
|
||||
if (xfs_can_free_eofblocks(ip))
|
||||
return xfs_free_eofblocks(ip);
|
||||
|
||||
/* inode could be preallocated or append-only */
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include "xfs_pnfs.h"
|
||||
#include "xfs_parent.h"
|
||||
#include "xfs_xattr.h"
|
||||
#include "xfs_sb.h"
|
||||
|
||||
struct kmem_cache *xfs_inode_cache;
|
||||
|
||||
@ -870,9 +871,16 @@ xfs_init_new_inode(
|
||||
* this saves us from needing to run a separate transaction to set the
|
||||
* fork offset in the immediate future.
|
||||
*/
|
||||
if (init_xattrs && xfs_has_attr(mp)) {
|
||||
if (init_xattrs) {
|
||||
ip->i_forkoff = xfs_default_attroffset(ip) >> 3;
|
||||
xfs_ifork_init_attr(ip, XFS_DINODE_FMT_EXTENTS, 0);
|
||||
|
||||
if (!xfs_has_attr(mp)) {
|
||||
spin_lock(&mp->m_sb_lock);
|
||||
xfs_add_attr(mp);
|
||||
spin_unlock(&mp->m_sb_lock);
|
||||
xfs_log_sb(tp);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1595,7 +1603,7 @@ xfs_release(
|
||||
if (!xfs_ilock_nowait(ip, XFS_IOLOCK_EXCL))
|
||||
return 0;
|
||||
|
||||
if (xfs_can_free_eofblocks(ip, false)) {
|
||||
if (xfs_can_free_eofblocks(ip)) {
|
||||
/*
|
||||
* Check if the inode is being opened, written and closed
|
||||
* frequently and we have delayed allocation blocks outstanding
|
||||
@ -1856,15 +1864,13 @@ xfs_inode_needs_inactive(
|
||||
|
||||
/*
|
||||
* This file isn't being freed, so check if there are post-eof blocks
|
||||
* to free. @force is true because we are evicting an inode from the
|
||||
* cache. Post-eof blocks must be freed, lest we end up with broken
|
||||
* free space accounting.
|
||||
* to free.
|
||||
*
|
||||
* Note: don't bother with iolock here since lockdep complains about
|
||||
* acquiring it in reclaim context. We have the only reference to the
|
||||
* inode at this point anyways.
|
||||
*/
|
||||
return xfs_can_free_eofblocks(ip, true);
|
||||
return xfs_can_free_eofblocks(ip);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1947,15 +1953,11 @@ xfs_inactive(
|
||||
|
||||
if (VFS_I(ip)->i_nlink != 0) {
|
||||
/*
|
||||
* force is true because we are evicting an inode from the
|
||||
* cache. Post-eof blocks must be freed, lest we end up with
|
||||
* broken free space accounting.
|
||||
*
|
||||
* Note: don't bother with iolock here since lockdep complains
|
||||
* about acquiring it in reclaim context. We have the only
|
||||
* reference to the inode at this point anyways.
|
||||
*/
|
||||
if (xfs_can_free_eofblocks(ip, true))
|
||||
if (xfs_can_free_eofblocks(ip))
|
||||
error = xfs_free_eofblocks(ip);
|
||||
|
||||
goto out;
|
||||
|
@ -1148,33 +1148,23 @@ xfs_buffered_write_iomap_begin(
|
||||
}
|
||||
}
|
||||
|
||||
retry:
|
||||
error = xfs_bmapi_reserve_delalloc(ip, allocfork, offset_fsb,
|
||||
end_fsb - offset_fsb, prealloc_blocks,
|
||||
allocfork == XFS_DATA_FORK ? &imap : &cmap,
|
||||
allocfork == XFS_DATA_FORK ? &icur : &ccur,
|
||||
allocfork == XFS_DATA_FORK ? eof : cow_eof);
|
||||
switch (error) {
|
||||
case 0:
|
||||
break;
|
||||
case -ENOSPC:
|
||||
case -EDQUOT:
|
||||
/* retry without any preallocation */
|
||||
trace_xfs_delalloc_enospc(ip, offset, count);
|
||||
if (prealloc_blocks) {
|
||||
prealloc_blocks = 0;
|
||||
goto retry;
|
||||
}
|
||||
fallthrough;
|
||||
default:
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (allocfork == XFS_COW_FORK) {
|
||||
error = xfs_bmapi_reserve_delalloc(ip, allocfork, offset_fsb,
|
||||
end_fsb - offset_fsb, prealloc_blocks, &cmap,
|
||||
&ccur, cow_eof);
|
||||
if (error)
|
||||
goto out_unlock;
|
||||
|
||||
trace_xfs_iomap_alloc(ip, offset, count, allocfork, &cmap);
|
||||
goto found_cow;
|
||||
}
|
||||
|
||||
error = xfs_bmapi_reserve_delalloc(ip, allocfork, offset_fsb,
|
||||
end_fsb - offset_fsb, prealloc_blocks, &imap, &icur,
|
||||
eof);
|
||||
if (error)
|
||||
goto out_unlock;
|
||||
|
||||
/*
|
||||
* Flag newly allocated delalloc blocks with IOMAP_F_NEW so we punch
|
||||
* them out if the write happens to fail.
|
||||
|
Loading…
Reference in New Issue
Block a user