inode.c 8.2 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
/* no locking */
static int read_inode(struct inode *inode, void *data)
{
G
Gao Xiang 已提交
14
	struct erofs_inode *vi = EROFS_I(inode);
15 16 17 18 19
	struct erofs_inode_compact *dic = data;
	struct erofs_inode_extended *die;

	const unsigned int ifmt = le16_to_cpu(dic->i_format);
	struct erofs_sb_info *sbi = EROFS_SB(inode->i_sb);
20
	erofs_blk_t nblks = 0;
G
Gao Xiang 已提交
21

22
	vi->datalayout = erofs_inode_datalayout(ifmt);
G
Gao Xiang 已提交
23

24 25 26
	if (vi->datalayout >= EROFS_INODE_DATALAYOUT_MAX) {
		errln("unsupported datalayout %u of nid %llu",
		      vi->datalayout, vi->nid);
G
Gao Xiang 已提交
27
		DBG_BUGON(1);
28
		return -EOPNOTSUPP;
G
Gao Xiang 已提交
29 30
	}

31 32 33
	switch (erofs_inode_version(ifmt)) {
	case EROFS_INODE_LAYOUT_EXTENDED:
		die = data;
G
Gao Xiang 已提交
34

35 36
		vi->inode_isize = sizeof(struct erofs_inode_extended);
		vi->xattr_isize = erofs_xattr_ibody_size(die->i_xattr_icount);
G
Gao Xiang 已提交
37

38 39 40 41 42 43 44 45 46
		inode->i_mode = le16_to_cpu(die->i_mode);
		switch (inode->i_mode & S_IFMT) {
		case S_IFREG:
		case S_IFDIR:
		case S_IFLNK:
			vi->raw_blkaddr = le32_to_cpu(die->i_u.raw_blkaddr);
			break;
		case S_IFCHR:
		case S_IFBLK:
C
Chao Yu 已提交
47
			inode->i_rdev =
48 49 50 51
				new_decode_dev(le32_to_cpu(die->i_u.rdev));
			break;
		case S_IFIFO:
		case S_IFSOCK:
C
Chao Yu 已提交
52
			inode->i_rdev = 0;
53 54
			break;
		default:
55
			goto bogusimode;
56 57 58 59
		}
		i_uid_write(inode, le32_to_cpu(die->i_uid));
		i_gid_write(inode, le32_to_cpu(die->i_gid));
		set_nlink(inode, le32_to_cpu(die->i_nlink));
G
Gao Xiang 已提交
60 61 62

		/* ns timestamp */
		inode->i_mtime.tv_sec = inode->i_ctime.tv_sec =
63
			le64_to_cpu(die->i_ctime);
G
Gao Xiang 已提交
64
		inode->i_mtime.tv_nsec = inode->i_ctime.tv_nsec =
65
			le32_to_cpu(die->i_ctime_nsec);
G
Gao Xiang 已提交
66

67
		inode->i_size = le64_to_cpu(die->i_size);
68 69

		/* total blocks for compressed files */
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
		if (erofs_inode_is_data_compressed(vi->datalayout))
			nblks = le32_to_cpu(die->i_u.compressed_blocks);
		break;
	case EROFS_INODE_LAYOUT_COMPACT:
		vi->inode_isize = sizeof(struct erofs_inode_compact);
		vi->xattr_isize = erofs_xattr_ibody_size(dic->i_xattr_icount);

		inode->i_mode = le16_to_cpu(dic->i_mode);
		switch (inode->i_mode & S_IFMT) {
		case S_IFREG:
		case S_IFDIR:
		case S_IFLNK:
			vi->raw_blkaddr = le32_to_cpu(dic->i_u.raw_blkaddr);
			break;
		case S_IFCHR:
		case S_IFBLK:
C
Chao Yu 已提交
86
			inode->i_rdev =
87 88 89 90
				new_decode_dev(le32_to_cpu(dic->i_u.rdev));
			break;
		case S_IFIFO:
		case S_IFSOCK:
C
Chao Yu 已提交
91
			inode->i_rdev = 0;
92 93
			break;
		default:
94
			goto bogusimode;
95 96 97 98
		}
		i_uid_write(inode, le16_to_cpu(dic->i_uid));
		i_gid_write(inode, le16_to_cpu(dic->i_gid));
		set_nlink(inode, le16_to_cpu(dic->i_nlink));
G
Gao Xiang 已提交
99 100 101 102 103 104 105

		/* 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;

106 107 108 109 110
		inode->i_size = le32_to_cpu(dic->i_size);
		if (erofs_inode_is_data_compressed(vi->datalayout))
			nblks = le32_to_cpu(dic->i_u.compressed_blocks);
		break;
	default:
G
Gao Xiang 已提交
111
		errln("unsupported on-disk inode version %u of nid %llu",
112
		      erofs_inode_version(ifmt), vi->nid);
G
Gao Xiang 已提交
113
		DBG_BUGON(1);
114
		return -EOPNOTSUPP;
G
Gao Xiang 已提交
115 116
	}

117 118 119 120 121
	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 已提交
122
	return 0;
123 124 125 126 127

bogusimode:
	errln("bogus i_mode (%o) @ nid %llu", inode->i_mode, vi->nid);
	DBG_BUGON(1);
	return -EFSCORRUPTED;
G
Gao Xiang 已提交
128 129
}

G
Gao Xiang 已提交
130 131
static int erofs_fill_symlink(struct inode *inode, void *data,
			      unsigned int m_pofs)
G
Gao Xiang 已提交
132
{
G
Gao Xiang 已提交
133
	struct erofs_inode *vi = EROFS_I(inode);
134
	struct erofs_sb_info *sbi = EROFS_I_SB(inode);
G
Gao Xiang 已提交
135
	char *lnk;
G
Gao Xiang 已提交
136

G
Gao Xiang 已提交
137 138 139 140
	/* if it cannot be handled with fast symlink scheme */
	if (vi->datalayout != EROFS_INODE_FLAT_INLINE ||
	    inode->i_size >= PAGE_SIZE) {
		inode->i_op = &erofs_symlink_iops;
G
Gao Xiang 已提交
141
		return 0;
G
Gao Xiang 已提交
142
	}
G
Gao Xiang 已提交
143

G
Gao Xiang 已提交
144 145 146
	lnk = erofs_kmalloc(sbi, inode->i_size + 1, GFP_KERNEL);
	if (!lnk)
		return -ENOMEM;
147

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

G
Gao Xiang 已提交
158 159
	memcpy(lnk, data + m_pofs, inode->i_size);
	lnk[inode->i_size] = '\0';
G
Gao Xiang 已提交
160

G
Gao Xiang 已提交
161 162
	inode->i_link = lnk;
	inode->i_op = &erofs_fast_symlink_iops;
163
	return 0;
G
Gao Xiang 已提交
164 165 166 167 168
}

static int fill_inode(struct inode *inode, int isdir)
{
	struct erofs_sb_info *sbi = EROFS_SB(inode->i_sb);
G
Gao Xiang 已提交
169
	struct erofs_inode *vi = EROFS_I(inode);
G
Gao Xiang 已提交
170 171 172 173
	struct page *page;
	void *data;
	int err;
	erofs_blk_t blkaddr;
174
	unsigned int ofs;
175
	erofs_off_t inode_loc;
G
Gao Xiang 已提交
176

C
Chao Yu 已提交
177
	trace_erofs_fill_inode(inode, isdir);
178 179 180
	inode_loc = iloc(sbi, vi->nid);
	blkaddr = erofs_blknr(inode_loc);
	ofs = erofs_blkoff(inode_loc);
G
Gao Xiang 已提交
181 182 183 184 185 186 187 188

	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",
189
		      vi->nid, PTR_ERR(page));
G
Gao Xiang 已提交
190 191 192
		return PTR_ERR(page);
	}

