diff options
Diffstat (limited to 'ubifs-utils/libubifs')
-rw-r--r-- | ubifs-utils/libubifs/io.c | 364 |
1 files changed, 90 insertions, 274 deletions
diff --git a/ubifs-utils/libubifs/io.c b/ubifs-utils/libubifs/io.c index 01d8eb1..6f17017 100644 --- a/ubifs-utils/libubifs/io.c +++ b/ubifs-utils/libubifs/io.c @@ -58,9 +58,11 @@ * they are read from the flash media. */ -#include <linux/crc32.h> -#include <linux/slab.h> +#include "kmem.h" +#include "crc32.h" #include "ubifs.h" +#include "defs.h" +#include "debug.h" /** * ubifs_ro_mode - switch UBIFS to read read-only mode. @@ -72,7 +74,6 @@ void ubifs_ro_mode(struct ubifs_info *c, int err) if (!c->ro_error) { c->ro_error = 1; c->no_chk_data_crc = 0; - c->vfs_sb->s_flags |= SB_RDONLY; ubifs_warn(c, "switched to read-only mode, error %d", err); dump_stack(); } @@ -87,9 +88,26 @@ void ubifs_ro_mode(struct ubifs_info *c, int err) int ubifs_leb_read(const struct ubifs_info *c, int lnum, void *buf, int offs, int len, int even_ebadmsg) { - int err; + int err = 0; + off_t pos = (off_t)lnum * c->leb_size + offs; + + if (!len) + return 0; - err = ubi_read(c->ubi, lnum, buf, offs, len); + /* + * The %-EBADMSG may be ignored in some case, the buf may not be filled + * with data in some buggy mtd drivers. So we'd better to reset the buf + * content before reading. + */ + memset(buf, 0, len); + if (lseek(c->dev_fd, pos, SEEK_SET) != pos) { + err = -errno; + goto out; + } + + if (read(c->dev_fd, buf, len) != len) + err = -errno; +out: /* * In case of %-EBADMSG print the error message only if the * @even_ebadmsg is true. @@ -105,15 +123,27 @@ int ubifs_leb_read(const struct ubifs_info *c, int lnum, void *buf, int offs, int ubifs_leb_write(struct ubifs_info *c, int lnum, const void *buf, int offs, int len) { - int err; + int err = 0; + off_t pos = (off_t)lnum * c->leb_size + offs; ubifs_assert(c, !c->ro_media && !c->ro_mount); if (c->ro_error) return -EROFS; - if (!dbg_is_tst_rcvry(c)) - err = ubi_leb_write(c->ubi, lnum, buf, offs, len); - else - err = dbg_leb_write(c, lnum, buf, offs, len); + if (!c->libubi) { + err = -ENODEV; + goto out; + } + + if (!len) + return 0; + + if (lseek(c->dev_fd, pos, SEEK_SET) != pos) { + err = -errno; + goto out; + } + if (write(c->dev_fd, buf, len) != len) + err = -errno; +out: if (err) { ubifs_err(c, "writing %d bytes to LEB %d:%d failed, error %d", len, lnum, offs, err); @@ -125,15 +155,31 @@ int ubifs_leb_write(struct ubifs_info *c, int lnum, const void *buf, int offs, int ubifs_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len) { - int err; + int err = 0; + off_t pos = (off_t)lnum * c->leb_size; ubifs_assert(c, !c->ro_media && !c->ro_mount); if (c->ro_error) return -EROFS; - if (!dbg_is_tst_rcvry(c)) - err = ubi_leb_change(c->ubi, lnum, buf, len); - else - err = dbg_leb_change(c, lnum, buf, len); + if (c->libubi) { + err = ubi_leb_change_start(c->libubi, c->dev_fd, lnum, len); + if (err) { + ubifs_err(c, "ubi_leb_change_start failed"); + err = -errno; + goto out; + } + } + + if (!len) + return 0; + + if (lseek(c->dev_fd, pos, SEEK_SET) != pos) { + err = -errno; + goto out; + } + if (write(c->dev_fd, buf, len) != len) + err = -errno; +out: if (err) { ubifs_err(c, "changing %d bytes in LEB %d failed, error %d", len, lnum, err); @@ -145,15 +191,15 @@ int ubifs_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len) int ubifs_leb_unmap(struct ubifs_info *c, int lnum) { - int err; + int err = 0; ubifs_assert(c, !c->ro_media && !c->ro_mount); if (c->ro_error) return -EROFS; - if (!dbg_is_tst_rcvry(c)) - err = ubi_leb_unmap(c->ubi, lnum); - else - err = dbg_leb_unmap(c, lnum); + if (!c->libubi) + return -ENODEV; + if (ubi_leb_unmap(c->dev_fd, lnum)) + err = -errno; if (err) { ubifs_err(c, "unmap LEB %d failed, error %d", lnum, err); ubifs_ro_mode(c, err); @@ -164,15 +210,15 @@ int ubifs_leb_unmap(struct ubifs_info *c, int lnum) int ubifs_leb_map(struct ubifs_info *c, int lnum) { - int err; + int err = 0; ubifs_assert(c, !c->ro_media && !c->ro_mount); if (c->ro_error) return -EROFS; - if (!dbg_is_tst_rcvry(c)) - err = ubi_leb_map(c->ubi, lnum); - else - err = dbg_leb_map(c, lnum); + if (!c->libubi) + return -ENODEV; + if (ubi_leb_map(c->dev_fd, lnum)) + err = -errno; if (err) { ubifs_err(c, "mapping LEB %d failed, error %d", lnum, err); ubifs_ro_mode(c, err); @@ -183,9 +229,12 @@ int ubifs_leb_map(struct ubifs_info *c, int lnum) int ubifs_is_mapped(const struct ubifs_info *c, int lnum) { - int err; + int err = 0; - err = ubi_is_mapped(c->ubi, lnum); + if (!c->libubi) + return -ENODEV; + if (ubi_is_mapped(c->dev_fd, lnum)) + err = -errno; if (err < 0) { ubifs_err(c, "ubi_is_mapped failed for LEB %d, error %d", lnum, err); @@ -194,24 +243,6 @@ int ubifs_is_mapped(const struct ubifs_info *c, int lnum) return err; } -static void record_magic_error(struct ubifs_stats_info *stats) -{ - if (stats) - stats->magic_errors++; -} - -static void record_node_error(struct ubifs_stats_info *stats) -{ - if (stats) - stats->node_errors++; -} - -static void record_crc_error(struct ubifs_stats_info *stats) -{ - if (stats) - stats->crc_errors++; -} - /** * ubifs_check_node - check node. * @c: UBIFS file-system description object @@ -256,7 +287,6 @@ int ubifs_check_node(const struct ubifs_info *c, const void *buf, int len, if (!quiet) ubifs_err(c, "bad magic %#08x, expected %#08x", magic, UBIFS_NODE_MAGIC); - record_magic_error(c->stats); err = -EUCLEAN; goto out; } @@ -265,7 +295,6 @@ int ubifs_check_node(const struct ubifs_info *c, const void *buf, int len, if (type < 0 || type >= UBIFS_NODE_TYPES_CNT) { if (!quiet) ubifs_err(c, "bad node type %d", type); - record_node_error(c->stats); goto out; } @@ -290,7 +319,6 @@ int ubifs_check_node(const struct ubifs_info *c, const void *buf, int len, if (!quiet) ubifs_err(c, "bad CRC: calculated %#08x, read %#08x", crc, node_crc); - record_crc_error(c->stats); err = -EUCLEAN; goto out; } @@ -395,7 +423,7 @@ void ubifs_init_node(struct ubifs_info *c, void *node, int len, int pad) } } -void ubifs_crc_node(struct ubifs_info *c, void *node, int len) +void ubifs_crc_node(__unused struct ubifs_info *c, void *node, int len) { struct ubifs_ch *ch = node; uint32_t crc; @@ -488,61 +516,6 @@ void ubifs_prep_grp_node(struct ubifs_info *c, void *node, int len, int last) } /** - * wbuf_timer_callback_nolock - write-buffer timer callback function. - * @timer: timer data (write-buffer descriptor) - * - * This function is called when the write-buffer timer expires. - */ -static enum hrtimer_restart wbuf_timer_callback_nolock(struct hrtimer *timer) -{ - struct ubifs_wbuf *wbuf = container_of(timer, struct ubifs_wbuf, timer); - - dbg_io("jhead %s", dbg_jhead(wbuf->jhead)); - wbuf->need_sync = 1; - wbuf->c->need_wbuf_sync = 1; - ubifs_wake_up_bgt(wbuf->c); - return HRTIMER_NORESTART; -} - -/** - * new_wbuf_timer_nolock - start new write-buffer timer. - * @c: UBIFS file-system description object - * @wbuf: write-buffer descriptor - */ -static void new_wbuf_timer_nolock(struct ubifs_info *c, struct ubifs_wbuf *wbuf) -{ - ktime_t softlimit = ms_to_ktime(dirty_writeback_interval * 10); - unsigned long long delta = dirty_writeback_interval; - - /* centi to milli, milli to nano, then 10% */ - delta *= 10ULL * NSEC_PER_MSEC / 10ULL; - - ubifs_assert(c, !hrtimer_active(&wbuf->timer)); - ubifs_assert(c, delta <= ULONG_MAX); - - if (wbuf->no_timer) - return; - dbg_io("set timer for jhead %s, %llu-%llu millisecs", - dbg_jhead(wbuf->jhead), - div_u64(ktime_to_ns(softlimit), USEC_PER_SEC), - div_u64(ktime_to_ns(softlimit) + delta, USEC_PER_SEC)); - hrtimer_start_range_ns(&wbuf->timer, softlimit, delta, - HRTIMER_MODE_REL); -} - -/** - * cancel_wbuf_timer_nolock - cancel write-buffer timer. - * @wbuf: write-buffer descriptor - */ -static void cancel_wbuf_timer_nolock(struct ubifs_wbuf *wbuf) -{ - if (wbuf->no_timer) - return; - wbuf->need_sync = 0; - hrtimer_cancel(&wbuf->timer); -} - -/** * ubifs_wbuf_sync_nolock - synchronize write-buffer. * @wbuf: write-buffer to synchronize * @@ -560,7 +533,6 @@ int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf) struct ubifs_info *c = wbuf->c; int err, dirt, sync_len; - cancel_wbuf_timer_nolock(wbuf); if (!wbuf->used || wbuf->lnum == -1) /* Write-buffer is empty or not seeked */ return 0; @@ -658,70 +630,6 @@ int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs) } /** - * ubifs_bg_wbufs_sync - synchronize write-buffers. - * @c: UBIFS file-system description object - * - * This function is called by background thread to synchronize write-buffers. - * Returns zero in case of success and a negative error code in case of - * failure. - */ -int ubifs_bg_wbufs_sync(struct ubifs_info *c) -{ - int err, i; - - ubifs_assert(c, !c->ro_media && !c->ro_mount); - if (!c->need_wbuf_sync) - return 0; - c->need_wbuf_sync = 0; - - if (c->ro_error) { - err = -EROFS; - goto out_timers; - } - - dbg_io("synchronize"); - for (i = 0; i < c->jhead_cnt; i++) { - struct ubifs_wbuf *wbuf = &c->jheads[i].wbuf; - - cond_resched(); - - /* - * If the mutex is locked then wbuf is being changed, so - * synchronization is not necessary. - */ - if (mutex_is_locked(&wbuf->io_mutex)) - continue; - - mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead); - if (!wbuf->need_sync) { - mutex_unlock(&wbuf->io_mutex); - continue; - } - - err = ubifs_wbuf_sync_nolock(wbuf); - mutex_unlock(&wbuf->io_mutex); - if (err) { - ubifs_err(c, "cannot sync write-buffer, error %d", err); - ubifs_ro_mode(c, err); - goto out_timers; - } - } - - return 0; - -out_timers: - /* Cancel all timers to prevent repeated errors */ - for (i = 0; i < c->jhead_cnt; i++) { - struct ubifs_wbuf *wbuf = &c->jheads[i].wbuf; - - mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead); - cancel_wbuf_timer_nolock(wbuf); - mutex_unlock(&wbuf->io_mutex); - } - return err; -} - -/** * ubifs_wbuf_write_nolock - write data to flash via write-buffer. * @wbuf: write-buffer * @buf: node to write @@ -763,8 +671,6 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len) goto out; } - cancel_wbuf_timer_nolock(wbuf); - if (c->ro_error) return -EROFS; @@ -925,9 +831,6 @@ exit: goto out; } - if (wbuf->used) - new_wbuf_timer_nolock(c, wbuf); - return 0; out: @@ -1110,32 +1013,30 @@ int ubifs_read_node(const struct ubifs_info *c, void *buf, int type, int len, return err; if (type != ch->node_type) { - ubifs_errc(c, "bad node type (%d but expected %d)", - ch->node_type, type); + ubifs_err(c, "bad node type (%d but expected %d)", + ch->node_type, type); goto out; } err = ubifs_check_node(c, buf, len, lnum, offs, 0, 0); if (err) { - ubifs_errc(c, "expected node type %d", type); + ubifs_err(c, "expected node type %d", type); return err; } l = le32_to_cpu(ch->len); if (l != len) { - ubifs_errc(c, "bad node length %d, expected %d", l, len); + ubifs_err(c, "bad node length %d, expected %d", l, len); goto out; } return 0; out: - ubifs_errc(c, "bad node at LEB %d:%d, LEB mapping status %d", lnum, - offs, ubi_is_mapped(c->ubi, lnum)); - if (!c->probing) { - ubifs_dump_node(c, buf, len); - dump_stack(); - } + ubifs_err(c, "bad node at LEB %d:%d, LEB mapping status %d", lnum, + offs, ubi_is_mapped(c->dev_fd, lnum)); + ubifs_dump_node(c, buf, len); + dump_stack(); return -EINVAL; } @@ -1166,12 +1067,12 @@ int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf) wbuf->used = 0; wbuf->lnum = wbuf->offs = -1; /* - * If the LEB starts at the max. write size aligned address, then - * write-buffer size has to be set to @c->max_write_size. Otherwise, - * set it to something smaller so that it ends at the closest max. - * write size boundary. + * Different from linux kernel, there is no way to get leb_start in + * userspace, set write-buffer size as @c->max_write_size directly. + * Since wbuf->lnum is initialized as -1, wbuf->size will always be + * reset in ubifs_wbuf_seek_nolock, it won't be any problems. */ - size = c->max_write_size - (c->leb_start % c->max_write_size); + size = c->max_write_size; wbuf->avail = wbuf->size = size; wbuf->sync_callback = NULL; mutex_init(&wbuf->io_mutex); @@ -1179,90 +1080,5 @@ int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf) wbuf->c = c; wbuf->next_ino = 0; - hrtimer_init(&wbuf->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - wbuf->timer.function = wbuf_timer_callback_nolock; - return 0; -} - -/** - * ubifs_wbuf_add_ino_nolock - add an inode number into the wbuf inode array. - * @wbuf: the write-buffer where to add - * @inum: the inode number - * - * This function adds an inode number to the inode array of the write-buffer. - */ -void ubifs_wbuf_add_ino_nolock(struct ubifs_wbuf *wbuf, ino_t inum) -{ - if (!wbuf->buf) - /* NOR flash or something similar */ - return; - - spin_lock(&wbuf->lock); - if (wbuf->used) - wbuf->inodes[wbuf->next_ino++] = inum; - spin_unlock(&wbuf->lock); -} - -/** - * wbuf_has_ino - returns if the wbuf contains data from the inode. - * @wbuf: the write-buffer - * @inum: the inode number - * - * This function returns with %1 if the write-buffer contains some data from the - * given inode otherwise it returns with %0. - */ -static int wbuf_has_ino(struct ubifs_wbuf *wbuf, ino_t inum) -{ - int i, ret = 0; - - spin_lock(&wbuf->lock); - for (i = 0; i < wbuf->next_ino; i++) - if (inum == wbuf->inodes[i]) { - ret = 1; - break; - } - spin_unlock(&wbuf->lock); - - return ret; -} - -/** - * ubifs_sync_wbufs_by_inode - synchronize write-buffers for an inode. - * @c: UBIFS file-system description object - * @inode: inode to synchronize - * - * This function synchronizes write-buffers which contain nodes belonging to - * @inode. Returns zero in case of success and a negative error code in case of - * failure. - */ -int ubifs_sync_wbufs_by_inode(struct ubifs_info *c, struct inode *inode) -{ - int i, err = 0; - - for (i = 0; i < c->jhead_cnt; i++) { - struct ubifs_wbuf *wbuf = &c->jheads[i].wbuf; - - if (i == GCHD) - /* - * GC head is special, do not look at it. Even if the - * head contains something related to this inode, it is - * a _copy_ of corresponding on-flash node which sits - * somewhere else. - */ - continue; - - if (!wbuf_has_ino(wbuf, inode->i_ino)) - continue; - - mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead); - if (wbuf_has_ino(wbuf, inode->i_ino)) - err = ubifs_wbuf_sync_nolock(wbuf); - mutex_unlock(&wbuf->io_mutex); - - if (err) { - ubifs_ro_mode(c, err); - return err; - } - } return 0; } |