Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 44c695b1 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'linux-next' of git://git.infradead.org/ubifs-2.6

* 'linux-next' of git://git.infradead.org/ubifs-2.6:
  UBIFS: fix corruption dump
  UBIFS: clean up free space checking
  UBIFS: small amendments in the LEB scanning code
  UBIFS: dump a little more in case of corruptions
  MAINTAINERS: update ahunter's e-mail address
  UBIFS: allow more than one volume to be mounted
  UBIFS: fix assertion warning
  UBIFS: minor spelling and grammar fixes
  UBIFS: fix 64-bit divisions in debug print
  UBIFS: few spelling fixes
  UBIFS: set write-buffer timout to 3-5 seconds
  UBIFS: slightly optimize write-buffer timer usage
  UBIFS: improve debugging messaged
  UBIFS: fix integer overflow warning
parents eee33abe 06112547
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -5854,7 +5854,7 @@ UBI FILE SYSTEM (UBIFS)
P:	Artem Bityutskiy
M:	dedekind@infradead.org
P:	Adrian Hunter
M:	ext-adrian.hunter@nokia.com
M:	adrian.hunter@nokia.com
L:	linux-mtd@lists.infradead.org
T:	git git://git.infradead.org/ubifs-2.6.git
W:	http://www.linux-mtd.infradead.org/doc/ubifs.html
+27 −30
Original line number Diff line number Diff line
@@ -297,6 +297,7 @@ 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 %d", wbuf->jhead);
	wbuf->need_sync = 1;
	wbuf->c->need_wbuf_sync = 1;
	ubifs_wake_up_bgt(wbuf->c);
@@ -311,8 +312,12 @@ static void new_wbuf_timer_nolock(struct ubifs_wbuf *wbuf)
{
	ubifs_assert(!hrtimer_active(&wbuf->timer));

	if (!ktime_to_ns(wbuf->softlimit))
	if (wbuf->no_timer)
		return;
	dbg_io("set timer for jhead %d, %llu-%llu millisecs", wbuf->jhead,
	       div_u64(ktime_to_ns(wbuf->softlimit), USEC_PER_SEC),
	       div_u64(ktime_to_ns(wbuf->softlimit) + wbuf->delta,
		       USEC_PER_SEC));
	hrtimer_start_range_ns(&wbuf->timer, wbuf->softlimit, wbuf->delta,
			       HRTIMER_MODE_REL);
}
@@ -323,11 +328,8 @@ static void new_wbuf_timer_nolock(struct ubifs_wbuf *wbuf)
 */
static void cancel_wbuf_timer_nolock(struct ubifs_wbuf *wbuf)
{
	/*
	 * If the syncer is waiting for the lock (from the background thread's
	 * context) and another task is changing write-buffer then the syncing
	 * should be canceled.
	 */
	if (wbuf->no_timer)
		return;
	wbuf->need_sync = 0;
	hrtimer_cancel(&wbuf->timer);
}
@@ -349,8 +351,8 @@ int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf)
		/* Write-buffer is empty or not seeked */
		return 0;

	dbg_io("LEB %d:%d, %d bytes",
	       wbuf->lnum, wbuf->offs, wbuf->used);
	dbg_io("LEB %d:%d, %d bytes, jhead %d",
	       wbuf->lnum, wbuf->offs, wbuf->used, wbuf->jhead);
	ubifs_assert(!(c->vfs_sb->s_flags & MS_RDONLY));
	ubifs_assert(!(wbuf->avail & 7));
	ubifs_assert(wbuf->offs + c->min_io_size <= c->leb_size);
@@ -390,7 +392,7 @@ int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf)
 * @offs: logical eraseblock offset to seek to
 * @dtype: data type
 *
 * This function targets the write buffer to logical eraseblock @lnum:@offs.
 * This function targets the write-buffer to logical eraseblock @lnum:@offs.
 * The write-buffer is synchronized if it is not empty. Returns zero in case of
 * success and a negative error code in case of failure.
 */
