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/ |
c5aa903a | 5 | * Copyright (C) 2021, Alibaba Cloud |
431339ba | 6 | */ |
b17500a0 | 7 | #include "xattr.h" |
13f06f48 CY |
8 | #include <trace/events/erofs.h> |
9 | ||
53d514b9 YW |
10 | static int erofs_fill_symlink(struct inode *inode, void *kaddr, |
11 | unsigned int m_pofs) | |
12 | { | |
13 | struct erofs_inode *vi = EROFS_I(inode); | |
14 | loff_t off; | |
15 | ||
16 | m_pofs += vi->xattr_isize; | |
17 | /* check if it cannot be handled with fast symlink scheme */ | |
025497e1 | 18 | if (vi->datalayout != EROFS_INODE_FLAT_INLINE || |
53d514b9 YW |
19 | check_add_overflow(m_pofs, inode->i_size, &off) || |
20 | off > i_blocksize(inode)) | |
21 | return 0; | |
22 | ||
23 | inode->i_link = kmemdup_nul(kaddr + m_pofs, inode->i_size, GFP_KERNEL); | |
24 | return inode->i_link ? 0 : -ENOMEM; | |
25 | } | |
26 | ||
27 | static int erofs_read_inode(struct inode *inode) | |
431339ba | 28 | { |
0dcd3c94 GX |
29 | struct super_block *sb = inode->i_sb; |
30 | struct erofs_sb_info *sbi = EROFS_SB(sb); | |
a5876e24 | 31 | struct erofs_inode *vi = EROFS_I(inode); |
b780d3fc | 32 | const erofs_off_t inode_loc = erofs_iloc(inode); |
0dcd3c94 | 33 | erofs_blk_t blkaddr, nblks = 0; |
c521e3ad | 34 | void *kaddr; |
0dcd3c94 GX |
35 | struct erofs_inode_compact *dic; |
36 | struct erofs_inode_extended *die, *copied = NULL; | |
914fa861 | 37 | union erofs_inode_i_u iu; |
53d514b9 YW |
38 | struct erofs_buf buf = __EROFS_BUF_INITIALIZER; |
39 | unsigned int ifmt, ofs; | |
40 | int err = 0; | |
8a765682 | 41 | |
3acea5fc | 42 | blkaddr = erofs_blknr(sb, inode_loc); |
53d514b9 | 43 | ofs = erofs_blkoff(sb, inode_loc); |
431339ba | 44 | |
53d514b9 | 45 | kaddr = erofs_read_metabuf(&buf, sb, erofs_pos(sb, blkaddr), EROFS_KMAP); |
c521e3ad | 46 | if (IS_ERR(kaddr)) { |
0dcd3c94 | 47 | erofs_err(sb, "failed to get inode (nid: %llu) page, err %ld", |
c521e3ad | 48 | vi->nid, PTR_ERR(kaddr)); |
53d514b9 | 49 | return PTR_ERR(kaddr); |
0dcd3c94 | 50 | } |
431339ba | 51 | |
53d514b9 | 52 | dic = kaddr + ofs; |
0dcd3c94 | 53 | ifmt = le16_to_cpu(dic->i_format); |
24a806d8 | 54 | if (ifmt & ~EROFS_I_ALL) { |
914fa861 | 55 | erofs_err(sb, "unsupported i_format %u of nid %llu", |
24a806d8 GX |
56 | ifmt, vi->nid); |
57 | err = -EOPNOTSUPP; | |
58 | goto err_out; | |
59 | } | |
60 | ||
0dcd3c94 | 61 | vi->datalayout = erofs_inode_datalayout(ifmt); |
8a765682 | 62 | if (vi->datalayout >= EROFS_INODE_DATALAYOUT_MAX) { |
914fa861 | 63 | erofs_err(sb, "unsupported datalayout %u of nid %llu", |
4f761fa2 | 64 | vi->datalayout, vi->nid); |
0dcd3c94 GX |
65 | err = -EOPNOTSUPP; |
66 | goto err_out; | |
431339ba GX |
67 | } |
68 | ||
8a765682 GX |
69 | switch (erofs_inode_version(ifmt)) { |
70 | case EROFS_INODE_LAYOUT_EXTENDED: | |
8a765682 | 71 | vi->inode_isize = sizeof(struct erofs_inode_extended); |
c521e3ad | 72 | /* check if the extended inode acrosses block boundary */ |
53d514b9 YW |
73 | if (ofs + vi->inode_isize <= sb->s_blocksize) { |
74 | ofs += vi->inode_isize; | |
0dcd3c94 GX |
75 | die = (struct erofs_inode_extended *)dic; |
76 | } else { | |
53d514b9 | 77 | const unsigned int gotten = sb->s_blocksize - ofs; |
0dcd3c94 | 78 | |
97cf5d53 | 79 | copied = kmalloc(vi->inode_isize, GFP_KERNEL); |
0dcd3c94 GX |
80 | if (!copied) { |
81 | err = -ENOMEM; | |
82 | goto err_out; | |
83 | } | |
84 | memcpy(copied, dic, gotten); | |
53d514b9 | 85 | kaddr = erofs_read_metabuf(&buf, sb, erofs_pos(sb, blkaddr + 1), |
c521e3ad GX |
86 | EROFS_KMAP); |
87 | if (IS_ERR(kaddr)) { | |
88 | erofs_err(sb, "failed to get inode payload block (nid: %llu), err %ld", | |
89 | vi->nid, PTR_ERR(kaddr)); | |
0dcd3c94 | 90 | kfree(copied); |
53d514b9 | 91 | return PTR_ERR(kaddr); |
0dcd3c94 | 92 | } |
53d514b9 YW |
93 | ofs = vi->inode_isize - gotten; |
94 | memcpy((u8 *)copied + gotten, kaddr, ofs); | |
0dcd3c94 GX |
95 | die = copied; |
96 | } | |
8a765682 | 97 | vi->xattr_isize = erofs_xattr_ibody_size(die->i_xattr_icount); |
431339ba | 98 | |
8a765682 | 99 | inode->i_mode = le16_to_cpu(die->i_mode); |
914fa861 | 100 | iu = die->i_u; |
8a765682 GX |
101 | i_uid_write(inode, le32_to_cpu(die->i_uid)); |
102 | i_gid_write(inode, le32_to_cpu(die->i_gid)); | |
103 | set_nlink(inode, le32_to_cpu(die->i_nlink)); | |
914fa861 | 104 | /* each extended inode has its own timestamp */ |
7be935e1 JL |
105 | inode_set_ctime(inode, le64_to_cpu(die->i_mtime), |
106 | le32_to_cpu(die->i_mtime_nsec)); | |
431339ba | 107 | |
8a765682 | 108 | inode->i_size = le64_to_cpu(die->i_size); |
0dcd3c94 | 109 | kfree(copied); |
8a765682 GX |
110 | break; |
111 | case EROFS_INODE_LAYOUT_COMPACT: | |
112 | vi->inode_isize = sizeof(struct erofs_inode_compact); | |
53d514b9 | 113 | ofs += vi->inode_isize; |
8a765682 GX |
114 | vi->xattr_isize = erofs_xattr_ibody_size(dic->i_xattr_icount); |
115 | ||
116 | inode->i_mode = le16_to_cpu(dic->i_mode); | |
914fa861 | 117 | iu = dic->i_u; |
8a765682 GX |
118 | i_uid_write(inode, le16_to_cpu(dic->i_uid)); |
119 | i_gid_write(inode, le16_to_cpu(dic->i_gid)); | |
120 | set_nlink(inode, le16_to_cpu(dic->i_nlink)); | |
d3938ee2 | 121 | /* use build time for compact inodes */ |
7be935e1 | 122 | inode_set_ctime(inode, sbi->build_time, sbi->build_time_nsec); |
431339ba | 123 | |
8a765682 | 124 | inode->i_size = le32_to_cpu(dic->i_size); |
8a765682 GX |
125 | break; |
126 | default: | |
914fa861 | 127 | erofs_err(sb, "unsupported on-disk inode version %u of nid %llu", |
4f761fa2 | 128 | erofs_inode_version(ifmt), vi->nid); |
0dcd3c94 GX |
129 | err = -EOPNOTSUPP; |
130 | goto err_out; | |
431339ba GX |
131 | } |
132 | ||
025497e1 GX |
133 | if (unlikely(inode->i_size < 0)) { |
134 | erofs_err(sb, "negative i_size @ nid %llu", vi->nid); | |
135 | err = -EFSCORRUPTED; | |
136 | goto err_out; | |
137 | } | |
914fa861 FM |
138 | switch (inode->i_mode & S_IFMT) { |
139 | case S_IFREG: | |
140 | case S_IFDIR: | |
141 | case S_IFLNK: | |
142 | vi->raw_blkaddr = le32_to_cpu(iu.raw_blkaddr); | |
53d514b9 YW |
143 | if(S_ISLNK(inode->i_mode)) { |
144 | err = erofs_fill_symlink(inode, kaddr, ofs); | |
145 | if (err) | |
146 | goto err_out; | |
147 | } | |
914fa861 FM |
148 | break; |
149 | case S_IFCHR: | |
150 | case S_IFBLK: | |
151 | inode->i_rdev = new_decode_dev(le32_to_cpu(iu.rdev)); | |
152 | break; | |
153 | case S_IFIFO: | |
154 | case S_IFSOCK: | |
155 | inode->i_rdev = 0; | |
156 | break; | |
157 | default: | |
158 | erofs_err(sb, "bogus i_mode (%o) @ nid %llu", inode->i_mode, | |
159 | vi->nid); | |
160 | err = -EFSCORRUPTED; | |
161 | goto err_out; | |
162 | } | |
163 | ||
164 | /* total blocks for compressed files */ | |
165 | if (erofs_inode_is_data_compressed(vi->datalayout)) { | |
166 | nblks = le32_to_cpu(iu.compressed_blocks); | |
167 | } else if (vi->datalayout == EROFS_INODE_CHUNK_BASED) { | |
168 | /* fill chunked inode summary info */ | |
169 | vi->chunkformat = le16_to_cpu(iu.c.format); | |
d705117d | 170 | if (vi->chunkformat & ~EROFS_CHUNK_FORMAT_ALL) { |
914fa861 | 171 | erofs_err(sb, "unsupported chunk format %x of nid %llu", |
c5aa903a GX |
172 | vi->chunkformat, vi->nid); |
173 | err = -EOPNOTSUPP; | |
174 | goto err_out; | |
175 | } | |
3acea5fc | 176 | vi->chunkbits = sb->s_blocksize_bits + |
c5aa903a GX |
177 | (vi->chunkformat & EROFS_CHUNK_FORMAT_BLKBITS_MASK); |
178 | } | |
594370f7 JL |
179 | inode_set_mtime_to_ts(inode, |
180 | inode_set_atime_to_ts(inode, inode_get_ctime(inode))); | |
d3938ee2 | 181 | |
06252e9c | 182 | inode->i_flags &= ~S_DAX; |
e6242465 | 183 | if (test_opt(&sbi->opt, DAX_ALWAYS) && S_ISREG(inode->i_mode) && |
18bddc5b XY |
184 | (vi->datalayout == EROFS_INODE_FLAT_PLAIN || |
185 | vi->datalayout == EROFS_INODE_CHUNK_BASED)) | |
06252e9c | 186 | inode->i_flags |= S_DAX; |
3acea5fc | 187 | |
fe6d9875 GX |
188 | if (!nblks) |
189 | /* measure inode.i_blocks as generic filesystems */ | |
3acea5fc | 190 | inode->i_blocks = round_up(inode->i_size, sb->s_blocksize) >> 9; |
fe6d9875 | 191 | else |
3acea5fc | 192 | inode->i_blocks = nblks << (sb->s_blocksize_bits - 9); |
0dcd3c94 | 193 | err_out: |
53d514b9 YW |
194 | DBG_BUGON(err); |
195 | erofs_put_metabuf(&buf); | |
196 | return err; | |
431339ba GX |
197 | } |
198 | ||
312fe643 | 199 | static int erofs_fill_inode(struct inode *inode) |
431339ba | 200 | { |
a5876e24 | 201 | struct erofs_inode *vi = EROFS_I(inode); |
53d514b9 | 202 | int err; |
431339ba | 203 | |
312fe643 | 204 | trace_erofs_fill_inode(inode); |
431339ba | 205 | |
0dcd3c94 | 206 | /* read inode base data from disk */ |
53d514b9 YW |
207 | err = erofs_read_inode(inode); |
208 | if (err) | |
209 | return err; | |
84947eb6 GX |
210 | |
211 | /* setup the new inode */ | |
212 | switch (inode->i_mode & S_IFMT) { | |
213 | case S_IFREG: | |
214 | inode->i_op = &erofs_generic_iops; | |
a08e67a0 HJ |
215 | if (erofs_inode_is_data_compressed(vi->datalayout)) |
216 | inode->i_fop = &generic_ro_fops; | |
217 | else | |
218 | inode->i_fop = &erofs_file_fops; | |
84947eb6 GX |
219 | break; |
220 | case S_IFDIR: | |
221 | inode->i_op = &erofs_dir_iops; | |
222 | inode->i_fop = &erofs_dir_fops; | |
927e5010 | 223 | inode_nohighmem(inode); |
84947eb6 GX |
224 | break; |
225 | case S_IFLNK: | |
53d514b9 YW |
226 | if (inode->i_link) |
227 | inode->i_op = &erofs_fast_symlink_iops; | |
228 | else | |
229 | inode->i_op = &erofs_symlink_iops; | |
84947eb6 GX |
230 | inode_nohighmem(inode); |
231 | break; | |
232 | case S_IFCHR: | |
233 | case S_IFBLK: | |
234 | case S_IFIFO: | |
235 | case S_IFSOCK: | |
236 | inode->i_op = &erofs_generic_iops; | |
237 | init_special_inode(inode, inode->i_mode, inode->i_rdev); | |
53d514b9 | 238 | return 0; |
84947eb6 | 239 | default: |
53d514b9 | 240 | return -EFSCORRUPTED; |
84947eb6 | 241 | } |
431339ba | 242 | |
e080a267 | 243 | mapping_set_large_folios(inode->i_mapping); |
ce63cb62 | 244 | if (erofs_inode_is_data_compressed(vi->datalayout)) { |
4fdadd5b | 245 | #ifdef CONFIG_EROFS_FS_ZIP |
a1bafc31 JX |
246 | DO_ONCE_LITE_IF(inode->i_blkbits != PAGE_SHIFT, |
247 | erofs_info, inode->i_sb, | |
248 | "EXPERIMENTAL EROFS subpage compressed block support in use. Use at your own risk!"); | |
249 | inode->i_mapping->a_ops = &z_erofs_aops; | |
e080a267 | 250 | #else |
4fdadd5b | 251 | err = -EOPNOTSUPP; |
e080a267 GX |
252 | #endif |
253 | } else { | |
ce63cb62 | 254 | inode->i_mapping->a_ops = &erofs_aops; |
1442b02b | 255 | #ifdef CONFIG_EROFS_FS_ONDEMAND |
e080a267 GX |
256 | if (erofs_is_fscache_mode(inode->i_sb)) |
257 | inode->i_mapping->a_ops = &erofs_fscache_access_aops; | |
ce63cb62 GX |
258 | #endif |
259 | #ifdef CONFIG_EROFS_FS_BACKED_BY_FILE | |
260 | if (erofs_is_fileio_mode(EROFS_SB(inode->i_sb))) | |
261 | inode->i_mapping->a_ops = &erofs_fileio_aops; | |
1442b02b | 262 | #endif |
e080a267 | 263 | } |
53d514b9 | 264 | |
431339ba GX |
265 | return err; |
266 | } | |
267 | ||
2abd7814 | 268 | /* |
7c3511a2 GX |
269 | * ino_t is 32-bits on 32-bit arch. We have to squash the 64-bit value down |
270 | * so that it will fit. | |
2abd7814 | 271 | */ |
7c3511a2 | 272 | static ino_t erofs_squash_ino(erofs_nid_t nid) |
2abd7814 | 273 | { |
7c3511a2 GX |
274 | ino_t ino = (ino_t)nid; |
275 | ||
276 | if (sizeof(ino_t) < sizeof(erofs_nid_t)) | |
277 | ino ^= nid >> (sizeof(erofs_nid_t) - sizeof(ino_t)) * 8; | |
278 | return ino; | |
279 | } | |
2abd7814 | 280 | |
7c3511a2 GX |
281 | static int erofs_iget5_eq(struct inode *inode, void *opaque) |
282 | { | |
283 | return EROFS_I(inode)->nid == *(erofs_nid_t *)opaque; | |
2abd7814 GX |
284 | } |
285 | ||
7c3511a2 | 286 | static int erofs_iget5_set(struct inode *inode, void *opaque) |
2abd7814 GX |
287 | { |
288 | const erofs_nid_t nid = *(erofs_nid_t *)opaque; | |
289 | ||
7c3511a2 GX |
290 | inode->i_ino = erofs_squash_ino(nid); |
291 | EROFS_I(inode)->nid = nid; | |
2abd7814 GX |
292 | return 0; |
293 | } | |
2abd7814 | 294 | |
312fe643 | 295 | struct inode *erofs_iget(struct super_block *sb, erofs_nid_t nid) |
2abd7814 | 296 | { |
312fe643 | 297 | struct inode *inode; |
2abd7814 | 298 | |
7c3511a2 GX |
299 | inode = iget5_locked(sb, erofs_squash_ino(nid), erofs_iget5_eq, |
300 | erofs_iget5_set, &nid); | |
8d8a09b0 | 301 | if (!inode) |
431339ba GX |
302 | return ERR_PTR(-ENOMEM); |
303 | ||
304 | if (inode->i_state & I_NEW) { | |
7c3511a2 | 305 | int err = erofs_fill_inode(inode); |
431339ba | 306 | |
7c3511a2 | 307 | if (err) { |
431339ba | 308 | iget_failed(inode); |
7c3511a2 | 309 | return ERR_PTR(err); |
431339ba | 310 | } |
7c3511a2 | 311 | unlock_new_inode(inode); |
431339ba GX |
312 | } |
313 | return inode; | |
314 | } | |
315 | ||
b74d24f7 | 316 | int erofs_getattr(struct mnt_idmap *idmap, const struct path *path, |
549c7297 CB |
317 | struct kstat *stat, u32 request_mask, |
318 | unsigned int query_flags) | |
89f27ede GX |
319 | { |
320 | struct inode *const inode = d_inode(path->dentry); | |
9c421ef3 HL |
321 | bool compressed = |
322 | erofs_inode_is_data_compressed(EROFS_I(inode)->datalayout); | |
89f27ede | 323 | |
9c421ef3 | 324 | if (compressed) |
89f27ede | 325 | stat->attributes |= STATX_ATTR_COMPRESSED; |
89f27ede GX |
326 | stat->attributes |= STATX_ATTR_IMMUTABLE; |
327 | stat->attributes_mask |= (STATX_ATTR_COMPRESSED | | |
328 | STATX_ATTR_IMMUTABLE); | |
329 | ||
9c421ef3 HL |
330 | /* |
331 | * Return the DIO alignment restrictions if requested. | |
332 | * | |
333 | * In EROFS, STATX_DIOALIGN is not supported in ondemand mode and | |
334 | * compressed files, so in these cases we report no DIO support. | |
335 | */ | |
336 | if ((request_mask & STATX_DIOALIGN) && S_ISREG(inode->i_mode)) { | |
337 | stat->result_mask |= STATX_DIOALIGN; | |
338 | if (!erofs_is_fscache_mode(inode->i_sb) && !compressed) { | |
339 | stat->dio_mem_align = | |
340 | bdev_logical_block_size(inode->i_sb->s_bdev); | |
341 | stat->dio_offset_align = stat->dio_mem_align; | |
342 | } | |
343 | } | |
0d72b928 | 344 | generic_fillattr(idmap, request_mask, inode, stat); |
89f27ede GX |
345 | return 0; |
346 | } | |
347 | ||
60939826 | 348 | const struct inode_operations erofs_generic_iops = { |
89f27ede | 349 | .getattr = erofs_getattr, |
b17500a0 | 350 | .listxattr = erofs_listxattr, |
cac2f8b8 | 351 | .get_inode_acl = erofs_get_acl, |
eadcd6b5 | 352 | .fiemap = erofs_fiemap, |
b17500a0 | 353 | }; |
b17500a0 | 354 | |
60939826 | 355 | const struct inode_operations erofs_symlink_iops = { |
b17500a0 | 356 | .get_link = page_get_link, |
89f27ede | 357 | .getattr = erofs_getattr, |
b17500a0 | 358 | .listxattr = erofs_listxattr, |
cac2f8b8 | 359 | .get_inode_acl = erofs_get_acl, |
b17500a0 | 360 | }; |
b17500a0 | 361 | |
60939826 | 362 | const struct inode_operations erofs_fast_symlink_iops = { |
b17500a0 | 363 | .get_link = simple_get_link, |
89f27ede | 364 | .getattr = erofs_getattr, |
b17500a0 | 365 | .listxattr = erofs_listxattr, |
cac2f8b8 | 366 | .get_inode_acl = erofs_get_acl, |
60939826 | 367 | }; |