xfs: fixes for v7.4-rc2

Signed-off-by: Carlos Maiolino <cem@kernel.org>
 -----BEGIN PGP SIGNATURE-----
 
 iJUEABMJAB0WIQSmtYVZ/MfVMGUq1GNcsMJ8RxYuYwUCau3PzQAKCRBcsMJ8RxYu
 Y5SKAYDYuEW5XCOtL9N7Vzm7wCRvhrVbmwXvGJ7X/niZ4zfGDU3OuIRGGuBO3Tlj
 TRbDdW0Bf2DhO9Szo8HZoapi7AkhUQcPc01HpMuaqcD785JrEwXnkBGHd/IhMyU7
 7XlKb1BrNw==
 =Yx7V
 -----END PGP SIGNATURE-----

Merge tag 'xfs-fixes-7.4-rc2' of git://git.kernel.org:/pub/scm/fs/xfs/xfs-linux

Pull xfs fixes from Carlos Maiolino:
 "The most notable fix here IMO is for xfs's pNFS support (mostly
  related to LAYOUTCOMMIT) and for that it contains several patches.

  Besides that, this contains bug fixes for different subsystems in xfs.
  The last patch is mostly a refactor than a bug fix, but the refactor
  is done to prevent a nasty journal transaction state corruption to
  happen"

* tag 'xfs-fixes-7.4-rc2' of git://git.kernel.org:/pub/scm/fs/xfs/xfs-linux:
  xfs: kill xfs_trans_set/clear_context() helpers
  xfs: fix recovery of partial attr removals
  xfs: make pNFS LAYOUTCOMMIT stable the way fdatasync does
  xfs: add datasync and log_flushed arguments to xfs_log_force_inode()
  xfs: take the invalidate lock while mapping a pNFS layout
  xfs: clamp the pNFS layout range to the maximum file size
  xfs: cap the block count of xfs_iomap_write_direct() at one extent
  xfs: clamp a pNFS LAYOUTCOMMIT extent before computing its end
  xfs: refuse a pNFS LAYOUTCOMMIT of a range without blocks
  xfs: add a flag to convert unwritten extents without allocating blocks
  xfs: mark the inode preallocated for pNFS write layouts past EOF
  xfs: fix wrong compat fields in xfs_ioctl32_bstat_copyin()
  xfs: fix temporary cursor leak in btree shift corruption paths
  xfs: skip iunlock with empty iolock flags in xfs_file_dio_write_aligned
  xfs: don't skip free extents of the longest length in a whole-AG FITRIM
  xfs: don't skip free extents in later batches of a whole-AG FITRIM
  xfs: fix unwind handling during xfs_mount_sysfs_init()
  xfs: mark i_mode=0 and shut down on attr fork inactivation failure
  xfs: set healthmon mount cookie before publishing it
This commit is contained in:
Linus Torvalds 2026-11-06 08:50:27 -08:00
commit 0ccc72d4b3
19 changed files with 202 additions and 129 deletions

View File

