Skip to content

Commit e3858e1

Browse files
Russell KingAl Viro
authored andcommitted
fs/adfs: super: extract filesystem block probe
Separate the filesystem block probing from the superblock filling so we can support other ADFS filesystem formats, such as the single-zone E and E+ floppy image formats which do not have a boot block. Signed-off-by: Russell King <[email protected]> Signed-off-by: Al Viro <[email protected]>
1 parent ccbc80a commit e3858e1

File tree

1 file changed

+78
-71
lines changed

1 file changed

+78
-71
lines changed

fs/adfs/super.c

Lines changed: 78 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -277,13 +277,80 @@ static const struct super_operations adfs_sops = {
277277
.show_options = adfs_show_options,
278278
};
279279

280-
static int adfs_fill_super(struct super_block *sb, void *data, int silent)
280+
static int adfs_probe(struct super_block *sb, unsigned int offset, int silent,
281+
int (*validate)(struct super_block *sb,
282+
struct buffer_head *bh,
283+
struct adfs_discrecord **bhp))
281284
{
285+
struct adfs_sb_info *asb = ADFS_SB(sb);
282286
struct adfs_discrecord *dr;
283287
struct buffer_head *bh;
284-
struct object_info root_obj;
288+
unsigned int blocksize = BLOCK_SIZE;
289+
int ret, try;
290+
291+
for (try = 0; try < 2; try++) {
292+
/* try to set the requested block size */
293+
if (sb->s_blocksize != blocksize &&
294+
!sb_set_blocksize(sb, blocksize)) {
295+
if (!silent)
296+
adfs_msg(sb, KERN_ERR,
297+
"error: unsupported blocksize");
298+
return -EINVAL;
299+
}
300+
301+
/* read the buffer */
302+
bh = sb_bread(sb, offset >> sb->s_blocksize_bits);
303+
if (!bh) {
304+
adfs_msg(sb, KERN_ERR,
305+
"error: unable to read block %u, try %d",
306+
offset >> sb->s_blocksize_bits, try);
307+
return -EIO;
308+
}
309+
310+
/* validate it */
311+
ret = validate(sb, bh, &dr);
312+
if (ret) {
313+
brelse(bh);
314+
return ret;
315+
}
316+
317+
/* does the block size match the filesystem block size? */
318+
blocksize = 1 << dr->log2secsize;
319+
if (sb->s_blocksize == blocksize) {
320+
asb->s_map = adfs_read_map(sb, dr);
321+
brelse(bh);
322+
return PTR_ERR_OR_ZERO(asb->s_map);
323+
}
324+
325+
brelse(bh);
326+
}
327+
328+
return -EIO;
329+
}
330+
331+
static int adfs_validate_bblk(struct super_block *sb, struct buffer_head *bh,
332+
struct adfs_discrecord **drp)
333+
{
334+
struct adfs_discrecord *dr;
285335
unsigned char *b_data;
286-
unsigned int blocksize;
336+
337+
b_data = bh->b_data + (ADFS_DISCRECORD % sb->s_blocksize);
338+
if (adfs_checkbblk(b_data))
339+
return -EILSEQ;
340+
341+
/* Do some sanity checks on the ADFS disc record */
342+
dr = (struct adfs_discrecord *)(b_data + ADFS_DR_OFFSET);
343+
if (adfs_checkdiscrecord(dr))
344+
return -EILSEQ;
345+
346+
*drp = dr;
347+
return 0;
348+
}
349+
350+
static int adfs_fill_super(struct super_block *sb, void *data, int silent)
351+
{
352+
struct adfs_discrecord *dr;
353+
struct object_info root_obj;
287354
struct adfs_sb_info *asb;
288355
struct inode *root;
289356
int ret = -EINVAL;
@@ -308,72 +375,19 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent)
308375
if (parse_options(sb, asb, data))
309376
goto error;
310377

311-
sb_set_blocksize(sb, BLOCK_SIZE);
312-
if (!(bh = sb_bread(sb, ADFS_DISCRECORD / BLOCK_SIZE))) {
313-
adfs_msg(sb, KERN_ERR, "error: unable to read superblock");
314-
ret = -EIO;
315-
goto error;
316-
}
317-
318-
b_data = bh->b_data + (ADFS_DISCRECORD % BLOCK_SIZE);
319-
320-
if (adfs_checkbblk(b_data)) {
321-
ret = -EINVAL;
322-
goto error_badfs;
323-
}
324-
325-
dr = (struct adfs_discrecord *)(b_data + ADFS_DR_OFFSET);
326-
327-
/*
328-
* Do some sanity checks on the ADFS disc record
329-
*/
330-
if (adfs_checkdiscrecord(dr)) {
331-
ret = -EINVAL;
332-
goto error_badfs;
333-
}
334-
335-
blocksize = 1 << dr->log2secsize;
336-
brelse(bh);
337-
338-
if (sb_set_blocksize(sb, blocksize)) {
339-
bh = sb_bread(sb, ADFS_DISCRECORD / sb->s_blocksize);
340-
if (!bh) {
341-
adfs_msg(sb, KERN_ERR,
342-
"error: couldn't read superblock on 2nd try.");
343-
ret = -EIO;
344-
goto error;
345-
}
346-
b_data = bh->b_data + (ADFS_DISCRECORD % sb->s_blocksize);
347-
if (adfs_checkbblk(b_data)) {
348-
adfs_msg(sb, KERN_ERR,
349-
"error: disc record mismatch, very weird!");
350-
ret = -EINVAL;
351-
goto error_free_bh;
352-
}
353-
dr = (struct adfs_discrecord *)(b_data + ADFS_DR_OFFSET);
354-
} else {
378+
/* Try to probe the filesystem boot block */
379+
ret = adfs_probe(sb, ADFS_DISCRECORD, silent, adfs_validate_bblk);
380+
if (ret == -EILSEQ) {
355381
if (!silent)
356382
adfs_msg(sb, KERN_ERR,
357-
"error: unsupported blocksize");
383+
"error: can't find an ADFS filesystem on dev %s.",
384+
sb->s_id);
358385
ret = -EINVAL;
359-
goto error;
360386
}
387+
if (ret)
388+
goto error;
361389

362-
/*
363-
* blocksize on this device should now be set to the ADFS log2secsize
364-
*/
365-
366-
asb->s_map = adfs_read_map(sb, dr);
367-
if (IS_ERR(asb->s_map)) {
368-
ret = PTR_ERR(asb->s_map);
369-
goto error_free_bh;
370-
}
371-
372-
brelse(bh);
373-
374-
/*
375-
* set up enough so that we can read an inode
376-
*/
390+
/* set up enough so that we can read an inode */
377391
sb->s_op = &adfs_sops;
378392

379393
dr = adfs_map_discrecord(asb->s_map);
@@ -417,13 +431,6 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent)
417431
}
418432
return 0;
419433

420-
error_badfs:
421-
if (!silent)
422-
adfs_msg(sb, KERN_ERR,
423-
"error: can't find an ADFS filesystem on dev %s.",
424-
sb->s_id);
425-
error_free_bh:
426-
brelse(bh);
427434
error:
428435
sb->s_fs_info = NULL;
429436
kfree(asb);

0 commit comments

Comments
 (0)