193
	DBG_BUGON(!PageUptodate(page));
G
Gao Xiang 已提交
194 195 196 197 198
	data = page_address(page);

	err = read_inode(inode, data + ofs);
	if (!err) {
		/* setup the new inode */
199 200
		switch (inode->i_mode & S_IFMT) {
		case S_IFREG:
201
			inode->i_op = &erofs_generic_iops;
G
Gao Xiang 已提交
202
			inode->i_fop = &generic_ro_fops;
203 204
			break;
		case S_IFDIR:
205
			inode->i_op = &erofs_dir_iops;
G
Gao Xiang 已提交
206
			inode->i_fop = &erofs_dir_fops;
207 208
			break;
		case S_IFLNK:
G
Gao Xiang 已提交
209 210 211
			err = erofs_fill_symlink(inode, data, ofs);
			if (err)
				goto out_unlock;
G
Gao Xiang 已提交
212
			inode_nohighmem(inode);
213 214 215 216 217
			break;
		case S_IFCHR:
		case S_IFBLK:
		case S_IFIFO:
		case S_IFSOCK:
218
			inode->i_op = &erofs_generic_iops;
C
Chao Yu 已提交
219
			init_special_inode(inode, inode->i_mode, inode->i_rdev);
220
			goto out_unlock;
221
		default:
222
			err = -EFSCORRUPTED;
G
Gao Xiang 已提交
223 224 225
			goto out_unlock;
		}

226
		if (erofs_inode_is_data_compressed(vi->datalayout)) {
227
			err = z_erofs_fill_inode(inode);
G
Gao Xiang 已提交
228 229 230 231 232 233 234 235 236 237 238
			goto out_unlock;
		}
		inode->i_mapping->a_ops = &erofs_raw_access_aops;
	}

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

239 240 241 242 243 244 245 246 247
/*
 * 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;

G
Gao Xiang 已提交
248
	return EROFS_I(inode)->nid == nid;
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
}

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 已提交
274
struct inode *erofs_iget(struct super_block *sb,
275 276
			 erofs_nid_t nid,
			 bool isdir)
G
Gao Xiang 已提交
277
{
278
	struct inode *inode = erofs_iget_locked(sb, nid);
G
Gao Xiang 已提交
279

280
	if (!inode)
G
Gao Xiang 已提交
281 282 283 284
		return ERR_PTR(-ENOMEM);

	if (inode->i_state & I_NEW) {
		int err;
G
Gao Xiang 已提交
285
		struct erofs_inode *vi = EROFS_I(inode);
286

G
Gao Xiang 已提交
287 288 289
		vi->nid = nid;

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

G
Gao Xiang 已提交
300 301 302 303 304
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);

G
Gao Xiang 已提交
305
	if (erofs_inode_is_data_compressed(EROFS_I(inode)->datalayout))
G
Gao Xiang 已提交
306 307 308 309 310 311 312 313 314 315
		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;
}

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

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

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