147e4937aSGao Xiang // SPDX-License-Identifier: GPL-2.0-only 247e4937aSGao Xiang /* 347e4937aSGao Xiang * Copyright (C) 2017-2018 HUAWEI, Inc. 4592e7cd0SAlexander A. Klimov * https://www.huawei.com/ 5c5aa903aSGao Xiang * Copyright (C) 2021, Alibaba Cloud 647e4937aSGao Xiang */ 747e4937aSGao Xiang #include "internal.h" 847e4937aSGao Xiang #include <linux/prefetch.h> 906252e9cSGao Xiang #include <linux/dax.h> 1047e4937aSGao Xiang #include <trace/events/erofs.h> 1147e4937aSGao Xiang 12e655b5b3SGao Xiang struct page *erofs_get_meta_page(struct super_block *sb, erofs_blk_t blkaddr) 1347e4937aSGao Xiang { 1455252ab7SGao Xiang struct address_space *const mapping = sb->s_bdev->bd_inode->i_mapping; 1555252ab7SGao Xiang struct page *page; 1647e4937aSGao Xiang 1755252ab7SGao Xiang page = read_cache_page_gfp(mapping, blkaddr, 18618f40eaSGao Xiang mapping_gfp_constraint(mapping, ~__GFP_FS)); 1955252ab7SGao Xiang /* should already be PageUptodate */ 2055252ab7SGao Xiang if (!IS_ERR(page)) 2155252ab7SGao Xiang lock_page(page); 2255252ab7SGao Xiang return page; 2347e4937aSGao Xiang } 2447e4937aSGao Xiang 2547e4937aSGao Xiang static int erofs_map_blocks_flatmode(struct inode *inode, 2647e4937aSGao Xiang struct erofs_map_blocks *map, 2747e4937aSGao Xiang int flags) 2847e4937aSGao Xiang { 2947e4937aSGao Xiang int err = 0; 3047e4937aSGao Xiang erofs_blk_t nblocks, lastblk; 3147e4937aSGao Xiang u64 offset = map->m_la; 32a5876e24SGao Xiang struct erofs_inode *vi = EROFS_I(inode); 338a765682SGao Xiang bool tailendpacking = (vi->datalayout == EROFS_INODE_FLAT_INLINE); 3447e4937aSGao Xiang 3547e4937aSGao Xiang trace_erofs_map_blocks_flatmode_enter(inode, map, flags); 3647e4937aSGao Xiang 3747e4937aSGao Xiang nblocks = DIV_ROUND_UP(inode->i_size, PAGE_SIZE); 388a765682SGao Xiang lastblk = nblocks - tailendpacking; 3947e4937aSGao Xiang 4047e4937aSGao Xiang /* there is no hole in flatmode */ 4147e4937aSGao Xiang map->m_flags = EROFS_MAP_MAPPED; 4247e4937aSGao Xiang 4347e4937aSGao Xiang if (offset < blknr_to_addr(lastblk)) { 4447e4937aSGao Xiang map->m_pa = blknr_to_addr(vi->raw_blkaddr) + map->m_la; 4547e4937aSGao Xiang map->m_plen = blknr_to_addr(lastblk) - offset; 468a765682SGao Xiang } else if (tailendpacking) { 4747e4937aSGao Xiang /* 2 - inode inline B: inode, [xattrs], inline last blk... */ 4847e4937aSGao Xiang struct erofs_sb_info *sbi = EROFS_SB(inode->i_sb); 4947e4937aSGao Xiang 5047e4937aSGao Xiang map->m_pa = iloc(sbi, vi->nid) + vi->inode_isize + 5147e4937aSGao Xiang vi->xattr_isize + erofs_blkoff(map->m_la); 5247e4937aSGao Xiang map->m_plen = inode->i_size - offset; 5347e4937aSGao Xiang 5447e4937aSGao Xiang /* inline data should be located in one meta block */ 5547e4937aSGao Xiang if (erofs_blkoff(map->m_pa) + map->m_plen > PAGE_SIZE) { 564f761fa2SGao Xiang erofs_err(inode->i_sb, 574f761fa2SGao Xiang "inline data cross block boundary @ nid %llu", 5847e4937aSGao Xiang vi->nid); 5947e4937aSGao Xiang DBG_BUGON(1); 6047e4937aSGao Xiang err = -EFSCORRUPTED; 6147e4937aSGao Xiang goto err_out; 6247e4937aSGao Xiang } 6347e4937aSGao Xiang 6447e4937aSGao Xiang map->m_flags |= EROFS_MAP_META; 6547e4937aSGao Xiang } else { 664f761fa2SGao Xiang erofs_err(inode->i_sb, 674f761fa2SGao Xiang "internal error @ nid: %llu (size %llu), m_la 0x%llx", 6847e4937aSGao Xiang vi->nid, inode->i_size, map->m_la); 6947e4937aSGao Xiang DBG_BUGON(1); 7047e4937aSGao Xiang err = -EIO; 7147e4937aSGao Xiang goto err_out; 7247e4937aSGao Xiang } 7347e4937aSGao Xiang 7447e4937aSGao Xiang map->m_llen = map->m_plen; 7547e4937aSGao Xiang err_out: 7647e4937aSGao Xiang trace_erofs_map_blocks_flatmode_exit(inode, map, flags, 0); 7747e4937aSGao Xiang return err; 7847e4937aSGao Xiang } 7947e4937aSGao Xiang 80c5aa903aSGao Xiang static int erofs_map_blocks(struct inode *inode, 81c5aa903aSGao Xiang struct erofs_map_blocks *map, int flags) 82c5aa903aSGao Xiang { 83c5aa903aSGao Xiang struct super_block *sb = inode->i_sb; 84c5aa903aSGao Xiang struct erofs_inode *vi = EROFS_I(inode); 85c5aa903aSGao Xiang struct erofs_inode_chunk_index *idx; 86c5aa903aSGao Xiang struct page *page; 87c5aa903aSGao Xiang u64 chunknr; 88c5aa903aSGao Xiang unsigned int unit; 89c5aa903aSGao Xiang erofs_off_t pos; 90c5aa903aSGao Xiang int err = 0; 91c5aa903aSGao Xiang 92dfeab2e9SGao Xiang map->m_deviceid = 0; 93c5aa903aSGao Xiang if (map->m_la >= inode->i_size) { 94c5aa903aSGao Xiang /* leave out-of-bound access unmapped */ 95c5aa903aSGao Xiang map->m_flags = 0; 96c5aa903aSGao Xiang map->m_plen = 0; 97c5aa903aSGao Xiang goto out; 98c5aa903aSGao Xiang } 99c5aa903aSGao Xiang 100c5aa903aSGao Xiang if (vi->datalayout != EROFS_INODE_CHUNK_BASED) 101c5aa903aSGao Xiang return erofs_map_blocks_flatmode(inode, map, flags); 102c5aa903aSGao Xiang 103c5aa903aSGao Xiang if (vi->chunkformat & EROFS_CHUNK_FORMAT_INDEXES) 104c5aa903aSGao Xiang unit = sizeof(*idx); /* chunk index */ 105c5aa903aSGao Xiang else 106c5aa903aSGao Xiang unit = EROFS_BLOCK_MAP_ENTRY_SIZE; /* block map */ 107c5aa903aSGao Xiang 108c5aa903aSGao Xiang chunknr = map->m_la >> vi->chunkbits; 109c5aa903aSGao Xiang pos = ALIGN(iloc(EROFS_SB(sb), vi->nid) + vi->inode_isize + 110c5aa903aSGao Xiang vi->xattr_isize, unit) + unit * chunknr; 111c5aa903aSGao Xiang 112c5aa903aSGao Xiang page = erofs_get_meta_page(inode->i_sb, erofs_blknr(pos)); 113c5aa903aSGao Xiang if (IS_ERR(page)) 114c5aa903aSGao Xiang return PTR_ERR(page); 115c5aa903aSGao Xiang 116c5aa903aSGao Xiang map->m_la = chunknr << vi->chunkbits; 117c5aa903aSGao Xiang map->m_plen = min_t(erofs_off_t, 1UL << vi->chunkbits, 118c5aa903aSGao Xiang roundup(inode->i_size - map->m_la, EROFS_BLKSIZ)); 119c5aa903aSGao Xiang 120c5aa903aSGao Xiang /* handle block map */ 121c5aa903aSGao Xiang if (!(vi->chunkformat & EROFS_CHUNK_FORMAT_INDEXES)) { 122c5aa903aSGao Xiang __le32 *blkaddr = page_address(page) + erofs_blkoff(pos); 123c5aa903aSGao Xiang 124c5aa903aSGao Xiang if (le32_to_cpu(*blkaddr) == EROFS_NULL_ADDR) { 125c5aa903aSGao Xiang map->m_flags = 0; 126c5aa903aSGao Xiang } else { 127c5aa903aSGao Xiang map->m_pa = blknr_to_addr(le32_to_cpu(*blkaddr)); 128c5aa903aSGao Xiang map->m_flags = EROFS_MAP_MAPPED; 129c5aa903aSGao Xiang } 130c5aa903aSGao Xiang goto out_unlock; 131c5aa903aSGao Xiang } 132c5aa903aSGao Xiang /* parse chunk indexes */ 133c5aa903aSGao Xiang idx = page_address(page) + erofs_blkoff(pos); 134c5aa903aSGao Xiang switch (le32_to_cpu(idx->blkaddr)) { 135c5aa903aSGao Xiang case EROFS_NULL_ADDR: 136c5aa903aSGao Xiang map->m_flags = 0; 137c5aa903aSGao Xiang break; 138c5aa903aSGao Xiang default: 139dfeab2e9SGao Xiang map->m_deviceid = le16_to_cpu(idx->device_id) & 140dfeab2e9SGao Xiang EROFS_SB(sb)->device_id_mask; 141c5aa903aSGao Xiang map->m_pa = blknr_to_addr(le32_to_cpu(idx->blkaddr)); 142c5aa903aSGao Xiang map->m_flags = EROFS_MAP_MAPPED; 143c5aa903aSGao Xiang break; 144c5aa903aSGao Xiang } 145c5aa903aSGao Xiang out_unlock: 146c5aa903aSGao Xiang unlock_page(page); 147c5aa903aSGao Xiang put_page(page); 148c5aa903aSGao Xiang out: 149c5aa903aSGao Xiang map->m_llen = map->m_plen; 150c5aa903aSGao Xiang return err; 151c5aa903aSGao Xiang } 152c5aa903aSGao Xiang 153dfeab2e9SGao Xiang int erofs_map_dev(struct super_block *sb, struct erofs_map_dev *map) 154dfeab2e9SGao Xiang { 155dfeab2e9SGao Xiang struct erofs_dev_context *devs = EROFS_SB(sb)->devs; 156dfeab2e9SGao Xiang struct erofs_device_info *dif; 157dfeab2e9SGao Xiang int id; 158dfeab2e9SGao Xiang 159dfeab2e9SGao Xiang /* primary device by default */ 160dfeab2e9SGao Xiang map->m_bdev = sb->s_bdev; 161dfeab2e9SGao Xiang map->m_daxdev = EROFS_SB(sb)->dax_dev; 162*de205114SChristoph Hellwig map->m_dax_part_off = EROFS_SB(sb)->dax_part_off; 163dfeab2e9SGao Xiang 164dfeab2e9SGao Xiang if (map->m_deviceid) { 165dfeab2e9SGao Xiang down_read(&devs->rwsem); 166dfeab2e9SGao Xiang dif = idr_find(&devs->tree, map->m_deviceid - 1); 167dfeab2e9SGao Xiang if (!dif) { 168dfeab2e9SGao Xiang up_read(&devs->rwsem); 169dfeab2e9SGao Xiang return -ENODEV; 170dfeab2e9SGao Xiang } 171dfeab2e9SGao Xiang map->m_bdev = dif->bdev; 172dfeab2e9SGao Xiang map->m_daxdev = dif->dax_dev; 173*de205114SChristoph Hellwig map->m_dax_part_off = dif->dax_part_off; 174dfeab2e9SGao Xiang up_read(&devs->rwsem); 175dfeab2e9SGao Xiang } else if (devs->extra_devices) { 176dfeab2e9SGao Xiang down_read(&devs->rwsem); 177dfeab2e9SGao Xiang idr_for_each_entry(&devs->tree, dif, id) { 178dfeab2e9SGao Xiang erofs_off_t startoff, length; 179dfeab2e9SGao Xiang 180dfeab2e9SGao Xiang if (!dif->mapped_blkaddr) 181dfeab2e9SGao Xiang continue; 182dfeab2e9SGao Xiang startoff = blknr_to_addr(dif->mapped_blkaddr); 183dfeab2e9SGao Xiang length = blknr_to_addr(dif->blocks); 184dfeab2e9SGao Xiang 185dfeab2e9SGao Xiang if (map->m_pa >= startoff && 186dfeab2e9SGao Xiang map->m_pa < startoff + length) { 187dfeab2e9SGao Xiang map->m_pa -= startoff; 188dfeab2e9SGao Xiang map->m_bdev = dif->bdev; 189dfeab2e9SGao Xiang map->m_daxdev = dif->dax_dev; 190*de205114SChristoph Hellwig map->m_dax_part_off = dif->dax_part_off; 191dfeab2e9SGao Xiang break; 192dfeab2e9SGao Xiang } 193dfeab2e9SGao Xiang } 194dfeab2e9SGao Xiang up_read(&devs->rwsem); 195dfeab2e9SGao Xiang } 196dfeab2e9SGao Xiang return 0; 197dfeab2e9SGao Xiang } 198dfeab2e9SGao Xiang 199a08e67a0SHuang Jianan static int erofs_iomap_begin(struct inode *inode, loff_t offset, loff_t length, 200a08e67a0SHuang Jianan unsigned int flags, struct iomap *iomap, struct iomap *srcmap) 201a08e67a0SHuang Jianan { 202a08e67a0SHuang Jianan int ret; 203a08e67a0SHuang Jianan struct erofs_map_blocks map; 204dfeab2e9SGao Xiang struct erofs_map_dev mdev; 205a08e67a0SHuang Jianan 206a08e67a0SHuang Jianan map.m_la = offset; 207a08e67a0SHuang Jianan map.m_llen = length; 208a08e67a0SHuang Jianan 209c5aa903aSGao Xiang ret = erofs_map_blocks(inode, &map, EROFS_GET_BLOCKS_RAW); 210a08e67a0SHuang Jianan if (ret < 0) 211a08e67a0SHuang Jianan return ret; 212a08e67a0SHuang Jianan 213dfeab2e9SGao Xiang mdev = (struct erofs_map_dev) { 214dfeab2e9SGao Xiang .m_deviceid = map.m_deviceid, 215dfeab2e9SGao Xiang .m_pa = map.m_pa, 216dfeab2e9SGao Xiang }; 217dfeab2e9SGao Xiang ret = erofs_map_dev(inode->i_sb, &mdev); 218dfeab2e9SGao Xiang if (ret) 219dfeab2e9SGao Xiang return ret; 220dfeab2e9SGao Xiang 221a08e67a0SHuang Jianan iomap->offset = map.m_la; 222*de205114SChristoph Hellwig if (flags & IOMAP_DAX) { 223*de205114SChristoph Hellwig iomap->dax_dev = mdev.m_daxdev; 224*de205114SChristoph Hellwig iomap->offset += mdev.m_dax_part_off; 225*de205114SChristoph Hellwig } else { 226*de205114SChristoph Hellwig iomap->bdev = mdev.m_bdev; 227*de205114SChristoph Hellwig } 228a08e67a0SHuang Jianan iomap->length = map.m_llen; 229a08e67a0SHuang Jianan iomap->flags = 0; 230771c994eSGao Xiang iomap->private = NULL; 231a08e67a0SHuang Jianan 232a08e67a0SHuang Jianan if (!(map.m_flags & EROFS_MAP_MAPPED)) { 233a08e67a0SHuang Jianan iomap->type = IOMAP_HOLE; 234a08e67a0SHuang Jianan iomap->addr = IOMAP_NULL_ADDR; 235a08e67a0SHuang Jianan if (!iomap->length) 236a08e67a0SHuang Jianan iomap->length = length; 237a08e67a0SHuang Jianan return 0; 238a08e67a0SHuang Jianan } 239a08e67a0SHuang Jianan 240a08e67a0SHuang Jianan if (map.m_flags & EROFS_MAP_META) { 241771c994eSGao Xiang struct page *ipage; 242771c994eSGao Xiang 243771c994eSGao Xiang iomap->type = IOMAP_INLINE; 244771c994eSGao Xiang ipage = erofs_get_meta_page(inode->i_sb, 245dfeab2e9SGao Xiang erofs_blknr(mdev.m_pa)); 246771c994eSGao Xiang if (IS_ERR(ipage)) 247771c994eSGao Xiang return PTR_ERR(ipage); 248771c994eSGao Xiang iomap->inline_data = page_address(ipage) + 249dfeab2e9SGao Xiang erofs_blkoff(mdev.m_pa); 250771c994eSGao Xiang iomap->private = ipage; 251771c994eSGao Xiang } else { 252a08e67a0SHuang Jianan iomap->type = IOMAP_MAPPED; 253dfeab2e9SGao Xiang iomap->addr = mdev.m_pa; 254771c994eSGao Xiang } 255a08e67a0SHuang Jianan return 0; 256a08e67a0SHuang Jianan } 257a08e67a0SHuang Jianan 258771c994eSGao Xiang static int erofs_iomap_end(struct inode *inode, loff_t pos, loff_t length, 259771c994eSGao Xiang ssize_t written, unsigned int flags, struct iomap *iomap) 260771c994eSGao Xiang { 261771c994eSGao Xiang struct page *ipage = iomap->private; 262771c994eSGao Xiang 263771c994eSGao Xiang if (ipage) { 264771c994eSGao Xiang DBG_BUGON(iomap->type != IOMAP_INLINE); 265771c994eSGao Xiang unlock_page(ipage); 266771c994eSGao Xiang put_page(ipage); 267771c994eSGao Xiang } else { 268771c994eSGao Xiang DBG_BUGON(iomap->type == IOMAP_INLINE); 269771c994eSGao Xiang } 270771c994eSGao Xiang return written; 271771c994eSGao Xiang } 272771c994eSGao Xiang 273a08e67a0SHuang Jianan static const struct iomap_ops erofs_iomap_ops = { 274a08e67a0SHuang Jianan .iomap_begin = erofs_iomap_begin, 275771c994eSGao Xiang .iomap_end = erofs_iomap_end, 276a08e67a0SHuang Jianan }; 277a08e67a0SHuang Jianan 278eadcd6b5SGao Xiang int erofs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, 279eadcd6b5SGao Xiang u64 start, u64 len) 280eadcd6b5SGao Xiang { 281eadcd6b5SGao Xiang if (erofs_inode_is_data_compressed(EROFS_I(inode)->datalayout)) { 282eadcd6b5SGao Xiang #ifdef CONFIG_EROFS_FS_ZIP 283eadcd6b5SGao Xiang return iomap_fiemap(inode, fieinfo, start, len, 284eadcd6b5SGao Xiang &z_erofs_iomap_report_ops); 285eadcd6b5SGao Xiang #else 286eadcd6b5SGao Xiang return -EOPNOTSUPP; 287eadcd6b5SGao Xiang #endif 288eadcd6b5SGao Xiang } 289eadcd6b5SGao Xiang return iomap_fiemap(inode, fieinfo, start, len, &erofs_iomap_ops); 290eadcd6b5SGao Xiang } 291eadcd6b5SGao Xiang 292771c994eSGao Xiang /* 293771c994eSGao Xiang * since we dont have write or truncate flows, so no inode 294771c994eSGao Xiang * locking needs to be held at the moment. 295771c994eSGao Xiang */ 296771c994eSGao Xiang static int erofs_readpage(struct file *file, struct page *page) 297771c994eSGao Xiang { 298771c994eSGao Xiang return iomap_readpage(page, &erofs_iomap_ops); 299771c994eSGao Xiang } 300771c994eSGao Xiang 301771c994eSGao Xiang static void erofs_readahead(struct readahead_control *rac) 302771c994eSGao Xiang { 303771c994eSGao Xiang return iomap_readahead(rac, &erofs_iomap_ops); 304771c994eSGao Xiang } 305771c994eSGao Xiang 306771c994eSGao Xiang static sector_t erofs_bmap(struct address_space *mapping, sector_t block) 307771c994eSGao Xiang { 308771c994eSGao Xiang return iomap_bmap(mapping, block, &erofs_iomap_ops); 309771c994eSGao Xiang } 310771c994eSGao Xiang 311a08e67a0SHuang Jianan static int erofs_prepare_dio(struct kiocb *iocb, struct iov_iter *to) 312a08e67a0SHuang Jianan { 313a08e67a0SHuang Jianan struct inode *inode = file_inode(iocb->ki_filp); 314a08e67a0SHuang Jianan loff_t align = iocb->ki_pos | iov_iter_count(to) | 315a08e67a0SHuang Jianan iov_iter_alignment(to); 316a08e67a0SHuang Jianan struct block_device *bdev = inode->i_sb->s_bdev; 317a08e67a0SHuang Jianan unsigned int blksize_mask; 318a08e67a0SHuang Jianan 319a08e67a0SHuang Jianan if (bdev) 320a08e67a0SHuang Jianan blksize_mask = (1 << ilog2(bdev_logical_block_size(bdev))) - 1; 321a08e67a0SHuang Jianan else 322a08e67a0SHuang Jianan blksize_mask = (1 << inode->i_blkbits) - 1; 323a08e67a0SHuang Jianan 324a08e67a0SHuang Jianan if (align & blksize_mask) 325a08e67a0SHuang Jianan return -EINVAL; 326a08e67a0SHuang Jianan return 0; 327a08e67a0SHuang Jianan } 328a08e67a0SHuang Jianan 329a08e67a0SHuang Jianan static ssize_t erofs_file_read_iter(struct kiocb *iocb, struct iov_iter *to) 330a08e67a0SHuang Jianan { 331a08e67a0SHuang Jianan /* no need taking (shared) inode lock since it's a ro filesystem */ 332a08e67a0SHuang Jianan if (!iov_iter_count(to)) 333a08e67a0SHuang Jianan return 0; 334a08e67a0SHuang Jianan 33506252e9cSGao Xiang #ifdef CONFIG_FS_DAX 33606252e9cSGao Xiang if (IS_DAX(iocb->ki_filp->f_mapping->host)) 33706252e9cSGao Xiang return dax_iomap_rw(iocb, to, &erofs_iomap_ops); 33806252e9cSGao Xiang #endif 339a08e67a0SHuang Jianan if (iocb->ki_flags & IOCB_DIRECT) { 340a08e67a0SHuang Jianan int err = erofs_prepare_dio(iocb, to); 341a08e67a0SHuang Jianan 342a08e67a0SHuang Jianan if (!err) 343a08e67a0SHuang Jianan return iomap_dio_rw(iocb, to, &erofs_iomap_ops, 3444fdccaa0SAndreas Gruenbacher NULL, 0, 0); 345a08e67a0SHuang Jianan if (err < 0) 346a08e67a0SHuang Jianan return err; 347a08e67a0SHuang Jianan } 348a08e67a0SHuang Jianan return filemap_read(iocb, to, 0); 349a08e67a0SHuang Jianan } 350a08e67a0SHuang Jianan 35147e4937aSGao Xiang /* for uncompressed (aligned) files and raw access for other files */ 35247e4937aSGao Xiang const struct address_space_operations erofs_raw_access_aops = { 353771c994eSGao Xiang .readpage = erofs_readpage, 354771c994eSGao Xiang .readahead = erofs_readahead, 35547e4937aSGao Xiang .bmap = erofs_bmap, 356a08e67a0SHuang Jianan .direct_IO = noop_direct_IO, 357a08e67a0SHuang Jianan }; 358a08e67a0SHuang Jianan 35906252e9cSGao Xiang #ifdef CONFIG_FS_DAX 36006252e9cSGao Xiang static vm_fault_t erofs_dax_huge_fault(struct vm_fault *vmf, 36106252e9cSGao Xiang enum page_entry_size pe_size) 36206252e9cSGao Xiang { 36306252e9cSGao Xiang return dax_iomap_fault(vmf, pe_size, NULL, NULL, &erofs_iomap_ops); 36406252e9cSGao Xiang } 36506252e9cSGao Xiang 36606252e9cSGao Xiang static vm_fault_t erofs_dax_fault(struct vm_fault *vmf) 36706252e9cSGao Xiang { 36806252e9cSGao Xiang return erofs_dax_huge_fault(vmf, PE_SIZE_PTE); 36906252e9cSGao Xiang } 37006252e9cSGao Xiang 37106252e9cSGao Xiang static const struct vm_operations_struct erofs_dax_vm_ops = { 37206252e9cSGao Xiang .fault = erofs_dax_fault, 37306252e9cSGao Xiang .huge_fault = erofs_dax_huge_fault, 37406252e9cSGao Xiang }; 37506252e9cSGao Xiang 37606252e9cSGao Xiang static int erofs_file_mmap(struct file *file, struct vm_area_struct *vma) 37706252e9cSGao Xiang { 37806252e9cSGao Xiang if (!IS_DAX(file_inode(file))) 37906252e9cSGao Xiang return generic_file_readonly_mmap(file, vma); 38006252e9cSGao Xiang 38106252e9cSGao Xiang if ((vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_MAYWRITE)) 38206252e9cSGao Xiang return -EINVAL; 38306252e9cSGao Xiang 38406252e9cSGao Xiang vma->vm_ops = &erofs_dax_vm_ops; 38506252e9cSGao Xiang vma->vm_flags |= VM_HUGEPAGE; 38606252e9cSGao Xiang return 0; 38706252e9cSGao Xiang } 38806252e9cSGao Xiang #else 38906252e9cSGao Xiang #define erofs_file_mmap generic_file_readonly_mmap 39006252e9cSGao Xiang #endif 39106252e9cSGao Xiang 392a08e67a0SHuang Jianan const struct file_operations erofs_file_fops = { 393a08e67a0SHuang Jianan .llseek = generic_file_llseek, 394a08e67a0SHuang Jianan .read_iter = erofs_file_read_iter, 39506252e9cSGao Xiang .mmap = erofs_file_mmap, 396a08e67a0SHuang Jianan .splice_read = generic_file_splice_read, 39747e4937aSGao Xiang }; 398