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
/* no locking */
12
static int erofs_read_inode(struct inode *inode, void *data)
G
Gao Xiang 已提交
13
{
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);
G
Gao Xiang 已提交
134
	char *lnk;
G
Gao Xiang 已提交
135

G
Gao Xiang 已提交
136 137 138 139
	/* 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 已提交
140
		return 0;
G
Gao Xiang 已提交
141
	}
G
Gao Xiang 已提交
142

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

G
Gao Xiang 已提交
147 148 149 150 151 152 153 154 155
	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 已提交
156

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

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

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

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

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

184
	page = erofs_get_meta_page(inode->i_sb, blkaddr);
G
Gao Xiang 已提交
185 186 187

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

192
	DBG_BUGON(!PageUptodate(page));
G
Gao Xiang 已提交
193 194
	data = page_address(page);

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

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

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

238 239 240 241 242 243 244 245 246
/*
 * 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 已提交
247
	return EROFS_I(inode)->nid == nid;
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
}

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

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

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

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

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

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

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

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

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