/** * ubifs_jnl_write_2_inodes - write 2 inodes to the journal. * @c: UBIFS file-system description object * @inode1: first inode to write * @inode2: second inode to write * @sync: non-zero if the write-buffer has to be synchronized * * This function writes 2 inodes @inode1 and @inode2 to the journal (to the * base head - first @inode1, then @inode2). Returns zero in case of success * and a negative error code in case of failure. */ int ubifs_jnl_write_2_inodes(struct ubifs_info *c, const struct inode *inode1, const struct inode *inode2, int sync) { int err, len1, len2, aligned_len, aligned_len1, lnum, offs; struct ubifs_ino_node *ino; union ubifs_key key; dbg_jnl("ino %lu, ino %lu", inode1->i_ino, inode2->i_ino); ubifs_assert(inode1->i_nlink > 0); ubifs_assert(inode2->i_nlink > 0); len1 = UBIFS_INO_NODE_SZ + ubifs_inode(inode1)->data_len; len2 = UBIFS_INO_NODE_SZ + ubifs_inode(inode2)->data_len; aligned_len1 = ALIGN(len1, 8); aligned_len = aligned_len1 + ALIGN(len2, 8); ino = kmalloc(aligned_len, GFP_NOFS); if (!ino) return -ENOMEM; /* Make reservation before allocating sequence numbers */ err = make_reservation(c, BASEHD, aligned_len); if (err) goto out_free; pack_inode(c, ino, inode1, 0, 0); pack_inode(c, (void *)ino + aligned_len1, inode2, 1, 0); err = write_head(c, BASEHD, ino, aligned_len, &lnum, &offs, 0); if (!sync && !err) { struct ubifs_wbuf *wbuf = &c->jheads[BASEHD].wbuf; ubifs_wbuf_add_ino_nolock(wbuf, inode1->i_ino); ubifs_wbuf_add_ino_nolock(wbuf, inode2->i_ino); } release_head(c, BASEHD); if (err) goto out_ro; ino_key_init(c, &key, inode1->i_ino); err = ubifs_tnc_add(c, &key, lnum, offs, len1); if (err) goto out_ro; ino_key_init(c, &key, inode2->i_ino); err = ubifs_tnc_add(c, &key, lnum, offs + aligned_len1, len2); if (err) goto out_ro; finish_reservation(c); kfree(ino); return 0; out_ro: ubifs_ro_mode(c, err); finish_reservation(c); out_free: kfree(ino); return err; }
/** * ubifs_jrn_write_inode - flush inode to the journal. * @c: UBIFS file-system description object * @inode: inode to flush * @last_reference: inode has been deleted * @sync: non-zero if the write-buffer has to be synchronized * * This function writes inode @inode to the journal (to the base head). Returns * zero in case of success and a negative error code in case of failure. */ int ubifs_jrn_write_inode(struct ubifs_info *c, const struct inode *inode, int last_reference, int sync) { int err, len, lnum, offs; struct ubifs_ino_node *ino; struct ubifs_inode *ui = ubifs_inode(inode); dbg_jrn("ino %lu%s", inode->i_ino, last_reference ? " (last reference)" : ""); if (last_reference) ubifs_assert(inode->i_nlink == 0); /* If the inode is deleted, do not write the attached data */ len = UBIFS_INO_NODE_SZ; if (!last_reference) len += ui->data_len; ino = kmalloc(len, GFP_NOFS); if (!ino) return -ENOMEM; pack_inode(c, ino, inode, 1, last_reference); err = make_reservation(c, BASEHD, len); if (err) goto out_free; err = write_head(c, BASEHD, ino, len, &lnum, &offs, sync); if (!sync && !err) ubifs_wbuf_add_ino_nolock(&c->jheads[BASEHD].wbuf, inode->i_ino); release_head(c, BASEHD); if (err) goto out_ro; if (last_reference) { err = ubifs_tnc_remove_ino(c, inode->i_ino); if (err) goto out_ro; ubifs_delete_orphan(c, inode->i_ino); err = ubifs_add_dirt(c, lnum, len); } else { union ubifs_key key; ino_key_init(c, &key, inode->i_ino); err = ubifs_tnc_add(c, &key, lnum, offs, len); } if (err) goto out_ro; finish_reservation(c); kfree(ino); return 0; out_ro: ubifs_ro_mode(c, err); finish_reservation(c); out_free: kfree(ino); return err; }
/** * create_default_filesystem - format empty UBI volume. * @c: UBIFS file-system description object * * This function creates default empty file-system. Returns zero in case of * success and a negative error code in case of failure. */ static int create_default_filesystem(struct ubifs_info *c) { struct ubifs_sb_node *sup; struct ubifs_mst_node *mst; struct ubifs_idx_node *idx; struct ubifs_branch *br; struct ubifs_ino_node *ino; struct ubifs_cs_node *cs; union ubifs_key key; int err, tmp, jnl_lebs, log_lebs, max_buds, main_lebs, main_first; int lpt_lebs, lpt_first, orph_lebs, big_lpt, ino_waste, sup_flags = 0; int min_leb_cnt = UBIFS_MIN_LEB_CNT; long long tmp64, main_bytes; __le64 tmp_le64; /* Some functions called from here depend on the @c->key_len filed */ c->key_len = UBIFS_SK_LEN; /* * First of all, we have to calculate default file-system geometry - * log size, journal size, etc. */ if (c->leb_cnt < 0x7FFFFFFF / DEFAULT_JNL_PERCENT) /* We can first multiply then divide and have no overflow */ jnl_lebs = c->leb_cnt * DEFAULT_JNL_PERCENT / 100; else jnl_lebs = (c->leb_cnt / 100) * DEFAULT_JNL_PERCENT; if (jnl_lebs < UBIFS_MIN_JNL_LEBS) jnl_lebs = UBIFS_MIN_JNL_LEBS; if (jnl_lebs * c->leb_size > DEFAULT_MAX_JNL) jnl_lebs = DEFAULT_MAX_JNL / c->leb_size; /* * The log should be large enough to fit reference nodes for all bud * LEBs. Because buds do not have to start from the beginning of LEBs * (half of the LEB may contain committed data), the log should * generally be larger, make it twice as large. */ tmp = 2 * (c->ref_node_alsz * jnl_lebs) + c->leb_size - 1; log_lebs = tmp / c->leb_size; /* Plus one LEB reserved for commit */ log_lebs += 1; if (c->leb_cnt - min_leb_cnt > 8) { /* And some extra space to allow writes while committing */ log_lebs += 1; min_leb_cnt += 1; } max_buds = jnl_lebs - log_lebs; if (max_buds < UBIFS_MIN_BUD_LEBS) max_buds = UBIFS_MIN_BUD_LEBS; /* * Orphan nodes are stored in a separate area. One node can store a lot * of orphan inode numbers, but when new orphan comes we just add a new * orphan node. At some point the nodes are consolidated into one * orphan node. */ orph_lebs = UBIFS_MIN_ORPH_LEBS; #ifdef CONFIG_UBIFS_FS_DEBUG if (c->leb_cnt - min_leb_cnt > 1) /* * For debugging purposes it is better to have at least 2 * orphan LEBs, because the orphan subsystem would need to do * consolidations and would be stressed more. */ orph_lebs += 1; #endif main_lebs = c->leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS - log_lebs; main_lebs -= orph_lebs; lpt_first = UBIFS_LOG_LNUM + log_lebs; c->lsave_cnt = DEFAULT_LSAVE_CNT; c->max_leb_cnt = c->leb_cnt; err = ubifs_create_dflt_lpt(c, &main_lebs, lpt_first, &lpt_lebs, &big_lpt); if (err) return err; dbg_gen("LEB Properties Tree created (LEBs %d-%d)", lpt_first, lpt_first + lpt_lebs - 1); main_first = c->leb_cnt - main_lebs; /* Create default superblock */ tmp = ALIGN(UBIFS_SB_NODE_SZ, c->min_io_size); sup = kzalloc(tmp, GFP_KERNEL); if (!sup) return -ENOMEM; tmp64 = (long long)max_buds * c->leb_size; if (big_lpt) sup_flags |= UBIFS_FLG_BIGLPT; sup->ch.node_type = UBIFS_SB_NODE; sup->key_hash = UBIFS_KEY_HASH_R5; sup->flags = cpu_to_le32(sup_flags); sup->min_io_size = cpu_to_le32(c->min_io_size); sup->leb_size = cpu_to_le32(c->leb_size); sup->leb_cnt = cpu_to_le32(c->leb_cnt); sup->max_leb_cnt = cpu_to_le32(c->max_leb_cnt); sup->max_bud_bytes = cpu_to_le64(tmp64); sup->log_lebs = cpu_to_le32(log_lebs); sup->lpt_lebs = cpu_to_le32(lpt_lebs); sup->orph_lebs = cpu_to_le32(orph_lebs); sup->jhead_cnt = cpu_to_le32(DEFAULT_JHEADS_CNT); sup->fanout = cpu_to_le32(DEFAULT_FANOUT); sup->lsave_cnt = cpu_to_le32(c->lsave_cnt); sup->fmt_version = cpu_to_le32(UBIFS_FORMAT_VERSION); sup->time_gran = cpu_to_le32(DEFAULT_TIME_GRAN); if (c->mount_opts.override_compr) sup->default_compr = cpu_to_le16(c->mount_opts.compr_type); else sup->default_compr = cpu_to_le16(UBIFS_COMPR_LZO); generate_random_uuid(sup->uuid); main_bytes = (long long)main_lebs * c->leb_size; tmp64 = div_u64(main_bytes * DEFAULT_RP_PERCENT, 100); if (tmp64 > DEFAULT_MAX_RP_SIZE) tmp64 = DEFAULT_MAX_RP_SIZE; sup->rp_size = cpu_to_le64(tmp64); sup->ro_compat_version = cpu_to_le32(UBIFS_RO_COMPAT_VERSION); err = ubifs_write_node(c, sup, UBIFS_SB_NODE_SZ, 0, 0, UBI_LONGTERM); kfree(sup); if (err) return err; dbg_gen("default superblock created at LEB 0:0"); /* Create default master node */ mst = kzalloc(c->mst_node_alsz, GFP_KERNEL); if (!mst) return -ENOMEM; mst->ch.node_type = UBIFS_MST_NODE; mst->log_lnum = cpu_to_le32(UBIFS_LOG_LNUM); mst->highest_inum = cpu_to_le64(UBIFS_FIRST_INO); mst->cmt_no = 0; mst->root_lnum = cpu_to_le32(main_first + DEFAULT_IDX_LEB); mst->root_offs = 0; tmp = ubifs_idx_node_sz(c, 1); mst->root_len = cpu_to_le32(tmp); mst->gc_lnum = cpu_to_le32(main_first + DEFAULT_GC_LEB); mst->ihead_lnum = cpu_to_le32(main_first + DEFAULT_IDX_LEB); mst->ihead_offs = cpu_to_le32(ALIGN(tmp, c->min_io_size)); mst->index_size = cpu_to_le64(ALIGN(tmp, 8)); mst->lpt_lnum = cpu_to_le32(c->lpt_lnum); mst->lpt_offs = cpu_to_le32(c->lpt_offs); mst->nhead_lnum = cpu_to_le32(c->nhead_lnum); mst->nhead_offs = cpu_to_le32(c->nhead_offs); mst->ltab_lnum = cpu_to_le32(c->ltab_lnum); mst->ltab_offs = cpu_to_le32(c->ltab_offs); mst->lsave_lnum = cpu_to_le32(c->lsave_lnum); mst->lsave_offs = cpu_to_le32(c->lsave_offs); mst->lscan_lnum = cpu_to_le32(main_first); mst->empty_lebs = cpu_to_le32(main_lebs - 2); mst->idx_lebs = cpu_to_le32(1); mst->leb_cnt = cpu_to_le32(c->leb_cnt); /* Calculate lprops statistics */ tmp64 = main_bytes; tmp64 -= ALIGN(ubifs_idx_node_sz(c, 1), c->min_io_size); tmp64 -= ALIGN(UBIFS_INO_NODE_SZ, c->min_io_size); mst->total_free = cpu_to_le64(tmp64); tmp64 = ALIGN(ubifs_idx_node_sz(c, 1), c->min_io_size); ino_waste = ALIGN(UBIFS_INO_NODE_SZ, c->min_io_size) - UBIFS_INO_NODE_SZ; tmp64 += ino_waste; tmp64 -= ALIGN(ubifs_idx_node_sz(c, 1), 8); mst->total_dirty = cpu_to_le64(tmp64); /* The indexing LEB does not contribute to dark space */ tmp64 = (c->main_lebs - 1) * c->dark_wm; mst->total_dark = cpu_to_le64(tmp64); mst->total_used = cpu_to_le64(UBIFS_INO_NODE_SZ); err = ubifs_write_node(c, mst, UBIFS_MST_NODE_SZ, UBIFS_MST_LNUM, 0, UBI_UNKNOWN); if (err) { kfree(mst); return err; } err = ubifs_write_node(c, mst, UBIFS_MST_NODE_SZ, UBIFS_MST_LNUM + 1, 0, UBI_UNKNOWN); kfree(mst); if (err) return err; dbg_gen("default master node created at LEB %d:0", UBIFS_MST_LNUM); /* Create the root indexing node */ tmp = ubifs_idx_node_sz(c, 1); idx = kzalloc(ALIGN(tmp, c->min_io_size), GFP_KERNEL); if (!idx) return -ENOMEM; c->key_fmt = UBIFS_SIMPLE_KEY_FMT; c->key_hash = key_r5_hash; idx->ch.node_type = UBIFS_IDX_NODE; idx->child_cnt = cpu_to_le16(1); ino_key_init(c, &key, UBIFS_ROOT_INO); br = ubifs_idx_branch(c, idx, 0); key_write_idx(c, &key, &br->key); br->lnum = cpu_to_le32(main_first + DEFAULT_DATA_LEB); br->len = cpu_to_le32(UBIFS_INO_NODE_SZ); err = ubifs_write_node(c, idx, tmp, main_first + DEFAULT_IDX_LEB, 0, UBI_UNKNOWN); kfree(idx); if (err) return err; dbg_gen("default root indexing node created LEB %d:0", main_first + DEFAULT_IDX_LEB); /* Create default root inode */ tmp = ALIGN(UBIFS_INO_NODE_SZ, c->min_io_size); ino = kzalloc(tmp, GFP_KERNEL); if (!ino) return -ENOMEM; ino_key_init_flash(c, &ino->key, UBIFS_ROOT_INO); ino->ch.node_type = UBIFS_INO_NODE; ino->creat_sqnum = cpu_to_le64(++c->max_sqnum); ino->nlink = cpu_to_le32(2); tmp_le64 = cpu_to_le64(CURRENT_TIME_SEC.tv_sec); ino->atime_sec = tmp_le64; ino->ctime_sec = tmp_le64; ino->mtime_sec = tmp_le64; ino->atime_nsec = 0; ino->ctime_nsec = 0; ino->mtime_nsec = 0; ino->mode = cpu_to_le32(S_IFDIR | S_IRUGO | S_IWUSR | S_IXUGO); ino->size = cpu_to_le64(UBIFS_INO_NODE_SZ); /* Set compression enabled by default */ ino->flags = cpu_to_le32(UBIFS_COMPR_FL); err = ubifs_write_node(c, ino, UBIFS_INO_NODE_SZ, main_first + DEFAULT_DATA_LEB, 0, UBI_UNKNOWN); kfree(ino); if (err) return err; dbg_gen("root inode created at LEB %d:0", main_first + DEFAULT_DATA_LEB); /* * The first node in the log has to be the commit start node. This is * always the case during normal file-system operation. Write a fake * commit start node to the log. */ tmp = ALIGN(UBIFS_CS_NODE_SZ, c->min_io_size); cs = kzalloc(tmp, GFP_KERNEL); if (!cs) return -ENOMEM; cs->ch.node_type = UBIFS_CS_NODE; err = ubifs_write_node(c, cs, UBIFS_CS_NODE_SZ, UBIFS_LOG_LNUM, 0, UBI_UNKNOWN); kfree(cs); ubifs_msg("default file-system created"); return 0; }
/** * ubifs_jrn_rename - rename a directory entry. * @c: UBIFS file-system description object * @old_dir: parent inode of directory entry to rename * @old_dentry: directory entry to rename * @new_dir: parent inode of directory entry to rename * @new_dentry: new directory entry (or directory entry to replace) * @sync: non-zero if the write-buffer has to be synchronized * * Returns zero in case of success and a negative error code in case of failure. */ int ubifs_jrn_rename(struct ubifs_info *c, const struct inode *old_dir, const struct dentry *old_dentry, const struct inode *new_dir, const struct dentry *new_dentry, int sync) { const struct inode *old_inode = old_dentry->d_inode; const struct inode *new_inode = new_dentry->d_inode; int err, dlen1, dlen2, ilen, lnum, offs, len; int aligned_dlen1, aligned_dlen2, plen = UBIFS_INO_NODE_SZ; int last_reference = !!(new_inode && new_inode->i_nlink == 0); struct ubifs_dent_node *dent, *dent2; void *p; union ubifs_key key; dbg_jrn("dent '%.*s' in dir ino %lu to dent '%.*s' in dir ino %lu", old_dentry->d_name.len, old_dentry->d_name.name, old_dir->i_ino, new_dentry->d_name.len, new_dentry->d_name.name, new_dir->i_ino); ubifs_assert(ubifs_inode(old_dir)->data_len == 0); ubifs_assert(ubifs_inode(new_dir)->data_len == 0); dlen1 = UBIFS_DENT_NODE_SZ + new_dentry->d_name.len + 1; dlen2 = UBIFS_DENT_NODE_SZ + old_dentry->d_name.len + 1; if (new_inode) { ilen = UBIFS_INO_NODE_SZ; if (!last_reference) ilen += ubifs_inode(new_inode)->data_len; } else ilen = 0; aligned_dlen1 = ALIGN(dlen1, 8); aligned_dlen2 = ALIGN(dlen2, 8); len = aligned_dlen1 + aligned_dlen2 + ALIGN(ilen, 8) + ALIGN(plen, 8); if (old_dir != new_dir) len += plen; dent = kmalloc(len, GFP_NOFS); if (!dent) return -ENOMEM; /* Make new dent */ dent->ch.node_type = UBIFS_DENT_NODE; dent_key_init_flash(c, &dent->key, new_dir->i_ino, &new_dentry->d_name); dent->inum = cpu_to_le64(old_inode->i_ino); dent->type = get_dent_type(old_inode->i_mode); dent->nlen = cpu_to_le16(new_dentry->d_name.len); memcpy(dent->name, new_dentry->d_name.name, new_dentry->d_name.len); dent->name[new_dentry->d_name.len] = '\0'; zero_dent_node_unused(dent); ubifs_prep_grp_node(c, dent, dlen1, 0); dent2 = (void *)dent + aligned_dlen1; /* Make deletion dent */ dent2->ch.node_type = UBIFS_DENT_NODE; dent_key_init_flash(c, &dent2->key, old_dir->i_ino, &old_dentry->d_name); dent2->inum = cpu_to_le64(0); dent2->type = DT_UNKNOWN; dent2->nlen = cpu_to_le16(old_dentry->d_name.len); memcpy(dent2->name, old_dentry->d_name.name, old_dentry->d_name.len); dent2->name[old_dentry->d_name.len] = '\0'; zero_dent_node_unused(dent2); ubifs_prep_grp_node(c, dent2, dlen2, 0); p = (void *)dent2 + aligned_dlen2; if (new_inode) { pack_inode(c, p, new_inode, 0, last_reference); p += ALIGN(ilen, 8); } if (old_dir == new_dir) pack_inode(c, p, old_dir, 1, 0); else { pack_inode(c, p, old_dir, 0, 0); p += ALIGN(plen, 8); pack_inode(c, p, new_dir, 1, 0); } err = make_reservation(c, BASEHD, len); if (err) goto out_free; if (last_reference) { err = ubifs_add_orphan(c, new_inode->i_ino); if (err) { release_head(c, BASEHD); goto out_finish; } } err = write_head(c, BASEHD, dent, len, &lnum, &offs, sync); if (!sync && !err) { struct ubifs_wbuf *wbuf = &c->jheads[BASEHD].wbuf; ubifs_wbuf_add_ino_nolock(wbuf, new_dir->i_ino); ubifs_wbuf_add_ino_nolock(wbuf, old_dir->i_ino); } release_head(c, BASEHD); if (err) goto out_ro; if (new_inode) ubifs_wbuf_add_ino_nolock(&c->jheads[BASEHD].wbuf, new_inode->i_ino); dent_key_init(c, &key, new_dir->i_ino, &new_dentry->d_name); err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen1, &new_dentry->d_name); if (err) goto out_ro; err = ubifs_add_dirt(c, lnum, dlen2); if (err) goto out_ro; dent_key_init(c, &key, old_dir->i_ino, &old_dentry->d_name); err = ubifs_tnc_remove_nm(c, &key, &old_dentry->d_name); if (err) goto out_ro; offs += aligned_dlen1 + aligned_dlen2; if (new_inode) { ino_key_init(c, &key, new_inode->i_ino); err = ubifs_tnc_add(c, &key, lnum, offs, ilen); if (err) goto out_ro; offs += ALIGN(ilen, 8); } ino_key_init(c, &key, old_dir->i_ino); err = ubifs_tnc_add(c, &key, lnum, offs, plen); if (err) goto out_ro; if (old_dir != new_dir) { offs += ALIGN(plen, 8); ino_key_init(c, &key, new_dir->i_ino); err = ubifs_tnc_add(c, &key, lnum, offs, plen); if (err) goto out_ro; } finish_reservation(c); kfree(dent); return 0; out_ro: ubifs_ro_mode(c, err); if (last_reference) ubifs_delete_orphan(c, new_inode->i_ino); out_finish: finish_reservation(c); out_free: kfree(dent); return err; }
/** * ubifs_jrn_update - update inode. * @c: UBIFS file-system description object * @dir: parent inode or host inode in case of extended attributes * @nm: directory entry name * @inode: inode * @deletion: indicates a directory entry deletion i.e unlink or rmdir * @sync: non-zero if the write-buffer has to be synchronized * @xent: non-zero if the directory entry is an extended attribute entry * * This function updates an inode by writing a directory entry (or extended * attribute entry), the inode itself, and the parent directory inode (or the * host inode) to the journal. * * The function writes the host inode @dir last, which is important in case of * extended attributes. Indeed, then we guarantee that if the host inode gets * synchronized, and the write-buffer it sits in gets flushed, the extended * attribute inode gets flushed too. And this is exactly what the user expects - * synchronizing the host inode synchronizes its extended attributes. * Similarly, this guarantees that if @dir is synchronized, its directory entry * corresponding to @nm gets synchronized too. * * This function returns %0 on success and a negative error code on failure. */ int ubifs_jrn_update(struct ubifs_info *c, const struct inode *dir, const struct qstr *nm, const struct inode *inode, int deletion, int sync, int xent) { int err, dlen, ilen, len, lnum, ino_offs, dent_offs; int aligned_dlen, aligned_ilen; int last_reference = !!(deletion && inode->i_nlink == 0); struct ubifs_dent_node *dent; struct ubifs_ino_node *ino; union ubifs_key dent_key, ino_key; dbg_jrn("ino %lu, dent '%.*s', data len %d in dir ino %lu", inode->i_ino, nm->len, nm->name, ubifs_inode(inode)->data_len, dir->i_ino); ubifs_assert(ubifs_inode(dir)->data_len == 0); dlen = UBIFS_DENT_NODE_SZ + nm->len + 1; ilen = UBIFS_INO_NODE_SZ; /* * If the last reference to the inode is being deleted, then there is no * need to attach and write inode data, it is being deleted anyway. */ if (!last_reference) ilen += ubifs_inode(inode)->data_len; aligned_dlen = ALIGN(dlen, 8); aligned_ilen = ALIGN(ilen, 8); len = aligned_dlen + aligned_ilen + UBIFS_INO_NODE_SZ; dent = kmalloc(len, GFP_NOFS); if (!dent) return -ENOMEM; if (!xent) { dent->ch.node_type = UBIFS_DENT_NODE; dent_key_init(c, &dent_key, dir->i_ino, nm); } else { dent->ch.node_type = UBIFS_XENT_NODE; xent_key_init(c, &dent_key, dir->i_ino, nm); } key_write(c, &dent_key, dent->key); dent->inum = deletion ? 0 : cpu_to_le64(inode->i_ino); dent->type = get_dent_type(inode->i_mode); dent->nlen = cpu_to_le16(nm->len); memcpy(dent->name, nm->name, nm->len); dent->name[nm->len] = '\0'; zero_dent_node_unused(dent); ubifs_prep_grp_node(c, dent, dlen, 0); ino = (void *)dent + aligned_dlen; pack_inode(c, ino, inode, 0, last_reference); ino = (void *)ino + aligned_ilen; pack_inode(c, ino, dir, 1, 0); err = make_reservation(c, BASEHD, len); if (err) goto out_free; if (last_reference) { err = ubifs_add_orphan(c, inode->i_ino); if (err) { release_head(c, BASEHD); goto out_finish; } } err = write_head(c, BASEHD, dent, len, &lnum, &dent_offs, sync); if (!sync && !err) { struct ubifs_wbuf *wbuf = &c->jheads[BASEHD].wbuf; ubifs_wbuf_add_ino_nolock(wbuf, inode->i_ino); ubifs_wbuf_add_ino_nolock(wbuf, dir->i_ino); } release_head(c, BASEHD); kfree(dent); if (err) goto out_ro; if (deletion) { err = ubifs_tnc_remove_nm(c, &dent_key, nm); if (err) goto out_ro; err = ubifs_add_dirt(c, lnum, dlen); } else err = ubifs_tnc_add_nm(c, &dent_key, lnum, dent_offs, dlen, nm); if (err) goto out_ro; /* * Note, we do not remove the inode from TNC even if the last reference * to it has just been deleted, because the inode may still be opened. * Instead, the inode has been added to orphan lists and the orphan * subsystem will take further care about it. */ ino_key_init(c, &ino_key, inode->i_ino); ino_offs = dent_offs + aligned_dlen; err = ubifs_tnc_add(c, &ino_key, lnum, ino_offs, ilen); if (err) goto out_ro; ino_key_init(c, &ino_key, dir->i_ino); ino_offs += aligned_ilen; err = ubifs_tnc_add(c, &ino_key, lnum, ino_offs, UBIFS_INO_NODE_SZ); if (err) goto out_ro; finish_reservation(c); return 0; out_finish: finish_reservation(c); out_free: kfree(dent); return err; out_ro: ubifs_ro_mode(c, err); if (last_reference) ubifs_delete_orphan(c, inode->i_ino); finish_reservation(c); return err; }
int ubifs_jrn_delete_xattr(struct ubifs_info *c, const struct inode *host, const struct inode *inode, const struct qstr *nm, int sync) { int err, xlen, hlen, len, lnum, xent_offs, aligned_xlen; struct ubifs_dent_node *xent; struct ubifs_ino_node *ino; union ubifs_key xent_key, key1, key2; dbg_jrn("host %lu, xattr ino %lu, name '%s', data len %d", host->i_ino, inode->i_ino, nm->name, ubifs_inode(inode)->data_len); ubifs_assert(inode->i_nlink == 0); /* * Since we are deleting the inode, we do not bother to attach any data * to it and assume its length is %UBIFS_INO_NODE_SZ. */ xlen = UBIFS_DENT_NODE_SZ + nm->len + 1; aligned_xlen = ALIGN(xlen, 8); hlen = ubifs_inode(host)->data_len + UBIFS_INO_NODE_SZ; len = aligned_xlen + UBIFS_INO_NODE_SZ + ALIGN(hlen, 8); xent = kmalloc(len, GFP_NOFS); if (!xent) return -ENOMEM; xent->ch.node_type = UBIFS_XENT_NODE; xent_key_init(c, &xent_key, host->i_ino, nm); key_write(c, &xent_key, xent->key); xent->inum = 0; xent->type = get_dent_type(inode->i_mode); xent->nlen = cpu_to_le16(nm->len); memcpy(xent->name, nm->name, nm->len); xent->name[nm->len] = '\0'; zero_dent_node_unused(xent); ubifs_prep_grp_node(c, xent, xlen, 0); ino = (void *)xent + aligned_xlen; pack_inode(c, ino, inode, 0, 1); ino = (void *)ino + UBIFS_INO_NODE_SZ; pack_inode(c, ino, host, 1, 0); err = make_reservation(c, BASEHD, len); if (err) { kfree(xent); return err; } err = write_head(c, BASEHD, xent, len, &lnum, &xent_offs, sync); if (!sync && !err) ubifs_wbuf_add_ino_nolock(&c->jheads[BASEHD].wbuf, host->i_ino); release_head(c, BASEHD); kfree(xent); if (err) goto out_ro; /* Remove the extended attribute entry from TNC */ err = ubifs_tnc_remove_nm(c, &xent_key, nm); if (err) goto out_ro; err = ubifs_add_dirt(c, lnum, xlen); if (err) goto out_ro; /* * Remove all nodes belonging to the extended attribute inode from TNC. * Well, there actually must be only one node - the inode itself. */ lowest_ino_key(c, &key1, inode->i_ino); highest_ino_key(c, &key2, inode->i_ino); err = ubifs_tnc_remove_range(c, &key1, &key2); if (err) goto out_ro; err = ubifs_add_dirt(c, lnum, UBIFS_INO_NODE_SZ); if (err) goto out_ro; /* And update TNC with the new host inode position */ ino_key_init(c, &key1, host->i_ino); err = ubifs_tnc_add(c, &key1, lnum, xent_offs + len - hlen, hlen); if (err) goto out_ro; finish_reservation(c); return 0; out_ro: ubifs_ro_mode(c, err); finish_reservation(c); return err; }
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); }