Consecutive calls to printk are non-atomic, which leads to various
implementations for accumulating strings which can be printed in one call.
This is a generic string buffer which can also be used for non-printk
purposes. There is no sb_scanf implementation yet as I haven't identified
a user for it.Signed-off-by: Matthew Wilcox <willy@linux.intel.com>
---
include/linux/stringbuf.h | 85 +++++++++++++++++++++++++++++++++++++++++++++
lib/Makefile | 2 +-
lib/stringbuf.c | 79 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 165 insertions(+), 1 deletions(-)
create mode 100644 include/linux/stringbuf.h
create mode 100644 lib/stringbuf.cdiff --git a/include/linux/stringbuf.h b/include/linux/stringbuf.h
new file mode 100644
index 0000000..f9200fe
--- /dev/null
+++ b/include/linux/stringbuf.h
@@ -0,0 +1,85 @@
+/*
+ * An auto-expanding string buffer. There's no sb_alloc because you really
+ * want to allocate it on the stack or embed it in another structure.
+ *
+ * Please don't access the elements directly; that will give us the chance
+ * to change the implementation later if necessary.
+ *
+ * No locking is performed, although memory allocation is done with
+ * GFP_ATOMIC to allow it to be called when you're holding a lock.
+ */
+
+#include <stdarg.h>
+#include <linux/string.h>
+
+struct stringbuf {
+ char *s;
+ int alloc;
+ int len;
+};
+
+/*
+ * Returns the current length of the string. Note that more memory
+ * may have been allocated for the string than this.
+ */
+static inline int sb_len(struct stringbuf *sb)
+{
+ return sb->len;
+}
+
+/*
+ * Returns a negative errno if an error has been found with this stringbuf,
+ * or 0 if no error has occurred. If an error has occurred, sb_string()
+ * returns a suitable description of the error
+ */
+static inline int sb_error(struct stringbuf *sb)
+{
+ return sb->alloc < 0 ? sb->alloc : 0;
+}
+
+/*
+ * Initialise a newly-allocated s...
I am not sure inlining these functions is a win.
--
vda
-
GFP_ATOMIC alloca5tion there is bad news. It can randomly fail.....
without good method of handling that in caller.Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
-
Hi,
How about putting ->gfp_flags to struct stringbuf and initializing
that in sb_init() instead of hard-coding to GFP_ATOMIC here?Btw, the "sb" abbrevation is already used for "superblock". Perhaps we
could use "str" for these?Pekka
-
I think alloc and len should be unsigned (including some return values
in the remaining patch).
-
I don't. Strings should never be as long as 2GB. To put this in
perspective, the *entire* Encyclopaedia Britannica (all 32 volumes)
is estimated at being 1GB of text.While it would be a fair criticism that I haven't put a check for
overrunning 2GB in the code, the implementation relies on a single
continuous buffer from kmalloc, and that's currently limited to 33554432
bytes (32MB). I don't foresee kmalloc's maximum size going up by 7
orders of magnitude -- and if it did, fragmentation would prevent you
from ever getting it.So, I might consider a change to set -E2BIG instead of -ENOMEM if we
pass KMALLOC_MAX_SIZE, but I do think this criticism is rather straining
at gnats.Also, 'alloc' can be an errno, and that is signalled by a negative number.
Yes, we could do something like if (sb->alloc > (unsigned)-4095) like
the mmap code does, but given the points above, it's just not worth doing.--
Intel are signing my paycheques ... these opinions are still mine
"Bill, look, we understand that you're interested in selling us this
operating system, but compare it to ours. We can't possibly take such
a retrograde step."
-
CoW isn't in the slightest bit helpful. The point of these is to
provide an accumulator, therefore the majority of accesses to theseIf we were trying to get rid of char * throughout the kernel, that might
I think you missed the part of the patch where I said that the stringbuf
is normally allocated on the stack or as part of some other structure.
The only thing that should be allocated is the string itself.--
Intel are signing my paycheques ... these opinions are still mine
"Bill, look, we understand that you're interested in selling us this
operating system, but compare it to ours. We can't possibly take such
a retrograde step."
-
On Tue, 2007-10-23 at 20:35 -0600, Matthew Wilcox wrote:
[...]
No contest, my suggestions only make sense for a general uses string
library.I suspect most in-kernel string manipulations are limited to prepare
buffers to be copied to (and read from) user-space.- Eric
-
Hmm. Have you looked at the git "strbuf" code?
And stuff like "sb_string()" are just evil. The string is there. Just call
it something better than "s", and let people just use "sb->buf" or
something. Why make the interface harder to use than necessary?Linus
-
I hadn't. It's quite spookily similar in some ways. There's a lot of
things you've added because you presumably have use for them in git that
could easily be added once we had users for them in the kernel. There's
a few things stringbufs do that strbufs don't need to because they're in
userspace.I can easily change the API at this point, so if renaming things will
It's a matter of taste ... some people prefer to use accessors for
everything, other people prefer to expose the underlying structure
directly. I have to confess to being influenced by Java in 1998-99,
so possibly I tend to go for accessors too often. Or possibly it's
just my experience of restructuring things in Linux where diffs would
be smaller if we only had used accessors for something. In any case,
I don't care to fight about this; if you want it to be called buf,
then buf it shall be called, and I'll get rid of sb_string.--
Intel are signing my paycheques ... these opinions are still mine
"Bill, look, we understand that you're interested in selling us this
operating system, but compare it to ours. We can't possibly take such
a retrograde step."
-
Experience tells us that when you use accessors you end up thanking
yourself later on. Especially when diddling struct page ;)Although one really should make a best-effort guess at "how likely is
this to change in the future". If the implementation-to-be-copied
has been out there for a while then "not very" is a good answer.But hey, don't listen to me - I like C++, and approve of Java.
-
I don't know if copy-on-write semantics are really useful for current
in-kernel uses, but I've coded and used a C++ string class like this in
the past:struct string_data
{
int nrefs;
unsigned len;
unsigned capacity;
//char data[capacity]; /* allocated along string_data */
};struct string /* or typedef in C... */
{
struct string *data;
};[ struct string_data is a hidden implementation detail, only struct
string is exposed ]Multiple string objects can share the same data, by increasing the nrefs
count, a new data is allocated if the string is modified and nrefs > 1.Not having to iterate over the string to calculate it's length,
allocating a larger buffer to eliminate re-allocation and copy-on-write
semantics make a string like this a vast performance improvement over a
normal C string for a minimal (about 3 ints per data buffer) memory
cost.By using it correctly it can prevents buffer overflows.
You still always null terminate the string stored in data to directly
use it a normal C string.You also statically allocate an empty string which is shared by all
"uninitialized" or empty strings.Even without copy-on-write semantics and reference counting, I think
this approach is better because it uses 1 less "object" and allocation:struct string - "handle" (pointer really) to string data
struct string_data - string dataversus:
struct stringbuf *sb - pointer to string object
struct stringbuf - string object
char *s (member of stringbuf) - string dataBest regards,
- Eric
-
You might want to consider growing the buffer by no less than a small
constant factor like 1.3x. This will keep things that do short concats
in a loop from degrading to O(n^2) performance due to realloc andToo small. That will guarantee that most users end up doing a realloc.
Can we have 128 instead?--
Mathematics is the supreme nostalgia of our time.
-
I looked at slab and slub, and would grow the buffer by no less than
1.5x each time, thanks to the buckets. I'd initially implemented 2x,
but switched to allocating size+1 and calling ksize() as being a more
efficient implementation.I presume slob is different? Actually, slob doesn't seem to
provide krealloc, so I think stringbuf won't work on slob. Will youHrm.
extern void sb_printf(struct stringbuf *sb, gfp_t gfp, const char *fmt, ...)
__attribute__((format(printf, 3, 4)));I don't care. Sure!
--
Intel are signing my paycheques ... these opinions are still mine
"Bill, look, we understand that you're interested in selling us this
operating system, but compare it to ours. We can't possibly take such
a retrograde step."
-
http://lxr.linux.no/source/mm/slob.c#L207
Most of these objects will have very short lifetimes, so there's very
little downside.--
Mathematics is the supreme nostalgia of our time.
-
That's 2.6.22.6; I was looking at 2.6.23, where clameter had moved
krealloc into mm/util.c. So that explains why I thought slob didn'tOK. I have no problem with making stringbuf allocate max(oldsize * 1.5,
I agree. It was good for testing though, when I inadvertently wrote to
the wrong bit of the string on a realloc ;-)--
Intel are signing my paycheques ... these opinions are still mine
"Bill, look, we understand that you're interested in selling us this
operating system, but compare it to ours. We can't possibly take such
a retrograde step."
-
Get rid of the _cdebbuf structure that was used to accumulate strings
for a debug printk and use the stringbuf instead. Allocate the stringbuf
on the stack instead of with kmalloc. Return a char * to the callers
rather than a stringbuf.Signed-off-by: Matthew Wilcox <willy@linux.intel.com>
---
drivers/isdn/capi/capidrv.c | 18 ++--
drivers/isdn/capi/capiutil.c | 220 ++++++++++-------------------------------
drivers/isdn/capi/kcapi.c | 35 +++----
include/linux/isdn/capiutil.h | 16 +---
4 files changed, 83 insertions(+), 206 deletions(-)diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c
index 476012b..ba6645c 100644
--- a/drivers/isdn/capi/capidrv.c
+++ b/drivers/isdn/capi/capidrv.c
@@ -995,7 +995,7 @@ static void handle_plci(_cmsg * cmsg)
capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
capidrv_plci *plcip;
isdn_ctrl cmd;
- _cdebbuf *cdb;
+ char *s;if (!card) {
printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
@@ -1128,11 +1128,11 @@ static void handle_plci(_cmsg * cmsg)
break;
}
}
- cdb = capi_cmsg2str(cmsg);
- if (cdb) {
+ s = capi_cmsg2str(cmsg);
+ if (s) {
printk(KERN_WARNING "capidrv-%d: %s\n",
- card->contrnr, cdb->buf);
- cdebbuf_free(cdb);
+ card->contrnr, s);
+ kfree(s);
} else
printk(KERN_WARNING "capidrv-%d: CAPI_INFO_IND InfoNumber %x not handled\n",
card->contrnr, cmsg->InfoNumber);
@@ -1385,12 +1385,12 @@ static void capidrv_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
{
capi_message2cmsg(&s_cmsg, skb->data);
if (debugmode > 3) {
- _cdebbuf *cdb = capi_cmsg2str(&s_cmsg);
+ char *s = capi_cmsg2str(&s_cmsg);- if (cdb) {
+ if (s) {
printk(KERN_DEBUG "%s: applid=%d %s\n", __FUNCTION__,
- ap->applid, cdb->buf);
- cdebbuf_free(cdb);
+ ap->applid, s);
+ kfree(s);
} else
printk(KERN_DEBUG "%s: applid=%d %s not traced\n",...
sound/ had its own snd_info_buffer for doing proc reads, which can be
profitably replaced with stringbuf. It actually finds a bug since ->read
and ->write now have a different signature.Signed-off-by: Matthew Wilcox <willy@linux.intel.com>
---
include/sound/info.h | 7 ++-
sound/core/hwdep.c | 2 +-
sound/core/info.c | 81 +++++--------------------------
sound/core/info_oss.c | 6 +-
sound/core/init.c | 8 ++--
sound/core/oss/mixer_oss.c | 2 +-
sound/core/oss/pcm_oss.c | 2 +-
sound/core/pcm.c | 16 +++---
sound/core/pcm_memory.c | 4 +-
sound/core/rawmidi.c | 2 +-
sound/core/seq/oss/seq_oss.c | 2 +-
sound/core/seq/oss/seq_oss_device.h | 8 ++--
sound/core/seq/oss/seq_oss_init.c | 2 +-
sound/core/seq/oss/seq_oss_midi.c | 2 +-
sound/core/seq/oss/seq_oss_readq.c | 2 +-
sound/core/seq/oss/seq_oss_synth.c | 2 +-
sound/core/seq/seq_clientmgr.c | 8 ++--
sound/core/seq/seq_device.c | 2 +-
sound/core/seq/seq_info.c | 2 +-
sound/core/seq/seq_info.h | 6 +-
sound/core/seq/seq_memory.c | 2 +-
sound/core/seq/seq_queue.c | 2 +-
sound/core/seq/seq_timer.c | 2 +-
sound/core/sound.c | 2 +-
sound/core/sound_oss.c | 2 +-
sound/core/timer.c | 2 +-
sound/drivers/vx/vx_core.c | 2 +-
sound/i2c/l3/uda1341.c | 4 +-
sound/isa/ad1848/ad1848_lib.c | 2 +-
sound/isa/gus/gus_irq.c | 2 +-
sound/isa/gus/gus_mem.c | 4 +-
sound/isa/opti9xx/miro.c | 2 +-
sound/isa/sb/sb16_csp.c | 4 +-
sound/pci/ac97/ac97_proc.c...
At Tue, 23 Oct 2007 17:12:45 -0400,
Do you mean the assignment of snd_ca0106_proc_reg_write?
I also found it out today coindentally :)This shouldn't be changed.
thanks,
Takashi
-
I was referring to this hunk, so yes:
@@ -448,10 +448,9 @@ int __devinit snd_ca0106_proc_init(struct snd_ca0106 * emu)
// entry->private_data = emu;
}
if(! snd_card_proc_new(emu->card, "ca0106_i2c", &entry)) {
- snd_info_set_text_ops(entry, emu, snd_ca0106_proc_i2c_write);
+ entry->private_data = emu;
entry->c.text.write = snd_ca0106_proc_i2c_write;
entry->mode |= S_IWUSR;
-// entry->private_data = emu;
}
if(! snd_card_proc_new(emu->card, "ca0106_regs2", &entry))Let me try to find them ... there was this warning fix:
diff --git a/sound/isa/ad1848/ad1848_lib.c b/sound/isa/ad1848/ad1848_lib.c
index a901cd1..9a64035 100644
--- a/sound/isa/ad1848/ad1848_lib.c
+++ b/sound/isa/ad1848/ad1848_lib.c
@@ -213,7 +213,7 @@ static void snd_ad1848_mce_down(struct snd_ad1848 *chip)
for (timeout = 12000; timeout > 0 && (inb(AD1848P(chip, REGSEL)) & AD184
8_INIT); timeout--)
udelay(100);- snd_printdd("(1) timeout = %d\n", timeout);
+ snd_printdd("(1) timeout = %ld\n", timeout);#ifdef CONFIG_SND_DEBUG
if (inb(AD1848P(chip, REGSEL)) & AD1848_INIT)Quite right, sorry about that, will omit it from the next round.
--
Intel are signing my paycheques ... these opinions are still mine
"Bill, look, we understand that you're interested in selling us this
operating system, but compare it to ours. We can't possibly take such
a retrograde step."
-
At Wed, 24 Oct 2007 10:01:05 -0600,
OK, thanks. I fixed it on ALSA tree now.
Takashi
-
With asynchronous disk scanning, it's quite common for the partition
report to be interrupted by reports of other discs being discovered.
Use a new function, print_partition, to accumulate the partitions into
a stringbuf.Signed-off-by: Matthew Wilcox <willy@linux.intel.com>
---
fs/partitions/acorn.c | 24 ++++++++++--------------
fs/partitions/amiga.c | 9 ++++-----
fs/partitions/atari.c | 20 +++++++++-----------
fs/partitions/check.c | 19 ++++++++++++++-----
fs/partitions/check.h | 6 +++++-
fs/partitions/efi.c | 1 -
fs/partitions/ibm.c | 11 +++++------
fs/partitions/karma.c | 1 -
fs/partitions/ldm.c | 11 +++++------
fs/partitions/mac.c | 3 +--
fs/partitions/msdos.c | 36 +++++++++++++++++-------------------
fs/partitions/osf.c | 1 -
fs/partitions/sgi.c | 1 -
fs/partitions/sun.c | 1 -
fs/partitions/sysv68.c | 5 ++---
fs/partitions/ultrix.c | 1 -
16 files changed, 72 insertions(+), 78 deletions(-)diff --git a/fs/partitions/acorn.c b/fs/partitions/acorn.c
index 3d3e166..7ece065 100644
--- a/fs/partitions/acorn.c
+++ b/fs/partitions/acorn.c
@@ -46,7 +46,7 @@ adfs_partition(struct parsed_partitions *state, char *name, char *data,
(le32_to_cpu(dr->disc_size) >> 9);if (name)
- printk(" [%s]", name);
+ print_partition(state, " [%s]", name);
put_partition(state, slot, first_sector, nr_sects);
return dr;
}
@@ -81,14 +81,14 @@ riscix_partition(struct parsed_partitions *state, struct block_device *bdev,
if (!rr)
return -1;- printk(" [RISCiX]");
+ print_partition(state, " [RISCiX]");if (rr->magic == RISCIX_MAGIC) {
unsigned long size = nr_sects > 2 ? 2 : nr_sects;
int part;- printk(" <");
+ print_partition(state, " <");put_partition(state, slot++, first_sect, size);
for (part = 0; part < 8; part++) {
@@ -97,11 +97,11 @@ riscix_partition(struct parsed_partitions *state, struct block_device *bdev,
p...
| Greg Kroah-Hartman | [PATCH 002/196] Chinese: rephrase English introduction in HOWTO |
| Tarkan Erimer | Re: Dual-Licensing Linux Kernel with GPL V2 and GPL V3 |
| Amit K. Arora | [RFC] Heads up on sys_fallocate() |
| Linus Torvalds | Re: 2.6.25-rc2 System no longer powers off after suspend-to-disk. Screen becomes g... |
git: | |
| David Miller | [GIT]: Networking |
| Jarek Poplawski | Re: [PATCH] pkt_sched: Destroy gen estimators under rtnl_lock(). |
| Gerrit Renker | [PATCH 27/37] dccp: Integration of dynamic feature activation - part 2 (server side) |
| Ray Lee | Re: [BUG] New Kernel Bugs |
