]> www.infradead.org Git - mtd-utils.git/commitdiff
ubifs-utils: Adapt io.c in libubifs
authorZhihao Cheng <chengzhihao1@huawei.com>
Mon, 11 Nov 2024 08:36:58 +0000 (16:36 +0800)
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>
Mon, 11 Nov 2024 09:32:45 +0000 (10:32 +0100)
Adapt io.c in libubifs, compared with linux kernel implementations:
 1. Modify io related functions(eg. ubifs_leb_read/ubifs_leb_write,
    etc.), adapt them with userspace io functions lseek/read/write.
 2. Remove some functions(eg. record_magic_error, ubifs_bg_wbufs_sync)
    which won't be used in fsck/mkfs.
 3. Replce ubifs_errc with ubifs_err, because there will be no SB_SILENT
    options in mkfs/fsck.
 4. Initiate wbuf->size as c->max_write_size.

Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com>
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
include/crc32.h
ubifs-utils/libubifs/io.c

index 9c1f742c6229a272bf4d92dd0ca1f1d7d088b9ef..f5271f3756b4ca380ef81bf039d9afab5bb72190 100644 (file)
@@ -10,4 +10,9 @@
 /* Return a 32-bit CRC of the contents of the buffer */
 extern uint32_t mtd_crc32(uint32_t val, const void *ss, int len);
 
+static inline uint32_t crc32(uint32_t val, const void *ss, int len)
+{
+       return mtd_crc32(val, ss, len);
+}
+
 #endif /* __CRC32_H__ */
index 01d8eb1703820c0f55c4c7b9a8ca1a2d3c205dcd..6f1701729e2c81b1b9b932bc96684d36647c9753 100644 (file)
  * 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;
@@ -487,61 +515,6 @@ void ubifs_prep_grp_node(struct ubifs_info *c, void *node, int len, int last)
        ch->crc = cpu_to_le32(crc);
 }
 
-/**
- * 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;
@@ -657,70 +629,6 @@ int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs)
        return 0;
 }
 
-/**
- * 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
@@ -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;
 }