diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c index 6068fad9dc9e..82932b5c02fd 100644 --- a/fs/xfs/libxfs/xfs_attr_leaf.c +++ b/fs/xfs/libxfs/xfs_attr_leaf.c @@ -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))); diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index ca49bf4a50c5..050522c58b16 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c @@ -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; diff --git a/fs/xfs/libxfs/xfs_bmap.h b/fs/xfs/libxfs/xfs_bmap.h index e9f5416e4c05..fb7481e8190c 100644 --- a/fs/xfs/libxfs/xfs_bmap.h +++ b/fs/xfs/libxfs/xfs_bmap.h @@ -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) diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c index 2434c54a3570..5d1d73f99ce0 100644 --- a/fs/xfs/libxfs/xfs_btree.c +++ b/fs/xfs/libxfs/xfs_btree.c @@ -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, diff --git a/fs/xfs/libxfs/xfs_trans.h b/fs/xfs/libxfs/xfs_trans.h index 05b3cc19a311..b0c7724d0619 100644 --- a/fs/xfs/libxfs/xfs_trans.h +++ b/fs/xfs/libxfs/xfs_trans.h @@ -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) diff --git a/fs/xfs/xfs_discard.c b/fs/xfs/xfs_discard.c index 906221ffe9ba..cdf660344c28 100644 --- a/fs/xfs/xfs_discard.c +++ b/fs/xfs/xfs_discard.c @@ -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; diff --git a/fs/xfs/xfs_export.c b/fs/xfs/xfs_export.c index 9afda52ed1a2..9dd6dd8c27c8 100644 --- a/fs/xfs/xfs_export.c +++ b/fs/xfs/xfs_export.c @@ -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 = { diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 7d0c8a197575..396aca8c66a9 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c @@ -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) diff --git a/fs/xfs/xfs_healthmon.c b/fs/xfs/xfs_healthmon.c index 2bdd747f1ead..05d6f0494139 100644 --- a/fs/xfs/xfs_healthmon.c +++ b/fs/xfs/xfs_healthmon.c @@ -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; diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 05a14da28031..cb61305e4b80 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -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); } /* diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index 75eff68c1e39..b16eee99b567 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h @@ -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)) diff --git a/fs/xfs/xfs_ioctl32.c b/fs/xfs/xfs_ioctl32.c index f6875a2cc706..77bc936bf0d9 100644 --- a/fs/xfs/xfs_ioctl32.c +++ b/fs/xfs/xfs_ioctl32.c @@ -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) || diff --git a/fs/xfs/xfs_ioend.c b/fs/xfs/xfs_ioend.c index 48becc3bf608..7f4a4a95afe5 100644 --- a/fs/xfs/xfs_ioend.c +++ b/fs/xfs/xfs_ioend.c @@ -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) && diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c index 329c745e3120..c3465204b8d5 100644 --- a/fs/xfs/xfs_iomap.c +++ b/fs/xfs/xfs_iomap.c @@ -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; diff --git a/fs/xfs/xfs_iomap.h b/fs/xfs/xfs_iomap.h index f2520a9b3a13..8fc0c6fc8bea 100644 --- a/fs/xfs/xfs_iomap.h +++ b/fs/xfs/xfs_iomap.h @@ -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); diff --git a/fs/xfs/xfs_pnfs.c b/fs/xfs/xfs_pnfs.c index ab385617003a..065875c8b7da 100644 --- a/fs/xfs/xfs_pnfs.c +++ b/fs/xfs/xfs_pnfs.c @@ -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); diff --git a/fs/xfs/xfs_sysfs.c b/fs/xfs/xfs_sysfs.c index e77917ac179d..4a6a8c92c3a1 100644 --- a/fs/xfs/xfs_sysfs.c +++ b/fs/xfs/xfs_sysfs.c @@ -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; diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c index 8f0c308f312f..973e82e1e323 100644 --- a/fs/xfs/xfs_trans.c +++ b/fs/xfs/xfs_trans.c @@ -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; diff --git a/fs/xfs/xfs_zone_gc.c b/fs/xfs/xfs_zone_gc.c index 54b70ed2922f..cea5447a886d 100644 --- a/fs/xfs/xfs_zone_gc.c +++ b/fs/xfs/xfs_zone_gc.c @@ -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;