@@ -399,7 +401,7 @@ int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs,
{
	const struct ubifs_info *c = wbuf->c;

	dbg_io("LEB %d:%d", lnum, offs);
	dbg_io("LEB %d:%d, jhead %d", lnum, offs, wbuf->jhead);
	ubifs_assert(lnum >= 0 && lnum < c->leb_cnt);
	ubifs_assert(offs >= 0 && offs <= c->leb_size);
	ubifs_assert(offs % c->min_io_size == 0 && !(offs & 7));
@@ -506,9 +508,9 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
	struct ubifs_info *c = wbuf->c;
	int err, written, n, aligned_len = ALIGN(len, 8), offs;

	dbg_io("%d bytes (%s) to wbuf at LEB %d:%d", len,
	       dbg_ntype(((struct ubifs_ch *)buf)->node_type), wbuf->lnum,
	       wbuf->offs + wbuf->used);
	dbg_io("%d bytes (%s) to jhead %d wbuf at LEB %d:%d", len,
	       dbg_ntype(((struct ubifs_ch *)buf)->node_type), wbuf->jhead,
	       wbuf->lnum, wbuf->offs + wbuf->used);
	ubifs_assert(len > 0 && wbuf->lnum >= 0 && wbuf->lnum < c->leb_cnt);
	ubifs_assert(wbuf->offs >= 0 && wbuf->offs % c->min_io_size == 0);
	ubifs_assert(!(wbuf->offs & 7) && wbuf->offs <= c->leb_size);
@@ -533,8 +535,8 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
		memcpy(wbuf->buf + wbuf->used, buf, len);

		if (aligned_len == wbuf->avail) {
			dbg_io("flush wbuf to LEB %d:%d", wbuf->lnum,
				wbuf->offs);
			dbg_io("flush jhead %d wbuf to LEB %d:%d",
			       wbuf->jhead, wbuf->lnum, wbuf->offs);
			err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf,
					    wbuf->offs, c->min_io_size,
					    wbuf->dtype);
@@ -562,7 +564,8 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
	 * minimal I/O unit. We have to fill and flush write-buffer and switch
	 * to the next min. I/O unit.
	 */
	dbg_io("flush wbuf to LEB %d:%d", wbuf->lnum, wbuf->offs);
	dbg_io("flush jhead %d wbuf to LEB %d:%d",
	       wbuf->jhead, wbuf->lnum, wbuf->offs);
	memcpy(wbuf->buf + wbuf->used, buf, wbuf->avail);
	err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf, wbuf->offs,
			    c->min_io_size, wbuf->dtype);
@@ -695,7 +698,8 @@ int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len,
	int err, rlen, overlap;
	struct ubifs_ch *ch = buf;

	dbg_io("LEB %d:%d, %s, length %d", lnum, offs, dbg_ntype(type), len);
	dbg_io("LEB %d:%d, %s, length %d, jhead %d", lnum, offs,
	       dbg_ntype(type), len, 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);
