f2fs: recovering broken superblock during mount
This patch recovers a broken superblock with the other valid one. Signed-off-by: hujianyang <hujianyang@huawei.com> [Jaegeuk Kim: reinitialize local variables in f2fs_fill_super for retrial] Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
This commit is contained in:
		
							parent
							
								
									304eecc346
								
							
						
					
					
						commit
						da554e48ca
					
				| @ -970,29 +970,36 @@ static void init_sb_info(struct f2fs_sb_info *sbi) | |||||||
|  */ |  */ | ||||||
| static int read_raw_super_block(struct super_block *sb, | static int read_raw_super_block(struct super_block *sb, | ||||||
| 			struct f2fs_super_block **raw_super, | 			struct f2fs_super_block **raw_super, | ||||||
| 			struct buffer_head **raw_super_buf) | 			struct buffer_head **raw_super_buf, | ||||||
|  | 			int *recovery) | ||||||
| { | { | ||||||
| 	int block = 0; | 	int block = 0; | ||||||
|  | 	struct buffer_head *buffer; | ||||||
|  | 	struct f2fs_super_block *super; | ||||||
|  | 	int err = 0; | ||||||
| 
 | 
 | ||||||
| retry: | retry: | ||||||
| 	*raw_super_buf = sb_bread(sb, block); | 	buffer = sb_bread(sb, block); | ||||||
| 	if (!*raw_super_buf) { | 	if (!buffer) { | ||||||
|  | 		*recovery = 1; | ||||||
| 		f2fs_msg(sb, KERN_ERR, "Unable to read %dth superblock", | 		f2fs_msg(sb, KERN_ERR, "Unable to read %dth superblock", | ||||||
| 				block + 1); | 				block + 1); | ||||||
| 		if (block == 0) { | 		if (block == 0) { | ||||||
| 			block++; | 			block++; | ||||||
| 			goto retry; | 			goto retry; | ||||||
| 		} else { | 		} else { | ||||||
| 			return -EIO; | 			err = -EIO; | ||||||
|  | 			goto out; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	*raw_super = (struct f2fs_super_block *) | 	super = (struct f2fs_super_block *) | ||||||
| 		((char *)(*raw_super_buf)->b_data + F2FS_SUPER_OFFSET); | 		((char *)(buffer)->b_data + F2FS_SUPER_OFFSET); | ||||||
| 
 | 
 | ||||||
| 	/* sanity checking of raw super */ | 	/* sanity checking of raw super */ | ||||||
| 	if (sanity_check_raw_super(sb, *raw_super)) { | 	if (sanity_check_raw_super(sb, super)) { | ||||||
| 		brelse(*raw_super_buf); | 		brelse(buffer); | ||||||
|  | 		*recovery = 1; | ||||||
| 		f2fs_msg(sb, KERN_ERR, | 		f2fs_msg(sb, KERN_ERR, | ||||||
| 			"Can't find valid F2FS filesystem in %dth superblock", | 			"Can't find valid F2FS filesystem in %dth superblock", | ||||||
| 								block + 1); | 								block + 1); | ||||||
| @ -1000,10 +1007,30 @@ retry: | |||||||
| 			block++; | 			block++; | ||||||
| 			goto retry; | 			goto retry; | ||||||
| 		} else { | 		} else { | ||||||
| 			return -EINVAL; | 			err = -EINVAL; | ||||||
|  | 			goto out; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if (!*raw_super) { | ||||||
|  | 		*raw_super_buf = buffer; | ||||||
|  | 		*raw_super = super; | ||||||
|  | 	} else { | ||||||
|  | 		/* already have a valid superblock */ | ||||||
|  | 		brelse(buffer); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* check the validity of the second superblock */ | ||||||
|  | 	if (block == 0) { | ||||||
|  | 		block++; | ||||||
|  | 		goto retry; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | out: | ||||||
|  | 	/* No valid superblock */ | ||||||
|  | 	if (!*raw_super) | ||||||
|  | 		return err; | ||||||
|  | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -1034,15 +1061,20 @@ out: | |||||||
| static int f2fs_fill_super(struct super_block *sb, void *data, int silent) | static int f2fs_fill_super(struct super_block *sb, void *data, int silent) | ||||||
| { | { | ||||||
| 	struct f2fs_sb_info *sbi; | 	struct f2fs_sb_info *sbi; | ||||||
| 	struct f2fs_super_block *raw_super = NULL; | 	struct f2fs_super_block *raw_super; | ||||||
| 	struct buffer_head *raw_super_buf; | 	struct buffer_head *raw_super_buf; | ||||||
| 	struct inode *root; | 	struct inode *root; | ||||||
| 	long err = -EINVAL; | 	long err; | ||||||
| 	bool retry = true, need_fsck = false; | 	bool retry = true, need_fsck = false; | ||||||
| 	char *options = NULL; | 	char *options = NULL; | ||||||
| 	int i; | 	int recovery, i; | ||||||
| 
 | 
 | ||||||
| try_onemore: | try_onemore: | ||||||
|  | 	err = -EINVAL; | ||||||
|  | 	raw_super = NULL; | ||||||
|  | 	raw_super_buf = NULL; | ||||||
|  | 	recovery = 0; | ||||||
|  | 
 | ||||||
| 	/* allocate memory for f2fs-specific super block info */ | 	/* allocate memory for f2fs-specific super block info */ | ||||||
| 	sbi = kzalloc(sizeof(struct f2fs_sb_info), GFP_KERNEL); | 	sbi = kzalloc(sizeof(struct f2fs_sb_info), GFP_KERNEL); | ||||||
| 	if (!sbi) | 	if (!sbi) | ||||||
| @ -1054,7 +1086,7 @@ try_onemore: | |||||||
| 		goto free_sbi; | 		goto free_sbi; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	err = read_raw_super_block(sb, &raw_super, &raw_super_buf); | 	err = read_raw_super_block(sb, &raw_super, &raw_super_buf, &recovery); | ||||||
| 	if (err) | 	if (err) | ||||||
| 		goto free_sbi; | 		goto free_sbi; | ||||||
| 
 | 
 | ||||||
| @ -1252,6 +1284,13 @@ try_onemore: | |||||||
| 			goto free_kobj; | 			goto free_kobj; | ||||||
| 	} | 	} | ||||||
| 	kfree(options); | 	kfree(options); | ||||||
|  | 
 | ||||||
|  | 	/* recover broken superblock */ | ||||||
|  | 	if (recovery && !f2fs_readonly(sb) && !bdev_read_only(sb->s_bdev)) { | ||||||
|  | 		f2fs_msg(sb, KERN_INFO, "Recover invalid superblock"); | ||||||
|  | 		f2fs_commit_super(sbi); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| 
 | 
 | ||||||
| free_kobj: | free_kobj: | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user