@@ -220,16 +220,59 @@ static int erofs_load_compr_cfgs(struct super_block *sb,
220
220
}
221
221
#endif
222
222
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 ,
224
269
struct erofs_super_block * dsb )
225
270
{
226
271
struct erofs_sb_info * sbi = EROFS_SB (sb );
227
272
unsigned int ondisk_extradevs ;
228
273
erofs_off_t pos ;
229
274
struct erofs_buf buf = __EROFS_BUF_INITIALIZER ;
230
275
struct erofs_device_info * dif ;
231
- struct erofs_deviceslot * dis ;
232
- void * ptr ;
233
276
int id , err = 0 ;
234
277
235
278
sbi -> total_blocks = sbi -> primarydevice_blocks ;
@@ -238,7 +281,8 @@ static int erofs_init_devices(struct super_block *sb,
238
281
else
239
282
ondisk_extradevs = le16_to_cpu (dsb -> extra_devices );
240
283
241
- if (ondisk_extradevs != sbi -> devs -> extra_devices ) {
284
+ if (sbi -> devs -> extra_devices &&
285
+ ondisk_extradevs != sbi -> devs -> extra_devices ) {
242
286
erofs_err (sb , "extra devices don't match (ondisk %u, given %u)" ,
243
287
ondisk_extradevs , sbi -> devs -> extra_devices );
244
288
return - EINVAL ;
@@ -249,39 +293,31 @@ static int erofs_init_devices(struct super_block *sb,
249
293
sbi -> device_id_mask = roundup_pow_of_two (ondisk_extradevs + 1 ) - 1 ;
250
294
pos = le16_to_cpu (dsb -> devt_slotoff ) * EROFS_DEVT_SLOT_SIZE ;
251
295
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 );
266
299
if (err )
267
300
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 ;
274
307
break ;
275
308
}
276
- dif -> bdev = bdev ;
277
- dif -> dax_dev = fs_dax_get_by_bdev (bdev ,
278
- & dif -> dax_part_off );
279
- }
280
309
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
+ }
285
321
}
286
322
up_read (& sbi -> devs -> rwsem );
287
323
erofs_put_metabuf (& buf );
@@ -368,7 +404,7 @@ static int erofs_read_superblock(struct super_block *sb)
368
404
goto out ;
369
405
370
406
/* handle multiple devices */
371
- ret = erofs_init_devices (sb , dsb );
407
+ ret = erofs_scan_devices (sb , dsb );
372
408
373
409
if (erofs_sb_has_ztailpacking (sbi ))
374
410
erofs_info (sb , "EXPERIMENTAL compressed inline data feature in use. Use at your own risk!" );
0 commit comments