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