18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2017-2018 HUAWEI, Inc.
48c2ecf20Sopenharmony_ci *             https://www.huawei.com/
58c2ecf20Sopenharmony_ci * Created by Gao Xiang <gaoxiang25@huawei.com>
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci#include "xattr.h"
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <trace/events/erofs.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci/*
128c2ecf20Sopenharmony_ci * if inode is successfully read, return its inode page (or sometimes
138c2ecf20Sopenharmony_ci * the inode payload page if it's an extended inode) in order to fill
148c2ecf20Sopenharmony_ci * inline data if possible.
158c2ecf20Sopenharmony_ci */
168c2ecf20Sopenharmony_cistatic struct page *erofs_read_inode(struct inode *inode,
178c2ecf20Sopenharmony_ci				     unsigned int *ofs)
188c2ecf20Sopenharmony_ci{
198c2ecf20Sopenharmony_ci	struct super_block *sb = inode->i_sb;
208c2ecf20Sopenharmony_ci	struct erofs_sb_info *sbi = EROFS_SB(sb);
218c2ecf20Sopenharmony_ci	struct erofs_inode *vi = EROFS_I(inode);
228c2ecf20Sopenharmony_ci	const erofs_off_t inode_loc = iloc(sbi, vi->nid);
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci	erofs_blk_t blkaddr, nblks = 0;
258c2ecf20Sopenharmony_ci	struct page *page;
268c2ecf20Sopenharmony_ci	struct erofs_inode_compact *dic;
278c2ecf20Sopenharmony_ci	struct erofs_inode_extended *die, *copied = NULL;
288c2ecf20Sopenharmony_ci	unsigned int ifmt;
298c2ecf20Sopenharmony_ci	int err;
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	blkaddr = erofs_blknr(inode_loc);
328c2ecf20Sopenharmony_ci	*ofs = erofs_blkoff(inode_loc);
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	erofs_dbg("%s, reading inode nid %llu at %u of blkaddr %u",
358c2ecf20Sopenharmony_ci		  __func__, vi->nid, *ofs, blkaddr);
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	page = erofs_get_meta_page(sb, blkaddr);
388c2ecf20Sopenharmony_ci	if (IS_ERR(page)) {
398c2ecf20Sopenharmony_ci		erofs_err(sb, "failed to get inode (nid: %llu) page, err %ld",
408c2ecf20Sopenharmony_ci			  vi->nid, PTR_ERR(page));
418c2ecf20Sopenharmony_ci		return page;
428c2ecf20Sopenharmony_ci	}
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	dic = page_address(page) + *ofs;
458c2ecf20Sopenharmony_ci	ifmt = le16_to_cpu(dic->i_format);
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	if (ifmt & ~EROFS_I_ALL) {
488c2ecf20Sopenharmony_ci		erofs_err(inode->i_sb, "unsupported i_format %u of nid %llu",
498c2ecf20Sopenharmony_ci			  ifmt, vi->nid);
508c2ecf20Sopenharmony_ci		err = -EOPNOTSUPP;
518c2ecf20Sopenharmony_ci		goto err_out;
528c2ecf20Sopenharmony_ci	}
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	vi->datalayout = erofs_inode_datalayout(ifmt);
558c2ecf20Sopenharmony_ci	if (vi->datalayout >= EROFS_INODE_DATALAYOUT_MAX) {
568c2ecf20Sopenharmony_ci		erofs_err(inode->i_sb, "unsupported datalayout %u of nid %llu",
578c2ecf20Sopenharmony_ci			  vi->datalayout, vi->nid);
588c2ecf20Sopenharmony_ci		err = -EOPNOTSUPP;
598c2ecf20Sopenharmony_ci		goto err_out;
608c2ecf20Sopenharmony_ci	}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	switch (erofs_inode_version(ifmt)) {
638c2ecf20Sopenharmony_ci	case EROFS_INODE_LAYOUT_EXTENDED:
648c2ecf20Sopenharmony_ci		vi->inode_isize = sizeof(struct erofs_inode_extended);
658c2ecf20Sopenharmony_ci		/* check if the inode acrosses page boundary */
668c2ecf20Sopenharmony_ci		if (*ofs + vi->inode_isize <= PAGE_SIZE) {
678c2ecf20Sopenharmony_ci			*ofs += vi->inode_isize;
688c2ecf20Sopenharmony_ci			die = (struct erofs_inode_extended *)dic;
698c2ecf20Sopenharmony_ci		} else {
708c2ecf20Sopenharmony_ci			const unsigned int gotten = PAGE_SIZE - *ofs;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci			copied = kmalloc(vi->inode_isize, GFP_NOFS);
738c2ecf20Sopenharmony_ci			if (!copied) {
748c2ecf20Sopenharmony_ci				err = -ENOMEM;
758c2ecf20Sopenharmony_ci				goto err_out;
768c2ecf20Sopenharmony_ci			}
778c2ecf20Sopenharmony_ci			memcpy(copied, dic, gotten);
788c2ecf20Sopenharmony_ci			unlock_page(page);
798c2ecf20Sopenharmony_ci			put_page(page);
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci			page = erofs_get_meta_page(sb, blkaddr + 1);
828c2ecf20Sopenharmony_ci			if (IS_ERR(page)) {
838c2ecf20Sopenharmony_ci				erofs_err(sb, "failed to get inode payload page (nid: %llu), err %ld",
848c2ecf20Sopenharmony_ci					  vi->nid, PTR_ERR(page));
858c2ecf20Sopenharmony_ci				kfree(copied);
868c2ecf20Sopenharmony_ci				return page;
878c2ecf20Sopenharmony_ci			}
888c2ecf20Sopenharmony_ci			*ofs = vi->inode_isize - gotten;
898c2ecf20Sopenharmony_ci			memcpy((u8 *)copied + gotten, page_address(page), *ofs);
908c2ecf20Sopenharmony_ci			die = copied;
918c2ecf20Sopenharmony_ci		}
928c2ecf20Sopenharmony_ci		vi->xattr_isize = erofs_xattr_ibody_size(die->i_xattr_icount);
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci		inode->i_mode = le16_to_cpu(die->i_mode);
958c2ecf20Sopenharmony_ci		switch (inode->i_mode & S_IFMT) {
968c2ecf20Sopenharmony_ci		case S_IFREG:
978c2ecf20Sopenharmony_ci		case S_IFDIR:
988c2ecf20Sopenharmony_ci		case S_IFLNK:
998c2ecf20Sopenharmony_ci			vi->raw_blkaddr = le32_to_cpu(die->i_u.raw_blkaddr);
1008c2ecf20Sopenharmony_ci			break;
1018c2ecf20Sopenharmony_ci		case S_IFCHR:
1028c2ecf20Sopenharmony_ci		case S_IFBLK:
1038c2ecf20Sopenharmony_ci			inode->i_rdev =
1048c2ecf20Sopenharmony_ci				new_decode_dev(le32_to_cpu(die->i_u.rdev));
1058c2ecf20Sopenharmony_ci			break;
1068c2ecf20Sopenharmony_ci		case S_IFIFO:
1078c2ecf20Sopenharmony_ci		case S_IFSOCK:
1088c2ecf20Sopenharmony_ci			inode->i_rdev = 0;
1098c2ecf20Sopenharmony_ci			break;
1108c2ecf20Sopenharmony_ci		default:
1118c2ecf20Sopenharmony_ci			goto bogusimode;
1128c2ecf20Sopenharmony_ci		}
1138c2ecf20Sopenharmony_ci		i_uid_write(inode, le32_to_cpu(die->i_uid));
1148c2ecf20Sopenharmony_ci		i_gid_write(inode, le32_to_cpu(die->i_gid));
1158c2ecf20Sopenharmony_ci		set_nlink(inode, le32_to_cpu(die->i_nlink));
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci		/* extended inode has its own timestamp */
1188c2ecf20Sopenharmony_ci		inode->i_ctime.tv_sec = le64_to_cpu(die->i_ctime);
1198c2ecf20Sopenharmony_ci		inode->i_ctime.tv_nsec = le32_to_cpu(die->i_ctime_nsec);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci		inode->i_size = le64_to_cpu(die->i_size);
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci		/* total blocks for compressed files */
1248c2ecf20Sopenharmony_ci		if (erofs_inode_is_data_compressed(vi->datalayout))
1258c2ecf20Sopenharmony_ci			nblks = le32_to_cpu(die->i_u.compressed_blocks);
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci		kfree(copied);
1288c2ecf20Sopenharmony_ci		break;
1298c2ecf20Sopenharmony_ci	case EROFS_INODE_LAYOUT_COMPACT:
1308c2ecf20Sopenharmony_ci		vi->inode_isize = sizeof(struct erofs_inode_compact);
1318c2ecf20Sopenharmony_ci		*ofs += vi->inode_isize;
1328c2ecf20Sopenharmony_ci		vi->xattr_isize = erofs_xattr_ibody_size(dic->i_xattr_icount);
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci		inode->i_mode = le16_to_cpu(dic->i_mode);
1358c2ecf20Sopenharmony_ci		switch (inode->i_mode & S_IFMT) {
1368c2ecf20Sopenharmony_ci		case S_IFREG:
1378c2ecf20Sopenharmony_ci		case S_IFDIR:
1388c2ecf20Sopenharmony_ci		case S_IFLNK:
1398c2ecf20Sopenharmony_ci			vi->raw_blkaddr = le32_to_cpu(dic->i_u.raw_blkaddr);
1408c2ecf20Sopenharmony_ci			break;
1418c2ecf20Sopenharmony_ci		case S_IFCHR:
1428c2ecf20Sopenharmony_ci		case S_IFBLK:
1438c2ecf20Sopenharmony_ci			inode->i_rdev =
1448c2ecf20Sopenharmony_ci				new_decode_dev(le32_to_cpu(dic->i_u.rdev));
1458c2ecf20Sopenharmony_ci			break;
1468c2ecf20Sopenharmony_ci		case S_IFIFO:
1478c2ecf20Sopenharmony_ci		case S_IFSOCK:
1488c2ecf20Sopenharmony_ci			inode->i_rdev = 0;
1498c2ecf20Sopenharmony_ci			break;
1508c2ecf20Sopenharmony_ci		default:
1518c2ecf20Sopenharmony_ci			goto bogusimode;
1528c2ecf20Sopenharmony_ci		}
1538c2ecf20Sopenharmony_ci		i_uid_write(inode, le16_to_cpu(dic->i_uid));
1548c2ecf20Sopenharmony_ci		i_gid_write(inode, le16_to_cpu(dic->i_gid));
1558c2ecf20Sopenharmony_ci		set_nlink(inode, le16_to_cpu(dic->i_nlink));
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci		/* use build time for compact inodes */
1588c2ecf20Sopenharmony_ci		inode->i_ctime.tv_sec = sbi->build_time;
1598c2ecf20Sopenharmony_ci		inode->i_ctime.tv_nsec = sbi->build_time_nsec;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci		inode->i_size = le32_to_cpu(dic->i_size);
1628c2ecf20Sopenharmony_ci		if (erofs_inode_is_data_compressed(vi->datalayout))
1638c2ecf20Sopenharmony_ci			nblks = le32_to_cpu(dic->i_u.compressed_blocks);
1648c2ecf20Sopenharmony_ci		break;
1658c2ecf20Sopenharmony_ci	default:
1668c2ecf20Sopenharmony_ci		erofs_err(inode->i_sb,
1678c2ecf20Sopenharmony_ci			  "unsupported on-disk inode version %u of nid %llu",
1688c2ecf20Sopenharmony_ci			  erofs_inode_version(ifmt), vi->nid);
1698c2ecf20Sopenharmony_ci		err = -EOPNOTSUPP;
1708c2ecf20Sopenharmony_ci		goto err_out;
1718c2ecf20Sopenharmony_ci	}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	inode->i_mtime.tv_sec = inode->i_ctime.tv_sec;
1748c2ecf20Sopenharmony_ci	inode->i_atime.tv_sec = inode->i_ctime.tv_sec;
1758c2ecf20Sopenharmony_ci	inode->i_mtime.tv_nsec = inode->i_ctime.tv_nsec;
1768c2ecf20Sopenharmony_ci	inode->i_atime.tv_nsec = inode->i_ctime.tv_nsec;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	if (!nblks)
1798c2ecf20Sopenharmony_ci		/* measure inode.i_blocks as generic filesystems */
1808c2ecf20Sopenharmony_ci		inode->i_blocks = roundup(inode->i_size, EROFS_BLKSIZ) >> 9;
1818c2ecf20Sopenharmony_ci	else
1828c2ecf20Sopenharmony_ci		inode->i_blocks = nblks << LOG_SECTORS_PER_BLOCK;
1838c2ecf20Sopenharmony_ci	return page;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_cibogusimode:
1868c2ecf20Sopenharmony_ci	erofs_err(inode->i_sb, "bogus i_mode (%o) @ nid %llu",
1878c2ecf20Sopenharmony_ci		  inode->i_mode, vi->nid);
1888c2ecf20Sopenharmony_ci	err = -EFSCORRUPTED;
1898c2ecf20Sopenharmony_cierr_out:
1908c2ecf20Sopenharmony_ci	DBG_BUGON(1);
1918c2ecf20Sopenharmony_ci	kfree(copied);
1928c2ecf20Sopenharmony_ci	unlock_page(page);
1938c2ecf20Sopenharmony_ci	put_page(page);
1948c2ecf20Sopenharmony_ci	return ERR_PTR(err);
1958c2ecf20Sopenharmony_ci}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_cistatic int erofs_fill_symlink(struct inode *inode, void *data,
1988c2ecf20Sopenharmony_ci			      unsigned int m_pofs)
1998c2ecf20Sopenharmony_ci{
2008c2ecf20Sopenharmony_ci	struct erofs_inode *vi = EROFS_I(inode);
2018c2ecf20Sopenharmony_ci	char *lnk;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	/* if it cannot be handled with fast symlink scheme */
2048c2ecf20Sopenharmony_ci	if (vi->datalayout != EROFS_INODE_FLAT_INLINE ||
2058c2ecf20Sopenharmony_ci	    inode->i_size >= PAGE_SIZE) {
2068c2ecf20Sopenharmony_ci		inode->i_op = &erofs_symlink_iops;
2078c2ecf20Sopenharmony_ci		return 0;
2088c2ecf20Sopenharmony_ci	}
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	lnk = kmalloc(inode->i_size + 1, GFP_KERNEL);
2118c2ecf20Sopenharmony_ci	if (!lnk)
2128c2ecf20Sopenharmony_ci		return -ENOMEM;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	m_pofs += vi->xattr_isize;
2158c2ecf20Sopenharmony_ci	/* inline symlink data shouldn't cross page boundary as well */
2168c2ecf20Sopenharmony_ci	if (m_pofs + inode->i_size > PAGE_SIZE) {
2178c2ecf20Sopenharmony_ci		kfree(lnk);
2188c2ecf20Sopenharmony_ci		erofs_err(inode->i_sb,
2198c2ecf20Sopenharmony_ci			  "inline data cross block boundary @ nid %llu",
2208c2ecf20Sopenharmony_ci			  vi->nid);
2218c2ecf20Sopenharmony_ci		DBG_BUGON(1);
2228c2ecf20Sopenharmony_ci		return -EFSCORRUPTED;
2238c2ecf20Sopenharmony_ci	}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	memcpy(lnk, data + m_pofs, inode->i_size);
2268c2ecf20Sopenharmony_ci	lnk[inode->i_size] = '\0';
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	inode->i_link = lnk;
2298c2ecf20Sopenharmony_ci	inode->i_op = &erofs_fast_symlink_iops;
2308c2ecf20Sopenharmony_ci	return 0;
2318c2ecf20Sopenharmony_ci}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_cistatic int erofs_fill_inode(struct inode *inode, int isdir)
2348c2ecf20Sopenharmony_ci{
2358c2ecf20Sopenharmony_ci	struct erofs_inode *vi = EROFS_I(inode);
2368c2ecf20Sopenharmony_ci	struct page *page;
2378c2ecf20Sopenharmony_ci	unsigned int ofs;
2388c2ecf20Sopenharmony_ci	int err = 0;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	trace_erofs_fill_inode(inode, isdir);
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	/* read inode base data from disk */
2438c2ecf20Sopenharmony_ci	page = erofs_read_inode(inode, &ofs);
2448c2ecf20Sopenharmony_ci	if (IS_ERR(page))
2458c2ecf20Sopenharmony_ci		return PTR_ERR(page);
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	/* setup the new inode */
2488c2ecf20Sopenharmony_ci	switch (inode->i_mode & S_IFMT) {
2498c2ecf20Sopenharmony_ci	case S_IFREG:
2508c2ecf20Sopenharmony_ci		inode->i_op = &erofs_generic_iops;
2518c2ecf20Sopenharmony_ci		inode->i_fop = &generic_ro_fops;
2528c2ecf20Sopenharmony_ci		break;
2538c2ecf20Sopenharmony_ci	case S_IFDIR:
2548c2ecf20Sopenharmony_ci		inode->i_op = &erofs_dir_iops;
2558c2ecf20Sopenharmony_ci		inode->i_fop = &erofs_dir_fops;
2568c2ecf20Sopenharmony_ci		break;
2578c2ecf20Sopenharmony_ci	case S_IFLNK:
2588c2ecf20Sopenharmony_ci		err = erofs_fill_symlink(inode, page_address(page), ofs);
2598c2ecf20Sopenharmony_ci		if (err)
2608c2ecf20Sopenharmony_ci			goto out_unlock;
2618c2ecf20Sopenharmony_ci		inode_nohighmem(inode);
2628c2ecf20Sopenharmony_ci		break;
2638c2ecf20Sopenharmony_ci	case S_IFCHR:
2648c2ecf20Sopenharmony_ci	case S_IFBLK:
2658c2ecf20Sopenharmony_ci	case S_IFIFO:
2668c2ecf20Sopenharmony_ci	case S_IFSOCK:
2678c2ecf20Sopenharmony_ci		inode->i_op = &erofs_generic_iops;
2688c2ecf20Sopenharmony_ci		init_special_inode(inode, inode->i_mode, inode->i_rdev);
2698c2ecf20Sopenharmony_ci		goto out_unlock;
2708c2ecf20Sopenharmony_ci	default:
2718c2ecf20Sopenharmony_ci		err = -EFSCORRUPTED;
2728c2ecf20Sopenharmony_ci		goto out_unlock;
2738c2ecf20Sopenharmony_ci	}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	if (erofs_inode_is_data_compressed(vi->datalayout)) {
2768c2ecf20Sopenharmony_ci		err = z_erofs_fill_inode(inode);
2778c2ecf20Sopenharmony_ci		goto out_unlock;
2788c2ecf20Sopenharmony_ci	}
2798c2ecf20Sopenharmony_ci	inode->i_mapping->a_ops = &erofs_raw_access_aops;
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ciout_unlock:
2828c2ecf20Sopenharmony_ci	unlock_page(page);
2838c2ecf20Sopenharmony_ci	put_page(page);
2848c2ecf20Sopenharmony_ci	return err;
2858c2ecf20Sopenharmony_ci}
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci/*
2888c2ecf20Sopenharmony_ci * erofs nid is 64bits, but i_ino is 'unsigned long', therefore
2898c2ecf20Sopenharmony_ci * we should do more for 32-bit platform to find the right inode.
2908c2ecf20Sopenharmony_ci */
2918c2ecf20Sopenharmony_cistatic int erofs_ilookup_test_actor(struct inode *inode, void *opaque)
2928c2ecf20Sopenharmony_ci{
2938c2ecf20Sopenharmony_ci	const erofs_nid_t nid = *(erofs_nid_t *)opaque;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	return EROFS_I(inode)->nid == nid;
2968c2ecf20Sopenharmony_ci}
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_cistatic int erofs_iget_set_actor(struct inode *inode, void *opaque)
2998c2ecf20Sopenharmony_ci{
3008c2ecf20Sopenharmony_ci	const erofs_nid_t nid = *(erofs_nid_t *)opaque;
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	inode->i_ino = erofs_inode_hash(nid);
3038c2ecf20Sopenharmony_ci	return 0;
3048c2ecf20Sopenharmony_ci}
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_cistatic inline struct inode *erofs_iget_locked(struct super_block *sb,
3078c2ecf20Sopenharmony_ci					      erofs_nid_t nid)
3088c2ecf20Sopenharmony_ci{
3098c2ecf20Sopenharmony_ci	const unsigned long hashval = erofs_inode_hash(nid);
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	return iget5_locked(sb, hashval, erofs_ilookup_test_actor,
3128c2ecf20Sopenharmony_ci		erofs_iget_set_actor, &nid);
3138c2ecf20Sopenharmony_ci}
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_cistruct inode *erofs_iget(struct super_block *sb,
3168c2ecf20Sopenharmony_ci			 erofs_nid_t nid,
3178c2ecf20Sopenharmony_ci			 bool isdir)
3188c2ecf20Sopenharmony_ci{
3198c2ecf20Sopenharmony_ci	struct inode *inode = erofs_iget_locked(sb, nid);
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	if (!inode)
3228c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	if (inode->i_state & I_NEW) {
3258c2ecf20Sopenharmony_ci		int err;
3268c2ecf20Sopenharmony_ci		struct erofs_inode *vi = EROFS_I(inode);
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci		vi->nid = nid;
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci		err = erofs_fill_inode(inode, isdir);
3318c2ecf20Sopenharmony_ci		if (!err)
3328c2ecf20Sopenharmony_ci			unlock_new_inode(inode);
3338c2ecf20Sopenharmony_ci		else {
3348c2ecf20Sopenharmony_ci			iget_failed(inode);
3358c2ecf20Sopenharmony_ci			inode = ERR_PTR(err);
3368c2ecf20Sopenharmony_ci		}
3378c2ecf20Sopenharmony_ci	}
3388c2ecf20Sopenharmony_ci	return inode;
3398c2ecf20Sopenharmony_ci}
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ciint erofs_getattr(const struct path *path, struct kstat *stat,
3428c2ecf20Sopenharmony_ci		  u32 request_mask, unsigned int query_flags)
3438c2ecf20Sopenharmony_ci{
3448c2ecf20Sopenharmony_ci	struct inode *const inode = d_inode(path->dentry);
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	if (erofs_inode_is_data_compressed(EROFS_I(inode)->datalayout))
3478c2ecf20Sopenharmony_ci		stat->attributes |= STATX_ATTR_COMPRESSED;
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	stat->attributes |= STATX_ATTR_IMMUTABLE;
3508c2ecf20Sopenharmony_ci	stat->attributes_mask |= (STATX_ATTR_COMPRESSED |
3518c2ecf20Sopenharmony_ci				  STATX_ATTR_IMMUTABLE);
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	generic_fillattr(inode, stat);
3548c2ecf20Sopenharmony_ci	return 0;
3558c2ecf20Sopenharmony_ci}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ciconst struct inode_operations erofs_generic_iops = {
3588c2ecf20Sopenharmony_ci	.getattr = erofs_getattr,
3598c2ecf20Sopenharmony_ci	.listxattr = erofs_listxattr,
3608c2ecf20Sopenharmony_ci	.get_acl = erofs_get_acl,
3618c2ecf20Sopenharmony_ci};
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ciconst struct inode_operations erofs_symlink_iops = {
3648c2ecf20Sopenharmony_ci	.get_link = page_get_link,
3658c2ecf20Sopenharmony_ci	.getattr = erofs_getattr,
3668c2ecf20Sopenharmony_ci	.listxattr = erofs_listxattr,
3678c2ecf20Sopenharmony_ci	.get_acl = erofs_get_acl,
3688c2ecf20Sopenharmony_ci};
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ciconst struct inode_operations erofs_fast_symlink_iops = {
3718c2ecf20Sopenharmony_ci	.get_link = simple_get_link,
3728c2ecf20Sopenharmony_ci	.getattr = erofs_getattr,
3738c2ecf20Sopenharmony_ci	.listxattr = erofs_listxattr,
3748c2ecf20Sopenharmony_ci	.get_acl = erofs_get_acl,
3758c2ecf20Sopenharmony_ci};
3768c2ecf20Sopenharmony_ci
377