// SPDX-License-Identifier: GPL-2.0-only
/*
 * Complete scope from Linux v6.18 fs/buffer.c.
 * Source: https://github.com/torvalds/linux/blob/v6.18/fs/buffer.c
 * Copyright (C) 1991, 1992, 2002  Linus Torvalds
 * Kernel excerpt; not a standalone program.
 * The book's exact source tag is not asserted.
 */

int generic_write_end(const struct kiocb *iocb, struct address_space *mapping,
		      loff_t pos, unsigned len, unsigned copied,
		      struct folio *folio, void *fsdata)
{
	struct inode *inode = mapping->host;
	loff_t old_size = inode->i_size;
	bool i_size_changed = false;

	copied = block_write_end(pos, len, copied, folio);

	/*
	 * No need to use i_size_read() here, the i_size cannot change under us
	 * because we hold i_rwsem.
	 *
	 * But it's important to update i_size while still holding folio lock:
	 * page writeout could otherwise come in and zero beyond i_size.
	 */
	if (pos + copied > inode->i_size) {
		i_size_write(inode, pos + copied);
		i_size_changed = true;
	}

	folio_unlock(folio);
	folio_put(folio);

	if (old_size < pos)
		pagecache_isize_extended(inode, old_size, pos);
	/*
	 * Don't mark the inode dirty under page lock. First, it unnecessarily
	 * makes the holding time of page lock longer. Second, it forces lock
	 * ordering of page lock and transaction start for journaling
	 * filesystems.
	 */
	if (i_size_changed)
		mark_inode_dirty(inode);
	return copied;
}
