inode.c 8.7 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
/* no locking */
static int read_inode(struct inode *inode, void *data)
{
	struct erofs_vnode *vi = EROFS_V(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 130 131 132 133 134 135 136 137 138 139
}

/*
 * 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.
 */
140 141
static int fill_inline_data(struct inode *inode, void *data,
			    unsigned int m_pofs)
G
Gao Xiang 已提交
142 143
{
	struct erofs_vnode *vi = EROFS_V(inode);
144
	struct erofs_sb_info *sbi = EROFS_I_SB(inode);
G
Gao Xiang 已提交
145

146 147
	/* should be tail-packing data inline */
	if (vi->datalayout != EROFS_INODE_FLAT_INLINE)
G
Gao Xiang 已提交
148 149 150 151
		return 0;

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

154
		if (!lnk)
G
Gao Xiang 已提交
155 156 157
			return -ENOMEM;

		m_pofs += vi->inode_isize + vi->xattr_isize;
158 159

		/* inline symlink data shouldn't across page boundary as well */
160
		if (m_pofs + inode->i_size > PAGE_SIZE) {
161
			kfree(lnk);
162 163 164 165
			errln("inline data cross block boundary @ nid %llu",
			      vi->nid);
			DBG_BUGON(1);
			return -EFSCORRUPTED;
166
		}
G
Gao Xiang 已提交
167 168 169 170 171 172 173 174

		/* 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);
	}
175
	return 0;
G
Gao Xiang 已提交
176 177 178 179 180 181 182 183 184 185
}

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;
186
	unsigned int ofs;
187
	erofs_off_t inode_loc;
G
Gao Xiang 已提交
188

C
Chao Yu 已提交
189
	trace_erofs_fill_inode(inode, isdir);
190 191 192
	inode_loc = iloc(sbi, vi->nid);
	blkaddr = erofs_blknr(inode_loc);
	ofs = erofs_blkoff(inode_loc);
G
Gao Xiang 已提交
193 194 195 196 197 198 199 200

	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",
201
		      vi->nid, PTR_ERR(page));
G
Gao Xiang 已提交
202 203 204
		return PTR_ERR(page);
	}

205
	DBG_BUGON(!PageUptodate(page));
G
Gao Xiang 已提交
206 207 208 209 210
	data = page_address(page);

	err = read_inode(inode, data + ofs);
	if (!err) {
		/* setup the new inode */
211 212
		switch (inode->i_mode & S_IFMT) {
		case S_IFREG:
213
			inode->i_op = &erofs_generic_iops;
G
Gao Xiang 已提交
214
			inode->i_fop = &generic_ro_fops;
215 216
			break;
		case S_IFDIR:
217
			inode->i_op = &erofs_dir_iops;
G
Gao Xiang 已提交
218
			inode->i_fop = &erofs_dir_fops;
219 220
			break;
		case S_IFLNK:
G
Gao Xiang 已提交
221
			/* by default, page_get_link is used for symlink */
222
			inode->i_op = &erofs_symlink_iops;
G
Gao Xiang 已提交
223
			inode_nohighmem(inode);
224 225 226 227 228
			break;
		case S_IFCHR:
		case S_IFBLK:
		case S_IFIFO:
		case S_IFSOCK:
229
			inode->i_op = &erofs_generic_iops;
C
Chao Yu 已提交
230
			init_special_inode(inode, inode->i_mode, inode->i_rdev);
231
			goto out_unlock;
232
		default:
233
			err = -EFSCORRUPTED;
G
Gao Xiang 已提交
234 235 236
			goto out_unlock;
		}

237
		if (erofs_inode_is_data_compressed(vi->datalayout)) {
238
			err = z_erofs_fill_inode(inode);
G
Gao Xiang 已提交
239 240 241 242 243 244
			goto out_unlock;
		}

		inode->i_mapping->a_ops = &erofs_raw_access_aops;

		/* fill last page if inline data is available */
245
		err = fill_inline_data(inode, data, ofs);
G
Gao Xiang 已提交
246 247 248 249 250 251 252 253
	}

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

254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
/*
 * 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 已提交
289
struct inode *erofs_iget(struct super_block *sb,
290 291
			 erofs_nid_t nid,
			 bool isdir)
G
Gao Xiang 已提交
292
{
293
	struct inode *inode = erofs_iget_locked(sb, nid);
G
Gao Xiang 已提交
294

295
	if (!inode)
G
Gao Xiang 已提交
296 297 298 299 300
		return ERR_PTR(-ENOMEM);

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

G
Gao Xiang 已提交
302 303 304
		vi->nid = nid;

		err = fill_inode(inode, isdir);
305
		if (!err)
G
Gao Xiang 已提交
306 307 308 309 310 311 312 313 314
			unlock_new_inode(inode);
		else {
			iget_failed(inode);
			inode = ERR_PTR(err);
		}
	}
	return inode;
}

G
Gao Xiang 已提交
315 316 317 318 319
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);

320
	if (erofs_inode_is_data_compressed(EROFS_V(inode)->datalayout))
G
Gao Xiang 已提交
321 322 323 324 325 326 327 328 329 330
		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;
}

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

339
const struct inode_operations erofs_symlink_iops = {
340
	.get_link = page_get_link,
G
Gao Xiang 已提交
341
	.getattr = erofs_getattr,
342
#ifdef CONFIG_EROFS_FS_XATTR
343
	.listxattr = erofs_listxattr,
344
#endif
345
	.get_acl = erofs_get_acl,
346 347
};

348
const struct inode_operations erofs_fast_symlink_iops = {
349
	.get_link = simple_get_link,
G
Gao Xiang 已提交
350
	.getattr = erofs_getattr,
351
#ifdef CONFIG_EROFS_FS_XATTR
352 353
	.listxattr = erofs_listxattr,
#endif
354
	.get_acl = erofs_get_acl,
355
};
356