162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2018-2023 Oracle.  All Rights Reserved.
462306a36Sopenharmony_ci * Author: Darrick J. Wong <djwong@kernel.org>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci#include "xfs.h"
762306a36Sopenharmony_ci#include "xfs_fs.h"
862306a36Sopenharmony_ci#include "xfs_shared.h"
962306a36Sopenharmony_ci#include "xfs_format.h"
1062306a36Sopenharmony_ci#include "xfs_log_format.h"
1162306a36Sopenharmony_ci#include "xfs_trans_resv.h"
1262306a36Sopenharmony_ci#include "xfs_mount.h"
1362306a36Sopenharmony_ci#include "scrub/xfile.h"
1462306a36Sopenharmony_ci#include "scrub/xfarray.h"
1562306a36Sopenharmony_ci#include "scrub/scrub.h"
1662306a36Sopenharmony_ci#include "scrub/trace.h"
1762306a36Sopenharmony_ci#include <linux/shmem_fs.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci/*
2062306a36Sopenharmony_ci * Swappable Temporary Memory
2162306a36Sopenharmony_ci * ==========================
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci * Online checking sometimes needs to be able to stage a large amount of data
2462306a36Sopenharmony_ci * in memory.  This information might not fit in the available memory and it
2562306a36Sopenharmony_ci * doesn't all need to be accessible at all times.  In other words, we want an
2662306a36Sopenharmony_ci * indexed data buffer to store data that can be paged out.
2762306a36Sopenharmony_ci *
2862306a36Sopenharmony_ci * When CONFIG_TMPFS=y, shmemfs is enough of a filesystem to meet those
2962306a36Sopenharmony_ci * requirements.  Therefore, the xfile mechanism uses an unlinked shmem file to
3062306a36Sopenharmony_ci * store our staging data.  This file is not installed in the file descriptor
3162306a36Sopenharmony_ci * table so that user programs cannot access the data, which means that the
3262306a36Sopenharmony_ci * xfile must be freed with xfile_destroy.
3362306a36Sopenharmony_ci *
3462306a36Sopenharmony_ci * xfiles assume that the caller will handle all required concurrency
3562306a36Sopenharmony_ci * management; standard vfs locks (freezer and inode) are not taken.  Reads
3662306a36Sopenharmony_ci * and writes are satisfied directly from the page cache.
3762306a36Sopenharmony_ci *
3862306a36Sopenharmony_ci * NOTE: The current shmemfs implementation has a quirk that in-kernel reads
3962306a36Sopenharmony_ci * of a hole cause a page to be mapped into the file.  If you are going to
4062306a36Sopenharmony_ci * create a sparse xfile, please be careful about reading from uninitialized
4162306a36Sopenharmony_ci * parts of the file.  These pages are !Uptodate and will eventually be
4262306a36Sopenharmony_ci * reclaimed if not written, but in the short term this boosts memory
4362306a36Sopenharmony_ci * consumption.
4462306a36Sopenharmony_ci */
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci/*
4762306a36Sopenharmony_ci * xfiles must not be exposed to userspace and require upper layers to
4862306a36Sopenharmony_ci * coordinate access to the one handle returned by the constructor, so
4962306a36Sopenharmony_ci * establish a separate lock class for xfiles to avoid confusing lockdep.
5062306a36Sopenharmony_ci */
5162306a36Sopenharmony_cistatic struct lock_class_key xfile_i_mutex_key;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci/*
5462306a36Sopenharmony_ci * Create an xfile of the given size.  The description will be used in the
5562306a36Sopenharmony_ci * trace output.
5662306a36Sopenharmony_ci */
5762306a36Sopenharmony_ciint
5862306a36Sopenharmony_cixfile_create(
5962306a36Sopenharmony_ci	const char		*description,
6062306a36Sopenharmony_ci	loff_t			isize,
6162306a36Sopenharmony_ci	struct xfile		**xfilep)
6262306a36Sopenharmony_ci{
6362306a36Sopenharmony_ci	struct inode		*inode;
6462306a36Sopenharmony_ci	struct xfile		*xf;
6562306a36Sopenharmony_ci	int			error = -ENOMEM;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	xf = kmalloc(sizeof(struct xfile), XCHK_GFP_FLAGS);
6862306a36Sopenharmony_ci	if (!xf)
6962306a36Sopenharmony_ci		return -ENOMEM;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	xf->file = shmem_file_setup(description, isize, 0);
7262306a36Sopenharmony_ci	if (!xf->file)
7362306a36Sopenharmony_ci		goto out_xfile;
7462306a36Sopenharmony_ci	if (IS_ERR(xf->file)) {
7562306a36Sopenharmony_ci		error = PTR_ERR(xf->file);
7662306a36Sopenharmony_ci		goto out_xfile;
7762306a36Sopenharmony_ci	}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	/*
8062306a36Sopenharmony_ci	 * We want a large sparse file that we can pread, pwrite, and seek.
8162306a36Sopenharmony_ci	 * xfile users are responsible for keeping the xfile hidden away from
8262306a36Sopenharmony_ci	 * all other callers, so we skip timestamp updates and security checks.
8362306a36Sopenharmony_ci	 * Make the inode only accessible by root, just in case the xfile ever
8462306a36Sopenharmony_ci	 * escapes.
8562306a36Sopenharmony_ci	 */
8662306a36Sopenharmony_ci	xf->file->f_mode |= FMODE_PREAD | FMODE_PWRITE | FMODE_NOCMTIME |
8762306a36Sopenharmony_ci			    FMODE_LSEEK;
8862306a36Sopenharmony_ci	xf->file->f_flags |= O_RDWR | O_LARGEFILE | O_NOATIME;
8962306a36Sopenharmony_ci	inode = file_inode(xf->file);
9062306a36Sopenharmony_ci	inode->i_flags |= S_PRIVATE | S_NOCMTIME | S_NOATIME;
9162306a36Sopenharmony_ci	inode->i_mode &= ~0177;
9262306a36Sopenharmony_ci	inode->i_uid = GLOBAL_ROOT_UID;
9362306a36Sopenharmony_ci	inode->i_gid = GLOBAL_ROOT_GID;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	lockdep_set_class(&inode->i_rwsem, &xfile_i_mutex_key);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	trace_xfile_create(xf);
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	*xfilep = xf;
10062306a36Sopenharmony_ci	return 0;
10162306a36Sopenharmony_ciout_xfile:
10262306a36Sopenharmony_ci	kfree(xf);
10362306a36Sopenharmony_ci	return error;
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci/* Close the file and release all resources. */
10762306a36Sopenharmony_civoid
10862306a36Sopenharmony_cixfile_destroy(
10962306a36Sopenharmony_ci	struct xfile		*xf)
11062306a36Sopenharmony_ci{
11162306a36Sopenharmony_ci	struct inode		*inode = file_inode(xf->file);
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	trace_xfile_destroy(xf);
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	lockdep_set_class(&inode->i_rwsem, &inode->i_sb->s_type->i_mutex_key);
11662306a36Sopenharmony_ci	fput(xf->file);
11762306a36Sopenharmony_ci	kfree(xf);
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci/*
12162306a36Sopenharmony_ci * Read a memory object directly from the xfile's page cache.  Unlike regular
12262306a36Sopenharmony_ci * pread, we return -E2BIG and -EFBIG for reads that are too large or at too
12362306a36Sopenharmony_ci * high an offset, instead of truncating the read.  Otherwise, we return
12462306a36Sopenharmony_ci * bytes read or an error code, like regular pread.
12562306a36Sopenharmony_ci */
12662306a36Sopenharmony_cissize_t
12762306a36Sopenharmony_cixfile_pread(
12862306a36Sopenharmony_ci	struct xfile		*xf,
12962306a36Sopenharmony_ci	void			*buf,
13062306a36Sopenharmony_ci	size_t			count,
13162306a36Sopenharmony_ci	loff_t			pos)
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci	struct inode		*inode = file_inode(xf->file);
13462306a36Sopenharmony_ci	struct address_space	*mapping = inode->i_mapping;
13562306a36Sopenharmony_ci	struct page		*page = NULL;
13662306a36Sopenharmony_ci	ssize_t			read = 0;
13762306a36Sopenharmony_ci	unsigned int		pflags;
13862306a36Sopenharmony_ci	int			error = 0;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	if (count > MAX_RW_COUNT)
14162306a36Sopenharmony_ci		return -E2BIG;
14262306a36Sopenharmony_ci	if (inode->i_sb->s_maxbytes - pos < count)
14362306a36Sopenharmony_ci		return -EFBIG;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	trace_xfile_pread(xf, pos, count);
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	pflags = memalloc_nofs_save();
14862306a36Sopenharmony_ci	while (count > 0) {
14962306a36Sopenharmony_ci		void		*p, *kaddr;
15062306a36Sopenharmony_ci		unsigned int	len;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci		len = min_t(ssize_t, count, PAGE_SIZE - offset_in_page(pos));
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci		/*
15562306a36Sopenharmony_ci		 * In-kernel reads of a shmem file cause it to allocate a page
15662306a36Sopenharmony_ci		 * if the mapping shows a hole.  Therefore, if we hit ENOMEM
15762306a36Sopenharmony_ci		 * we can continue by zeroing the caller's buffer.
15862306a36Sopenharmony_ci		 */
15962306a36Sopenharmony_ci		page = shmem_read_mapping_page_gfp(mapping, pos >> PAGE_SHIFT,
16062306a36Sopenharmony_ci				__GFP_NOWARN);
16162306a36Sopenharmony_ci		if (IS_ERR(page)) {
16262306a36Sopenharmony_ci			error = PTR_ERR(page);
16362306a36Sopenharmony_ci			if (error != -ENOMEM)
16462306a36Sopenharmony_ci				break;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci			memset(buf, 0, len);
16762306a36Sopenharmony_ci			goto advance;
16862306a36Sopenharmony_ci		}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci		if (PageUptodate(page)) {
17162306a36Sopenharmony_ci			/*
17262306a36Sopenharmony_ci			 * xfile pages must never be mapped into userspace, so
17362306a36Sopenharmony_ci			 * we skip the dcache flush.
17462306a36Sopenharmony_ci			 */
17562306a36Sopenharmony_ci			kaddr = kmap_local_page(page);
17662306a36Sopenharmony_ci			p = kaddr + offset_in_page(pos);
17762306a36Sopenharmony_ci			memcpy(buf, p, len);
17862306a36Sopenharmony_ci			kunmap_local(kaddr);
17962306a36Sopenharmony_ci		} else {
18062306a36Sopenharmony_ci			memset(buf, 0, len);
18162306a36Sopenharmony_ci		}
18262306a36Sopenharmony_ci		put_page(page);
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ciadvance:
18562306a36Sopenharmony_ci		count -= len;
18662306a36Sopenharmony_ci		pos += len;
18762306a36Sopenharmony_ci		buf += len;
18862306a36Sopenharmony_ci		read += len;
18962306a36Sopenharmony_ci	}
19062306a36Sopenharmony_ci	memalloc_nofs_restore(pflags);
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	if (read > 0)
19362306a36Sopenharmony_ci		return read;
19462306a36Sopenharmony_ci	return error;
19562306a36Sopenharmony_ci}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci/*
19862306a36Sopenharmony_ci * Write a memory object directly to the xfile's page cache.  Unlike regular
19962306a36Sopenharmony_ci * pwrite, we return -E2BIG and -EFBIG for writes that are too large or at too
20062306a36Sopenharmony_ci * high an offset, instead of truncating the write.  Otherwise, we return
20162306a36Sopenharmony_ci * bytes written or an error code, like regular pwrite.
20262306a36Sopenharmony_ci */
20362306a36Sopenharmony_cissize_t
20462306a36Sopenharmony_cixfile_pwrite(
20562306a36Sopenharmony_ci	struct xfile		*xf,
20662306a36Sopenharmony_ci	const void		*buf,
20762306a36Sopenharmony_ci	size_t			count,
20862306a36Sopenharmony_ci	loff_t			pos)
20962306a36Sopenharmony_ci{
21062306a36Sopenharmony_ci	struct inode		*inode = file_inode(xf->file);
21162306a36Sopenharmony_ci	struct address_space	*mapping = inode->i_mapping;
21262306a36Sopenharmony_ci	const struct address_space_operations *aops = mapping->a_ops;
21362306a36Sopenharmony_ci	struct page		*page = NULL;
21462306a36Sopenharmony_ci	ssize_t			written = 0;
21562306a36Sopenharmony_ci	unsigned int		pflags;
21662306a36Sopenharmony_ci	int			error = 0;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	if (count > MAX_RW_COUNT)
21962306a36Sopenharmony_ci		return -E2BIG;
22062306a36Sopenharmony_ci	if (inode->i_sb->s_maxbytes - pos < count)
22162306a36Sopenharmony_ci		return -EFBIG;
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	trace_xfile_pwrite(xf, pos, count);
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	pflags = memalloc_nofs_save();
22662306a36Sopenharmony_ci	while (count > 0) {
22762306a36Sopenharmony_ci		void		*fsdata = NULL;
22862306a36Sopenharmony_ci		void		*p, *kaddr;
22962306a36Sopenharmony_ci		unsigned int	len;
23062306a36Sopenharmony_ci		int		ret;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci		len = min_t(ssize_t, count, PAGE_SIZE - offset_in_page(pos));
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci		/*
23562306a36Sopenharmony_ci		 * We call write_begin directly here to avoid all the freezer
23662306a36Sopenharmony_ci		 * protection lock-taking that happens in the normal path.
23762306a36Sopenharmony_ci		 * shmem doesn't support fs freeze, but lockdep doesn't know
23862306a36Sopenharmony_ci		 * that and will trip over that.
23962306a36Sopenharmony_ci		 */
24062306a36Sopenharmony_ci		error = aops->write_begin(NULL, mapping, pos, len, &page,
24162306a36Sopenharmony_ci				&fsdata);
24262306a36Sopenharmony_ci		if (error)
24362306a36Sopenharmony_ci			break;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci		/*
24662306a36Sopenharmony_ci		 * xfile pages must never be mapped into userspace, so we skip
24762306a36Sopenharmony_ci		 * the dcache flush.  If the page is not uptodate, zero it
24862306a36Sopenharmony_ci		 * before writing data.
24962306a36Sopenharmony_ci		 */
25062306a36Sopenharmony_ci		kaddr = kmap_local_page(page);
25162306a36Sopenharmony_ci		if (!PageUptodate(page)) {
25262306a36Sopenharmony_ci			memset(kaddr, 0, PAGE_SIZE);
25362306a36Sopenharmony_ci			SetPageUptodate(page);
25462306a36Sopenharmony_ci		}
25562306a36Sopenharmony_ci		p = kaddr + offset_in_page(pos);
25662306a36Sopenharmony_ci		memcpy(p, buf, len);
25762306a36Sopenharmony_ci		kunmap_local(kaddr);
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci		ret = aops->write_end(NULL, mapping, pos, len, len, page,
26062306a36Sopenharmony_ci				fsdata);
26162306a36Sopenharmony_ci		if (ret < 0) {
26262306a36Sopenharmony_ci			error = ret;
26362306a36Sopenharmony_ci			break;
26462306a36Sopenharmony_ci		}
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci		written += ret;
26762306a36Sopenharmony_ci		if (ret != len)
26862306a36Sopenharmony_ci			break;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci		count -= ret;
27162306a36Sopenharmony_ci		pos += ret;
27262306a36Sopenharmony_ci		buf += ret;
27362306a36Sopenharmony_ci	}
27462306a36Sopenharmony_ci	memalloc_nofs_restore(pflags);
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	if (written > 0)
27762306a36Sopenharmony_ci		return written;
27862306a36Sopenharmony_ci	return error;
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci/* Find the next written area in the xfile data for a given offset. */
28262306a36Sopenharmony_ciloff_t
28362306a36Sopenharmony_cixfile_seek_data(
28462306a36Sopenharmony_ci	struct xfile		*xf,
28562306a36Sopenharmony_ci	loff_t			pos)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	loff_t			ret;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	ret = vfs_llseek(xf->file, pos, SEEK_DATA);
29062306a36Sopenharmony_ci	trace_xfile_seek_data(xf, pos, ret);
29162306a36Sopenharmony_ci	return ret;
29262306a36Sopenharmony_ci}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci/* Query stat information for an xfile. */
29562306a36Sopenharmony_ciint
29662306a36Sopenharmony_cixfile_stat(
29762306a36Sopenharmony_ci	struct xfile		*xf,
29862306a36Sopenharmony_ci	struct xfile_stat	*statbuf)
29962306a36Sopenharmony_ci{
30062306a36Sopenharmony_ci	struct kstat		ks;
30162306a36Sopenharmony_ci	int			error;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	error = vfs_getattr_nosec(&xf->file->f_path, &ks,
30462306a36Sopenharmony_ci			STATX_SIZE | STATX_BLOCKS, AT_STATX_DONT_SYNC);
30562306a36Sopenharmony_ci	if (error)
30662306a36Sopenharmony_ci		return error;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	statbuf->size = ks.size;
30962306a36Sopenharmony_ci	statbuf->bytes = ks.blocks << SECTOR_SHIFT;
31062306a36Sopenharmony_ci	return 0;
31162306a36Sopenharmony_ci}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci/*
31462306a36Sopenharmony_ci * Grab the (locked) page for a memory object.  The object cannot span a page
31562306a36Sopenharmony_ci * boundary.  Returns 0 (and a locked page) if successful, -ENOTBLK if we
31662306a36Sopenharmony_ci * cannot grab the page, or the usual negative errno.
31762306a36Sopenharmony_ci */
31862306a36Sopenharmony_ciint
31962306a36Sopenharmony_cixfile_get_page(
32062306a36Sopenharmony_ci	struct xfile		*xf,
32162306a36Sopenharmony_ci	loff_t			pos,
32262306a36Sopenharmony_ci	unsigned int		len,
32362306a36Sopenharmony_ci	struct xfile_page	*xfpage)
32462306a36Sopenharmony_ci{
32562306a36Sopenharmony_ci	struct inode		*inode = file_inode(xf->file);
32662306a36Sopenharmony_ci	struct address_space	*mapping = inode->i_mapping;
32762306a36Sopenharmony_ci	const struct address_space_operations *aops = mapping->a_ops;
32862306a36Sopenharmony_ci	struct page		*page = NULL;
32962306a36Sopenharmony_ci	void			*fsdata = NULL;
33062306a36Sopenharmony_ci	loff_t			key = round_down(pos, PAGE_SIZE);
33162306a36Sopenharmony_ci	unsigned int		pflags;
33262306a36Sopenharmony_ci	int			error;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	if (inode->i_sb->s_maxbytes - pos < len)
33562306a36Sopenharmony_ci		return -ENOMEM;
33662306a36Sopenharmony_ci	if (len > PAGE_SIZE - offset_in_page(pos))
33762306a36Sopenharmony_ci		return -ENOTBLK;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	trace_xfile_get_page(xf, pos, len);
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	pflags = memalloc_nofs_save();
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	/*
34462306a36Sopenharmony_ci	 * We call write_begin directly here to avoid all the freezer
34562306a36Sopenharmony_ci	 * protection lock-taking that happens in the normal path.  shmem
34662306a36Sopenharmony_ci	 * doesn't support fs freeze, but lockdep doesn't know that and will
34762306a36Sopenharmony_ci	 * trip over that.
34862306a36Sopenharmony_ci	 */
34962306a36Sopenharmony_ci	error = aops->write_begin(NULL, mapping, key, PAGE_SIZE, &page,
35062306a36Sopenharmony_ci			&fsdata);
35162306a36Sopenharmony_ci	if (error)
35262306a36Sopenharmony_ci		goto out_pflags;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	/* We got the page, so make sure we push out EOF. */
35562306a36Sopenharmony_ci	if (i_size_read(inode) < pos + len)
35662306a36Sopenharmony_ci		i_size_write(inode, pos + len);
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	/*
35962306a36Sopenharmony_ci	 * If the page isn't up to date, fill it with zeroes before we hand it
36062306a36Sopenharmony_ci	 * to the caller and make sure the backing store will hold on to them.
36162306a36Sopenharmony_ci	 */
36262306a36Sopenharmony_ci	if (!PageUptodate(page)) {
36362306a36Sopenharmony_ci		void	*kaddr;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci		kaddr = kmap_local_page(page);
36662306a36Sopenharmony_ci		memset(kaddr, 0, PAGE_SIZE);
36762306a36Sopenharmony_ci		kunmap_local(kaddr);
36862306a36Sopenharmony_ci		SetPageUptodate(page);
36962306a36Sopenharmony_ci	}
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	/*
37262306a36Sopenharmony_ci	 * Mark each page dirty so that the contents are written to some
37362306a36Sopenharmony_ci	 * backing store when we drop this buffer, and take an extra reference
37462306a36Sopenharmony_ci	 * to prevent the xfile page from being swapped or removed from the
37562306a36Sopenharmony_ci	 * page cache by reclaim if the caller unlocks the page.
37662306a36Sopenharmony_ci	 */
37762306a36Sopenharmony_ci	set_page_dirty(page);
37862306a36Sopenharmony_ci	get_page(page);
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	xfpage->page = page;
38162306a36Sopenharmony_ci	xfpage->fsdata = fsdata;
38262306a36Sopenharmony_ci	xfpage->pos = key;
38362306a36Sopenharmony_ciout_pflags:
38462306a36Sopenharmony_ci	memalloc_nofs_restore(pflags);
38562306a36Sopenharmony_ci	return error;
38662306a36Sopenharmony_ci}
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci/*
38962306a36Sopenharmony_ci * Release the (locked) page for a memory object.  Returns 0 or a negative
39062306a36Sopenharmony_ci * errno.
39162306a36Sopenharmony_ci */
39262306a36Sopenharmony_ciint
39362306a36Sopenharmony_cixfile_put_page(
39462306a36Sopenharmony_ci	struct xfile		*xf,
39562306a36Sopenharmony_ci	struct xfile_page	*xfpage)
39662306a36Sopenharmony_ci{
39762306a36Sopenharmony_ci	struct inode		*inode = file_inode(xf->file);
39862306a36Sopenharmony_ci	struct address_space	*mapping = inode->i_mapping;
39962306a36Sopenharmony_ci	const struct address_space_operations *aops = mapping->a_ops;
40062306a36Sopenharmony_ci	unsigned int		pflags;
40162306a36Sopenharmony_ci	int			ret;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	trace_xfile_put_page(xf, xfpage->pos, PAGE_SIZE);
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	/* Give back the reference that we took in xfile_get_page. */
40662306a36Sopenharmony_ci	put_page(xfpage->page);
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	pflags = memalloc_nofs_save();
40962306a36Sopenharmony_ci	ret = aops->write_end(NULL, mapping, xfpage->pos, PAGE_SIZE, PAGE_SIZE,
41062306a36Sopenharmony_ci			xfpage->page, xfpage->fsdata);
41162306a36Sopenharmony_ci	memalloc_nofs_restore(pflags);
41262306a36Sopenharmony_ci	memset(xfpage, 0, sizeof(struct xfile_page));
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	if (ret < 0)
41562306a36Sopenharmony_ci		return ret;
41662306a36Sopenharmony_ci	if (ret != PAGE_SIZE)
41762306a36Sopenharmony_ci		return -EIO;
41862306a36Sopenharmony_ci	return 0;
41962306a36Sopenharmony_ci}
420