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/ 547e4937aSGao Xiang * Created by Gao Xiang <gaoxiang25@huawei.com> 647e4937aSGao Xiang */ 747e4937aSGao Xiang #include "xattr.h" 847e4937aSGao Xiang 947e4937aSGao Xiang #include <trace/events/erofs.h> 1047e4937aSGao Xiang 1147e4937aSGao Xiang /* no locking */ 1299634bf3SGao Xiang static int erofs_read_inode(struct inode *inode, void *data) 1347e4937aSGao Xiang { 14a5876e24SGao Xiang struct erofs_inode *vi = EROFS_I(inode); 158a765682SGao Xiang struct erofs_inode_compact *dic = data; 168a765682SGao Xiang struct erofs_inode_extended *die; 178a765682SGao Xiang 188a765682SGao Xiang const unsigned int ifmt = le16_to_cpu(dic->i_format); 198a765682SGao Xiang struct erofs_sb_info *sbi = EROFS_SB(inode->i_sb); 2047e4937aSGao Xiang erofs_blk_t nblks = 0; 2147e4937aSGao Xiang 228a765682SGao Xiang vi->datalayout = erofs_inode_datalayout(ifmt); 2347e4937aSGao Xiang 248a765682SGao Xiang if (vi->datalayout >= EROFS_INODE_DATALAYOUT_MAX) { 254f761fa2SGao Xiang erofs_err(inode->i_sb, "unsupported datalayout %u of nid %llu", 268a765682SGao Xiang vi->datalayout, vi->nid); 2747e4937aSGao Xiang DBG_BUGON(1); 2847e4937aSGao Xiang return -EOPNOTSUPP; 2947e4937aSGao Xiang } 3047e4937aSGao Xiang 318a765682SGao Xiang switch (erofs_inode_version(ifmt)) { 328a765682SGao Xiang case EROFS_INODE_LAYOUT_EXTENDED: 338a765682SGao Xiang die = data; 3447e4937aSGao Xiang 358a765682SGao Xiang vi->inode_isize = sizeof(struct erofs_inode_extended); 368a765682SGao Xiang vi->xattr_isize = erofs_xattr_ibody_size(die->i_xattr_icount); 3747e4937aSGao Xiang 388a765682SGao Xiang inode->i_mode = le16_to_cpu(die->i_mode); 398a765682SGao Xiang switch (inode->i_mode & S_IFMT) { 408a765682SGao Xiang case S_IFREG: 418a765682SGao Xiang case S_IFDIR: 428a765682SGao Xiang case S_IFLNK: 438a765682SGao Xiang vi->raw_blkaddr = le32_to_cpu(die->i_u.raw_blkaddr); 448a765682SGao Xiang break; 458a765682SGao Xiang case S_IFCHR: 468a765682SGao Xiang case S_IFBLK: 4747e4937aSGao Xiang inode->i_rdev = 488a765682SGao Xiang new_decode_dev(le32_to_cpu(die->i_u.rdev)); 498a765682SGao Xiang break; 508a765682SGao Xiang case S_IFIFO: 518a765682SGao Xiang case S_IFSOCK: 5247e4937aSGao Xiang inode->i_rdev = 0; 538a765682SGao Xiang break; 548a765682SGao Xiang default: 5547e4937aSGao Xiang goto bogusimode; 568a765682SGao Xiang } 578a765682SGao Xiang i_uid_write(inode, le32_to_cpu(die->i_uid)); 588a765682SGao Xiang i_gid_write(inode, le32_to_cpu(die->i_gid)); 598a765682SGao Xiang set_nlink(inode, le32_to_cpu(die->i_nlink)); 6047e4937aSGao Xiang 6147e4937aSGao Xiang /* ns timestamp */ 6247e4937aSGao Xiang inode->i_mtime.tv_sec = inode->i_ctime.tv_sec = 638a765682SGao Xiang le64_to_cpu(die->i_ctime); 6447e4937aSGao Xiang inode->i_mtime.tv_nsec = inode->i_ctime.tv_nsec = 658a765682SGao Xiang le32_to_cpu(die->i_ctime_nsec); 6647e4937aSGao Xiang 678a765682SGao Xiang inode->i_size = le64_to_cpu(die->i_size); 6847e4937aSGao Xiang 6947e4937aSGao Xiang /* total blocks for compressed files */ 708a765682SGao Xiang if (erofs_inode_is_data_compressed(vi->datalayout)) 718a765682SGao Xiang nblks = le32_to_cpu(die->i_u.compressed_blocks); 728a765682SGao Xiang break; 738a765682SGao Xiang case EROFS_INODE_LAYOUT_COMPACT: 748a765682SGao Xiang vi->inode_isize = sizeof(struct erofs_inode_compact); 758a765682SGao Xiang vi->xattr_isize = erofs_xattr_ibody_size(dic->i_xattr_icount); 7647e4937aSGao Xiang 778a765682SGao Xiang inode->i_mode = le16_to_cpu(dic->i_mode); 788a765682SGao Xiang switch (inode->i_mode & S_IFMT) { 798a765682SGao Xiang case S_IFREG: 808a765682SGao Xiang case S_IFDIR: 818a765682SGao Xiang case S_IFLNK: 828a765682SGao Xiang vi->raw_blkaddr = le32_to_cpu(dic->i_u.raw_blkaddr); 838a765682SGao Xiang break; 848a765682SGao Xiang case S_IFCHR: 858a765682SGao Xiang case S_IFBLK: 8647e4937aSGao Xiang inode->i_rdev = 878a765682SGao Xiang new_decode_dev(le32_to_cpu(dic->i_u.rdev)); 888a765682SGao Xiang break; 898a765682SGao Xiang case S_IFIFO: 908a765682SGao Xiang case S_IFSOCK: 9147e4937aSGao Xiang inode->i_rdev = 0; 928a765682SGao Xiang break; 938a765682SGao Xiang default: 9447e4937aSGao Xiang goto bogusimode; 958a765682SGao Xiang } 968a765682SGao Xiang i_uid_write(inode, le16_to_cpu(dic->i_uid)); 978a765682SGao Xiang i_gid_write(inode, le16_to_cpu(dic->i_gid)); 988a765682SGao Xiang set_nlink(inode, le16_to_cpu(dic->i_nlink)); 9947e4937aSGao Xiang 10047e4937aSGao Xiang /* use build time to derive all file time */ 10147e4937aSGao Xiang inode->i_mtime.tv_sec = inode->i_ctime.tv_sec = 10247e4937aSGao Xiang sbi->build_time; 10347e4937aSGao Xiang inode->i_mtime.tv_nsec = inode->i_ctime.tv_nsec = 10447e4937aSGao Xiang sbi->build_time_nsec; 10547e4937aSGao Xiang 1068a765682SGao Xiang inode->i_size = le32_to_cpu(dic->i_size); 1078a765682SGao Xiang if (erofs_inode_is_data_compressed(vi->datalayout)) 1088a765682SGao Xiang nblks = le32_to_cpu(dic->i_u.compressed_blocks); 1098a765682SGao Xiang break; 1108a765682SGao Xiang default: 1114f761fa2SGao Xiang erofs_err(inode->i_sb, 1124f761fa2SGao Xiang "unsupported on-disk inode version %u of nid %llu", 1138a765682SGao Xiang erofs_inode_version(ifmt), vi->nid); 11447e4937aSGao Xiang DBG_BUGON(1); 11547e4937aSGao Xiang return -EOPNOTSUPP; 11647e4937aSGao Xiang } 11747e4937aSGao Xiang 11847e4937aSGao Xiang if (!nblks) 11947e4937aSGao Xiang /* measure inode.i_blocks as generic filesystems */ 12047e4937aSGao Xiang inode->i_blocks = roundup(inode->i_size, EROFS_BLKSIZ) >> 9; 12147e4937aSGao Xiang else 12247e4937aSGao Xiang inode->i_blocks = nblks << LOG_SECTORS_PER_BLOCK; 12347e4937aSGao Xiang return 0; 12447e4937aSGao Xiang 12547e4937aSGao Xiang bogusimode: 1264f761fa2SGao Xiang erofs_err(inode->i_sb, "bogus i_mode (%o) @ nid %llu", 1274f761fa2SGao Xiang inode->i_mode, vi->nid); 12847e4937aSGao Xiang DBG_BUGON(1); 12947e4937aSGao Xiang return -EFSCORRUPTED; 13047e4937aSGao Xiang } 13147e4937aSGao Xiang 132a2c75c81SGao Xiang static int erofs_fill_symlink(struct inode *inode, void *data, 13347e4937aSGao Xiang unsigned int m_pofs) 13447e4937aSGao Xiang { 135a5876e24SGao Xiang struct erofs_inode *vi = EROFS_I(inode); 136a2c75c81SGao Xiang char *lnk; 13747e4937aSGao Xiang 138a2c75c81SGao Xiang /* if it cannot be handled with fast symlink scheme */ 139a2c75c81SGao Xiang if (vi->datalayout != EROFS_INODE_FLAT_INLINE || 140a2c75c81SGao Xiang inode->i_size >= PAGE_SIZE) { 141a2c75c81SGao Xiang inode->i_op = &erofs_symlink_iops; 14247e4937aSGao Xiang return 0; 143a2c75c81SGao Xiang } 14447e4937aSGao Xiang 145e2c71e74SGao Xiang lnk = kmalloc(inode->i_size + 1, GFP_KERNEL); 1468d8a09b0SGao Xiang if (!lnk) 14747e4937aSGao Xiang return -ENOMEM; 14847e4937aSGao Xiang 14947e4937aSGao Xiang m_pofs += vi->inode_isize + vi->xattr_isize; 1502d78c209SGao Xiang /* inline symlink data shouldn't cross page boundary as well */ 1518d8a09b0SGao Xiang if (m_pofs + inode->i_size > PAGE_SIZE) { 15247e4937aSGao Xiang kfree(lnk); 1534f761fa2SGao Xiang erofs_err(inode->i_sb, 1544f761fa2SGao Xiang "inline data cross block boundary @ nid %llu", 15547e4937aSGao Xiang vi->nid); 15647e4937aSGao Xiang DBG_BUGON(1); 15747e4937aSGao Xiang return -EFSCORRUPTED; 15847e4937aSGao Xiang } 15947e4937aSGao Xiang 16047e4937aSGao Xiang memcpy(lnk, data + m_pofs, inode->i_size); 16147e4937aSGao Xiang lnk[inode->i_size] = '\0'; 16247e4937aSGao Xiang 16347e4937aSGao Xiang inode->i_link = lnk; 164a2c75c81SGao Xiang inode->i_op = &erofs_fast_symlink_iops; 16547e4937aSGao Xiang return 0; 16647e4937aSGao Xiang } 16747e4937aSGao Xiang 16899634bf3SGao Xiang static int erofs_fill_inode(struct inode *inode, int isdir) 16947e4937aSGao Xiang { 1704f761fa2SGao Xiang struct super_block *sb = inode->i_sb; 171a5876e24SGao Xiang struct erofs_inode *vi = EROFS_I(inode); 17247e4937aSGao Xiang struct page *page; 17347e4937aSGao Xiang void *data; 17447e4937aSGao Xiang int err; 17547e4937aSGao Xiang erofs_blk_t blkaddr; 17647e4937aSGao Xiang unsigned int ofs; 17747e4937aSGao Xiang erofs_off_t inode_loc; 17847e4937aSGao Xiang 17947e4937aSGao Xiang trace_erofs_fill_inode(inode, isdir); 1804f761fa2SGao Xiang inode_loc = iloc(EROFS_SB(sb), vi->nid); 18147e4937aSGao Xiang blkaddr = erofs_blknr(inode_loc); 18247e4937aSGao Xiang ofs = erofs_blkoff(inode_loc); 18347e4937aSGao Xiang 1844f761fa2SGao Xiang erofs_dbg("%s, reading inode nid %llu at %u of blkaddr %u", 18547e4937aSGao Xiang __func__, vi->nid, ofs, blkaddr); 18647e4937aSGao Xiang 1874f761fa2SGao Xiang page = erofs_get_meta_page(sb, blkaddr); 18847e4937aSGao Xiang 18947e4937aSGao Xiang if (IS_ERR(page)) { 1904f761fa2SGao Xiang erofs_err(sb, "failed to get inode (nid: %llu) page, err %ld", 19147e4937aSGao Xiang vi->nid, PTR_ERR(page)); 19247e4937aSGao Xiang return PTR_ERR(page); 19347e4937aSGao Xiang } 19447e4937aSGao Xiang 19547e4937aSGao Xiang DBG_BUGON(!PageUptodate(page)); 19647e4937aSGao Xiang data = page_address(page); 19747e4937aSGao Xiang 19899634bf3SGao Xiang err = erofs_read_inode(inode, data + ofs); 19984947eb6SGao Xiang if (err) 20084947eb6SGao Xiang goto out_unlock; 20184947eb6SGao Xiang 20247e4937aSGao Xiang /* setup the new inode */ 203512f9922SPratik Shinde switch (inode->i_mode & S_IFMT) { 204512f9922SPratik Shinde case S_IFREG: 20547e4937aSGao Xiang inode->i_op = &erofs_generic_iops; 20647e4937aSGao Xiang inode->i_fop = &generic_ro_fops; 207512f9922SPratik Shinde break; 208512f9922SPratik Shinde case S_IFDIR: 20947e4937aSGao Xiang inode->i_op = &erofs_dir_iops; 21047e4937aSGao Xiang inode->i_fop = &erofs_dir_fops; 211512f9922SPratik Shinde break; 212512f9922SPratik Shinde case S_IFLNK: 213a2c75c81SGao Xiang err = erofs_fill_symlink(inode, data, ofs); 214a2c75c81SGao Xiang if (err) 215a2c75c81SGao Xiang goto out_unlock; 21647e4937aSGao Xiang inode_nohighmem(inode); 217512f9922SPratik Shinde break; 218512f9922SPratik Shinde case S_IFCHR: 219512f9922SPratik Shinde case S_IFBLK: 220512f9922SPratik Shinde case S_IFIFO: 221512f9922SPratik Shinde case S_IFSOCK: 22247e4937aSGao Xiang inode->i_op = &erofs_generic_iops; 22347e4937aSGao Xiang init_special_inode(inode, inode->i_mode, inode->i_rdev); 22447e4937aSGao Xiang goto out_unlock; 225512f9922SPratik Shinde default: 22647e4937aSGao Xiang err = -EFSCORRUPTED; 22747e4937aSGao Xiang goto out_unlock; 22847e4937aSGao Xiang } 22947e4937aSGao Xiang 2308a765682SGao Xiang if (erofs_inode_is_data_compressed(vi->datalayout)) { 23147e4937aSGao Xiang err = z_erofs_fill_inode(inode); 23247e4937aSGao Xiang goto out_unlock; 23347e4937aSGao Xiang } 23447e4937aSGao Xiang inode->i_mapping->a_ops = &erofs_raw_access_aops; 23547e4937aSGao Xiang 23647e4937aSGao Xiang out_unlock: 23747e4937aSGao Xiang unlock_page(page); 23847e4937aSGao Xiang put_page(page); 23947e4937aSGao Xiang return err; 24047e4937aSGao Xiang } 24147e4937aSGao Xiang 24247e4937aSGao Xiang /* 24347e4937aSGao Xiang * erofs nid is 64bits, but i_ino is 'unsigned long', therefore 24447e4937aSGao Xiang * we should do more for 32-bit platform to find the right inode. 24547e4937aSGao Xiang */ 24647e4937aSGao Xiang static int erofs_ilookup_test_actor(struct inode *inode, void *opaque) 24747e4937aSGao Xiang { 24847e4937aSGao Xiang const erofs_nid_t nid = *(erofs_nid_t *)opaque; 24947e4937aSGao Xiang 250a5876e24SGao Xiang return EROFS_I(inode)->nid == nid; 25147e4937aSGao Xiang } 25247e4937aSGao Xiang 25347e4937aSGao Xiang static int erofs_iget_set_actor(struct inode *inode, void *opaque) 25447e4937aSGao Xiang { 25547e4937aSGao Xiang const erofs_nid_t nid = *(erofs_nid_t *)opaque; 25647e4937aSGao Xiang 25747e4937aSGao Xiang inode->i_ino = erofs_inode_hash(nid); 25847e4937aSGao Xiang return 0; 25947e4937aSGao Xiang } 26047e4937aSGao Xiang 26147e4937aSGao Xiang static inline struct inode *erofs_iget_locked(struct super_block *sb, 26247e4937aSGao Xiang erofs_nid_t nid) 26347e4937aSGao Xiang { 26447e4937aSGao Xiang const unsigned long hashval = erofs_inode_hash(nid); 26547e4937aSGao Xiang 26647e4937aSGao Xiang return iget5_locked(sb, hashval, erofs_ilookup_test_actor, 26747e4937aSGao Xiang erofs_iget_set_actor, &nid); 26847e4937aSGao Xiang } 26947e4937aSGao Xiang 27047e4937aSGao Xiang struct inode *erofs_iget(struct super_block *sb, 27147e4937aSGao Xiang erofs_nid_t nid, 27247e4937aSGao Xiang bool isdir) 27347e4937aSGao Xiang { 27447e4937aSGao Xiang struct inode *inode = erofs_iget_locked(sb, nid); 27547e4937aSGao Xiang 2768d8a09b0SGao Xiang if (!inode) 27747e4937aSGao Xiang return ERR_PTR(-ENOMEM); 27847e4937aSGao Xiang 27947e4937aSGao Xiang if (inode->i_state & I_NEW) { 28047e4937aSGao Xiang int err; 281a5876e24SGao Xiang struct erofs_inode *vi = EROFS_I(inode); 28247e4937aSGao Xiang 28347e4937aSGao Xiang vi->nid = nid; 28447e4937aSGao Xiang 28599634bf3SGao Xiang err = erofs_fill_inode(inode, isdir); 2868d8a09b0SGao Xiang if (!err) 28747e4937aSGao Xiang unlock_new_inode(inode); 28847e4937aSGao Xiang else { 28947e4937aSGao Xiang iget_failed(inode); 29047e4937aSGao Xiang inode = ERR_PTR(err); 29147e4937aSGao Xiang } 29247e4937aSGao Xiang } 29347e4937aSGao Xiang return inode; 29447e4937aSGao Xiang } 29547e4937aSGao Xiang 29647e4937aSGao Xiang int erofs_getattr(const struct path *path, struct kstat *stat, 29747e4937aSGao Xiang u32 request_mask, unsigned int query_flags) 29847e4937aSGao Xiang { 29947e4937aSGao Xiang struct inode *const inode = d_inode(path->dentry); 30047e4937aSGao Xiang 301a5876e24SGao Xiang if (erofs_inode_is_data_compressed(EROFS_I(inode)->datalayout)) 30247e4937aSGao Xiang stat->attributes |= STATX_ATTR_COMPRESSED; 30347e4937aSGao Xiang 30447e4937aSGao Xiang stat->attributes |= STATX_ATTR_IMMUTABLE; 30547e4937aSGao Xiang stat->attributes_mask |= (STATX_ATTR_COMPRESSED | 30647e4937aSGao Xiang STATX_ATTR_IMMUTABLE); 30747e4937aSGao Xiang 30847e4937aSGao Xiang generic_fillattr(inode, stat); 30947e4937aSGao Xiang return 0; 31047e4937aSGao Xiang } 31147e4937aSGao Xiang 31247e4937aSGao Xiang const struct inode_operations erofs_generic_iops = { 31347e4937aSGao Xiang .getattr = erofs_getattr, 31447e4937aSGao Xiang .listxattr = erofs_listxattr, 31547e4937aSGao Xiang .get_acl = erofs_get_acl, 31647e4937aSGao Xiang }; 31747e4937aSGao Xiang 31847e4937aSGao Xiang const struct inode_operations erofs_symlink_iops = { 31947e4937aSGao Xiang .get_link = page_get_link, 32047e4937aSGao Xiang .getattr = erofs_getattr, 32147e4937aSGao Xiang .listxattr = erofs_listxattr, 32247e4937aSGao Xiang .get_acl = erofs_get_acl, 32347e4937aSGao Xiang }; 32447e4937aSGao Xiang 32547e4937aSGao Xiang const struct inode_operations erofs_fast_symlink_iops = { 32647e4937aSGao Xiang .get_link = simple_get_link, 32747e4937aSGao Xiang .getattr = erofs_getattr, 32847e4937aSGao Xiang .listxattr = erofs_listxattr, 32947e4937aSGao Xiang .get_acl = erofs_get_acl, 33047e4937aSGao Xiang }; 33147e4937aSGao Xiang 332