]>
Commit | Line | Data |
---|---|---|
29b24f6c | 1 | // SPDX-License-Identifier: GPL-2.0-only |
431339ba | 2 | /* |
431339ba | 3 | * Copyright (C) 2017-2018 HUAWEI, Inc. |
592e7cd0 | 4 | * https://www.huawei.com/ |
431339ba | 5 | * Created by Gao Xiang <gaoxiang25@huawei.com> |
431339ba | 6 | */ |
b17500a0 | 7 | #include "xattr.h" |
431339ba | 8 | |
13f06f48 CY |
9 | #include <trace/events/erofs.h> |
10 | ||
0dcd3c94 GX |
11 | /* |
12 | * if inode is successfully read, return its inode page (or sometimes | |
13 | * the inode payload page if it's an extended inode) in order to fill | |
14 | * inline data if possible. | |
15 | */ | |
16 | static struct page *erofs_read_inode(struct inode *inode, | |
17 | unsigned int *ofs) | |
431339ba | 18 | { |
0dcd3c94 GX |
19 | struct super_block *sb = inode->i_sb; |
20 | struct erofs_sb_info *sbi = EROFS_SB(sb); | |
a5876e24 | 21 | struct erofs_inode *vi = EROFS_I(inode); |
0dcd3c94 GX |
22 | const erofs_off_t inode_loc = iloc(sbi, vi->nid); |
23 | ||
24 | erofs_blk_t blkaddr, nblks = 0; | |
25 | struct page *page; | |
26 | struct erofs_inode_compact *dic; | |
27 | struct erofs_inode_extended *die, *copied = NULL; | |
28 | unsigned int ifmt; | |
29 | int err; | |
8a765682 | 30 | |
0dcd3c94 GX |
31 | blkaddr = erofs_blknr(inode_loc); |
32 | *ofs = erofs_blkoff(inode_loc); | |
431339ba | 33 | |
0dcd3c94 GX |
34 | erofs_dbg("%s, reading inode nid %llu at %u of blkaddr %u", |
35 | __func__, vi->nid, *ofs, blkaddr); | |
36 | ||
37 | page = erofs_get_meta_page(sb, blkaddr); | |
38 | if (IS_ERR(page)) { | |
39 | erofs_err(sb, "failed to get inode (nid: %llu) page, err %ld", | |
40 | vi->nid, PTR_ERR(page)); | |
41 | return page; | |
42 | } | |
431339ba | 43 | |
0dcd3c94 GX |
44 | dic = page_address(page) + *ofs; |
45 | ifmt = le16_to_cpu(dic->i_format); | |
46 | ||
df623b0a GX |
47 | if (ifmt & ~EROFS_I_ALL) { |
48 | erofs_err(inode->i_sb, "unsupported i_format %u of nid %llu", | |
49 | ifmt, vi->nid); | |
50 | err = -EOPNOTSUPP; | |
51 | goto err_out; | |
52 | } | |
53 | ||
0dcd3c94 | 54 | vi->datalayout = erofs_inode_datalayout(ifmt); |
8a765682 | 55 | if (vi->datalayout >= EROFS_INODE_DATALAYOUT_MAX) { |
4f761fa2 GX |
56 | erofs_err(inode->i_sb, "unsupported datalayout %u of nid %llu", |
57 | vi->datalayout, vi->nid); | |
0dcd3c94 GX |
58 | err = -EOPNOTSUPP; |
59 | goto err_out; | |
431339ba GX |
60 | } |
61 | ||
8a765682 GX |
62 | switch (erofs_inode_version(ifmt)) { |
63 | case EROFS_INODE_LAYOUT_EXTENDED: | |
8a765682 | 64 | vi->inode_isize = sizeof(struct erofs_inode_extended); |
0dcd3c94 GX |
65 | /* check if the inode acrosses page boundary */ |
66 | if (*ofs + vi->inode_isize <= PAGE_SIZE) { | |
67 | *ofs += vi->inode_isize; | |
68 | die = (struct erofs_inode_extended *)dic; | |
69 | } else { | |
70 | const unsigned int gotten = PAGE_SIZE - *ofs; | |
71 | ||
72 | copied = kmalloc(vi->inode_isize, GFP_NOFS); | |
73 | if (!copied) { | |
74 | err = -ENOMEM; | |
75 | goto err_out; | |
76 | } | |
77 | memcpy(copied, dic, gotten); | |
78 | unlock_page(page); | |
79 | put_page(page); | |
80 | ||
81 | page = erofs_get_meta_page(sb, blkaddr + 1); | |
82 | if (IS_ERR(page)) { | |
83 | erofs_err(sb, "failed to get inode payload page (nid: %llu), err %ld", | |
84 | vi->nid, PTR_ERR(page)); | |
85 | kfree(copied); | |
86 | return page; | |
87 | } | |
88 | *ofs = vi->inode_isize - gotten; | |
89 | memcpy((u8 *)copied + gotten, page_address(page), *ofs); | |
90 | die = copied; | |
91 | } | |
8a765682 | 92 | vi->xattr_isize = erofs_xattr_ibody_size(die->i_xattr_icount); |
431339ba | 93 | |
8a765682 GX |
94 | inode->i_mode = le16_to_cpu(die->i_mode); |
95 | switch (inode->i_mode & S_IFMT) { | |
96 | case S_IFREG: | |
97 | case S_IFDIR: | |
98 | case S_IFLNK: | |
99 | vi->raw_blkaddr = le32_to_cpu(die->i_u.raw_blkaddr); | |
100 | break; | |
101 | case S_IFCHR: | |
102 | case S_IFBLK: | |
d5beb31b | 103 | inode->i_rdev = |
8a765682 GX |
104 | new_decode_dev(le32_to_cpu(die->i_u.rdev)); |
105 | break; | |
106 | case S_IFIFO: | |
107 | case S_IFSOCK: | |
d5beb31b | 108 | inode->i_rdev = 0; |
8a765682 GX |
109 | break; |
110 | default: | |
a6b9b1d5 | 111 | goto bogusimode; |
8a765682 GX |
112 | } |
113 | i_uid_write(inode, le32_to_cpu(die->i_uid)); | |
114 | i_gid_write(inode, le32_to_cpu(die->i_gid)); | |
115 | set_nlink(inode, le32_to_cpu(die->i_nlink)); | |
431339ba | 116 | |
d3938ee2 GX |
117 | /* extended inode has its own timestamp */ |
118 | inode->i_ctime.tv_sec = le64_to_cpu(die->i_ctime); | |
119 | inode->i_ctime.tv_nsec = le32_to_cpu(die->i_ctime_nsec); | |
431339ba | 120 | |
8a765682 | 121 | inode->i_size = le64_to_cpu(die->i_size); |
fe6d9875 GX |
122 | |
123 | /* total blocks for compressed files */ | |
8a765682 GX |
124 | if (erofs_inode_is_data_compressed(vi->datalayout)) |
125 | nblks = le32_to_cpu(die->i_u.compressed_blocks); | |
0dcd3c94 GX |
126 | |
127 | kfree(copied); | |
8a765682 GX |
128 | break; |
129 | case EROFS_INODE_LAYOUT_COMPACT: | |
130 | vi->inode_isize = sizeof(struct erofs_inode_compact); | |
0dcd3c94 | 131 | *ofs += vi->inode_isize; |
8a765682 GX |
132 | vi->xattr_isize = erofs_xattr_ibody_size(dic->i_xattr_icount); |
133 | ||
134 | inode->i_mode = le16_to_cpu(dic->i_mode); | |
135 | switch (inode->i_mode & S_IFMT) { | |
136 | case S_IFREG: | |
137 | case S_IFDIR: | |
138 | case S_IFLNK: | |
139 | vi->raw_blkaddr = le32_to_cpu(dic->i_u.raw_blkaddr); | |
140 | break; | |
141 | case S_IFCHR: | |
142 | case S_IFBLK: | |
d5beb31b | 143 | inode->i_rdev = |
8a765682 GX |
144 | new_decode_dev(le32_to_cpu(dic->i_u.rdev)); |
145 | break; | |
146 | case S_IFIFO: | |
147 | case S_IFSOCK: | |
d5beb31b | 148 | inode->i_rdev = 0; |
8a765682 GX |
149 | break; |
150 | default: | |
a6b9b1d5 | 151 | goto bogusimode; |
8a765682 GX |
152 | } |
153 | i_uid_write(inode, le16_to_cpu(dic->i_uid)); | |
154 | i_gid_write(inode, le16_to_cpu(dic->i_gid)); | |
155 | set_nlink(inode, le16_to_cpu(dic->i_nlink)); | |
431339ba | 156 | |
d3938ee2 GX |
157 | /* use build time for compact inodes */ |
158 | inode->i_ctime.tv_sec = sbi->build_time; | |
159 | inode->i_ctime.tv_nsec = sbi->build_time_nsec; | |
431339ba | 160 | |
8a765682 GX |
161 | inode->i_size = le32_to_cpu(dic->i_size); |
162 | if (erofs_inode_is_data_compressed(vi->datalayout)) | |
163 | nblks = le32_to_cpu(dic->i_u.compressed_blocks); | |
164 | break; | |
165 | default: | |
4f761fa2 GX |
166 | erofs_err(inode->i_sb, |
167 | "unsupported on-disk inode version %u of nid %llu", | |
168 | erofs_inode_version(ifmt), vi->nid); | |
0dcd3c94 GX |
169 | err = -EOPNOTSUPP; |
170 | goto err_out; | |
431339ba GX |
171 | } |
172 | ||
d3938ee2 GX |
173 | inode->i_mtime.tv_sec = inode->i_ctime.tv_sec; |
174 | inode->i_atime.tv_sec = inode->i_ctime.tv_sec; | |
175 | inode->i_mtime.tv_nsec = inode->i_ctime.tv_nsec; | |
176 | inode->i_atime.tv_nsec = inode->i_ctime.tv_nsec; | |
177 | ||
fe6d9875 GX |
178 | if (!nblks) |
179 | /* measure inode.i_blocks as generic filesystems */ | |
180 | inode->i_blocks = roundup(inode->i_size, EROFS_BLKSIZ) >> 9; | |
181 | else | |
182 | inode->i_blocks = nblks << LOG_SECTORS_PER_BLOCK; | |
0dcd3c94 | 183 | return page; |
a6b9b1d5 GX |
184 | |
185 | bogusimode: | |
4f761fa2 GX |
186 | erofs_err(inode->i_sb, "bogus i_mode (%o) @ nid %llu", |
187 | inode->i_mode, vi->nid); | |
0dcd3c94 GX |
188 | err = -EFSCORRUPTED; |
189 | err_out: | |
a6b9b1d5 | 190 | DBG_BUGON(1); |
0dcd3c94 GX |
191 | kfree(copied); |
192 | unlock_page(page); | |
193 | put_page(page); | |
194 | return ERR_PTR(err); | |
431339ba GX |
195 | } |
196 | ||
a2c75c81 GX |
197 | static int erofs_fill_symlink(struct inode *inode, void *data, |
198 | unsigned int m_pofs) | |
431339ba | 199 | { |
a5876e24 | 200 | struct erofs_inode *vi = EROFS_I(inode); |
a2c75c81 | 201 | char *lnk; |
431339ba | 202 | |
a2c75c81 GX |
203 | /* if it cannot be handled with fast symlink scheme */ |
204 | if (vi->datalayout != EROFS_INODE_FLAT_INLINE || | |
205 | inode->i_size >= PAGE_SIZE) { | |
206 | inode->i_op = &erofs_symlink_iops; | |
431339ba | 207 | return 0; |
a2c75c81 | 208 | } |
431339ba | 209 | |
e2c71e74 | 210 | lnk = kmalloc(inode->i_size + 1, GFP_KERNEL); |
a2c75c81 GX |
211 | if (!lnk) |
212 | return -ENOMEM; | |
8b987bca | 213 | |
0dcd3c94 | 214 | m_pofs += vi->xattr_isize; |
a2c75c81 GX |
215 | /* inline symlink data shouldn't cross page boundary as well */ |
216 | if (m_pofs + inode->i_size > PAGE_SIZE) { | |
217 | kfree(lnk); | |
4f761fa2 GX |
218 | erofs_err(inode->i_sb, |
219 | "inline data cross block boundary @ nid %llu", | |
220 | vi->nid); | |
a2c75c81 GX |
221 | DBG_BUGON(1); |
222 | return -EFSCORRUPTED; | |
223 | } | |
431339ba | 224 | |
a2c75c81 GX |
225 | memcpy(lnk, data + m_pofs, inode->i_size); |
226 | lnk[inode->i_size] = '\0'; | |
431339ba | 227 | |
a2c75c81 GX |
228 | inode->i_link = lnk; |
229 | inode->i_op = &erofs_fast_symlink_iops; | |
55457459 | 230 | return 0; |
431339ba GX |
231 | } |
232 | ||
99634bf3 | 233 | static int erofs_fill_inode(struct inode *inode, int isdir) |
431339ba | 234 | { |
a5876e24 | 235 | struct erofs_inode *vi = EROFS_I(inode); |
431339ba | 236 | struct page *page; |
7dd68b14 | 237 | unsigned int ofs; |
0dcd3c94 | 238 | int err = 0; |
431339ba | 239 | |
13f06f48 | 240 | trace_erofs_fill_inode(inode, isdir); |
431339ba | 241 | |
0dcd3c94 GX |
242 | /* read inode base data from disk */ |
243 | page = erofs_read_inode(inode, &ofs); | |
244 | if (IS_ERR(page)) | |
431339ba | 245 | return PTR_ERR(page); |
84947eb6 GX |
246 | |
247 | /* setup the new inode */ | |
248 | switch (inode->i_mode & S_IFMT) { | |
249 | case S_IFREG: | |
250 | inode->i_op = &erofs_generic_iops; | |
251 | inode->i_fop = &generic_ro_fops; | |
252 | break; | |
253 | case S_IFDIR: | |
254 | inode->i_op = &erofs_dir_iops; | |
255 | inode->i_fop = &erofs_dir_fops; | |
256 | break; | |
257 | case S_IFLNK: | |
0dcd3c94 | 258 | err = erofs_fill_symlink(inode, page_address(page), ofs); |
84947eb6 | 259 | if (err) |
431339ba | 260 | goto out_unlock; |
84947eb6 GX |
261 | inode_nohighmem(inode); |
262 | break; | |
263 | case S_IFCHR: | |
264 | case S_IFBLK: | |
265 | case S_IFIFO: | |
266 | case S_IFSOCK: | |
267 | inode->i_op = &erofs_generic_iops; | |
268 | init_special_inode(inode, inode->i_mode, inode->i_rdev); | |
269 | goto out_unlock; | |
270 | default: | |
271 | err = -EFSCORRUPTED; | |
272 | goto out_unlock; | |
273 | } | |
431339ba | 274 | |
84947eb6 GX |
275 | if (erofs_inode_is_data_compressed(vi->datalayout)) { |
276 | err = z_erofs_fill_inode(inode); | |
277 | goto out_unlock; | |
431339ba | 278 | } |
84947eb6 | 279 | inode->i_mapping->a_ops = &erofs_raw_access_aops; |
431339ba GX |
280 | |
281 | out_unlock: | |
282 | unlock_page(page); | |
283 | put_page(page); | |
284 | return err; | |
285 | } | |
286 | ||
2abd7814 GX |
287 | /* |
288 | * erofs nid is 64bits, but i_ino is 'unsigned long', therefore | |
289 | * we should do more for 32-bit platform to find the right inode. | |
290 | */ | |
2abd7814 GX |
291 | static int erofs_ilookup_test_actor(struct inode *inode, void *opaque) |
292 | { | |
293 | const erofs_nid_t nid = *(erofs_nid_t *)opaque; | |
294 | ||
a5876e24 | 295 | return EROFS_I(inode)->nid == nid; |
2abd7814 GX |
296 | } |
297 | ||
298 | static int erofs_iget_set_actor(struct inode *inode, void *opaque) | |
299 | { | |
300 | const erofs_nid_t nid = *(erofs_nid_t *)opaque; | |
301 | ||
302 | inode->i_ino = erofs_inode_hash(nid); | |
303 | return 0; | |
304 | } | |
2abd7814 GX |
305 | |
306 | static inline struct inode *erofs_iget_locked(struct super_block *sb, | |
307 | erofs_nid_t nid) | |
308 | { | |
309 | const unsigned long hashval = erofs_inode_hash(nid); | |
310 | ||
2abd7814 GX |
311 | return iget5_locked(sb, hashval, erofs_ilookup_test_actor, |
312 | erofs_iget_set_actor, &nid); | |
2abd7814 GX |
313 | } |
314 | ||
431339ba | 315 | struct inode *erofs_iget(struct super_block *sb, |
447a3621 JM |
316 | erofs_nid_t nid, |
317 | bool isdir) | |
431339ba | 318 | { |
2abd7814 | 319 | struct inode *inode = erofs_iget_locked(sb, nid); |
431339ba | 320 | |
8d8a09b0 | 321 | if (!inode) |
431339ba GX |
322 | return ERR_PTR(-ENOMEM); |
323 | ||
324 | if (inode->i_state & I_NEW) { | |
325 | int err; | |
a5876e24 | 326 | struct erofs_inode *vi = EROFS_I(inode); |
8af36478 | 327 | |
431339ba GX |
328 | vi->nid = nid; |
329 | ||
99634bf3 | 330 | err = erofs_fill_inode(inode, isdir); |
8d8a09b0 | 331 | if (!err) |
431339ba GX |
332 | unlock_new_inode(inode); |
333 | else { | |
334 | iget_failed(inode); | |
335 | inode = ERR_PTR(err); | |
336 | } | |
337 | } | |
338 | return inode; | |
339 | } | |
340 | ||
89f27ede GX |
341 | int erofs_getattr(const struct path *path, struct kstat *stat, |
342 | u32 request_mask, unsigned int query_flags) | |
343 | { | |
344 | struct inode *const inode = d_inode(path->dentry); | |
89f27ede | 345 | |
a5876e24 | 346 | if (erofs_inode_is_data_compressed(EROFS_I(inode)->datalayout)) |
89f27ede GX |
347 | stat->attributes |= STATX_ATTR_COMPRESSED; |
348 | ||
349 | stat->attributes |= STATX_ATTR_IMMUTABLE; | |
350 | stat->attributes_mask |= (STATX_ATTR_COMPRESSED | | |
351 | STATX_ATTR_IMMUTABLE); | |
352 | ||
353 | generic_fillattr(inode, stat); | |
354 | return 0; | |
355 | } | |
356 | ||
60939826 | 357 | const struct inode_operations erofs_generic_iops = { |
89f27ede | 358 | .getattr = erofs_getattr, |
b17500a0 | 359 | .listxattr = erofs_listxattr, |
516c115c | 360 | .get_acl = erofs_get_acl, |
b17500a0 | 361 | }; |
b17500a0 | 362 | |
60939826 | 363 | const struct inode_operations erofs_symlink_iops = { |
b17500a0 | 364 | .get_link = page_get_link, |
89f27ede | 365 | .getattr = erofs_getattr, |
b17500a0 | 366 | .listxattr = erofs_listxattr, |
516c115c | 367 | .get_acl = erofs_get_acl, |
b17500a0 | 368 | }; |
b17500a0 | 369 | |
60939826 | 370 | const struct inode_operations erofs_fast_symlink_iops = { |
b17500a0 | 371 | .get_link = simple_get_link, |
89f27ede | 372 | .getattr = erofs_getattr, |
b17500a0 | 373 | .listxattr = erofs_listxattr, |
516c115c | 374 | .get_acl = erofs_get_acl, |
60939826 | 375 | }; |
b17500a0 | 376 |