diff options
| author | Zhihao Cheng <chengzhihao1@huawei.com> | 2024-11-11 16:36:58 +0800 | 
|---|---|---|
| committer | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2024-11-11 10:32:45 +0100 | 
| commit | 5fb520b07182de04eea6373e95b580a88dca3037 (patch) | |
| tree | a34c3e57f10ef9bea7a2347b6ff56fc9f4e2a6dc /ubifs-utils | |
| parent | 9de315de437bac81eb08f32edb0a9a8e3c416ae8 (diff) | |
ubifs-utils: Adapt io.c in libubifs
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>
Diffstat (limited to 'ubifs-utils')
| -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;  } | 
