18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/fs/hpfs/file.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * file VFS functions 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include "hpfs_fn.h" 118c2ecf20Sopenharmony_ci#include <linux/mpage.h> 128c2ecf20Sopenharmony_ci#include <linux/fiemap.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#define BLOCKS(size) (((size) + 511) >> 9) 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_cistatic int hpfs_file_release(struct inode *inode, struct file *file) 178c2ecf20Sopenharmony_ci{ 188c2ecf20Sopenharmony_ci hpfs_lock(inode->i_sb); 198c2ecf20Sopenharmony_ci hpfs_write_if_changed(inode); 208c2ecf20Sopenharmony_ci hpfs_unlock(inode->i_sb); 218c2ecf20Sopenharmony_ci return 0; 228c2ecf20Sopenharmony_ci} 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ciint hpfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci struct inode *inode = file->f_mapping->host; 278c2ecf20Sopenharmony_ci int ret; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci ret = file_write_and_wait_range(file, start, end); 308c2ecf20Sopenharmony_ci if (ret) 318c2ecf20Sopenharmony_ci return ret; 328c2ecf20Sopenharmony_ci return sync_blockdev(inode->i_sb->s_bdev); 338c2ecf20Sopenharmony_ci} 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* 368c2ecf20Sopenharmony_ci * generic_file_read often calls bmap with non-existing sector, 378c2ecf20Sopenharmony_ci * so we must ignore such errors. 388c2ecf20Sopenharmony_ci */ 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic secno hpfs_bmap(struct inode *inode, unsigned file_secno, unsigned *n_secs) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci struct hpfs_inode_info *hpfs_inode = hpfs_i(inode); 438c2ecf20Sopenharmony_ci unsigned n, disk_secno; 448c2ecf20Sopenharmony_ci struct fnode *fnode; 458c2ecf20Sopenharmony_ci struct buffer_head *bh; 468c2ecf20Sopenharmony_ci if (BLOCKS(hpfs_i(inode)->mmu_private) <= file_secno) return 0; 478c2ecf20Sopenharmony_ci n = file_secno - hpfs_inode->i_file_sec; 488c2ecf20Sopenharmony_ci if (n < hpfs_inode->i_n_secs) { 498c2ecf20Sopenharmony_ci *n_secs = hpfs_inode->i_n_secs - n; 508c2ecf20Sopenharmony_ci return hpfs_inode->i_disk_sec + n; 518c2ecf20Sopenharmony_ci } 528c2ecf20Sopenharmony_ci if (!(fnode = hpfs_map_fnode(inode->i_sb, inode->i_ino, &bh))) return 0; 538c2ecf20Sopenharmony_ci disk_secno = hpfs_bplus_lookup(inode->i_sb, inode, &fnode->btree, file_secno, bh); 548c2ecf20Sopenharmony_ci if (disk_secno == -1) return 0; 558c2ecf20Sopenharmony_ci if (hpfs_chk_sectors(inode->i_sb, disk_secno, 1, "bmap")) return 0; 568c2ecf20Sopenharmony_ci n = file_secno - hpfs_inode->i_file_sec; 578c2ecf20Sopenharmony_ci if (n < hpfs_inode->i_n_secs) { 588c2ecf20Sopenharmony_ci *n_secs = hpfs_inode->i_n_secs - n; 598c2ecf20Sopenharmony_ci return hpfs_inode->i_disk_sec + n; 608c2ecf20Sopenharmony_ci } 618c2ecf20Sopenharmony_ci *n_secs = 1; 628c2ecf20Sopenharmony_ci return disk_secno; 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_civoid hpfs_truncate(struct inode *i) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci if (IS_IMMUTABLE(i)) return /*-EPERM*/; 688c2ecf20Sopenharmony_ci hpfs_lock_assert(i->i_sb); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci hpfs_i(i)->i_n_secs = 0; 718c2ecf20Sopenharmony_ci i->i_blocks = 1 + ((i->i_size + 511) >> 9); 728c2ecf20Sopenharmony_ci hpfs_i(i)->mmu_private = i->i_size; 738c2ecf20Sopenharmony_ci hpfs_truncate_btree(i->i_sb, i->i_ino, 1, ((i->i_size + 511) >> 9)); 748c2ecf20Sopenharmony_ci hpfs_write_inode(i); 758c2ecf20Sopenharmony_ci hpfs_i(i)->i_n_secs = 0; 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistatic int hpfs_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci int r; 818c2ecf20Sopenharmony_ci secno s; 828c2ecf20Sopenharmony_ci unsigned n_secs; 838c2ecf20Sopenharmony_ci hpfs_lock(inode->i_sb); 848c2ecf20Sopenharmony_ci s = hpfs_bmap(inode, iblock, &n_secs); 858c2ecf20Sopenharmony_ci if (s) { 868c2ecf20Sopenharmony_ci if (bh_result->b_size >> 9 < n_secs) 878c2ecf20Sopenharmony_ci n_secs = bh_result->b_size >> 9; 888c2ecf20Sopenharmony_ci n_secs = hpfs_search_hotfix_map_for_range(inode->i_sb, s, n_secs); 898c2ecf20Sopenharmony_ci if (unlikely(!n_secs)) { 908c2ecf20Sopenharmony_ci s = hpfs_search_hotfix_map(inode->i_sb, s); 918c2ecf20Sopenharmony_ci n_secs = 1; 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci map_bh(bh_result, inode->i_sb, s); 948c2ecf20Sopenharmony_ci bh_result->b_size = n_secs << 9; 958c2ecf20Sopenharmony_ci goto ret_0; 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci if (!create) goto ret_0; 988c2ecf20Sopenharmony_ci if (iblock<<9 != hpfs_i(inode)->mmu_private) { 998c2ecf20Sopenharmony_ci BUG(); 1008c2ecf20Sopenharmony_ci r = -EIO; 1018c2ecf20Sopenharmony_ci goto ret_r; 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci if ((s = hpfs_add_sector_to_btree(inode->i_sb, inode->i_ino, 1, inode->i_blocks - 1)) == -1) { 1048c2ecf20Sopenharmony_ci hpfs_truncate_btree(inode->i_sb, inode->i_ino, 1, inode->i_blocks - 1); 1058c2ecf20Sopenharmony_ci r = -ENOSPC; 1068c2ecf20Sopenharmony_ci goto ret_r; 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci inode->i_blocks++; 1098c2ecf20Sopenharmony_ci hpfs_i(inode)->mmu_private += 512; 1108c2ecf20Sopenharmony_ci set_buffer_new(bh_result); 1118c2ecf20Sopenharmony_ci map_bh(bh_result, inode->i_sb, hpfs_search_hotfix_map(inode->i_sb, s)); 1128c2ecf20Sopenharmony_ci ret_0: 1138c2ecf20Sopenharmony_ci r = 0; 1148c2ecf20Sopenharmony_ci ret_r: 1158c2ecf20Sopenharmony_ci hpfs_unlock(inode->i_sb); 1168c2ecf20Sopenharmony_ci return r; 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistatic int hpfs_readpage(struct file *file, struct page *page) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci return mpage_readpage(page, hpfs_get_block); 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic int hpfs_writepage(struct page *page, struct writeback_control *wbc) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci return block_write_full_page(page, hpfs_get_block, wbc); 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic void hpfs_readahead(struct readahead_control *rac) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci mpage_readahead(rac, hpfs_get_block); 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic int hpfs_writepages(struct address_space *mapping, 1358c2ecf20Sopenharmony_ci struct writeback_control *wbc) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci return mpage_writepages(mapping, wbc, hpfs_get_block); 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic void hpfs_write_failed(struct address_space *mapping, loff_t to) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci struct inode *inode = mapping->host; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci hpfs_lock(inode->i_sb); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci if (to > inode->i_size) { 1478c2ecf20Sopenharmony_ci truncate_pagecache(inode, inode->i_size); 1488c2ecf20Sopenharmony_ci hpfs_truncate(inode); 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci hpfs_unlock(inode->i_sb); 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cistatic int hpfs_write_begin(struct file *file, struct address_space *mapping, 1558c2ecf20Sopenharmony_ci loff_t pos, unsigned len, unsigned flags, 1568c2ecf20Sopenharmony_ci struct page **pagep, void **fsdata) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci int ret; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci *pagep = NULL; 1618c2ecf20Sopenharmony_ci ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, 1628c2ecf20Sopenharmony_ci hpfs_get_block, 1638c2ecf20Sopenharmony_ci &hpfs_i(mapping->host)->mmu_private); 1648c2ecf20Sopenharmony_ci if (unlikely(ret)) 1658c2ecf20Sopenharmony_ci hpfs_write_failed(mapping, pos + len); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci return ret; 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic int hpfs_write_end(struct file *file, struct address_space *mapping, 1718c2ecf20Sopenharmony_ci loff_t pos, unsigned len, unsigned copied, 1728c2ecf20Sopenharmony_ci struct page *pagep, void *fsdata) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci struct inode *inode = mapping->host; 1758c2ecf20Sopenharmony_ci int err; 1768c2ecf20Sopenharmony_ci err = generic_write_end(file, mapping, pos, len, copied, pagep, fsdata); 1778c2ecf20Sopenharmony_ci if (err < len) 1788c2ecf20Sopenharmony_ci hpfs_write_failed(mapping, pos + len); 1798c2ecf20Sopenharmony_ci if (!(err < 0)) { 1808c2ecf20Sopenharmony_ci /* make sure we write it on close, if not earlier */ 1818c2ecf20Sopenharmony_ci hpfs_lock(inode->i_sb); 1828c2ecf20Sopenharmony_ci hpfs_i(inode)->i_dirty = 1; 1838c2ecf20Sopenharmony_ci hpfs_unlock(inode->i_sb); 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci return err; 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic sector_t _hpfs_bmap(struct address_space *mapping, sector_t block) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci return generic_block_bmap(mapping, block, hpfs_get_block); 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic int hpfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, u64 start, u64 len) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci return generic_block_fiemap(inode, fieinfo, start, len, hpfs_get_block); 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ciconst struct address_space_operations hpfs_aops = { 1998c2ecf20Sopenharmony_ci .readpage = hpfs_readpage, 2008c2ecf20Sopenharmony_ci .writepage = hpfs_writepage, 2018c2ecf20Sopenharmony_ci .readahead = hpfs_readahead, 2028c2ecf20Sopenharmony_ci .writepages = hpfs_writepages, 2038c2ecf20Sopenharmony_ci .write_begin = hpfs_write_begin, 2048c2ecf20Sopenharmony_ci .write_end = hpfs_write_end, 2058c2ecf20Sopenharmony_ci .bmap = _hpfs_bmap 2068c2ecf20Sopenharmony_ci}; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ciconst struct file_operations hpfs_file_ops = 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci .llseek = generic_file_llseek, 2118c2ecf20Sopenharmony_ci .read_iter = generic_file_read_iter, 2128c2ecf20Sopenharmony_ci .write_iter = generic_file_write_iter, 2138c2ecf20Sopenharmony_ci .mmap = generic_file_mmap, 2148c2ecf20Sopenharmony_ci .release = hpfs_file_release, 2158c2ecf20Sopenharmony_ci .fsync = hpfs_file_fsync, 2168c2ecf20Sopenharmony_ci .splice_read = generic_file_splice_read, 2178c2ecf20Sopenharmony_ci .unlocked_ioctl = hpfs_ioctl, 2188c2ecf20Sopenharmony_ci .compat_ioctl = compat_ptr_ioctl, 2198c2ecf20Sopenharmony_ci}; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ciconst struct inode_operations hpfs_file_iops = 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci .setattr = hpfs_setattr, 2248c2ecf20Sopenharmony_ci .fiemap = hpfs_fiemap, 2258c2ecf20Sopenharmony_ci}; 226