inode.c 8.6 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0-only
G
Gao Xiang 已提交
2 3 4 5 6
/*
 * Copyright (C) 2017-2018 HUAWEI, Inc.
 *             http://www.huawei.com/
 * Created by Gao Xiang <gaoxiang25@huawei.com>
 */
7
#include "xattr.h"
G
Gao Xiang 已提交
8

C
Chao Yu 已提交
9 10
#include <trace/events/erofs.h>

G
Gao Xiang 已提交
11 12 13 14 15
/* no locking */
static int read_inode(struct inode *inode, void *data)
{
	struct erofs_vnode *vi = EROFS_V(inode);
	struct erofs_inode_v1 *v1 = data;
16
	const unsigned int advise = le16_to_cpu(v1->i_advise);
17
	erofs_blk_t nblks = 0;
G
Gao Xiang 已提交
18

19
	vi->datamode = __inode_data_mapping(advise);
G
Gao Xiang 已提交
20

21
	if (vi->datamode >= EROFS_INODE_LAYOUT_MAX) {
22 23
		errln("unsupported data mapping %u of nid %llu",
		      vi->datamode, vi->nid);
G
Gao Xiang 已提交
24
		DBG_BUGON(1);
25
		return -EOPNOTSUPP;
G
Gao Xiang 已提交
26 27 28 29 30 31
	}

	if (__inode_version(advise) == EROFS_INODE_LAYOUT_V2) {
		struct erofs_inode_v2 *v2 = data;

		vi->inode_isize = sizeof(struct erofs_inode_v2);
32
		vi->xattr_isize = erofs_xattr_ibody_size(v2->i_xattr_icount);
G
Gao Xiang 已提交
33 34

		inode->i_mode = le16_to_cpu(v2->i_mode);
C
Chao Yu 已提交
35
		if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
36
		    S_ISLNK(inode->i_mode))
C
Chao Yu 已提交
37
			vi->raw_blkaddr = le32_to_cpu(v2->i_u.raw_blkaddr);
38
		else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
C
Chao Yu 已提交
39 40
			inode->i_rdev =
				new_decode_dev(le32_to_cpu(v2->i_u.rdev));
41
		else if (S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode))
C
Chao Yu 已提交
42
			inode->i_rdev = 0;
43
		else
44
			goto bogusimode;
G
Gao Xiang 已提交
45 46 47 48 49 50 51 52 53 54 55 56

		i_uid_write(inode, le32_to_cpu(v2->i_uid));
		i_gid_write(inode, le32_to_cpu(v2->i_gid));
		set_nlink(inode, le32_to_cpu(v2->i_nlink));

		/* ns timestamp */
		inode->i_mtime.tv_sec = inode->i_ctime.tv_sec =
			le64_to_cpu(v2->i_ctime);
		inode->i_mtime.tv_nsec = inode->i_ctime.tv_nsec =
			le32_to_cpu(v2->i_ctime_nsec);

		inode->i_size = le64_to_cpu(v2->i_size);
57 58

		/* total blocks for compressed files */
59
		if (is_inode_layout_compression(inode))
60
			nblks = le32_to_cpu(v2->i_u.compressed_blocks);
G
Gao Xiang 已提交
61 62 63 64
	} else if (__inode_version(advise) == EROFS_INODE_LAYOUT_V1) {
		struct erofs_sb_info *sbi = EROFS_SB(inode->i_sb);

		vi->inode_isize = sizeof(struct erofs_inode_v1);
65
		vi->xattr_isize = erofs_xattr_ibody_size(v1->i_xattr_icount);
G
Gao Xiang 已提交
66 67

		inode->i_mode = le16_to_cpu(v1->i_mode);
C
Chao Yu 已提交
68
		if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
69
		    S_ISLNK(inode->i_mode))
C
Chao Yu 已提交
70
			vi->raw_blkaddr = le32_to_cpu(v1->i_u.raw_blkaddr);
71
		else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
C
Chao Yu 已提交
72 73
			inode->i_rdev =
				new_decode_dev(le32_to_cpu(v1->i_u.rdev));
74
		else if (S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode))
C
Chao Yu 已提交
75
			inode->i_rdev = 0;
76
		else
77
			goto bogusimode;
G
Gao Xiang 已提交
78 79 80 81 82 83 84 85 86 87 88 89

		i_uid_write(inode, le16_to_cpu(v1->i_uid));
		i_gid_write(inode, le16_to_cpu(v1->i_gid));
		set_nlink(inode, le16_to_cpu(v1->i_nlink));

		/* use build time to derive all file time */
		inode->i_mtime.tv_sec = inode->i_ctime.tv_sec =
			sbi->build_time;
		inode->i_mtime.tv_nsec = inode->i_ctime.tv_nsec =
			sbi->build_time_nsec;

		inode->i_size = le32_to_cpu(v1->i_size);
90
		if (is_inode_layout_compression(inode))
91
			nblks = le32_to_cpu(v1->i_u.compressed_blocks);
