All of lore.kernel.org
 help / color / mirror / Atom feed
From: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
To: Yury Norov <yury.norov@gmail.com>
Cc: Andrew Morton <akpm@linux-foundation.org>,
	Rasmus Villemoes <linux@rasmusvillemoes.dk>,
	Arnd Bergmann <arnd@arndb.de>, Kees Cook <keescook@chromium.org>,
	Matthew Wilcox <willy@infradead.org>,
	Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>,
	Yury Norov <ynorov@marvell.com>,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH 3/6] bitmap_parselist: rework input string parser
Date: Tue, 26 Mar 2019 12:10:45 +0200	[thread overview]
Message-ID: <20190326101045.GT9224@smile.fi.intel.com> (raw)
In-Reply-To: <20190325210748.6571-4-ynorov@marvell.com>

On Tue, Mar 26, 2019 at 12:07:45AM +0300, Yury Norov wrote:
> The requirement for this rework is to keep the __bitmap_parselist()
> copy-less and single-pass but make it more readable and maintainable by
> splitting into logical parts and removing explicit nested cycles and
> opaque local variables.
> 
> __bitmap_parselist() can parse userspace inputs and therefore we cannot
> use simple_strtoul() to parse numbers.

> +static long get_char(char *c, const char *str, int is_user)
> +{
> +	if (unlikely(is_user))

Can is_user be boolean?

Can we name it from_user or is_from_user?

> +		return __get_user(*c, (const char __force __user *)str);
> +
> +	*c = *str;
> +	return 0;
> +}
> +
> +static const char *bitmap_getnum(unsigned int *num, const char *str,
> +			    const char *const end, int is_user)
> +{
> +	unsigned int n = 0;
> +	const char *_str;
> +	long ret;
> +	char c;
> +

> +	for (_str = str, *num = 0; _str <= end; _str++) {
> +		ret = get_char(&c, _str, is_user);
> +		if (ret)
> +			return ERR_PTR(ret);
> +
> +		if (!isdigit(c)) {
> +			if (_str == str)
> +				return ERR_PTR(-EINVAL);
> +
> +			return _str;
> +		}
> +
> +		*num = *num * 10 + (c - '0');
> +		if (*num < n)
> +			return ERR_PTR(-EOVERFLOW);
> +
> +		n = *num;
> +	}

Can't we do other way around, i.e. move the loop body to a helper and do
	something like this:

if (is_from_user) {
	for (...) {
		__get_user(...);
		helper1();
		helper2();
	}
} else {
	for (...) {
		*c = *str;
		helper1();
		helper2()
	}
}

Each branch can be optimized more I think.

> +
> +	return _str;
> +}
> +
> +static const char *bitmap_find_region(const char *str,
> +			const char *const end, int is_user)
> +{
> +	long ret;
> +	char c;
> +
> +	for (; str <= end; str++) {
> +		ret = get_char(&c, str, is_user);
> +		if (ret)
> +			return ERR_PTR(ret);
> +
> +		/* Unexpected end of line. */
> +		if (c == 0 || c == '\n')
> +			return NULL;
> +
> +		/*
> +		 * The format allows commas and whitespases
> +		 * at the beginning of the region, so skip it.
> +		 */
> +		if (!isspace(c) && c != ',')
> +			break;
> +	}
> +
> +	return str <= end ? str : NULL;
> +}
> +
> +static const char *bitmap_parse_region(struct region *r, const char *str,
> +				 const char *const end, int is_user)
> +{
> +	long ret;
> +	char c;
> +
> +	str = bitmap_getnum(&r->start, str, end, is_user);
> +	if (IS_ERR(str))
> +		return str;
> +
> +	ret = get_char(&c, str, is_user);
> +	if (ret)
> +		return (char *)ret;
> +
> +	if (c == 0 || c == '\n') {
> +		str = end + 1;
> +		goto no_end;
> +	}
> +
> +	if (isspace(c) || c == ',')
> +		goto no_end;
> +
> +	if (c != '-')
> +		return ERR_PTR(-EINVAL);
> +
> +	str = bitmap_getnum(&r->end, str + 1, end, is_user);
> +	if (IS_ERR(str))
> +		return str;
> +
> +	ret = get_char(&c, str, is_user);
> +	if (ret)
> +		return ERR_PTR(ret);
> +
> +	if (c == 0 || c == '\n') {
> +		str = end + 1;
> +		goto no_pattern;
> +	}
> +
> +	if (isspace(c) || c == ',')
> +		goto no_pattern;
> +
> +	if (c != ':')
> +		return ERR_PTR(-EINVAL);
> +
> +	str = bitmap_getnum(&r->off, str + 1, end, is_user);
> +	if (IS_ERR(str))
> +		return str;
> +
> +	ret = get_char(&c, str, is_user);
> +	if (ret)
> +		return (char *)ret;
> +
> +	if (c != '/')
> +		return ERR_PTR(-EINVAL);
> +

> +	str = bitmap_getnum(&r->grlen, str + 1, end, is_user);
> +
> +	return str;

return bitmap_getnum(...);

> +
> +no_end:
> +	r->end = r->start;
> +no_pattern:
> +	r->off = r->end + 1;
> +	r->grlen = r->end + 1;
> +
> +	return str;
> +}
> +

So, all above depends to what memory we access kernel / user space.
Perhaps we can get copy of memory of a given size and then parse it in kernel space always?

-- 
With Best Regards,
Andy Shevchenko



  reply	other threads:[~2019-03-26 10:10 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-03-25 21:07 [PATCH v2 RESEND 0/6] lib: rework bitmap_parselist and tests Yury Norov
2019-03-25 21:07 ` [PATCH 1/6] bitmap_parselist: don't calculate length of the input string Yury Norov
2019-03-26 10:09   ` Andy Shevchenko
2019-03-25 21:07 ` [PATCH 2/6] bitmap_parselist: move non-parser logic to helpers Yury Norov
2019-03-25 21:54   ` Andrew Morton
2019-03-25 21:07 ` [PATCH 3/6] bitmap_parselist: rework input string parser Yury Norov
2019-03-26 10:10   ` Andy Shevchenko [this message]
2019-03-26 21:09     ` Yuri Norov
2019-03-26 21:58       ` Mike Travis
2019-03-25 21:07 ` [PATCH 4/6] lib/test_bitmap: switch test_bitmap_parselist to ktime_get() Yury Norov
2019-03-25 21:07 ` [PATCH 5/6] lib/test_bitmap: add testcases for bitmap_parselist Yury Norov
2019-03-25 21:07 ` [PATCH 6/6] lib/test_bitmap: add tests for bitmap_parselist_user Yury Norov
2019-03-26 10:12   ` Andy Shevchenko
  -- strict thread matches above, loose matches on Subject: below --
2019-02-20  8:36 [PATCH v2 0/5] lib: rework bitmap_parselist and tests Yury Norov
2019-02-20  8:37 ` [PATCH 3/6] bitmap_parselist: rework input string parser Yury Norov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190326101045.GT9224@smile.fi.intel.com \
    --to=andriy.shevchenko@linux.intel.com \
    --cc=akpm@linux-foundation.org \
    --cc=arnd@arndb.de \
    --cc=keescook@chromium.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux@rasmusvillemoes.dk \
    --cc=penguin-kernel@I-love.SAKURA.ne.jp \
    --cc=willy@infradead.org \
    --cc=ynorov@marvell.com \
    --cc=yury.norov@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.