* [PATCH 1/3] regmap: debugfs: Avoid overflows for very small reads
@ 2012-12-10 16:25 Mark Brown
2012-12-10 16:25 ` [PATCH 2/3] regmap: debugfs: Factor out initial seek Mark Brown
2012-12-10 16:25 ` [PATCH 3/3] regmap: debugfs: Cache offsets of valid regions for dump Mark Brown
0 siblings, 2 replies; 3+ messages in thread
From: Mark Brown @ 2012-12-10 16:25 UTC (permalink / raw)
To: linux-kernel; +Cc: Mark Brown
If count is less than the size of a register then we may hit integer
wraparound when trying to move backwards to check if we're still in
the buffer. Instead move the position forwards to check if it's still
in the buffer, we are unlikely to be able to allocate a buffer
sufficiently big to overflow here.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
drivers/base/regmap/regmap-debugfs.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c
index 00fbd58..3df274e 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -93,7 +93,7 @@ static ssize_t regmap_read_debugfs(struct regmap *map, unsigned int from,
/* If we're in the region the user is trying to read */
if (p >= *ppos) {
/* ...but not beyond it */
- if (buf_pos >= count - 1 - map->debugfs_tot_len)
+ if (buf_pos + 1 + map->debugfs_tot_len >= count)
break;
/* Format the register */
--
1.7.10.4
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH 2/3] regmap: debugfs: Factor out initial seek
2012-12-10 16:25 [PATCH 1/3] regmap: debugfs: Avoid overflows for very small reads Mark Brown
@ 2012-12-10 16:25 ` Mark Brown
2012-12-10 16:25 ` [PATCH 3/3] regmap: debugfs: Cache offsets of valid regions for dump Mark Brown
1 sibling, 0 replies; 3+ messages in thread
From: Mark Brown @ 2012-12-10 16:25 UTC (permalink / raw)
To: linux-kernel; +Cc: Mark Brown
In preparation for doing things a bit more quickly than a linear scan
factor out the initial seek from the debugfs register dump.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
drivers/base/regmap/regmap-debugfs.c | 39 +++++++++++++++++++++++++++++++---
1 file changed, 36 insertions(+), 3 deletions(-)
diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c
index 3df274e..749a1dc 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -56,16 +56,46 @@ static const struct file_operations regmap_name_fops = {
.llseek = default_llseek,
};
+/*
+ * Work out where the start offset maps into register numbers, bearing
+ * in mind that we suppress hidden registers.
+ */
+static unsigned int regmap_debugfs_get_dump_start(struct regmap *map,
+ unsigned int base,
+ loff_t from,
+ loff_t *pos)
+{
+ loff_t p = *pos;
+ unsigned int i;
+
+ for (i = base; i <= map->max_register; i += map->reg_stride) {
+ if (!regmap_readable(map, i))
+ continue;
+
+ if (regmap_precious(map, i))
+ continue;
+
+ if (i >= from) {
+ *pos = p;
+ return i;
+ }
+
+ p += map->debugfs_tot_len;
+ }
+
+ return base;
+}
+
static ssize_t regmap_read_debugfs(struct regmap *map, unsigned int from,
unsigned int to, char __user *user_buf,
size_t count, loff_t *ppos)
{
size_t buf_pos = 0;
- loff_t p = 0;
+ loff_t p = *ppos;
ssize_t ret;
int i;
char *buf;
- unsigned int val;
+ unsigned int val, start_reg;
if (*ppos < 0 || !count)
return -EINVAL;
@@ -83,7 +113,10 @@ static ssize_t regmap_read_debugfs(struct regmap *map, unsigned int from,
map->debugfs_val_len + 3; /* : \n */
}
- for (i = from; i <= to; i += map->reg_stride) {
+ /* Work out which register we're starting at */
+ start_reg = regmap_debugfs_get_dump_start(map, from, *ppos, &p);
+
+ for (i = start_reg; i <= to; i += map->reg_stride) {
if (!regmap_readable(map, i))
continue;
--
1.7.10.4
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH 3/3] regmap: debugfs: Cache offsets of valid regions for dump
2012-12-10 16:25 [PATCH 1/3] regmap: debugfs: Avoid overflows for very small reads Mark Brown
2012-12-10 16:25 ` [PATCH 2/3] regmap: debugfs: Factor out initial seek Mark Brown
@ 2012-12-10 16:25 ` Mark Brown
1 sibling, 0 replies; 3+ messages in thread
From: Mark Brown @ 2012-12-10 16:25 UTC (permalink / raw)
To: linux-kernel; +Cc: Mark Brown
Avoid doing a linear scan of the entire register map for each read() of
the debugfs register dump by recording the offsets where valid registers
exist when we first read the registers file. This assumes the set of
valid registers never changes, if this is not the case invalidation of
the cache will be required.
This could be further improved for large blocks of contiguous registers
by calculating the register we will read from within the block - currently
we do a linear scan of the block. An rbtree may also be worthwhile.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
drivers/base/regmap/internal.h | 10 +++++
drivers/base/regmap/regmap-debugfs.c | 67 +++++++++++++++++++++++++++-------
2 files changed, 63 insertions(+), 14 deletions(-)
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index 7cf8c64..8580388 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -15,6 +15,7 @@
#include <linux/regmap.h>
#include <linux/fs.h>
+#include <linux/list.h>
struct regmap;
struct regcache_ops;
@@ -31,6 +32,13 @@ struct regmap_format {
unsigned int (*parse_val)(void *buf);
};
+struct regmap_debugfs_off_cache {
+ struct list_head list;
+ off_t min;
+ off_t max;
+ unsigned int base_reg;
+};
+
struct regmap {
struct mutex mutex;
spinlock_t spinlock;
@@ -52,6 +60,8 @@ struct regmap {
unsigned int debugfs_reg_len;
unsigned int debugfs_val_len;
unsigned int debugfs_tot_len;
+
+ struct list_head debugfs_off_cache;
#endif
unsigned int max_register;
diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c
index 749a1dc..07aad78 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -65,25 +65,53 @@ static unsigned int regmap_debugfs_get_dump_start(struct regmap *map,
loff_t from,
loff_t *pos)
{
- loff_t p = *pos;
- unsigned int i;
-
- for (i = base; i <= map->max_register; i += map->reg_stride) {
- if (!regmap_readable(map, i))
- continue;
-
- if (regmap_precious(map, i))
- continue;
+ struct regmap_debugfs_off_cache *c = NULL;
+ loff_t p = 0;
+ unsigned int i, ret;
+
+ /*
+ * If we don't have a cache build one so we don't have to do a
+ * linear scan each time.
+ */
+ if (list_empty(&map->debugfs_off_cache)) {
+ for (i = base; i <= map->max_register; i += map->reg_stride) {
+ /* Skip unprinted registers, closing off cache entry */
+ if (!regmap_readable(map, i) ||
+ regmap_precious(map, i)) {
+ if (c) {
+ c->max = p - 1;
+ list_add_tail(&c->list,
+ &map->debugfs_off_cache);
+ c = NULL;
+ }
+
+ continue;
+ }
+
+ /* No cache entry? Start a new one */
+ if (!c) {
+ c = kzalloc(sizeof(*c), GFP_KERNEL);
+ if (!c)
+ break;
+ c->min = p;
+ c->base_reg = i;
+ }
+
+ p += map->debugfs_tot_len;
+ }
+ }
- if (i >= from) {
- *pos = p;
- return i;
+ /* Find the relevant block */
+ list_for_each_entry(c, &map->debugfs_off_cache, list) {
+ if (*pos >= c->min && *pos <= c->max) {
+ *pos = c->min;
+ return c->base_reg;
}
- p += map->debugfs_tot_len;
+ ret = c->max;
}
- return base;
+ return ret;
}
static ssize_t regmap_read_debugfs(struct regmap *map, unsigned int from,
@@ -309,6 +337,8 @@ void regmap_debugfs_init(struct regmap *map, const char *name)
struct rb_node *next;
struct regmap_range_node *range_node;
+ INIT_LIST_HEAD(&map->debugfs_off_cache);
+
if (name) {
map->debugfs_name = kasprintf(GFP_KERNEL, "%s-%s",
dev_name(map->dev), name);
@@ -357,7 +387,16 @@ void regmap_debugfs_init(struct regmap *map, const char *name)
void regmap_debugfs_exit(struct regmap *map)
{
+ struct regmap_debugfs_off_cache *c;
+
debugfs_remove_recursive(map->debugfs);
+ while (!list_empty(&map->debugfs_off_cache)) {
+ c = list_first_entry(&map->debugfs_off_cache,
+ struct regmap_debugfs_off_cache,
+ list);
+ list_del(&c->list);
+ kfree(c);
+ }
kfree(map->debugfs_name);
}
--
1.7.10.4
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2012-12-10 16:25 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-12-10 16:25 [PATCH 1/3] regmap: debugfs: Avoid overflows for very small reads Mark Brown
2012-12-10 16:25 ` [PATCH 2/3] regmap: debugfs: Factor out initial seek Mark Brown
2012-12-10 16:25 ` [PATCH 3/3] regmap: debugfs: Cache offsets of valid regions for dump Mark Brown
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®