G
Gao Xiang 已提交
92 93
	} else {
		errln("unsupported on-disk inode version %u of nid %llu",
94
		      __inode_version(advise), vi->nid);
G
Gao Xiang 已提交
95
		DBG_BUGON(1);
96
		return -EOPNOTSUPP;
G
Gao Xiang 已提交
97 98
	}

99 100 101 102 103
	if (!nblks)
		/* measure inode.i_blocks as generic filesystems */
		inode->i_blocks = roundup(inode->i_size, EROFS_BLKSIZ) >> 9;
	else
		inode->i_blocks = nblks << LOG_SECTORS_PER_BLOCK;
G
Gao Xiang 已提交
104
	return 0;
105 106 107 108 109

bogusimode:
	errln("bogus i_mode (%o) @ nid %llu", inode->i_mode, vi->nid);
	DBG_BUGON(1);
	return -EFSCORRUPTED;
G
Gao Xiang 已提交
110 111 112 113 114 115 116 117 118 119 120 121
}

/*
 * try_lock can be required since locking order is:
 *   file data(fs_inode)
 *        meta(bd_inode)
 * but the majority of the callers is "iget",
 * in that case we are pretty sure no deadlock since
 * no data operations exist. However I tend to
 * try_lock since it takes no much overhead and
 * will success immediately.
 */
122 123
static int fill_inline_data(struct inode *inode, void *data,
			    unsigned int m_pofs)
G
Gao Xiang 已提交
124 125
{
	struct erofs_vnode *vi = EROFS_V(inode);
126
	struct erofs_sb_info *sbi = EROFS_I_SB(inode);
G
Gao Xiang 已提交
127 128

	/* should be inode inline C */
129
	if (!is_inode_flat_inline(inode))
G
Gao Xiang 已提交
130 131 132 133
		return 0;

	/* fast symlink (following ext4) */
	if (S_ISLNK(inode->i_mode) && inode->i_size < PAGE_SIZE) {
134
		char *lnk = erofs_kmalloc(sbi, inode->i_size + 1, GFP_KERNEL);
G
Gao Xiang 已提交
135

136
		if (!lnk)
G
Gao Xiang 已提交
137 138 139
			return -ENOMEM;

		m_pofs += vi->inode_isize + vi->xattr_isize;
140 141

		/* inline symlink data shouldn't across page boundary as well */
142
		if (m_pofs + inode->i_size > PAGE_SIZE) {
143
			kfree(lnk);
144 145 146 147
			errln("inline data cross block boundary @ nid %llu",
			      vi->nid);
			DBG_BUGON(1);
			return -EFSCORRUPTED;
148
		}
G
Gao Xiang 已提交
149 150 151 152 153 154 155 156

		/* get in-page inline data */
		memcpy(lnk, data + m_pofs, inode->i_size);
		lnk[inode->i_size] = '\0';

		inode->i_link = lnk;
		set_inode_fast_symlink(inode);
	}
157
	return 0;
G
Gao Xiang 已提交
158 159 160 161 162 163 164 165 166 167
}

static int fill_inode(struct inode *inode, int isdir)
{
	struct erofs_sb_info *sbi = EROFS_SB(inode->i_sb);
	struct erofs_vnode *vi = EROFS_V(inode);
	struct page *page;
	void *data;
	int err;
	erofs_blk_t blkaddr;
168
	unsigned int ofs;
169
	erofs_off_t inode_loc;
G
Gao Xiang 已提交
170

C
Chao Yu 已提交
171
	trace_erofs_fill_inode(inode, isdir);
172 173 174
	inode_loc = iloc(sbi, vi->nid);
	blkaddr = erofs_blknr(inode_loc);
	ofs = erofs_blkoff(inode_loc);
G
Gao Xiang 已提交
175 176 177 178 179 180 181 182

	debugln("%s, reading inode nid %llu at %u of blkaddr %u",
		__func__, vi->nid, ofs, blkaddr);

	page = erofs_get_meta_page(inode->i_sb, blkaddr, isdir);

	if (IS_ERR(page)) {
		errln("failed to get inode (nid: %llu) page, err %ld",
183
		      vi->nid, PTR_ERR(page));
G
Gao Xiang 已提交
184 185 186
		return PTR_ERR(page);
	}

187
	DBG_BUGON(!PageUptodate(page));
G
Gao Xiang 已提交
188 189 190 191 192
	data = page_address(page);

	err = read_inode(inode, data + ofs);
	if (!err) {
		/* setup the new inode */
193 194
		switch (inode->i_mode & S_IFMT) {
		case S_IFREG:
195
			inode->i_op = &erofs_generic_iops;
G
Gao Xiang 已提交
196
			inode->i_fop = &generic_ro_fops;
197 198
			break;
		case S_IFDIR:
199
			inode->i_op = &erofs_dir_iops;
G
Gao Xiang 已提交
200
			inode->i_fop = &erofs_dir_fops;
201 202
			break;
		case S_IFLNK:
G
Gao Xiang 已提交
203
			/* by default, page_get_link is used for symlink */
204
			inode->i_op = &erofs_symlink_iops;
G
Gao Xiang 已提交
205
			inode_nohighmem(inode);
206 207 208 209 210
			break;
		case S_IFCHR:
		case S_IFBLK:
		case S_IFIFO:
		case S_IFSOCK:
211
			inode->i_op = &erofs_generic_iops;
C
Chao Yu 已提交
212
			init_special_inode(inode, inode->i_mode, inode->i_rdev);
213
			goto out_unlock;
214
		default:
215
			err = -EFSCORRUPTED;
G
Gao Xiang 已提交
216 217 218 219
			goto out_unlock;
		}

		if (is_inode_layout_compression(inode)) {
220
			err = z_erofs_fill_inode(inode);
G
Gao Xiang 已提交
221 222 223 224 225 226
			goto out_unlock;
		}

		inode->i_mapping->a_ops = &erofs_raw_access_aops;

		/* fill last page if inline data is available */
227
		err = fill_inline_data(inode, data, ofs);
G
Gao Xiang 已提交
228 229 230 231 232 233 234 235
	}

out_unlock:
	unlock_page(page);
	put_page(page);
	return err;
}

