1
1
// SPDX-License-Identifier: GPL-2.0-only
2
2
/*
3
3
* Copyright (C) 2017-2018 HUAWEI, Inc.
4
- * http ://www.huawei.com/
4
+ * https ://www.huawei.com/
5
5
* Created by Gao Xiang <[email protected] >
6
6
*/
7
7
#include "xattr.h"
8
8
9
9
#include <trace/events/erofs.h>
10
10
11
- /* no locking */
12
- static int erofs_read_inode (struct inode * inode , void * data )
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 )
13
18
{
19
+ struct super_block * sb = inode -> i_sb ;
20
+ struct erofs_sb_info * sbi = EROFS_SB (sb );
14
21
struct erofs_inode * vi = EROFS_I (inode );
15
- struct erofs_inode_compact * dic = data ;
16
- struct erofs_inode_extended * die ;
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 ;
17
30
18
- const unsigned int ifmt = le16_to_cpu (dic -> i_format );
19
- struct erofs_sb_info * sbi = EROFS_SB (inode -> i_sb );
20
- erofs_blk_t nblks = 0 ;
31
+ blkaddr = erofs_blknr (inode_loc );
32
+ * ofs = erofs_blkoff (inode_loc );
21
33
22
- vi -> datalayout = erofs_inode_datalayout (ifmt );
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
+ }
23
43
44
+ dic = page_address (page ) + * ofs ;
45
+ ifmt = le16_to_cpu (dic -> i_format );
46
+
47
+ vi -> datalayout = erofs_inode_datalayout (ifmt );
24
48
if (vi -> datalayout >= EROFS_INODE_DATALAYOUT_MAX ) {
25
49
erofs_err (inode -> i_sb , "unsupported datalayout %u of nid %llu" ,
26
50
vi -> datalayout , vi -> nid );
27
- DBG_BUGON ( 1 ) ;
28
- return - EOPNOTSUPP ;
51
+ err = - EOPNOTSUPP ;
52
+ goto err_out ;
29
53
}
30
54
31
55
switch (erofs_inode_version (ifmt )) {
32
56
case EROFS_INODE_LAYOUT_EXTENDED :
33
- die = data ;
34
-
35
57
vi -> inode_isize = sizeof (struct erofs_inode_extended );
58
+ /* check if the inode acrosses page boundary */
59
+ if (* ofs + vi -> inode_isize <= PAGE_SIZE ) {
60
+ * ofs += vi -> inode_isize ;
61
+ die = (struct erofs_inode_extended * )dic ;
62
+ } else {
63
+ const unsigned int gotten = PAGE_SIZE - * ofs ;
64
+
65
+ copied = kmalloc (vi -> inode_isize , GFP_NOFS );
66
+ if (!copied ) {
67
+ err = - ENOMEM ;
68
+ goto err_out ;
69
+ }
70
+ memcpy (copied , dic , gotten );
71
+ unlock_page (page );
72
+ put_page (page );
73
+
74
+ page = erofs_get_meta_page (sb , blkaddr + 1 );
75
+ if (IS_ERR (page )) {
76
+ erofs_err (sb , "failed to get inode payload page (nid: %llu), err %ld" ,
77
+ vi -> nid , PTR_ERR (page ));
78
+ kfree (copied );
79
+ return page ;
80
+ }
81
+ * ofs = vi -> inode_isize - gotten ;
82
+ memcpy ((u8 * )copied + gotten , page_address (page ), * ofs );
83
+ die = copied ;
84
+ }
36
85
vi -> xattr_isize = erofs_xattr_ibody_size (die -> i_xattr_icount );
37
86
38
87
inode -> i_mode = le16_to_cpu (die -> i_mode );
@@ -69,9 +118,12 @@ static int erofs_read_inode(struct inode *inode, void *data)
69
118
/* total blocks for compressed files */
70
119
if (erofs_inode_is_data_compressed (vi -> datalayout ))
71
120
nblks = le32_to_cpu (die -> i_u .compressed_blocks );
121
+
122
+ kfree (copied );
72
123
break ;
73
124
case EROFS_INODE_LAYOUT_COMPACT :
74
125
vi -> inode_isize = sizeof (struct erofs_inode_compact );
126
+ * ofs += vi -> inode_isize ;
75
127
vi -> xattr_isize = erofs_xattr_ibody_size (dic -> i_xattr_icount );
76
128
77
129
inode -> i_mode = le16_to_cpu (dic -> i_mode );
@@ -111,22 +163,27 @@ static int erofs_read_inode(struct inode *inode, void *data)
111
163
erofs_err (inode -> i_sb ,
112
164
"unsupported on-disk inode version %u of nid %llu" ,
113
165
erofs_inode_version (ifmt ), vi -> nid );
114
- DBG_BUGON ( 1 ) ;
115
- return - EOPNOTSUPP ;
166
+ err = - EOPNOTSUPP ;
167
+ goto err_out ;
116
168
}
117
169
118
170
if (!nblks )
119
171
/* measure inode.i_blocks as generic filesystems */
120
172
inode -> i_blocks = roundup (inode -> i_size , EROFS_BLKSIZ ) >> 9 ;
121
173
else
122
174
inode -> i_blocks = nblks << LOG_SECTORS_PER_BLOCK ;
123
- return 0 ;
175
+ return page ;
124
176
125
177
bogusimode :
126
178
erofs_err (inode -> i_sb , "bogus i_mode (%o) @ nid %llu" ,
127
179
inode -> i_mode , vi -> nid );
180
+ err = - EFSCORRUPTED ;
181
+ err_out :
128
182
DBG_BUGON (1 );
129
- return - EFSCORRUPTED ;
183
+ kfree (copied );
184
+ unlock_page (page );
185
+ put_page (page );
186
+ return ERR_PTR (err );
130
187
}
131
188
132
189
static int erofs_fill_symlink (struct inode * inode , void * data ,
@@ -146,7 +203,7 @@ static int erofs_fill_symlink(struct inode *inode, void *data,
146
203
if (!lnk )
147
204
return - ENOMEM ;
148
205
149
- m_pofs += vi -> inode_isize + vi -> xattr_isize ;
206
+ m_pofs += vi -> xattr_isize ;
150
207
/* inline symlink data shouldn't cross page boundary as well */
151
208
if (m_pofs + inode -> i_size > PAGE_SIZE ) {
152
209
kfree (lnk );
@@ -167,37 +224,17 @@ static int erofs_fill_symlink(struct inode *inode, void *data,
167
224
168
225
static int erofs_fill_inode (struct inode * inode , int isdir )
169
226
{
170
- struct super_block * sb = inode -> i_sb ;
171
227
struct erofs_inode * vi = EROFS_I (inode );
172
228
struct page * page ;
173
- void * data ;
174
- int err ;
175
- erofs_blk_t blkaddr ;
176
229
unsigned int ofs ;
177
- erofs_off_t inode_loc ;
230
+ int err = 0 ;
178
231
179
232
trace_erofs_fill_inode (inode , isdir );
180
- inode_loc = iloc (EROFS_SB (sb ), vi -> nid );
181
- blkaddr = erofs_blknr (inode_loc );
182
- ofs = erofs_blkoff (inode_loc );
183
-
184
- erofs_dbg ("%s, reading inode nid %llu at %u of blkaddr %u" ,
185
- __func__ , vi -> nid , ofs , blkaddr );
186
233
187
- page = erofs_get_meta_page (sb , blkaddr );
188
-
189
- if (IS_ERR (page )) {
190
- erofs_err (sb , "failed to get inode (nid: %llu) page, err %ld" ,
191
- vi -> nid , PTR_ERR (page ));
234
+ /* read inode base data from disk */
235
+ page = erofs_read_inode (inode , & ofs );
236
+ if (IS_ERR (page ))
192
237
return PTR_ERR (page );
193
- }
194
-
195
- DBG_BUGON (!PageUptodate (page ));
196
- data = page_address (page );
197
-
198
- err = erofs_read_inode (inode , data + ofs );
199
- if (err )
200
- goto out_unlock ;
201
238
202
239
/* setup the new inode */
203
240
switch (inode -> i_mode & S_IFMT ) {
@@ -210,7 +247,7 @@ static int erofs_fill_inode(struct inode *inode, int isdir)
210
247
inode -> i_fop = & erofs_dir_fops ;
211
248
break ;
212
249
case S_IFLNK :
213
- err = erofs_fill_symlink (inode , data , ofs );
250
+ err = erofs_fill_symlink (inode , page_address ( page ) , ofs );
214
251
if (err )
215
252
goto out_unlock ;
216
253
inode_nohighmem (inode );
0 commit comments