162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/fs/ext2/file.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 1992, 1993, 1994, 1995 662306a36Sopenharmony_ci * Remy Card (card@masi.ibp.fr) 762306a36Sopenharmony_ci * Laboratoire MASI - Institut Blaise Pascal 862306a36Sopenharmony_ci * Universite Pierre et Marie Curie (Paris VI) 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * from 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * linux/fs/minix/file.c 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * Copyright (C) 1991, 1992 Linus Torvalds 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * ext2 fs regular file handling primitives 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * 64-bit file support on 64-bit platforms by Jakub Jelinek 1962306a36Sopenharmony_ci * (jj@sunsite.ms.mff.cuni.cz) 2062306a36Sopenharmony_ci */ 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include <linux/time.h> 2362306a36Sopenharmony_ci#include <linux/pagemap.h> 2462306a36Sopenharmony_ci#include <linux/dax.h> 2562306a36Sopenharmony_ci#include <linux/quotaops.h> 2662306a36Sopenharmony_ci#include <linux/iomap.h> 2762306a36Sopenharmony_ci#include <linux/uio.h> 2862306a36Sopenharmony_ci#include <linux/buffer_head.h> 2962306a36Sopenharmony_ci#include "ext2.h" 3062306a36Sopenharmony_ci#include "xattr.h" 3162306a36Sopenharmony_ci#include "acl.h" 3262306a36Sopenharmony_ci#include "trace.h" 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#ifdef CONFIG_FS_DAX 3562306a36Sopenharmony_cistatic ssize_t ext2_dax_read_iter(struct kiocb *iocb, struct iov_iter *to) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci struct inode *inode = iocb->ki_filp->f_mapping->host; 3862306a36Sopenharmony_ci ssize_t ret; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci if (!iov_iter_count(to)) 4162306a36Sopenharmony_ci return 0; /* skip atime */ 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci inode_lock_shared(inode); 4462306a36Sopenharmony_ci ret = dax_iomap_rw(iocb, to, &ext2_iomap_ops); 4562306a36Sopenharmony_ci inode_unlock_shared(inode); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci file_accessed(iocb->ki_filp); 4862306a36Sopenharmony_ci return ret; 4962306a36Sopenharmony_ci} 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistatic ssize_t ext2_dax_write_iter(struct kiocb *iocb, struct iov_iter *from) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci struct file *file = iocb->ki_filp; 5462306a36Sopenharmony_ci struct inode *inode = file->f_mapping->host; 5562306a36Sopenharmony_ci ssize_t ret; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci inode_lock(inode); 5862306a36Sopenharmony_ci ret = generic_write_checks(iocb, from); 5962306a36Sopenharmony_ci if (ret <= 0) 6062306a36Sopenharmony_ci goto out_unlock; 6162306a36Sopenharmony_ci ret = file_remove_privs(file); 6262306a36Sopenharmony_ci if (ret) 6362306a36Sopenharmony_ci goto out_unlock; 6462306a36Sopenharmony_ci ret = file_update_time(file); 6562306a36Sopenharmony_ci if (ret) 6662306a36Sopenharmony_ci goto out_unlock; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci ret = dax_iomap_rw(iocb, from, &ext2_iomap_ops); 6962306a36Sopenharmony_ci if (ret > 0 && iocb->ki_pos > i_size_read(inode)) { 7062306a36Sopenharmony_ci i_size_write(inode, iocb->ki_pos); 7162306a36Sopenharmony_ci mark_inode_dirty(inode); 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ciout_unlock: 7562306a36Sopenharmony_ci inode_unlock(inode); 7662306a36Sopenharmony_ci if (ret > 0) 7762306a36Sopenharmony_ci ret = generic_write_sync(iocb, ret); 7862306a36Sopenharmony_ci return ret; 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci/* 8262306a36Sopenharmony_ci * The lock ordering for ext2 DAX fault paths is: 8362306a36Sopenharmony_ci * 8462306a36Sopenharmony_ci * mmap_lock (MM) 8562306a36Sopenharmony_ci * sb_start_pagefault (vfs, freeze) 8662306a36Sopenharmony_ci * address_space->invalidate_lock 8762306a36Sopenharmony_ci * address_space->i_mmap_rwsem or page_lock (mutually exclusive in DAX) 8862306a36Sopenharmony_ci * ext2_inode_info->truncate_mutex 8962306a36Sopenharmony_ci * 9062306a36Sopenharmony_ci * The default page_lock and i_size verification done by non-DAX fault paths 9162306a36Sopenharmony_ci * is sufficient because ext2 doesn't support hole punching. 9262306a36Sopenharmony_ci */ 9362306a36Sopenharmony_cistatic vm_fault_t ext2_dax_fault(struct vm_fault *vmf) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci struct inode *inode = file_inode(vmf->vma->vm_file); 9662306a36Sopenharmony_ci vm_fault_t ret; 9762306a36Sopenharmony_ci bool write = (vmf->flags & FAULT_FLAG_WRITE) && 9862306a36Sopenharmony_ci (vmf->vma->vm_flags & VM_SHARED); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci if (write) { 10162306a36Sopenharmony_ci sb_start_pagefault(inode->i_sb); 10262306a36Sopenharmony_ci file_update_time(vmf->vma->vm_file); 10362306a36Sopenharmony_ci } 10462306a36Sopenharmony_ci filemap_invalidate_lock_shared(inode->i_mapping); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci ret = dax_iomap_fault(vmf, 0, NULL, NULL, &ext2_iomap_ops); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci filemap_invalidate_unlock_shared(inode->i_mapping); 10962306a36Sopenharmony_ci if (write) 11062306a36Sopenharmony_ci sb_end_pagefault(inode->i_sb); 11162306a36Sopenharmony_ci return ret; 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic const struct vm_operations_struct ext2_dax_vm_ops = { 11562306a36Sopenharmony_ci .fault = ext2_dax_fault, 11662306a36Sopenharmony_ci /* 11762306a36Sopenharmony_ci * .huge_fault is not supported for DAX because allocation in ext2 11862306a36Sopenharmony_ci * cannot be reliably aligned to huge page sizes and so pmd faults 11962306a36Sopenharmony_ci * will always fail and fail back to regular faults. 12062306a36Sopenharmony_ci */ 12162306a36Sopenharmony_ci .page_mkwrite = ext2_dax_fault, 12262306a36Sopenharmony_ci .pfn_mkwrite = ext2_dax_fault, 12362306a36Sopenharmony_ci}; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic int ext2_file_mmap(struct file *file, struct vm_area_struct *vma) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci if (!IS_DAX(file_inode(file))) 12862306a36Sopenharmony_ci return generic_file_mmap(file, vma); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci file_accessed(file); 13162306a36Sopenharmony_ci vma->vm_ops = &ext2_dax_vm_ops; 13262306a36Sopenharmony_ci return 0; 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci#else 13562306a36Sopenharmony_ci#define ext2_file_mmap generic_file_mmap 13662306a36Sopenharmony_ci#endif 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci/* 13962306a36Sopenharmony_ci * Called when filp is released. This happens when all file descriptors 14062306a36Sopenharmony_ci * for a single struct file are closed. Note that different open() calls 14162306a36Sopenharmony_ci * for the same file yield different struct file structures. 14262306a36Sopenharmony_ci */ 14362306a36Sopenharmony_cistatic int ext2_release_file (struct inode * inode, struct file * filp) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci if (filp->f_mode & FMODE_WRITE) { 14662306a36Sopenharmony_ci mutex_lock(&EXT2_I(inode)->truncate_mutex); 14762306a36Sopenharmony_ci ext2_discard_reservation(inode); 14862306a36Sopenharmony_ci mutex_unlock(&EXT2_I(inode)->truncate_mutex); 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci return 0; 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ciint ext2_fsync(struct file *file, loff_t start, loff_t end, int datasync) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci int ret; 15662306a36Sopenharmony_ci struct super_block *sb = file->f_mapping->host->i_sb; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci ret = generic_buffers_fsync(file, start, end, datasync); 15962306a36Sopenharmony_ci if (ret == -EIO) 16062306a36Sopenharmony_ci /* We don't really know where the IO error happened... */ 16162306a36Sopenharmony_ci ext2_error(sb, __func__, 16262306a36Sopenharmony_ci "detected IO error when writing metadata buffers"); 16362306a36Sopenharmony_ci return ret; 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic ssize_t ext2_dio_read_iter(struct kiocb *iocb, struct iov_iter *to) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci struct file *file = iocb->ki_filp; 16962306a36Sopenharmony_ci struct inode *inode = file->f_mapping->host; 17062306a36Sopenharmony_ci ssize_t ret; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci trace_ext2_dio_read_begin(iocb, to, 0); 17362306a36Sopenharmony_ci inode_lock_shared(inode); 17462306a36Sopenharmony_ci ret = iomap_dio_rw(iocb, to, &ext2_iomap_ops, NULL, 0, NULL, 0); 17562306a36Sopenharmony_ci inode_unlock_shared(inode); 17662306a36Sopenharmony_ci trace_ext2_dio_read_end(iocb, to, ret); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci return ret; 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic int ext2_dio_write_end_io(struct kiocb *iocb, ssize_t size, 18262306a36Sopenharmony_ci int error, unsigned int flags) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci loff_t pos = iocb->ki_pos; 18562306a36Sopenharmony_ci struct inode *inode = file_inode(iocb->ki_filp); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci if (error) 18862306a36Sopenharmony_ci goto out; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci /* 19162306a36Sopenharmony_ci * If we are extending the file, we have to update i_size here before 19262306a36Sopenharmony_ci * page cache gets invalidated in iomap_dio_rw(). This prevents racing 19362306a36Sopenharmony_ci * buffered reads from zeroing out too much from page cache pages. 19462306a36Sopenharmony_ci * Note that all extending writes always happens synchronously with 19562306a36Sopenharmony_ci * inode lock held by ext2_dio_write_iter(). So it is safe to update 19662306a36Sopenharmony_ci * inode size here for extending file writes. 19762306a36Sopenharmony_ci */ 19862306a36Sopenharmony_ci pos += size; 19962306a36Sopenharmony_ci if (pos > i_size_read(inode)) { 20062306a36Sopenharmony_ci i_size_write(inode, pos); 20162306a36Sopenharmony_ci mark_inode_dirty(inode); 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ciout: 20462306a36Sopenharmony_ci trace_ext2_dio_write_endio(iocb, size, error); 20562306a36Sopenharmony_ci return error; 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_cistatic const struct iomap_dio_ops ext2_dio_write_ops = { 20962306a36Sopenharmony_ci .end_io = ext2_dio_write_end_io, 21062306a36Sopenharmony_ci}; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic ssize_t ext2_dio_write_iter(struct kiocb *iocb, struct iov_iter *from) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci struct file *file = iocb->ki_filp; 21562306a36Sopenharmony_ci struct inode *inode = file->f_mapping->host; 21662306a36Sopenharmony_ci ssize_t ret; 21762306a36Sopenharmony_ci unsigned int flags = 0; 21862306a36Sopenharmony_ci unsigned long blocksize = inode->i_sb->s_blocksize; 21962306a36Sopenharmony_ci loff_t offset = iocb->ki_pos; 22062306a36Sopenharmony_ci loff_t count = iov_iter_count(from); 22162306a36Sopenharmony_ci ssize_t status = 0; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci trace_ext2_dio_write_begin(iocb, from, 0); 22462306a36Sopenharmony_ci inode_lock(inode); 22562306a36Sopenharmony_ci ret = generic_write_checks(iocb, from); 22662306a36Sopenharmony_ci if (ret <= 0) 22762306a36Sopenharmony_ci goto out_unlock; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci ret = kiocb_modified(iocb); 23062306a36Sopenharmony_ci if (ret) 23162306a36Sopenharmony_ci goto out_unlock; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci /* use IOMAP_DIO_FORCE_WAIT for unaligned or extending writes */ 23462306a36Sopenharmony_ci if (iocb->ki_pos + iov_iter_count(from) > i_size_read(inode) || 23562306a36Sopenharmony_ci (!IS_ALIGNED(iocb->ki_pos | iov_iter_alignment(from), blocksize))) 23662306a36Sopenharmony_ci flags |= IOMAP_DIO_FORCE_WAIT; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci ret = iomap_dio_rw(iocb, from, &ext2_iomap_ops, &ext2_dio_write_ops, 23962306a36Sopenharmony_ci flags, NULL, 0); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci /* ENOTBLK is magic return value for fallback to buffered-io */ 24262306a36Sopenharmony_ci if (ret == -ENOTBLK) 24362306a36Sopenharmony_ci ret = 0; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci if (ret < 0 && ret != -EIOCBQUEUED) 24662306a36Sopenharmony_ci ext2_write_failed(inode->i_mapping, offset + count); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci /* handle case for partial write and for fallback to buffered write */ 24962306a36Sopenharmony_ci if (ret >= 0 && iov_iter_count(from)) { 25062306a36Sopenharmony_ci loff_t pos, endbyte; 25162306a36Sopenharmony_ci int ret2; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci iocb->ki_flags &= ~IOCB_DIRECT; 25462306a36Sopenharmony_ci pos = iocb->ki_pos; 25562306a36Sopenharmony_ci status = generic_perform_write(iocb, from); 25662306a36Sopenharmony_ci if (unlikely(status < 0)) { 25762306a36Sopenharmony_ci ret = status; 25862306a36Sopenharmony_ci goto out_unlock; 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci ret += status; 26262306a36Sopenharmony_ci endbyte = pos + status - 1; 26362306a36Sopenharmony_ci ret2 = filemap_write_and_wait_range(inode->i_mapping, pos, 26462306a36Sopenharmony_ci endbyte); 26562306a36Sopenharmony_ci if (!ret2) 26662306a36Sopenharmony_ci invalidate_mapping_pages(inode->i_mapping, 26762306a36Sopenharmony_ci pos >> PAGE_SHIFT, 26862306a36Sopenharmony_ci endbyte >> PAGE_SHIFT); 26962306a36Sopenharmony_ci if (ret > 0) 27062306a36Sopenharmony_ci generic_write_sync(iocb, ret); 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ciout_unlock: 27462306a36Sopenharmony_ci inode_unlock(inode); 27562306a36Sopenharmony_ci if (status) 27662306a36Sopenharmony_ci trace_ext2_dio_write_buff_end(iocb, from, status); 27762306a36Sopenharmony_ci trace_ext2_dio_write_end(iocb, from, ret); 27862306a36Sopenharmony_ci return ret; 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_cistatic ssize_t ext2_file_read_iter(struct kiocb *iocb, struct iov_iter *to) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci#ifdef CONFIG_FS_DAX 28462306a36Sopenharmony_ci if (IS_DAX(iocb->ki_filp->f_mapping->host)) 28562306a36Sopenharmony_ci return ext2_dax_read_iter(iocb, to); 28662306a36Sopenharmony_ci#endif 28762306a36Sopenharmony_ci if (iocb->ki_flags & IOCB_DIRECT) 28862306a36Sopenharmony_ci return ext2_dio_read_iter(iocb, to); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci return generic_file_read_iter(iocb, to); 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistatic ssize_t ext2_file_write_iter(struct kiocb *iocb, struct iov_iter *from) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci#ifdef CONFIG_FS_DAX 29662306a36Sopenharmony_ci if (IS_DAX(iocb->ki_filp->f_mapping->host)) 29762306a36Sopenharmony_ci return ext2_dax_write_iter(iocb, from); 29862306a36Sopenharmony_ci#endif 29962306a36Sopenharmony_ci if (iocb->ki_flags & IOCB_DIRECT) 30062306a36Sopenharmony_ci return ext2_dio_write_iter(iocb, from); 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci return generic_file_write_iter(iocb, from); 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ciconst struct file_operations ext2_file_operations = { 30662306a36Sopenharmony_ci .llseek = generic_file_llseek, 30762306a36Sopenharmony_ci .read_iter = ext2_file_read_iter, 30862306a36Sopenharmony_ci .write_iter = ext2_file_write_iter, 30962306a36Sopenharmony_ci .unlocked_ioctl = ext2_ioctl, 31062306a36Sopenharmony_ci#ifdef CONFIG_COMPAT 31162306a36Sopenharmony_ci .compat_ioctl = ext2_compat_ioctl, 31262306a36Sopenharmony_ci#endif 31362306a36Sopenharmony_ci .mmap = ext2_file_mmap, 31462306a36Sopenharmony_ci .open = dquot_file_open, 31562306a36Sopenharmony_ci .release = ext2_release_file, 31662306a36Sopenharmony_ci .fsync = ext2_fsync, 31762306a36Sopenharmony_ci .get_unmapped_area = thp_get_unmapped_area, 31862306a36Sopenharmony_ci .splice_read = filemap_splice_read, 31962306a36Sopenharmony_ci .splice_write = iter_file_splice_write, 32062306a36Sopenharmony_ci}; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ciconst struct inode_operations ext2_file_inode_operations = { 32362306a36Sopenharmony_ci .listxattr = ext2_listxattr, 32462306a36Sopenharmony_ci .getattr = ext2_getattr, 32562306a36Sopenharmony_ci .setattr = ext2_setattr, 32662306a36Sopenharmony_ci .get_inode_acl = ext2_get_acl, 32762306a36Sopenharmony_ci .set_acl = ext2_set_acl, 32862306a36Sopenharmony_ci .fiemap = ext2_fiemap, 32962306a36Sopenharmony_ci .fileattr_get = ext2_fileattr_get, 33062306a36Sopenharmony_ci .fileattr_set = ext2_fileattr_set, 33162306a36Sopenharmony_ci}; 332