236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
/*
 * erofs nid is 64bits, but i_ino is 'unsigned long', therefore
 * we should do more for 32-bit platform to find the right inode.
 */
#if BITS_PER_LONG == 32
static int erofs_ilookup_test_actor(struct inode *inode, void *opaque)
{
	const erofs_nid_t nid = *(erofs_nid_t *)opaque;

	return EROFS_V(inode)->nid == nid;
}

static int erofs_iget_set_actor(struct inode *inode, void *opaque)
{
	const erofs_nid_t nid = *(erofs_nid_t *)opaque;

	inode->i_ino = erofs_inode_hash(nid);
	return 0;
}
#endif

static inline struct inode *erofs_iget_locked(struct super_block *sb,
					      erofs_nid_t nid)
{
	const unsigned long hashval = erofs_inode_hash(nid);

#if BITS_PER_LONG >= 64
	/* it is safe to use iget_locked for >= 64-bit platform */
	return iget_locked(sb, hashval);
#else
	return iget5_locked(sb, hashval, erofs_ilookup_test_actor,
		erofs_iget_set_actor, &nid);
#endif
}

G
Gao Xiang 已提交
271
struct inode *erofs_iget(struct super_block *sb,
272 273
			 erofs_nid_t nid,
			 bool isdir)
G
Gao Xiang 已提交
274
{
275
	struct inode *inode = erofs_iget_locked(sb, nid);
G
Gao Xiang 已提交
276

277
	if (!inode)
G
Gao Xiang 已提交
278 279 280 281 282
		return ERR_PTR(-ENOMEM);

	if (inode->i_state & I_NEW) {
		int err;
		struct erofs_vnode *vi = EROFS_V(inode);
283

G
Gao Xiang 已提交
284 285 286
		vi->nid = nid;

		err = fill_inode(inode, isdir);
287
		if (!err)
G
Gao Xiang 已提交
288 289 290 291 292 293 294 295 296
			unlock_new_inode(inode);
		else {
			iget_failed(inode);
			inode = ERR_PTR(err);
		}
	}
	return inode;
}

G
Gao Xiang 已提交
297 298 299 300 301
int erofs_getattr(const struct path *path, struct kstat *stat,
		  u32 request_mask, unsigned int query_flags)
{
	struct inode *const inode = d_inode(path->dentry);

302
	if (is_inode_layout_compression(inode))
G
Gao Xiang 已提交
303 304 305 306 307 308 309 310 311 312
		stat->attributes |= STATX_ATTR_COMPRESSED;

	stat->attributes |= STATX_ATTR_IMMUTABLE;
	stat->attributes_mask |= (STATX_ATTR_COMPRESSED |
				  STATX_ATTR_IMMUTABLE);

	generic_fillattr(inode, stat);
	return 0;
}

313
const struct inode_operations erofs_generic_iops = {
G
Gao Xiang 已提交
314
	.getattr = erofs_getattr,
315 316
#ifdef CONFIG_EROFS_FS_XATTR
	.listxattr = erofs_listxattr,
317
#endif
318
	.get_acl = erofs_get_acl,
319 320
};

321
const struct inode_operations erofs_symlink_iops = {
322
	.get_link = page_get_link,
G
Gao Xiang 已提交
323
	.getattr = erofs_getattr,
324
#ifdef CONFIG_EROFS_FS_XATTR
325
	.listxattr = erofs_listxattr,
326
#endif
327
	.get_acl = erofs_get_acl,
328 329
};

330
const struct inode_operations erofs_fast_symlink_iops = {
331
	.get_link = simple_get_link,
G
Gao Xiang 已提交
332
	.getattr = erofs_getattr,
333
#ifdef CONFIG_EROFS_FS_XATTR
334 335
	.listxattr = erofs_listxattr,
#endif
336
	.get_acl = erofs_get_acl,
337
};
338