@@ -819,13 +823,12 @@ int ubifs_read_node(const struct ubifs_info *c, void *buf, int type, int len,
 * @c: UBIFS file-system description object
 * @wbuf: write-buffer to initialize
 *
 * This function initializes write buffer. Returns zero in case of success
 * This function initializes write-buffer. Returns zero in case of success
 * %-ENOMEM in case of failure.
 */
int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf)
{
	size_t size;
	ktime_t hardlimit;

	wbuf->buf = kmalloc(c->min_io_size, GFP_KERNEL);
	if (!wbuf->buf)
@@ -851,16 +854,10 @@ int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf)

	hrtimer_init(&wbuf->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
	wbuf->timer.function = wbuf_timer_callback_nolock;
	/*
	 * Make write-buffer soft limit to be 20% of the hard limit. The
	 * write-buffer timer is allowed to expire any time between the soft
	 * and hard limits.
	 */
	hardlimit = ktime_set(DEFAULT_WBUF_TIMEOUT_SECS, 0);
	wbuf->delta = (DEFAULT_WBUF_TIMEOUT_SECS * NSEC_PER_SEC) * 2 / 10;
	wbuf->softlimit = ktime_sub_ns(hardlimit, wbuf->delta);
	hrtimer_set_expires_range_ns(&wbuf->timer,  wbuf->softlimit,
				     wbuf->delta);
	wbuf->softlimit = ktime_set(WBUF_TIMEOUT_SOFTLIMIT, 0);
	wbuf->delta = WBUF_TIMEOUT_HARDLIMIT - WBUF_TIMEOUT_SOFTLIMIT;
	wbuf->delta *= 1000000000ULL;
	ubifs_assert(wbuf->delta <= ULONG_MAX);
	return 0;
}

+33 −24
Original line number Diff line number Diff line
@@ -52,6 +52,25 @@ static int is_empty(void *buf, int len)
	return 1;
}

/**
 * first_non_ff - find offset of the first non-0xff byte.
 * @buf: buffer to search in
 * @len: length of buffer
 *
 * This function returns offset of the first non-0xff byte in @buf or %-1 if
 * the buffer contains only 0xff bytes.
 */
static int first_non_ff(void *buf, int len)
{
	uint8_t *p = buf;
	int i;

	for (i = 0; i < len; i++)
		if (*p++ != 0xff)
			return i;
	return -1;
}

/**
 * get_master_node - get the last valid master node allowing for corruption.
 * @c: UBIFS file-system description object
@@ -357,11 +376,7 @@ static int is_last_write(const struct ubifs_info *c, void *buf, int offs)
	empty_offs = ALIGN(offs + 1, c->min_io_size);
	check_len = c->leb_size - empty_offs;
	p = buf + empty_offs - offs;

	for (; check_len > 0; check_len--)
		if (*p++ != 0xff)
			return 0;
	return 1;
	return is_empty(p, check_len);
}

/**
@@ -543,8 +558,8 @@ static int drop_incomplete_group(struct ubifs_scan_leb *sleb, int *offs)
 *
 * This function does a scan of a LEB, but caters for errors that might have
 * been caused by the unclean unmount from which we are attempting to recover.
 *
 * This function returns %0 on success and a negative error code on failure.
 * Returns %0 in case of success, %-EUCLEAN if an unrecoverable corruption is
 * found, and a negative error code in case of failure.
 */
struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
					 int offs, void *sbuf, int grouped)
@@ -643,7 +658,8 @@ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
			goto corrupted;
		default:
			dbg_err("unknown");
			goto corrupted;
			err = -EINVAL;
			goto error;
		}
	}

@@ -652,8 +668,13 @@ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
			clean_buf(c, &buf, lnum, &offs, &len);
			need_clean = 1;
		} else {
			ubifs_err("corrupt empty space at LEB %d:%d",
				  lnum, offs);
			int corruption = first_non_ff(buf, len);

			ubifs_err("corrupt empty space LEB %d:%d, corruption "
				  "starts at %d", lnum, offs, corruption);
			/* Make sure we dump interesting non-0xFF data */
			offs = corruption;
			buf += corruption;
			goto corrupted;
		}
	}
