162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2017-2018 HUAWEI, Inc. 462306a36Sopenharmony_ci * https://www.huawei.com/ 562306a36Sopenharmony_ci * Copyright (C) 2021, Alibaba Cloud 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci#include "xattr.h" 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <trace/events/erofs.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_cistatic void *erofs_read_inode(struct erofs_buf *buf, 1262306a36Sopenharmony_ci struct inode *inode, unsigned int *ofs) 1362306a36Sopenharmony_ci{ 1462306a36Sopenharmony_ci struct super_block *sb = inode->i_sb; 1562306a36Sopenharmony_ci struct erofs_sb_info *sbi = EROFS_SB(sb); 1662306a36Sopenharmony_ci struct erofs_inode *vi = EROFS_I(inode); 1762306a36Sopenharmony_ci const erofs_off_t inode_loc = erofs_iloc(inode); 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci erofs_blk_t blkaddr, nblks = 0; 2062306a36Sopenharmony_ci void *kaddr; 2162306a36Sopenharmony_ci struct erofs_inode_compact *dic; 2262306a36Sopenharmony_ci struct erofs_inode_extended *die, *copied = NULL; 2362306a36Sopenharmony_ci unsigned int ifmt; 2462306a36Sopenharmony_ci int err; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci blkaddr = erofs_blknr(sb, inode_loc); 2762306a36Sopenharmony_ci *ofs = erofs_blkoff(sb, inode_loc); 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci kaddr = erofs_read_metabuf(buf, sb, blkaddr, EROFS_KMAP); 3062306a36Sopenharmony_ci if (IS_ERR(kaddr)) { 3162306a36Sopenharmony_ci erofs_err(sb, "failed to get inode (nid: %llu) page, err %ld", 3262306a36Sopenharmony_ci vi->nid, PTR_ERR(kaddr)); 3362306a36Sopenharmony_ci return kaddr; 3462306a36Sopenharmony_ci } 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci dic = kaddr + *ofs; 3762306a36Sopenharmony_ci ifmt = le16_to_cpu(dic->i_format); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci if (ifmt & ~EROFS_I_ALL) { 4062306a36Sopenharmony_ci erofs_err(inode->i_sb, "unsupported i_format %u of nid %llu", 4162306a36Sopenharmony_ci ifmt, vi->nid); 4262306a36Sopenharmony_ci err = -EOPNOTSUPP; 4362306a36Sopenharmony_ci goto err_out; 4462306a36Sopenharmony_ci } 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci vi->datalayout = erofs_inode_datalayout(ifmt); 4762306a36Sopenharmony_ci if (vi->datalayout >= EROFS_INODE_DATALAYOUT_MAX) { 4862306a36Sopenharmony_ci erofs_err(inode->i_sb, "unsupported datalayout %u of nid %llu", 4962306a36Sopenharmony_ci vi->datalayout, vi->nid); 5062306a36Sopenharmony_ci err = -EOPNOTSUPP; 5162306a36Sopenharmony_ci goto err_out; 5262306a36Sopenharmony_ci } 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci switch (erofs_inode_version(ifmt)) { 5562306a36Sopenharmony_ci case EROFS_INODE_LAYOUT_EXTENDED: 5662306a36Sopenharmony_ci vi->inode_isize = sizeof(struct erofs_inode_extended); 5762306a36Sopenharmony_ci /* check if the extended inode acrosses block boundary */ 5862306a36Sopenharmony_ci if (*ofs + vi->inode_isize <= sb->s_blocksize) { 5962306a36Sopenharmony_ci *ofs += vi->inode_isize; 6062306a36Sopenharmony_ci die = (struct erofs_inode_extended *)dic; 6162306a36Sopenharmony_ci } else { 6262306a36Sopenharmony_ci const unsigned int gotten = sb->s_blocksize - *ofs; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci copied = kmalloc(vi->inode_isize, GFP_NOFS); 6562306a36Sopenharmony_ci if (!copied) { 6662306a36Sopenharmony_ci err = -ENOMEM; 6762306a36Sopenharmony_ci goto err_out; 6862306a36Sopenharmony_ci } 6962306a36Sopenharmony_ci memcpy(copied, dic, gotten); 7062306a36Sopenharmony_ci kaddr = erofs_read_metabuf(buf, sb, blkaddr + 1, 7162306a36Sopenharmony_ci EROFS_KMAP); 7262306a36Sopenharmony_ci if (IS_ERR(kaddr)) { 7362306a36Sopenharmony_ci erofs_err(sb, "failed to get inode payload block (nid: %llu), err %ld", 7462306a36Sopenharmony_ci vi->nid, PTR_ERR(kaddr)); 7562306a36Sopenharmony_ci kfree(copied); 7662306a36Sopenharmony_ci return kaddr; 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci *ofs = vi->inode_isize - gotten; 7962306a36Sopenharmony_ci memcpy((u8 *)copied + gotten, kaddr, *ofs); 8062306a36Sopenharmony_ci die = copied; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci vi->xattr_isize = erofs_xattr_ibody_size(die->i_xattr_icount); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci inode->i_mode = le16_to_cpu(die->i_mode); 8562306a36Sopenharmony_ci switch (inode->i_mode & S_IFMT) { 8662306a36Sopenharmony_ci case S_IFREG: 8762306a36Sopenharmony_ci case S_IFDIR: 8862306a36Sopenharmony_ci case S_IFLNK: 8962306a36Sopenharmony_ci vi->raw_blkaddr = le32_to_cpu(die->i_u.raw_blkaddr); 9062306a36Sopenharmony_ci break; 9162306a36Sopenharmony_ci case S_IFCHR: 9262306a36Sopenharmony_ci case S_IFBLK: 9362306a36Sopenharmony_ci inode->i_rdev = 9462306a36Sopenharmony_ci new_decode_dev(le32_to_cpu(die->i_u.rdev)); 9562306a36Sopenharmony_ci break; 9662306a36Sopenharmony_ci case S_IFIFO: 9762306a36Sopenharmony_ci case S_IFSOCK: 9862306a36Sopenharmony_ci inode->i_rdev = 0; 9962306a36Sopenharmony_ci break; 10062306a36Sopenharmony_ci default: 10162306a36Sopenharmony_ci goto bogusimode; 10262306a36Sopenharmony_ci } 10362306a36Sopenharmony_ci i_uid_write(inode, le32_to_cpu(die->i_uid)); 10462306a36Sopenharmony_ci i_gid_write(inode, le32_to_cpu(die->i_gid)); 10562306a36Sopenharmony_ci set_nlink(inode, le32_to_cpu(die->i_nlink)); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci /* extended inode has its own timestamp */ 10862306a36Sopenharmony_ci inode_set_ctime(inode, le64_to_cpu(die->i_mtime), 10962306a36Sopenharmony_ci le32_to_cpu(die->i_mtime_nsec)); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci inode->i_size = le64_to_cpu(die->i_size); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci /* total blocks for compressed files */ 11462306a36Sopenharmony_ci if (erofs_inode_is_data_compressed(vi->datalayout)) 11562306a36Sopenharmony_ci nblks = le32_to_cpu(die->i_u.compressed_blocks); 11662306a36Sopenharmony_ci else if (vi->datalayout == EROFS_INODE_CHUNK_BASED) 11762306a36Sopenharmony_ci /* fill chunked inode summary info */ 11862306a36Sopenharmony_ci vi->chunkformat = le16_to_cpu(die->i_u.c.format); 11962306a36Sopenharmony_ci kfree(copied); 12062306a36Sopenharmony_ci copied = NULL; 12162306a36Sopenharmony_ci break; 12262306a36Sopenharmony_ci case EROFS_INODE_LAYOUT_COMPACT: 12362306a36Sopenharmony_ci vi->inode_isize = sizeof(struct erofs_inode_compact); 12462306a36Sopenharmony_ci *ofs += vi->inode_isize; 12562306a36Sopenharmony_ci vi->xattr_isize = erofs_xattr_ibody_size(dic->i_xattr_icount); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci inode->i_mode = le16_to_cpu(dic->i_mode); 12862306a36Sopenharmony_ci switch (inode->i_mode & S_IFMT) { 12962306a36Sopenharmony_ci case S_IFREG: 13062306a36Sopenharmony_ci case S_IFDIR: 13162306a36Sopenharmony_ci case S_IFLNK: 13262306a36Sopenharmony_ci vi->raw_blkaddr = le32_to_cpu(dic->i_u.raw_blkaddr); 13362306a36Sopenharmony_ci break; 13462306a36Sopenharmony_ci case S_IFCHR: 13562306a36Sopenharmony_ci case S_IFBLK: 13662306a36Sopenharmony_ci inode->i_rdev = 13762306a36Sopenharmony_ci new_decode_dev(le32_to_cpu(dic->i_u.rdev)); 13862306a36Sopenharmony_ci break; 13962306a36Sopenharmony_ci case S_IFIFO: 14062306a36Sopenharmony_ci case S_IFSOCK: 14162306a36Sopenharmony_ci inode->i_rdev = 0; 14262306a36Sopenharmony_ci break; 14362306a36Sopenharmony_ci default: 14462306a36Sopenharmony_ci goto bogusimode; 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci i_uid_write(inode, le16_to_cpu(dic->i_uid)); 14762306a36Sopenharmony_ci i_gid_write(inode, le16_to_cpu(dic->i_gid)); 14862306a36Sopenharmony_ci set_nlink(inode, le16_to_cpu(dic->i_nlink)); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci /* use build time for compact inodes */ 15162306a36Sopenharmony_ci inode_set_ctime(inode, sbi->build_time, sbi->build_time_nsec); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci inode->i_size = le32_to_cpu(dic->i_size); 15462306a36Sopenharmony_ci if (erofs_inode_is_data_compressed(vi->datalayout)) 15562306a36Sopenharmony_ci nblks = le32_to_cpu(dic->i_u.compressed_blocks); 15662306a36Sopenharmony_ci else if (vi->datalayout == EROFS_INODE_CHUNK_BASED) 15762306a36Sopenharmony_ci vi->chunkformat = le16_to_cpu(dic->i_u.c.format); 15862306a36Sopenharmony_ci break; 15962306a36Sopenharmony_ci default: 16062306a36Sopenharmony_ci erofs_err(inode->i_sb, 16162306a36Sopenharmony_ci "unsupported on-disk inode version %u of nid %llu", 16262306a36Sopenharmony_ci erofs_inode_version(ifmt), vi->nid); 16362306a36Sopenharmony_ci err = -EOPNOTSUPP; 16462306a36Sopenharmony_ci goto err_out; 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci if (vi->datalayout == EROFS_INODE_CHUNK_BASED) { 16862306a36Sopenharmony_ci if (vi->chunkformat & ~EROFS_CHUNK_FORMAT_ALL) { 16962306a36Sopenharmony_ci erofs_err(inode->i_sb, 17062306a36Sopenharmony_ci "unsupported chunk format %x of nid %llu", 17162306a36Sopenharmony_ci vi->chunkformat, vi->nid); 17262306a36Sopenharmony_ci err = -EOPNOTSUPP; 17362306a36Sopenharmony_ci goto err_out; 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci vi->chunkbits = sb->s_blocksize_bits + 17662306a36Sopenharmony_ci (vi->chunkformat & EROFS_CHUNK_FORMAT_BLKBITS_MASK); 17762306a36Sopenharmony_ci } 17862306a36Sopenharmony_ci inode->i_mtime = inode->i_atime = inode_get_ctime(inode); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci inode->i_flags &= ~S_DAX; 18162306a36Sopenharmony_ci if (test_opt(&sbi->opt, DAX_ALWAYS) && S_ISREG(inode->i_mode) && 18262306a36Sopenharmony_ci (vi->datalayout == EROFS_INODE_FLAT_PLAIN || 18362306a36Sopenharmony_ci vi->datalayout == EROFS_INODE_CHUNK_BASED)) 18462306a36Sopenharmony_ci inode->i_flags |= S_DAX; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci if (!nblks) 18762306a36Sopenharmony_ci /* measure inode.i_blocks as generic filesystems */ 18862306a36Sopenharmony_ci inode->i_blocks = round_up(inode->i_size, sb->s_blocksize) >> 9; 18962306a36Sopenharmony_ci else 19062306a36Sopenharmony_ci inode->i_blocks = nblks << (sb->s_blocksize_bits - 9); 19162306a36Sopenharmony_ci return kaddr; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_cibogusimode: 19462306a36Sopenharmony_ci erofs_err(inode->i_sb, "bogus i_mode (%o) @ nid %llu", 19562306a36Sopenharmony_ci inode->i_mode, vi->nid); 19662306a36Sopenharmony_ci err = -EFSCORRUPTED; 19762306a36Sopenharmony_cierr_out: 19862306a36Sopenharmony_ci DBG_BUGON(1); 19962306a36Sopenharmony_ci kfree(copied); 20062306a36Sopenharmony_ci erofs_put_metabuf(buf); 20162306a36Sopenharmony_ci return ERR_PTR(err); 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cistatic int erofs_fill_symlink(struct inode *inode, void *kaddr, 20562306a36Sopenharmony_ci unsigned int m_pofs) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci struct erofs_inode *vi = EROFS_I(inode); 20862306a36Sopenharmony_ci unsigned int bsz = i_blocksize(inode); 20962306a36Sopenharmony_ci char *lnk; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci /* if it cannot be handled with fast symlink scheme */ 21262306a36Sopenharmony_ci if (vi->datalayout != EROFS_INODE_FLAT_INLINE || 21362306a36Sopenharmony_ci inode->i_size >= bsz || inode->i_size < 0) { 21462306a36Sopenharmony_ci inode->i_op = &erofs_symlink_iops; 21562306a36Sopenharmony_ci return 0; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci lnk = kmalloc(inode->i_size + 1, GFP_KERNEL); 21962306a36Sopenharmony_ci if (!lnk) 22062306a36Sopenharmony_ci return -ENOMEM; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci m_pofs += vi->xattr_isize; 22362306a36Sopenharmony_ci /* inline symlink data shouldn't cross block boundary */ 22462306a36Sopenharmony_ci if (m_pofs + inode->i_size > bsz) { 22562306a36Sopenharmony_ci kfree(lnk); 22662306a36Sopenharmony_ci erofs_err(inode->i_sb, 22762306a36Sopenharmony_ci "inline data cross block boundary @ nid %llu", 22862306a36Sopenharmony_ci vi->nid); 22962306a36Sopenharmony_ci DBG_BUGON(1); 23062306a36Sopenharmony_ci return -EFSCORRUPTED; 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci memcpy(lnk, kaddr + m_pofs, inode->i_size); 23362306a36Sopenharmony_ci lnk[inode->i_size] = '\0'; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci inode->i_link = lnk; 23662306a36Sopenharmony_ci inode->i_op = &erofs_fast_symlink_iops; 23762306a36Sopenharmony_ci return 0; 23862306a36Sopenharmony_ci} 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_cistatic int erofs_fill_inode(struct inode *inode) 24162306a36Sopenharmony_ci{ 24262306a36Sopenharmony_ci struct erofs_inode *vi = EROFS_I(inode); 24362306a36Sopenharmony_ci struct erofs_buf buf = __EROFS_BUF_INITIALIZER; 24462306a36Sopenharmony_ci void *kaddr; 24562306a36Sopenharmony_ci unsigned int ofs; 24662306a36Sopenharmony_ci int err = 0; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci trace_erofs_fill_inode(inode); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci /* read inode base data from disk */ 25162306a36Sopenharmony_ci kaddr = erofs_read_inode(&buf, inode, &ofs); 25262306a36Sopenharmony_ci if (IS_ERR(kaddr)) 25362306a36Sopenharmony_ci return PTR_ERR(kaddr); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci /* setup the new inode */ 25662306a36Sopenharmony_ci switch (inode->i_mode & S_IFMT) { 25762306a36Sopenharmony_ci case S_IFREG: 25862306a36Sopenharmony_ci inode->i_op = &erofs_generic_iops; 25962306a36Sopenharmony_ci if (erofs_inode_is_data_compressed(vi->datalayout)) 26062306a36Sopenharmony_ci inode->i_fop = &generic_ro_fops; 26162306a36Sopenharmony_ci else 26262306a36Sopenharmony_ci inode->i_fop = &erofs_file_fops; 26362306a36Sopenharmony_ci break; 26462306a36Sopenharmony_ci case S_IFDIR: 26562306a36Sopenharmony_ci inode->i_op = &erofs_dir_iops; 26662306a36Sopenharmony_ci inode->i_fop = &erofs_dir_fops; 26762306a36Sopenharmony_ci inode_nohighmem(inode); 26862306a36Sopenharmony_ci break; 26962306a36Sopenharmony_ci case S_IFLNK: 27062306a36Sopenharmony_ci err = erofs_fill_symlink(inode, kaddr, ofs); 27162306a36Sopenharmony_ci if (err) 27262306a36Sopenharmony_ci goto out_unlock; 27362306a36Sopenharmony_ci inode_nohighmem(inode); 27462306a36Sopenharmony_ci break; 27562306a36Sopenharmony_ci case S_IFCHR: 27662306a36Sopenharmony_ci case S_IFBLK: 27762306a36Sopenharmony_ci case S_IFIFO: 27862306a36Sopenharmony_ci case S_IFSOCK: 27962306a36Sopenharmony_ci inode->i_op = &erofs_generic_iops; 28062306a36Sopenharmony_ci init_special_inode(inode, inode->i_mode, inode->i_rdev); 28162306a36Sopenharmony_ci goto out_unlock; 28262306a36Sopenharmony_ci default: 28362306a36Sopenharmony_ci err = -EFSCORRUPTED; 28462306a36Sopenharmony_ci goto out_unlock; 28562306a36Sopenharmony_ci } 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci if (erofs_inode_is_data_compressed(vi->datalayout)) { 28862306a36Sopenharmony_ci#ifdef CONFIG_EROFS_FS_ZIP 28962306a36Sopenharmony_ci if (!erofs_is_fscache_mode(inode->i_sb) && 29062306a36Sopenharmony_ci inode->i_sb->s_blocksize_bits == PAGE_SHIFT) { 29162306a36Sopenharmony_ci inode->i_mapping->a_ops = &z_erofs_aops; 29262306a36Sopenharmony_ci err = 0; 29362306a36Sopenharmony_ci goto out_unlock; 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci#endif 29662306a36Sopenharmony_ci err = -EOPNOTSUPP; 29762306a36Sopenharmony_ci goto out_unlock; 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci inode->i_mapping->a_ops = &erofs_raw_access_aops; 30062306a36Sopenharmony_ci mapping_set_large_folios(inode->i_mapping); 30162306a36Sopenharmony_ci#ifdef CONFIG_EROFS_FS_ONDEMAND 30262306a36Sopenharmony_ci if (erofs_is_fscache_mode(inode->i_sb)) 30362306a36Sopenharmony_ci inode->i_mapping->a_ops = &erofs_fscache_access_aops; 30462306a36Sopenharmony_ci#endif 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ciout_unlock: 30762306a36Sopenharmony_ci erofs_put_metabuf(&buf); 30862306a36Sopenharmony_ci return err; 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci/* 31262306a36Sopenharmony_ci * ino_t is 32-bits on 32-bit arch. We have to squash the 64-bit value down 31362306a36Sopenharmony_ci * so that it will fit. 31462306a36Sopenharmony_ci */ 31562306a36Sopenharmony_cistatic ino_t erofs_squash_ino(erofs_nid_t nid) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci ino_t ino = (ino_t)nid; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci if (sizeof(ino_t) < sizeof(erofs_nid_t)) 32062306a36Sopenharmony_ci ino ^= nid >> (sizeof(erofs_nid_t) - sizeof(ino_t)) * 8; 32162306a36Sopenharmony_ci return ino; 32262306a36Sopenharmony_ci} 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_cistatic int erofs_iget5_eq(struct inode *inode, void *opaque) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci return EROFS_I(inode)->nid == *(erofs_nid_t *)opaque; 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_cistatic int erofs_iget5_set(struct inode *inode, void *opaque) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci const erofs_nid_t nid = *(erofs_nid_t *)opaque; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci inode->i_ino = erofs_squash_ino(nid); 33462306a36Sopenharmony_ci EROFS_I(inode)->nid = nid; 33562306a36Sopenharmony_ci return 0; 33662306a36Sopenharmony_ci} 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_cistruct inode *erofs_iget(struct super_block *sb, erofs_nid_t nid) 33962306a36Sopenharmony_ci{ 34062306a36Sopenharmony_ci struct inode *inode; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci inode = iget5_locked(sb, erofs_squash_ino(nid), erofs_iget5_eq, 34362306a36Sopenharmony_ci erofs_iget5_set, &nid); 34462306a36Sopenharmony_ci if (!inode) 34562306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci if (inode->i_state & I_NEW) { 34862306a36Sopenharmony_ci int err = erofs_fill_inode(inode); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci if (err) { 35162306a36Sopenharmony_ci iget_failed(inode); 35262306a36Sopenharmony_ci return ERR_PTR(err); 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci unlock_new_inode(inode); 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci return inode; 35762306a36Sopenharmony_ci} 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ciint erofs_getattr(struct mnt_idmap *idmap, const struct path *path, 36062306a36Sopenharmony_ci struct kstat *stat, u32 request_mask, 36162306a36Sopenharmony_ci unsigned int query_flags) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci struct inode *const inode = d_inode(path->dentry); 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci if (erofs_inode_is_data_compressed(EROFS_I(inode)->datalayout)) 36662306a36Sopenharmony_ci stat->attributes |= STATX_ATTR_COMPRESSED; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci stat->attributes |= STATX_ATTR_IMMUTABLE; 36962306a36Sopenharmony_ci stat->attributes_mask |= (STATX_ATTR_COMPRESSED | 37062306a36Sopenharmony_ci STATX_ATTR_IMMUTABLE); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci generic_fillattr(idmap, request_mask, inode, stat); 37362306a36Sopenharmony_ci return 0; 37462306a36Sopenharmony_ci} 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ciconst struct inode_operations erofs_generic_iops = { 37762306a36Sopenharmony_ci .getattr = erofs_getattr, 37862306a36Sopenharmony_ci .listxattr = erofs_listxattr, 37962306a36Sopenharmony_ci .get_inode_acl = erofs_get_acl, 38062306a36Sopenharmony_ci .fiemap = erofs_fiemap, 38162306a36Sopenharmony_ci}; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ciconst struct inode_operations erofs_symlink_iops = { 38462306a36Sopenharmony_ci .get_link = page_get_link, 38562306a36Sopenharmony_ci .getattr = erofs_getattr, 38662306a36Sopenharmony_ci .listxattr = erofs_listxattr, 38762306a36Sopenharmony_ci .get_inode_acl = erofs_get_acl, 38862306a36Sopenharmony_ci}; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ciconst struct inode_operations erofs_fast_symlink_iops = { 39162306a36Sopenharmony_ci .get_link = simple_get_link, 39262306a36Sopenharmony_ci .getattr = erofs_getattr, 39362306a36Sopenharmony_ci .listxattr = erofs_listxattr, 39462306a36Sopenharmony_ci .get_inode_acl = erofs_get_acl, 39562306a36Sopenharmony_ci}; 396