struct inode *ubifs_iget(struct super_block *sb, unsigned long inum) { int err; union ubifs_key key; struct ubifs_ino_node *ino; struct ubifs_info *c = sb->s_fs_info; struct inode *inode; struct ubifs_inode *ui; int i; dbg_gen("inode %lu", inum); /* * U-Boot special handling of locked down inodes via recovery * e.g. ubifs_recover_size() */ for (i = 0; i < INODE_LOCKED_MAX; i++) { /* * Exit on last entry (NULL), inode not found in list */ if (inodes_locked_down[i] == NULL) break; if (inodes_locked_down[i]->i_ino == inum) { /* * We found the locked down inode in our array, * so just return this pointer instead of creating * a new one. */ return inodes_locked_down[i]; } } inode = iget_locked(sb, inum); if (!inode) return ERR_PTR(-ENOMEM); if (!(inode->i_state & I_NEW)) return inode; ui = ubifs_inode(inode); ino = kmalloc(UBIFS_MAX_INO_NODE_SZ, GFP_NOFS); if (!ino) { err = -ENOMEM; goto out; } ino_key_init(c, &key, inode->i_ino); err = ubifs_tnc_lookup(c, &key, ino); if (err) goto out_ino; inode->i_flags |= (S_NOCMTIME | S_NOATIME); inode->i_nlink = le32_to_cpu(ino->nlink); inode->i_uid = le32_to_cpu(ino->uid); inode->i_gid = le32_to_cpu(ino->gid); inode->i_atime.tv_sec = (int64_t)le64_to_cpu(ino->atime_sec); inode->i_atime.tv_nsec = le32_to_cpu(ino->atime_nsec); inode->i_mtime.tv_sec = (int64_t)le64_to_cpu(ino->mtime_sec); inode->i_mtime.tv_nsec = le32_to_cpu(ino->mtime_nsec); inode->i_ctime.tv_sec = (int64_t)le64_to_cpu(ino->ctime_sec); inode->i_ctime.tv_nsec = le32_to_cpu(ino->ctime_nsec); inode->i_mode = le32_to_cpu(ino->mode); inode->i_size = le64_to_cpu(ino->size); ui->data_len = le32_to_cpu(ino->data_len); ui->flags = le32_to_cpu(ino->flags); ui->compr_type = le16_to_cpu(ino->compr_type); ui->creat_sqnum = le64_to_cpu(ino->creat_sqnum); ui->synced_i_size = ui->ui_size = inode->i_size; err = validate_inode(c, inode); if (err) goto out_invalid; if ((inode->i_mode & S_IFMT) == S_IFLNK) { if (ui->data_len <= 0 || ui->data_len > UBIFS_MAX_INO_DATA) { err = 12; goto out_invalid; } ui->data = kmalloc(ui->data_len + 1, GFP_NOFS); if (!ui->data) { err = -ENOMEM; goto out_ino; } memcpy(ui->data, ino->data, ui->data_len); ((char *)ui->data)[ui->data_len] = '\0'; } kfree(ino); inode->i_state &= ~(I_LOCK | I_NEW); return inode; out_invalid: ubifs_err("inode %lu validation failed, error %d", inode->i_ino, err); dbg_dump_node(c, ino); dbg_dump_inode(c, inode); err = -EINVAL; out_ino: kfree(ino); out: ubifs_err("failed to read inode %lu, error %d", inode->i_ino, err); return ERR_PTR(err); }
/** * validate_sb - validate superblock node. * @c: UBIFS file-system description object * @sup: superblock node * * This function validates superblock node @sup. Since most of data was read * from the superblock and stored in @c, the function validates fields in @c * instead. Returns zero in case of success and %-EINVAL in case of validation * failure. */ static int validate_sb(struct ubifs_info *c, struct ubifs_sb_node *sup) { long long max_bytes; int err = 1, min_leb_cnt; if (!c->key_hash) { err = 2; goto failed; } if (sup->key_fmt != UBIFS_SIMPLE_KEY_FMT) { err = 3; goto failed; } if (le32_to_cpu(sup->min_io_size) != c->min_io_size) { ubifs_err("min. I/O unit mismatch: %d in superblock, %d real", le32_to_cpu(sup->min_io_size), c->min_io_size); goto failed; } if (le32_to_cpu(sup->leb_size) != c->leb_size) { ubifs_err("LEB size mismatch: %d in superblock, %d real", le32_to_cpu(sup->leb_size), c->leb_size); goto failed; } if (c->log_lebs < UBIFS_MIN_LOG_LEBS || c->lpt_lebs < UBIFS_MIN_LPT_LEBS || c->orph_lebs < UBIFS_MIN_ORPH_LEBS || c->main_lebs < UBIFS_MIN_MAIN_LEBS) { err = 4; goto failed; } /* * Calculate minimum allowed amount of main area LEBs. This is very * similar to %UBIFS_MIN_LEB_CNT, but we take into account real what we * have just read from the superblock. */ min_leb_cnt = UBIFS_SB_LEBS + UBIFS_MST_LEBS + c->log_lebs; min_leb_cnt += c->lpt_lebs + c->orph_lebs + c->jhead_cnt + 6; if (c->leb_cnt < min_leb_cnt || c->leb_cnt > c->vi.size) { ubifs_err("bad LEB count: %d in superblock, %d on UBI volume, " "%d minimum required", c->leb_cnt, c->vi.size, min_leb_cnt); goto failed; } if (c->max_leb_cnt < c->leb_cnt) { ubifs_err("max. LEB count %d less than LEB count %d", c->max_leb_cnt, c->leb_cnt); goto failed; } if (c->main_lebs < UBIFS_MIN_MAIN_LEBS) { err = 7; goto failed; } if (c->max_bud_bytes < (long long)c->leb_size * UBIFS_MIN_BUD_LEBS || c->max_bud_bytes > (long long)c->leb_size * c->main_lebs) { err = 8; goto failed; } if (c->jhead_cnt < NONDATA_JHEADS_CNT + 1 || c->jhead_cnt > NONDATA_JHEADS_CNT + UBIFS_MAX_JHEADS) { err = 9; goto failed; } if (c->fanout < UBIFS_MIN_FANOUT || ubifs_idx_node_sz(c, c->fanout) > c->leb_size) { err = 10; goto failed; } if (c->lsave_cnt < 0 || (c->lsave_cnt > DEFAULT_LSAVE_CNT && c->lsave_cnt > c->max_leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS - c->log_lebs - c->lpt_lebs - c->orph_lebs)) { err = 11; goto failed; } if (UBIFS_SB_LEBS + UBIFS_MST_LEBS + c->log_lebs + c->lpt_lebs + c->orph_lebs + c->main_lebs != c->leb_cnt) { err = 12; goto failed; } if (c->default_compr < 0 || c->default_compr >= UBIFS_COMPR_TYPES_CNT) { err = 13; goto failed; } max_bytes = c->main_lebs * (long long)c->leb_size; if (c->rp_size < 0 || max_bytes < c->rp_size) { err = 14; goto failed; } if (le32_to_cpu(sup->time_gran) > 1000000000 || le32_to_cpu(sup->time_gran) < 1) { err = 15; goto failed; } return 0; failed: ubifs_err("bad superblock, error %d", err); dbg_dump_node(c, sup); return -EINVAL; }