@@ -813,7 +834,7 @@ struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum,
static int recover_head(const struct ubifs_info *c, int lnum, int offs,
			void *sbuf)
{
	int len, err, need_clean = 0;
	int len, err;

	if (c->min_io_size > 1)
		len = c->min_io_size;
@@ -827,19 +848,7 @@ static int recover_head(const struct ubifs_info *c, int lnum, int offs,

	/* Read at the head location and check it is empty flash */
	err = ubi_read(c->ubi, lnum, sbuf, offs, len);
	if (err)
		need_clean = 1;
	else {
		uint8_t *p = sbuf;

		while (len--)
			if (*p++ != 0xff) {
				need_clean = 1;
				break;
			}
	}

	if (need_clean) {
	if (err || !is_empty(sbuf, len)) {
		dbg_rcvry("cleaning head at %d:%d", lnum, offs);
		if (offs == 0)
			return ubifs_leb_unmap(c, lnum);
+5 −4
Original line number Diff line number Diff line
@@ -838,7 +838,8 @@ static int replay_log_leb(struct ubifs_info *c, int lnum, int offs, void *sbuf)
	dbg_mnt("replay log LEB %d:%d", lnum, offs);
	sleb = ubifs_scan(c, lnum, offs, sbuf);
	if (IS_ERR(sleb) ) {
		if (c->need_recovery)
		if (PTR_ERR(sleb) != -EUCLEAN || !c->need_recovery)
			return PTR_ERR(sleb);
		sleb = ubifs_recover_log_leb(c, lnum, offs, sbuf);
		if (IS_ERR(sleb))
			return PTR_ERR(sleb);
@@ -957,7 +958,7 @@ static int replay_log_leb(struct ubifs_info *c, int lnum, int offs, void *sbuf)
	return err;

out_dump:
	ubifs_err("log error detected while replying the log at LEB %d:%d",
	ubifs_err("log error detected while replaying the log at LEB %d:%d",
		  lnum, offs + snod->offs);
	dbg_dump_node(c, snod->node);
	ubifs_scan_destroy(sleb);
+12 −8
Original line number Diff line number Diff line
@@ -238,12 +238,12 @@ void ubifs_scanned_corruption(const struct ubifs_info *c, int lnum, int offs,
{
	int len;

	ubifs_err("corrupted data at LEB %d:%d", lnum, offs);
	ubifs_err("corruption at LEB %d:%d", lnum, offs);
	if (dbg_failure_mode)
		return;
	len = c->leb_size - offs;
	if (len > 4096)
		len = 4096;
	if (len > 8192)
		len = 8192;
	dbg_err("first %d bytes from LEB %d:%d", len, lnum, offs);
	print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 4, buf, len, 1);
}
@@ -256,7 +256,9 @@ void ubifs_scanned_corruption(const struct ubifs_info *c, int lnum, int offs,
 * @sbuf: scan buffer (must be c->leb_size)
 *
 * This function scans LEB number @lnum and returns complete information about
 * its contents. Returns an error code in case of failure.
 * its contents. Returns the scaned information in case of success and,
 * %-EUCLEAN if the LEB neads recovery, and other negative error codes in case
 * of failure.
 */
struct ubifs_scan_leb *ubifs_scan(const struct ubifs_info *c, int lnum,
				  int offs, void *sbuf)
@@ -279,7 +281,6 @@ struct ubifs_scan_leb *ubifs_scan(const struct ubifs_info *c, int lnum,
		cond_resched();

		ret = ubifs_scan_a_node(c, buf, len, lnum, offs, 0);

		if (ret > 0) {
			/* Padding bytes or a valid padding node */
			offs += ret;
@@ -304,7 +305,8 @@ struct ubifs_scan_leb *ubifs_scan(const struct ubifs_info *c, int lnum,
			goto corrupted;
		default:
			dbg_err("unknown");
			goto corrupted;
			err = -EINVAL;
			goto error;
		}

		err = ubifs_add_snod(c, sleb, buf, offs);
@@ -317,8 +319,10 @@ struct ubifs_scan_leb *ubifs_scan(const struct ubifs_info *c, int lnum,
		len -= node_len;
	}

	if (offs % c->min_io_size)
		goto corrupted;
	if (offs % c->min_io_size) {
		ubifs_err("empty space starts at non-aligned offset %d", offs);
		goto corrupted;;
	}

	ubifs_end_scan(c, sleb, lnum, offs);

Loading