@ -3042,7 +3042,14 @@ xfs_attr3_leaf_setflag(
#endif
entry = &xfs_attr3_leaf_entryp(leaf)[args->index];
ASSERT((entry->flags & XFS_ATTR_INCOMPLETE) == 0);
if (entry->flags & XFS_ATTR_INCOMPLETE) {
if (!(args->op_flags & XFS_DA_OP_RECOVERY)) {
ASSERT(args->op_flags & XFS_DA_OP_RECOVERY);
return -EFSCORRUPTED;
}
return 0;
}
entry->flags |= XFS_ATTR_INCOMPLETE;
xfs_trans_log_buf(args->trans, bp,
XFS_DA_LOGRANGE(leaf, entry, sizeof(*entry)));

View File

@ -4130,6 +4130,8 @@ xfs_bmapi_finish(
* Returns a negative error code on failure, including -ENOSPC when it could not
* allocate any blocks and -ENOSR when it did allocate blocks to convert a
* delalloc range, but those blocks were before the passed in range.
* With XFS_BMAPI_CONVERT_ONLY, it stops at a hole or a delalloc extent instead
* of allocating blocks, and returns -ENOSR if it stops before mapping anything.
*/
int
xfs_bmapi_write(
@ -4189,6 +4191,8 @@ xfs_bmapi_write(
*/
ASSERT((flags & (XFS_BMAPI_PREALLOC | XFS_BMAPI_ZERO)) !=
(XFS_BMAPI_PREALLOC | XFS_BMAPI_ZERO));
ASSERT(!(flags & XFS_BMAPI_CONVERT_ONLY) ||
(flags & XFS_BMAPI_CONVERT));
if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ifp)) ||
XFS_TEST_ERROR(mp, XFS_ERRTAG_BMAPIFORMAT)) {
@ -4237,6 +4241,9 @@ xfs_bmapi_write(
* that we found, if any.
*/
if (need_alloc || wasdelay) {
if (flags & XFS_BMAPI_CONVERT_ONLY)
break;
bma.eof = eof;
bma.conv = !!(flags & XFS_BMAPI_CONVERT);
bma.wasdel = wasdelay;
@ -4332,10 +4339,13 @@ xfs_bmapi_write(
*
* To avoid a successful return with *nmap set to 0, return the magic
* -ENOSR error code for this particular case so that the caller can
* handle it.
* handle it. The same goes for XFS_BMAPI_CONVERT_ONLY stopping at a
* hole or a delalloc extent at the start of the range, in which case
* nothing has been changed.
*/
if (!n) {
ASSERT(bma.nallocs >= *nmap);
ASSERT((flags & XFS_BMAPI_CONVERT_ONLY) ? bma.nallocs == 0 :
bma.nallocs >= *nmap);
return -ENOSR;
}
*nmap = n;

View File

@ -90,6 +90,13 @@ struct xfs_bmalloca {
/* Try to align allocations to the extent size hint */
#define XFS_BMAPI_EXTSZALIGN (1u << 11)
/*
* Use with XFS_BMAPI_CONVERT to convert unwritten extents without allocating
* blocks. Stop at a hole or a delalloc extent: return the mappings found so
* far, or -ENOSR if there are none.
*/
#define XFS_BMAPI_CONVERT_ONLY (1u << 12)
#define XFS_BMAPI_FLAGS \
{ XFS_BMAPI_ENTIRE, "ENTIRE" }, \
{ XFS_BMAPI_METADATA, "METADATA" }, \
@ -102,7 +109,8 @@ struct xfs_bmalloca {
{ XFS_BMAPI_COWFORK, "COWFORK" }, \
{ XFS_BMAPI_NODISCARD, "NODISCARD" }, \
{ XFS_BMAPI_NORMAP, "NORMAP" },\
{ XFS_BMAPI_EXTSZALIGN, "EXTSZALIGN" }
{ XFS_BMAPI_EXTSZALIGN, "EXTSZALIGN" }, \
{ XFS_BMAPI_CONVERT_ONLY, "CONVERT_ONLY" }
static inline int xfs_bmapi_aflag(int w)

View File

@ -2567,7 +2567,7 @@ xfs_btree_lshift(
if (XFS_IS_CORRUPT(tcur->bc_mp, i != 1)) {
xfs_btree_mark_sick(cur);
error = -EFSCORRUPTED;
goto error0;
goto error1;
}
error = xfs_btree_decrement(tcur, level, &i);
@ -2737,7 +2737,7 @@ xfs_btree_rshift(
if (XFS_IS_CORRUPT(tcur->bc_mp, i != 1)) {
xfs_btree_mark_sick(cur);
error = -EFSCORRUPTED;
goto error0;
goto error1;
}
error = xfs_btree_increment(tcur, level, &i);
@ -3009,10 +3009,6 @@ xfs_btree_split_worker(
struct xfs_btree_split_args, work);
unsigned int nofs_flags;
/*
* Don't use xfs_trans_set_context() here: it would overwrite the
* caller's saved NOFS state in tp->t_pflags. Use a local scope.
*/
nofs_flags = memalloc_nofs_save();
args->result = __xfs_btree_split(args->cur, args->level, args->ptrp,

View File

@ -264,20 +264,6 @@ int xfs_trans_alloc_dir(struct xfs_inode *dp, struct xfs_trans_res *resv,
struct xfs_inode *ip, unsigned int *dblocks,
struct xfs_trans **tpp, int *nospace_error);
static inline void
xfs_trans_set_context(
struct xfs_trans *tp)
{
tp->t_pflags = memalloc_nofs_save();
}
static inline void
xfs_trans_clear_context(
struct xfs_trans *tp)
{
memalloc_nofs_restore(tp->t_pflags);
}
static inline void
xfs_trans_cancel(
struct xfs_trans *tp)

View File

@ -155,6 +155,8 @@ struct xfs_trim_cur {
xfs_agblock_t end;
xfs_extlen_t minlen;
bool by_bno;
/* restart point (with count) for the by-length walk */
xfs_agblock_t restart_bno;
};
static int
@ -198,14 +200,15 @@ xfs_trim_gather_extents(
error = xfs_alloc_lookup_le(cur, tcur->start, 0, &i);
if (!error && !i)
error = xfs_alloc_lookup_ge(cur, tcur->start, 0, &i);
} else if (tcur->start == 0) {
/* first time through a by-len starts with max length */
cur = xfs_cntbt_init_cursor(mp, tp, agbp, pag);
error = xfs_alloc_lookup_ge(cur, 0, tcur->count, &i);
} else {
/* nth time through a by-len starts where we left off */
/*
* A by-len walk starts at the last record of the longest
* length (restart_bno is NULLAGBLOCK until the first batch
* ends) and then where the previous batch stopped.
*/
cur = xfs_cntbt_init_cursor(mp, tp, agbp, pag);
error = xfs_alloc_lookup_le(cur, tcur->start, tcur->count, &i);
error = xfs_alloc_lookup_le(cur, tcur->restart_bno,
tcur->count, &i);
}
if (error)
goto out_del_cursor;
@ -235,9 +238,15 @@ xfs_trim_gather_extents(
if (--batch <= 0) {
/*
* Update the cursor to point at this extent so we
* restart the next batch from this extent.
* restart the next batch from this extent. The
* by-length walk does not visit extents in block
* order, so it must keep the start of the range and
* restart from restart_bno instead.
*/
tcur->start = fbno;
if (tcur->by_bno)
tcur->start = fbno;
else
tcur->restart_bno = fbno;
tcur->count = flen;
break;
}
@ -340,6 +349,7 @@ xfs_trim_perag_extents(
.start = start,
.end = end,
.minlen = minlen,
.restart_bno = NULLAGBLOCK,
};
int error = 0;

View File

@ -234,7 +234,7 @@ STATIC int
xfs_fs_nfs_commit_metadata(
struct inode *inode)
{
return xfs_log_force_inode(XFS_I(inode));
return xfs_log_force_inode(XFS_I(inode), false, NULL);
}
const struct export_operations xfs_export_operations = {

View File

@ -76,49 +76,7 @@ xfs_dir_fsync(
struct xfs_inode *ip = XFS_I(file->f_mapping->host);
trace_xfs_dir_fsync(ip);
return xfs_log_force_inode(ip);
}
/*
* All metadata updates are logged, which means that we just have to push the
* journal to the required sequence number than holds the updates. We track
* datasync commits separately to full sync commits, and hence only need to
* select the correct sequence number for the log force here.
*
* We don't have to serialise against concurrent modifications, as we do not
* have to wait for modifications that have not yet completed. We define a
* transaction commit as completing when the commit sequence number is updated,
* hence if the sequence number has not updated, the sync operation has been
* run before the commit completed and we don't have to wait for it.
*
* If we have concurrent fsync/fdatasync() calls, the sequence numbers remain
* set on the log item until - at least - the journal flush completes. In
* reality, they are only cleared when the inode is fully unpinned (i.e.
* persistent in the journal and not dirty in the CIL), and so we rely on
* xfs_log_force_seq() either skipping sequences that have been persisted or
* waiting on sequences that are still in flight to correctly order concurrent
* sync operations.
*/
static int
xfs_fsync_flush_log(
struct xfs_inode *ip,
bool datasync,
int *log_flushed)
{
struct xfs_inode_log_item *iip = ip->i_itemp;
xfs_csn_t seq = 0;
spin_lock(&iip->ili_lock);
if (datasync)
seq = iip->ili_datasync_seq;
else
seq = iip->ili_commit_seq;
spin_unlock(&iip->ili_lock);
if (!seq)
return 0;
return xfs_log_force_seq(ip->i_mount, seq, XFS_LOG_SYNC, log_flushed);
return xfs_log_force_inode(ip, false, NULL);
}
STATIC int
@ -151,7 +109,7 @@ xfs_file_fsync(
* no modifications to this inode that need to be pushed out.
*/
if (ip->i_itemp) {
error = xfs_fsync_flush_log(ip, datasync, &log_flushed);
error = xfs_log_force_inode(ip, datasync, &log_flushed);
if (error)
return error;
}
@ -666,7 +624,7 @@ xfs_dio_write_end_io(
* they are converted.
*/
if (flags & IOMAP_DIO_UNWRITTEN) {
error = xfs_iomap_write_unwritten(ip, offset, size, true);
error = xfs_iomap_write_unwritten(ip, offset, size, true, 0);
goto out;
}
@ -766,7 +724,8 @@ xfs_file_dio_write_aligned(
trace_xfs_file_direct_write(iocb, from);
ret = iomap_dio_rw(iocb, from, ops, dops, dio_flags, ac, 0);
out_unlock:
xfs_iunlock(ip, iolock);
if (iolock)
xfs_iunlock(ip, iolock);
return ret;
}
@ -1599,7 +1558,7 @@ __xfs_file_fallocate(
}
if (!error && xfs_file_sync_writes(file))
error = xfs_log_force_inode(ip);
error = xfs_log_force_inode(ip, false, NULL);
out_unlock:
xfs_iunlock(ip, iolock);
@ -1750,7 +1709,7 @@ xfs_file_remap_range(
goto out_unlock;
if (xfs_file_sync_writes(file_in) || xfs_file_sync_writes(file_out))
xfs_log_force_inode(dest);
xfs_log_force_inode(dest, false, NULL);
out_unlock:
xfs_iunlock2_remapping(src, dest);
if (ret)

View File

@ -114,8 +114,8 @@ xfs_healthmon_attach(
}
refcount_inc(&hm->ref);
rcu_assign_pointer(mp->m_healthmon, hm);
hm->mount_cookie = (uintptr_t)mp->m_super;
rcu_assign_pointer(mp->m_healthmon, hm);
spin_unlock(&xfs_healthmon_lock);
return 0;

View File

@ -1481,8 +1481,17 @@ xfs_inactive(
*/
if (xfs_inode_has_attr_fork(ip)) {
error = xfs_attr_inactive(ip);
if (error)
if (error) {
/*
* Attr teardown failed, leaking blocks with no in-core
* record. Clear i_mode to block xfs_iget() recycling,
* then shut down so recovery cleans up the inode.
*/
VFS_I(ip)->i_mode = 0;
if (!xfs_is_shutdown(mp))
xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
goto out;
}
}
ASSERT(ip->i_forkoff == 0);
@ -2669,11 +2678,36 @@ xfs_irele(
}
/*
* Ensure all committed transactions touching the inode are written to the log.
* Ensure all committed transactions touching the inode are written to the log,
* or with @datasync only those that fdatasync has to wait for.
*
* All metadata updates are logged, which means that we just have to push the
* journal to the required sequence number that holds the updates. We track
* datasync commits separately to full sync commits, and hence only need to
* select the correct sequence number for the log force here.
*
* We don't have to serialise against concurrent modifications, as we do not
* have to wait for modifications that have not yet completed. We define a
* transaction commit as completing when the commit sequence number is updated,
* hence if the sequence number has not updated, the sync operation has been
* run before the commit completed and we don't have to wait for it.
*
* If we have concurrent fsync/fdatasync() calls, the sequence numbers remain
* set on the log item until - at least - the journal flush completes. In
* reality, they are only cleared when the inode is fully unpinned (i.e.
* persistent in the journal and not dirty in the CIL), and so we rely on
* xfs_log_force_seq() either skipping sequences that have been persisted or
* waiting on sequences that are still in flight to correctly order concurrent
* sync operations.
*
* If @log_flushed is not NULL, it is set when the log force wrote an iclog,
* which flushes the device caches before the log write.
*/
int
xfs_log_force_inode(
struct xfs_inode *ip)
struct xfs_inode *ip,
bool datasync,
int *log_flushed)
{
struct xfs_inode_log_item *iip = ip->i_itemp;
xfs_csn_t seq = 0;
@ -2682,12 +2716,15 @@ xfs_log_force_inode(
return 0;
spin_lock(&iip->ili_lock);
seq = iip->ili_commit_seq;
if (datasync)
seq = iip->ili_datasync_seq;
else
seq = iip->ili_commit_seq;
spin_unlock(&iip->ili_lock);
if (!seq)
return 0;
return xfs_log_force_seq(ip->i_mount, seq, XFS_LOG_SYNC, NULL);
return xfs_log_force_seq(ip->i_mount, seq, XFS_LOG_SYNC, log_flushed);
}
/*

View File

@ -595,7 +595,8 @@ int xfs_ifree(struct xfs_trans *, struct xfs_inode *);
int xfs_itruncate_extents_flags(struct xfs_trans **,
struct xfs_inode *, int, xfs_fsize_t, int);
int xfs_log_force_inode(struct xfs_inode *ip);
int xfs_log_force_inode(struct xfs_inode *ip, bool datasync,
int *log_flushed);
void xfs_iunpin_wait(xfs_inode_t *);
#define xfs_ipincount(ip) ((unsigned int) atomic_read(&ip->i_pincount))

View File

@ -143,8 +143,8 @@ xfs_ioctl32_bstat_copyin(
xfs_ioctl32_bstime_copyin(&bstat->bs_atime, &bstat32->bs_atime) ||
xfs_ioctl32_bstime_copyin(&bstat->bs_mtime, &bstat32->bs_mtime) ||
xfs_ioctl32_bstime_copyin(&bstat->bs_ctime, &bstat32->bs_ctime) ||
get_user(bstat->bs_blocks, &bstat32->bs_size) ||
get_user(bstat->bs_xflags, &bstat32->bs_size) ||
get_user(bstat->bs_blocks, &bstat32->bs_blocks) ||
get_user(bstat->bs_xflags, &bstat32->bs_xflags) ||
get_user(bstat->bs_extsize, &bstat32->bs_extsize) ||
get_user(bstat->bs_extents, &bstat32->bs_extents) ||
get_user(bstat->bs_gen, &bstat32->bs_gen) ||

View File

@ -237,7 +237,7 @@ xfs_end_ioend_write(
if (ioend->io_flags & IOMAP_IOEND_SHARED)
error = xfs_reflink_end_cow(ip, offset, size);
else if (ioend->io_flags & IOMAP_IOEND_UNWRITTEN)
error = xfs_iomap_write_unwritten(ip, offset, size, false);
error = xfs_iomap_write_unwritten(ip, offset, size, false, 0);
if (!error &&
!(ioend->io_flags & IOMAP_IOEND_DIRECT) &&

View File

@ -285,6 +285,14 @@ xfs_iomap_write_direct(
ASSERT(count_fsb > 0);
/*
* xfs_bmapi_write() maps at most XFS_MAX_BMBT_EXTLEN blocks in one
* mapping, so don't reserve blocks for more. A pNFS layout range
* comes from a client, and its block count may not even fit the
* 32-bit reservation. The caller maps the rest with a later call.
*/
count_fsb = min_t(xfs_filblks_t, count_fsb, XFS_MAX_BMBT_EXTLEN);
resaligned = xfs_aligned_fsb_count(offset_fsb, count_fsb,
xfs_get_extsz_hint(ip));
if (unlikely(XFS_IS_REALTIME_INODE(ip))) {
@ -614,7 +622,8 @@ xfs_iomap_write_unwritten(
xfs_inode_t *ip,
xfs_off_t offset,
xfs_off_t count,
bool update_isize)
bool update_isize,
uint32_t bmapi_flags)
{
xfs_mount_t *mp = ip->i_mount;
xfs_fileoff_t offset_fsb;
@ -676,8 +685,21 @@ xfs_iomap_write_unwritten(
*/
nimaps = 1;
error = xfs_bmapi_write(tp, ip, offset_fsb, count_fsb,
XFS_BMAPI_CONVERT, resblks, &imap,
&nimaps);
XFS_BMAPI_CONVERT | bmapi_flags,
resblks, &imap, &nimaps);
if (error == -ENOSR && (bmapi_flags & XFS_BMAPI_CONVERT_ONLY)) {
/*
* Nothing was mapped: the rest of the range starts
* with a hole or a delalloc extent. Nothing was
* changed either, but xfs_iext_count_extend() may
* have logged the inode, and cancelling a dirty
* transaction shuts the filesystem down. Commit it,
* as xfs_alloc_file_space() does on -ENOSR.
*/
error = xfs_trans_commit(tp);
xfs_iunlock(ip, XFS_ILOCK_EXCL);
return error ? error : -EIO;
}
if (error)
goto error_on_bmapi_transaction;

View File

@ -15,7 +15,8 @@ struct xfs_zone_alloc_ctx;
int xfs_iomap_write_direct(struct xfs_inode *ip, xfs_fileoff_t offset_fsb,
xfs_fileoff_t count_fsb, unsigned int flags,
struct xfs_bmbt_irec *imap, u64 *sequence);
int xfs_iomap_write_unwritten(struct xfs_inode *, xfs_off_t, xfs_off_t, bool);
int xfs_iomap_write_unwritten(struct xfs_inode *ip, xfs_off_t offset,
xfs_off_t count, bool update_isize, uint32_t bmapi_flags);
xfs_fileoff_t xfs_iomap_eof_align_last_fsb(struct xfs_inode *ip,
xfs_fileoff_t end_fsb);

View File

@ -110,7 +110,15 @@ xfs_fs_map_update_inode(
ip->i_diflags |= XFS_DIFLAG_PREALLOC;
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
return xfs_trans_commit(tp);
error = xfs_trans_commit(tp);
if (error)
return error;
/*
* Force the log so that the blocks handed out to the client are
* guaranteed to be present even after a server crash.
*/
return xfs_log_force_inode(ip, false, NULL);
}
/*
@ -134,6 +142,7 @@ xfs_fs_map_blocks(
uint lock_flags;
int error = 0;
u64 seq;
bool update_inode = false;
if (xfs_is_shutdown(mp))
return -EIO;
@ -159,18 +168,20 @@ xfs_fs_map_blocks(
* similar to direct I/O, except that the synchronization is much more
* complicated. See the comment near xfs_break_leased_layouts
* for a detailed explanation.
*
* Take the invalidate lock as well, so that page faults cannot add
* delalloc extents to the range while it is being mapped.
*/
xfs_ilock(ip, XFS_IOLOCK_EXCL);
xfs_ilock(ip, XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL);
error = -EINVAL;
limit = mp->m_super->s_maxbytes;
if (!write)
limit = max(limit, round_up(i_size_read(inode),
inode->i_sb->s_blocksize));
if (offset > limit)
if (offset < 0 || offset >= limit)
goto out_unlock;
if (offset > limit - length)
length = limit - offset;
length = min_t(u64, length, limit - offset);
error = filemap_write_and_wait(inode->i_mapping);
if (error)
@ -221,28 +232,35 @@ xfs_fs_map_blocks(
end_fsb - offset_fsb, 0, &imap, &seq);
if (error)
goto out_unlock;
/*
* Ensure the next transaction is committed synchronously so
* that the blocks allocated and handed out to the client are
* guaranteed to be present even after a server crash.
*/
error = xfs_fs_map_update_inode(ip);
if (!error)
error = xfs_log_force_inode(ip);
if (error)
goto out_unlock;
update_inode = true;
} else {
xfs_iunlock(ip, lock_flags);
/*
* Blocks past EOF that were allocated for buffered writes, such
* as speculative preallocation, can be freed by
* xfs_free_eofblocks() without breaking the layout unless the
* inode is marked as preallocated. Mark it before handing them
* out for writing, as for blocks allocated above.
*/
if (write && !(ip->i_diflags & XFS_DIFLAG_PREALLOC) &&
imap.br_startoff + imap.br_blockcount >
XFS_B_TO_FSB(mp, XFS_ISIZE(ip)))
update_inode = true;
}
xfs_iunlock(ip, XFS_IOLOCK_EXCL);
if (update_inode) {
error = xfs_fs_map_update_inode(ip);
if (error)
goto out_unlock;
}
xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL);
error = xfs_bmbt_to_iomap(ip, iomap, &imap, 0, 0, seq);
*device_generation = mp->m_generation;
return error;
out_unlock:
xfs_iunlock(ip, XFS_IOLOCK_EXCL);
xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL);
return error;
}
@ -277,10 +295,12 @@ xfs_pnfs_validate_isize(
* converting any unwritten extents, flushing the disk cache and updating the
* time stamps.
*
* Note that we rely on the caller to always send us a timestamp update so that
* we always commit a transaction here. If that stops being true we will have
* to manually flush the cache here similar to what the fsync code path does
* for datasyncs on files that have no dirty metadata.
* Like fdatasync, a commit that only updates the timestamps does not force the
* log: they are logged as XFS_ILOG_TIMESTAMP and reach the disk with a later
* log write. The log is forced up to the last change that a datasync needs,
* such as the unwritten extent conversions or a new size, and the cache of the
* device holding the file data is flushed if that log force did not write an
* iclog itself.
*/
static int
xfs_fs_commit_blocks(
@ -294,6 +314,7 @@ xfs_fs_commit_blocks(
struct xfs_trans *tp;
struct timespec64 now;
bool update_isize = false;
int log_flushed = 0;
int error, i;
loff_t size;
@ -312,9 +333,7 @@ xfs_fs_commit_blocks(
if (start > size)
continue;
end = start + maps[i].length;
if (end > size)
end = size;
end = start + min_t(u64, maps[i].length, size - start);
length = end - start;
if (!length)
@ -328,7 +347,14 @@ xfs_fs_commit_blocks(
(end - 1) >> PAGE_SHIFT);
WARN_ON_ONCE(error);
error = xfs_iomap_write_unwritten(ip, start, length, false);
/*
* A client may only write to blocks that a layout handed out,
* and xfs_fs_map_blocks() allocates blocks for any hole in a
* write layout, so refuse to allocate blocks for a hole or a
* delalloc extent in the committed range.
*/
error = xfs_iomap_write_unwritten(ip, start, length, false,
XFS_BMAPI_CONVERT_ONLY);
if (error)
goto out_drop_iolock;
}
@ -345,7 +371,8 @@ xfs_fs_commit_blocks(
xfs_ilock(ip, XFS_ILOCK_EXCL);
xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
xfs_trans_log_inode(tp, ip,
update_isize ? XFS_ILOG_CORE : XFS_ILOG_TIMESTAMP);
now = inode_set_ctime_current(inode);
inode_set_atime_to_ts(inode, now);
@ -356,8 +383,13 @@ xfs_fs_commit_blocks(
ip->i_disk_size = new_size;
}
xfs_trans_set_sync(tp);
error = xfs_trans_commit(tp);
if (error)
goto out_drop_iolock;
error = xfs_log_force_inode(ip, true, &log_flushed);
if (!error && !log_flushed)
error = blkdev_issue_flush(xfs_inode_buftarg(ip)->bt_bdev);
out_drop_iolock:
xfs_iunlock(ip, XFS_IOLOCK_EXCL);

View File

@ -906,7 +906,7 @@ xfs_mount_sysfs_init(
"metadata", &mp->m_error_meta_kobj,
xfs_error_meta_init);
if (error)
goto out_remove_csum_dir;
goto out_remove_error_dir;
return 0;

View File

@ -72,7 +72,7 @@ xfs_trans_free(
xfs_extent_busy_clear(&tp->t_busy, false);
trace_xfs_trans_free(tp, _RET_IP_);
xfs_trans_clear_context(tp);
memalloc_nofs_restore(tp->t_pflags);
if (!(tp->t_flags & XFS_TRANS_NO_WRITECOUNT))
sb_end_intwrite(tp->t_mountp->m_super);
xfs_trans_free_dqinfo(tp);
@ -220,7 +220,11 @@ __xfs_trans_alloc(
tp = kmem_cache_zalloc(xfs_trans_cache, GFP_KERNEL | __GFP_NOFAIL);
if (!(flags & XFS_TRANS_NO_WRITECOUNT))
sb_start_intwrite(mp->m_super);
xfs_trans_set_context(tp);
/*
* Save NOFS state for xfs_trans_free() to restore. Only the
* transaction owner thread may touch tp->t_pflags.
*/
tp->t_pflags = memalloc_nofs_save();
tp->t_flags = flags;
tp->t_mountp = mp;
INIT_LIST_HEAD(&tp->t_items);
@ -1038,7 +1042,7 @@ xfs_trans_roll(
* xfs_trans_free. Set it again here before doing memory
* allocations.
*/
xfs_trans_set_context(tp);
tp->t_pflags = memalloc_nofs_save();
if (error)
return error;

View File

@ -1018,7 +1018,7 @@ xfs_zone_gc_reset_zones(
struct xfs_gc_bio *chunk;
struct bio *bio;
xfs_log_force_inode(rtg_rmap(rtg));
xfs_log_force_inode(rtg_rmap(rtg), false, NULL);
next = rtg_group(rtg)->xg_next_reset;
rtg_group(rtg)->xg_next_reset = NULL;