static int validate_superblock(struct super_block *sb, struct f2fs_super_block **raw_super, struct buffer_head **raw_super_buf, sector_t block) { const char *super = (block == 0 ? "first" : "second"); /* read f2fs raw super block */ *raw_super_buf = sb_bread(sb, block); if (!*raw_super_buf) { f2fs_msg(sb, KERN_ERR, "unable to read %s superblock", super); return -EIO; } *raw_super = (struct f2fs_super_block *) ((char *)(*raw_super_buf)->b_data + F2FS_SUPER_OFFSET); /* sanity checking of raw super */ if (!sanity_check_raw_super(sb, *raw_super)) return 0; f2fs_msg(sb, KERN_ERR, "Can't find a valid F2FS filesystem " "in %s superblock", super); return -EINVAL; }
/* * Read f2fs raw super block. * Because we have two copies of super block, so read the first one at first, * if the first one is invalid, move to read the second one. */ static int read_raw_super_block(struct super_block *sb, struct f2fs_super_block **raw_super, int *valid_super_block, int *recovery) { int block = 0; struct buffer_head *bh; struct f2fs_super_block *super, *buf; int err = 0; super = kzalloc(sizeof(struct f2fs_super_block), GFP_KERNEL); if (!super) return -ENOMEM; retry: bh = sb_bread(sb, block); if (!bh) { *recovery = 1; f2fs_msg(sb, KERN_ERR, "Unable to read %dth superblock", block + 1); err = -EIO; goto next; } buf = (struct f2fs_super_block *)(bh->b_data + F2FS_SUPER_OFFSET); /* sanity checking of raw super */ if (sanity_check_raw_super(sb, buf)) { brelse(bh); *recovery = 1; f2fs_msg(sb, KERN_ERR, "Can't find valid F2FS filesystem in %dth superblock", block + 1); err = -EINVAL; goto next; } if (!*raw_super) { memcpy(super, buf, sizeof(*super)); *valid_super_block = block; *raw_super = super; } brelse(bh); next: /* check the validity of the second superblock */ if (block == 0) { block++; goto retry; } /* No valid superblock */ if (!*raw_super) { kfree(super); return err; } return 0; }
/* * Read f2fs raw super block. * Because we have two copies of super block, so read both of them * to get the first valid one. If any one of them is broken, we pass * them recovery flag back to the caller. */ static int read_raw_super_block(struct super_block *sb, struct f2fs_super_block **raw_super, int *valid_super_block, int *recovery) { int block; struct buffer_head *bh; struct f2fs_super_block *super, *buf; int err = 0; super = kzalloc(sizeof(struct f2fs_super_block), GFP_KERNEL); if (!super) return -ENOMEM; for (block = 0; block < 2; block++) { bh = sb_bread(sb, block); if (!bh) { f2fs_msg(sb, KERN_ERR, "Unable to read %dth superblock", block + 1); err = -EIO; continue; } buf = (struct f2fs_super_block *) (bh->b_data + F2FS_SUPER_OFFSET); /* sanity checking of raw super */ if (sanity_check_raw_super(sb, buf)) { f2fs_msg(sb, KERN_ERR, "Can't find valid F2FS filesystem in %dth superblock", block + 1); err = -EINVAL; brelse(bh); continue; } if (!*raw_super) { memcpy(super, buf, sizeof(*super)); *valid_super_block = block; *raw_super = super; } brelse(bh); } /* Fail to read any one of the superblocks*/ if (err < 0) *recovery = 1; /* No valid superblock */ if (!*raw_super) kfree(super); else err = 0; return err; }
/* * Read f2fs raw super block. * Because we have two copies of super block, so read the first one at first, * if the first one is invalid, move to read the second one. */ static int read_raw_super_block(struct super_block *sb, struct f2fs_super_block **raw_super, struct buffer_head **raw_super_buf) { int block = 0; retry: *raw_super_buf = sb_bread(sb, block); if (!*raw_super_buf) { f2fs_msg(sb, KERN_ERR, "Unable to read %dth superblock", block + 1); if (block == 0) { block++; goto retry; } else { return -EIO; } } *raw_super = (struct f2fs_super_block *) ((char *)(*raw_super_buf)->b_data + F2FS_SUPER_OFFSET); /* sanity checking of raw super */ if (sanity_check_raw_super(sb, *raw_super)) { brelse(*raw_super_buf); f2fs_msg(sb, KERN_ERR, "Can't find valid F2FS filesystem in %dth superblock", block + 1); if (block == 0) { block++; goto retry; } else { return -EINVAL; } } return 0; }
/* * Read f2fs raw super block. * Because we have two copies of super block, so read the first one at first, * if the first one is invalid, move to read the second one. */ static int read_raw_super_block(struct super_block *sb, struct f2fs_super_block **raw_super, struct buffer_head **raw_super_buf, int *recovery) { int block = 0; struct buffer_head *buffer; struct f2fs_super_block *super; int err = 0; retry: buffer = sb_bread(sb, block); if (!buffer) { *recovery = 1; f2fs_msg(sb, KERN_ERR, "Unable to read %dth superblock", block + 1); if (block == 0) { block++; goto retry; } else { err = -EIO; goto out; } } super = (struct f2fs_super_block *) ((char *)(buffer)->b_data + F2FS_SUPER_OFFSET); /* sanity checking of raw super */ if (sanity_check_raw_super(sb, super)) { brelse(buffer); *recovery = 1; f2fs_msg(sb, KERN_ERR, "Can't find valid F2FS filesystem in %dth superblock", block + 1); if (block == 0) { block++; goto retry; } else { 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; }
static int f2fs_fill_super(struct super_block *sb, void *data, int silent) { struct f2fs_sb_info *sbi; struct f2fs_super_block *raw_super; struct buffer_head *raw_super_buf; struct inode *root; int i; /* allocate memory for f2fs-specific super block info */ sbi = kzalloc(sizeof(struct f2fs_sb_info), GFP_KERNEL); if (!sbi) return -ENOMEM; /* set a temporary block size */ if (!sb_set_blocksize(sb, F2FS_BLKSIZE)) goto free_sbi; /* read f2fs raw super block */ raw_super_buf = sb_bread(sb, F2FS_SUPER_OFFSET); if (!raw_super_buf) goto free_sbi; raw_super = (struct f2fs_super_block *) ((char *)raw_super_buf->b_data); /* init some FS parameters */ set_opt(sbi, BG_GC); #ifdef CONFIG_F2FS_FS_XATTR set_opt(sbi, XATTR_USER); #endif #ifdef CONFIG_F2FS_FS_POSIX_ACL set_opt(sbi, POSIX_ACL); #endif /* parse mount options */ if (parse_options(sbi, (char *)data)) goto free_sb_buf; /* sanity checking of raw super */ if (sanity_check_raw_super(raw_super)) goto free_sb_buf; sb->s_maxbytes = max_file_size(raw_super->log_blocksize); sb->s_op = &f2fs_sops; sb->s_xattr = f2fs_xattr_handlers; sb->s_magic = F2FS_SUPER_MAGIC; sb->s_fs_info = sbi; sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | (test_opt(sbi, POSIX_ACL) ? MS_POSIXACL : 0); /* init f2fs-specific super block info */ sbi->sb = sb; sbi->raw_super = raw_super; sbi->raw_super_buf = raw_super_buf; mutex_init(&sbi->gc_mutex); mutex_init(&sbi->write_inode); mutex_init(&sbi->writepages); mutex_init(&sbi->cp_mutex); for (i = 0; i < NR_LOCK_TYPE; i++) mutex_init(&sbi->fs_lock[i]); sbi->por_doing = 0; spin_lock_init(&sbi->stat_lock); init_rwsem(&sbi->bio_sem); init_sb_info(sbi); /* get an inode for meta space */ sbi->meta_inode = f2fs_iget(sb, F2FS_META_INO(sbi)); if (IS_ERR(sbi->meta_inode)) goto free_sb_buf; if (get_valid_checkpoint(sbi)) goto free_meta_inode; /* sanity checking of checkpoint */ if (sanity_check_ckpt(raw_super, sbi->ckpt)) goto free_cp; sbi->total_valid_node_count = le32_to_cpu(sbi->ckpt->valid_node_count); sbi->total_valid_inode_count = le32_to_cpu(sbi->ckpt->valid_inode_count); sbi->user_block_count = le64_to_cpu(sbi->ckpt->user_block_count); sbi->total_valid_block_count = le64_to_cpu(sbi->ckpt->valid_block_count); sbi->last_valid_block_count = sbi->total_valid_block_count; sbi->alloc_valid_block_count = 0; INIT_LIST_HEAD(&sbi->dir_inode_list); spin_lock_init(&sbi->dir_inode_lock); /* init super block */ if (!sb_set_blocksize(sb, sbi->blocksize)) goto free_cp; init_orphan_info(sbi); /* setup f2fs internal modules */ if (build_segment_manager(sbi)) goto free_sm; if (build_node_manager(sbi)) goto free_nm; if (build_gc_manager(sbi)) goto free_gc; /* get an inode for node space */ sbi->node_inode = f2fs_iget(sb, F2FS_NODE_INO(sbi)); if (IS_ERR(sbi->node_inode)) goto free_gc; /* if there are nt orphan nodes free them */ if (recover_orphan_inodes(sbi)) goto free_node_inode; /* read root inode and dentry */ root = f2fs_iget(sb, F2FS_ROOT_INO(sbi)); if (IS_ERR(root)) goto free_node_inode; if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) goto free_root_inode; sb->s_root = d_alloc_root(root); /* allocate root dentry */ if (!sb->s_root) goto free_root_inode; /* recover fsynced data */ if (!test_opt(sbi, DISABLE_ROLL_FORWARD)) recover_fsync_data(sbi); /* After POR, we can run background GC thread */ if (start_gc_thread(sbi)) goto fail; #ifdef CONFIG_F2FS_STAT_FS if (f2fs_proc_root) { sbi->s_proc = proc_mkdir(sb->s_id, f2fs_proc_root); if (f2fs_stat_init(sbi)) goto fail; } #endif return 0; fail: stop_gc_thread(sbi); free_root_inode: make_bad_inode(root); iput(root); free_node_inode: make_bad_inode(sbi->node_inode); iput(sbi->node_inode); free_gc: destroy_gc_manager(sbi); free_nm: destroy_node_manager(sbi); free_sm: destroy_segment_manager(sbi); free_cp: kfree(sbi->ckpt); free_meta_inode: make_bad_inode(sbi->meta_inode); iput(sbi->meta_inode); free_sb_buf: brelse(raw_super_buf); free_sbi: kfree(sbi); return -EINVAL; }