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