@@ -220,16 +220,59 @@ static int erofs_load_compr_cfgs(struct super_block *sb,
220220}
221221#endif
222222
223- static int erofs_init_devices (struct super_block * sb ,
223+ static int erofs_init_device (struct erofs_buf * buf , struct super_block * sb ,
224+ struct erofs_device_info * dif , erofs_off_t * pos )
225+ {
226+ struct erofs_sb_info * sbi = EROFS_SB (sb );
227+ struct erofs_deviceslot * dis ;
228+ struct block_device * bdev ;
229+ void * ptr ;
230+ int ret ;
231+
232+ ptr = erofs_read_metabuf (buf , sb , erofs_blknr (* pos ), EROFS_KMAP );
233+ if (IS_ERR (ptr ))
234+ return PTR_ERR (ptr );
235+ dis = ptr + erofs_blkoff (* pos );
236+
237+ if (!dif -> path ) {
238+ if (!dis -> tag [0 ]) {
239+ erofs_err (sb , "empty device tag @ pos %llu" , * pos );
240+ return - EINVAL ;
241+ }
242+ dif -> path = kmemdup_nul (dis -> tag , sizeof (dis -> tag ), GFP_KERNEL );
243+ if (!dif -> path )
244+ return - ENOMEM ;
245+ }
246+
247+ if (erofs_is_fscache_mode (sb )) {
248+ ret = erofs_fscache_register_cookie (sb , & dif -> fscache ,
249+ dif -> path , false);
250+ if (ret )
251+ return ret ;
252+ } else {
253+ bdev = blkdev_get_by_path (dif -> path , FMODE_READ | FMODE_EXCL ,
254+ sb -> s_type );
255+ if (IS_ERR (bdev ))
256+ return PTR_ERR (bdev );
257+ dif -> bdev = bdev ;
258+ dif -> dax_dev = fs_dax_get_by_bdev (bdev , & dif -> dax_part_off );
259+ }
260+
261+ dif -> blocks = le32_to_cpu (dis -> blocks );
262+ dif -> mapped_blkaddr = le32_to_cpu (dis -> mapped_blkaddr );
263+ sbi -> total_blocks += dif -> blocks ;
264+ * pos += EROFS_DEVT_SLOT_SIZE ;
265+ return 0 ;
266+ }
267+
268+ static int erofs_scan_devices (struct super_block * sb ,
224269 struct erofs_super_block * dsb )
225270{
226271 struct erofs_sb_info * sbi = EROFS_SB (sb );
227272 unsigned int ondisk_extradevs ;
228273 erofs_off_t pos ;
229274 struct erofs_buf buf = __EROFS_BUF_INITIALIZER ;
230275 struct erofs_device_info * dif ;
231- struct erofs_deviceslot * dis ;
232- void * ptr ;
233276 int id , err = 0 ;
234277
235278 sbi -> total_blocks = sbi -> primarydevice_blocks ;
@@ -238,7 +281,8 @@ static int erofs_init_devices(struct super_block *sb,
238281 else
239282 ondisk_extradevs = le16_to_cpu (dsb -> extra_devices );
240283
241- if (ondisk_extradevs != sbi -> devs -> extra_devices ) {
284+ if (sbi -> devs -> extra_devices &&
285+ ondisk_extradevs != sbi -> devs -> extra_devices ) {
242286 erofs_err (sb , "extra devices don't match (ondisk %u, given %u)" ,
243287 ondisk_extradevs , sbi -> devs -> extra_devices );
244288 return - EINVAL ;
@@ -249,39 +293,31 @@ static int erofs_init_devices(struct super_block *sb,
249293 sbi -> device_id_mask = roundup_pow_of_two (ondisk_extradevs + 1 ) - 1 ;
250294 pos = le16_to_cpu (dsb -> devt_slotoff ) * EROFS_DEVT_SLOT_SIZE ;
251295 down_read (& sbi -> devs -> rwsem );
252- idr_for_each_entry (& sbi -> devs -> tree , dif , id ) {
253- struct block_device * bdev ;
254-
255- ptr = erofs_read_metabuf (& buf , sb , erofs_blknr (pos ),
256- EROFS_KMAP );
257- if (IS_ERR (ptr )) {
258- err = PTR_ERR (ptr );
259- break ;
260- }
261- dis = ptr + erofs_blkoff (pos );
262-
263- if (erofs_is_fscache_mode (sb )) {
264- err = erofs_fscache_register_cookie (sb , & dif -> fscache ,
265- dif -> path , false);
296+ if (sbi -> devs -> extra_devices ) {
297+ idr_for_each_entry (& sbi -> devs -> tree , dif , id ) {
298+ err = erofs_init_device (& buf , sb , dif , & pos );
266299 if (err )
267300 break ;
268- } else {
269- bdev = blkdev_get_by_path ( dif -> path ,
270- FMODE_READ | FMODE_EXCL ,
271- sb -> s_type );
272- if (IS_ERR ( bdev ) ) {
273- err = PTR_ERR ( bdev ) ;
301+ }
302+ } else {
303+ for ( id = 0 ; id < ondisk_extradevs ; id ++ ) {
304+ dif = kzalloc ( sizeof ( * dif ), GFP_KERNEL );
305+ if (! dif ) {
306+ err = - ENOMEM ;
274307 break ;
275308 }
276- dif -> bdev = bdev ;
277- dif -> dax_dev = fs_dax_get_by_bdev (bdev ,
278- & dif -> dax_part_off );
279- }
280309
281- dif -> blocks = le32_to_cpu (dis -> blocks );
282- dif -> mapped_blkaddr = le32_to_cpu (dis -> mapped_blkaddr );
283- sbi -> total_blocks += dif -> blocks ;
284- pos += EROFS_DEVT_SLOT_SIZE ;
310+ err = idr_alloc (& sbi -> devs -> tree , dif , 0 , 0 , GFP_KERNEL );
311+ if (err < 0 ) {
312+ kfree (dif );
313+ break ;
314+ }
315+ ++ sbi -> devs -> extra_devices ;
316+
317+ err = erofs_init_device (& buf , sb , dif , & pos );
318+ if (err )
319+ break ;
320+ }
285321 }
286322 up_read (& sbi -> devs -> rwsem );
287323 erofs_put_metabuf (& buf );
@@ -368,7 +404,7 @@ static int erofs_read_superblock(struct super_block *sb)
368404 goto out ;
369405
370406 /* handle multiple devices */
371- ret = erofs_init_devices (sb , dsb );
407+ ret = erofs_scan_devices (sb , dsb );
372408
373409 if (erofs_sb_has_ztailpacking (sbi ))
374410 erofs_info (sb , "EXPERIMENTAL compressed inline data feature in use. Use at your own risk!" );
0 commit comments