/** * ubifs_start_scan - create LEB scanning information at start of scan. * @c: UBIFS file-system description object * @lnum: logical eraseblock number * @offs: offset to start at (usually zero) * @sbuf: scan buffer (must be c->leb_size) * * This function returns %0 on success and a negative error code on failure. */ struct ubifs_scan_leb *ubifs_start_scan(const struct ubifs_info *c, int lnum, int offs, void *sbuf) { struct ubifs_scan_leb *sleb; int err; dbg_scan("scan LEB %d:%d", lnum, offs); sleb = kzalloc(sizeof(struct ubifs_scan_leb), GFP_NOFS); if (!sleb) return ERR_PTR(-ENOMEM); sleb->lnum = lnum; INIT_LIST_HEAD(&sleb->nodes); sleb->buf = sbuf; err = ubi_read(c->ubi, lnum, sbuf + offs, offs, c->leb_size - offs); if (err && err != -EBADMSG) { ubifs_err("cannot read %d bytes from LEB %d:%d," " error %d", c->leb_size - offs, lnum, offs, err); kfree(sleb); return ERR_PTR(err); } if (err == -EBADMSG) sleb->ecc = 1; return sleb; }
/** * ubifs_read_node - read node. * @c: UBIFS file-system description object * @buf: buffer to read to * @type: node type * @len: node length (not aligned) * @lnum: logical eraseblock number * @offs: offset within the logical eraseblock * * This function reads a node of known type and and length, checks it and * stores in @buf. Returns zero in case of success, %-EUCLEAN if CRC mismatched * and a negative error code in case of failure. */ int ubifs_read_node(const struct ubifs_info *c, void *buf, int type, int len, int lnum, int offs) { int err, l; struct ubifs_ch *ch = buf; int try_count = 0; dbg_io("LEB %d:%d, %s, length %d", lnum, offs, dbg_ntype(type), len); ubifs_assert(lnum >= 0 && lnum < c->leb_cnt && offs >= 0); ubifs_assert(len >= UBIFS_CH_SZ && offs + len <= c->leb_size); ubifs_assert(!(offs & 7) && offs < c->leb_size); ubifs_assert(type >= 0 && type < UBIFS_NODE_TYPES_CNT); try_read: err = ubi_read(c->ubi, lnum, buf, offs, len); if (err && err != -EBADMSG) { ubifs_err("cannot read node %d from LEB %d:%d, error %d", type, lnum, offs, err); return err; } if (type != ch->node_type) { ubifs_err("bad node type (%d but expected %d)", ch->node_type, type); goto out; } err = ubifs_check_node(c, buf, lnum, offs, 0, 0); if (err) { ubifs_err("expected node type %d", type); if(try_count < 3){ try_count++; udelay(100); goto try_read; } else{ return err; } } l = le32_to_cpu(ch->len); if (l != len) { ubifs_err("bad node length %d, expected %d", l, len); goto out; } return 0; out: ubifs_err("bad node at LEB %d:%d, LEB mapping status %d", lnum, offs, ubi_is_mapped(c->ubi, lnum)); dbg_dump_node(c, buf); dbg_dump_stack(); return -EINVAL; }
int ubifs_leb_read(const struct ubifs_info *c, int lnum, void *buf, int offs, int len, int even_ebadmsg) { int err; err = ubi_read(c->ubi, lnum, buf, offs, len); /* * In case of %-EBADMSG print the error message only if the * @even_ebadmsg is true. */ if (err && (err != -EBADMSG || even_ebadmsg)) { ubifs_err("reading %d bytes from LEB %d:%d failed, error %d", len, lnum, offs, err); dbg_dump_stack(); } return err; }
/** * fixup_leb - fixup/unmap an LEB containing free space. * @c: UBIFS file-system description object * @lnum: the LEB number to fix up * @len: number of used bytes in LEB (starting at offset 0) * * This function reads the contents of the given LEB number @lnum, then fixes * it up, so that empty min. I/O units in the end of LEB are actually erased on * flash (rather than being just all-0xff real data). If the LEB is completely * empty, it is simply unmapped. */ static int fixup_leb(struct ubifs_info *c, int lnum, int len) { int err; ubifs_assert(len >= 0); ubifs_assert(len % c->min_io_size == 0); ubifs_assert(len < c->leb_size); if (len == 0) { dbg_mnt("unmap empty LEB %d", lnum); return ubi_leb_unmap(c->ubi, lnum); } dbg_mnt("fixup LEB %d, data len %d", lnum, len); err = ubi_read(c->ubi, lnum, c->sbuf, 0, len); if (err) return err; return ubi_leb_change(c->ubi, lnum, c->sbuf, len, UBI_UNKNOWN); }
/** * ubifs_read_node_wbuf - read node from the media or write-buffer. * @wbuf: wbuf to check for un-written data * @buf: buffer to read to * @type: node type * @len: node length * @lnum: logical eraseblock number * @offs: offset within the logical eraseblock * * This function reads a node of known type and length, checks it and stores * in @buf. If the node partially or fully sits in the write-buffer, this * function takes data from the buffer, otherwise it reads the flash media. * Returns zero in case of success, %-EUCLEAN if CRC mismatched and a negative * error code in case of failure. */ int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len, int lnum, int offs) { const struct ubifs_info *c = wbuf->c; int err, rlen, overlap; struct ubifs_ch *ch = buf; dbg_io("LEB %d:%d, %s, length %d, jhead %s", lnum, offs, dbg_ntype(type), len, dbg_jhead(wbuf->jhead)); ubifs_assert(wbuf && lnum >= 0 && lnum < c->leb_cnt && offs >= 0); ubifs_assert(!(offs & 7) && offs < c->leb_size); ubifs_assert(type >= 0 && type < UBIFS_NODE_TYPES_CNT); spin_lock(&wbuf->lock); overlap = (lnum == wbuf->lnum && offs + len > wbuf->offs); if (!overlap) { /* We may safely unlock the write-buffer and read the data */ spin_unlock(&wbuf->lock); return ubifs_read_node(c, buf, type, len, lnum, offs); } /* Don't read under wbuf */ rlen = wbuf->offs - offs; if (rlen < 0) rlen = 0; /* Copy the rest from the write-buffer */ memcpy(buf + rlen, wbuf->buf + offs + rlen - wbuf->offs, len - rlen); spin_unlock(&wbuf->lock); if (rlen > 0) { /* Read everything that goes before write-buffer */ err = ubi_read(c->ubi, lnum, buf, offs, rlen); if (err && err != -EBADMSG) { ubifs_err("failed to read node %d from LEB %d:%d, " "error %d", type, lnum, offs, err); dbg_dump_stack(); return err; } } if (type != ch->node_type) { ubifs_err("bad node type (%d but expected %d)", ch->node_type, type); goto out; } err = ubifs_check_node(c, buf, lnum, offs, 0, 0); if (err) { ubifs_err("expected node type %d", type); return err; } rlen = le32_to_cpu(ch->len); if (rlen != len) { ubifs_err("bad node length %d, expected %d", rlen, len); goto out; } return 0; out: ubifs_err("bad node at LEB %d:%d", lnum, offs); dbg_dump_node(c, buf); dbg_dump_stack(); return -EINVAL; }