All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
To: Andi Kleen <andi@firstfloor.org>
Cc: linux-kernel@vger.kernel.org, ebiederm@xmission.com
Subject: Re: [PATCH] [1/11] Add rcustring ADT for RCU protected strings
Date: Mon, 21 Dec 2009 18:46:35 -0800	[thread overview]
Message-ID: <20091222024635.GA9279@linux.vnet.ibm.com> (raw)
In-Reply-To: <20091221012022.9C5C4B160D@basil.firstfloor.org>

On Mon, Dec 21, 2009 at 02:20:22AM +0100, Andi Kleen wrote:
> 
> Add a little ADT for RCU protected strings. RCU is a convenient
> way to manage modifications to read-often-write-seldom strings.
> Add some helper functions to make this more straight forward.
> 
> Used by follow-on patches to implement RCU protected sysctl strings.
> 
>  * General rules:
>  * Reader has to use rcu_read_lock() and not sleep while accessing the string,
>  * or alternatively get a copy with access_rcu_string()
>  * Writer needs an own lock against each other.
>  * Each modification should allocate a new string first and free the old
>  * one with free_rcu_string()
>  * In writers use rcu_assign_pointer to publicize the updated string to
>  * global readers.
>  * The size passed to access_rcu_string() must be the same as passed
>  * to alloc_rcu_string() and be known in advance. Don't use strlen()!
>  *
>  * For sysctls also see proc_rcu_string() as a convenient wrapper

Looks very interesting, possibly extremely useful!

I do have a couple of questions below, one a debugging suggestion, and
the other either a bug or extreme confusion on my part.

							Thanx, Paul

> Cc: paulmck@linux.vnet.ibm.com
> Signed-off-by: Andi Kleen <ak@linux.intel.com>
> 
> ---
>  include/linux/rcustring.h |   20 ++++++++
>  lib/Makefile              |    3 -
>  lib/rcustring.c           |  112 ++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 134 insertions(+), 1 deletion(-)
> 
> Index: linux-2.6.33-rc1-ak/include/linux/rcustring.h
> ===================================================================
> --- /dev/null
> +++ linux-2.6.33-rc1-ak/include/linux/rcustring.h
> @@ -0,0 +1,20 @@
> +#ifndef _RCUSTRING_H
> +#define _RCUSTRING_H 1
> +
> +#include <linux/gfp.h>
> +#include <linux/rcupdate.h>
> +
> +/*
> + * Simple wrapper to manage strings by RCU.
> + */
> +
> +extern char *alloc_rcu_string(int size, gfp_t gfp);
> +extern void free_rcu_string(const char *string);
> +
> +/*
> + * size must be the same as alloc_rcu_string, don't
> + * use strlen on str!
> + */
> +extern char *access_rcu_string(const char *str, int size, gfp_t gfp);
> +
> +#endif
> Index: linux-2.6.33-rc1-ak/lib/rcustring.c
> ===================================================================
> --- /dev/null
> +++ linux-2.6.33-rc1-ak/lib/rcustring.c
> @@ -0,0 +1,112 @@
> +/*
> + * Manage strings by Read-Copy-Update. This is useful for global strings
> + * that change only very rarely, but are read often.
> + *
> + * Author: Andi Kleen
> + *
> + * General rules:
> + * Reader has to use rcu_read_lock() and not sleep while accessing the string,
> + * or alternatively get a copy with access_rcu_string()
> + * Writer needs an own lock against each other.
> + * Each modification should allocate a new string first and free the old
> + * one with free_rcu_string()
> + * In writers use rcu_assign_pointer to publicize the updated string to
> + * global readers.
> + * The size passed to access_rcu_string() must be the same as passed
> + * to alloc_rcu_string() and be known in advance. Don't use strlen()!
> + *
> + * For sysctls also see proc_rcu_string() as a convenient wrapper
> + *
> + * Typical example:
> + * #define MAX_GLOBAL_SIZE ...
> + * char *global = "default";
> + *
> + * Rare writer:
> + * char *old, *new;
> + * DECLARE_MUTEX(writer_lock);
> + * mutex_lock(&writer_lock);
> + * new = alloc_rcu_string(MAX_GLOBAL_SIZE, GFP_KERNEL);
> + * if (!new) {
> + *      mutex_unlock(&writer_lock);
> + *      return -ENOMEM;
> + * }
> + * strlcpy(new, new_value, MAX_GLOBAL_SIZE);
> + * old = global;
> + * rcu_assign_pointer(global, new);
> + * mutex_unlock(&writer_lock);
> + * free_rcu_string(old);
> + *
> + * Sleepy reader:
> + * char *str = access_rcu_string(global, MAX_GLOBAL_SIZE, GFP_KERNEL);
> + * if (!str)
> + *     return -ENOMEM;
> + * ... use str while sleeping ...
> + * kfree(string);
> + *
> + * Non sleepy reader:
> + * rcu_read_lock();
> + * ... read str ...
> + * rcu_read_unlock();
> + *
> + * Note this code could be relatively easily generalized for other kinds
> + * of non-atomic data, but this initial version only handles strings.
> + * Only need to change the strlcpy() below to memcpy()
> + */
> +#include <linux/kernel.h>
> +#include <linux/rcustring.h>
> +#include <linux/slab.h>
> +#include <linux/rcupdate.h>
> +#include <linux/module.h>
> +#include <linux/string.h>
> +
> +struct rcu_string {
> +	struct rcu_head rcu;
> +	char str[0];

My guess is that you will sooner or later need a size field, perhaps
under some debug config parameter.

> +};
> +
> +char *alloc_rcu_string(int size, gfp_t gfp)
> +{
> +	struct rcu_string *rs = kmalloc(sizeof(struct rcu_string) + size, gfp);
> +	if (!rs)
> +		return NULL;
> +	return rs->str;
> +}
> +EXPORT_SYMBOL(alloc_rcu_string);
> +
> +static void do_free_rcu_string(struct rcu_head *h)
> +{
> +	kfree(container_of(h, struct rcu_string, rcu));
> +}
> +
> +static inline struct rcu_string *str_to_rcustr(const char *str)
> +{
> +	/*
> +	 * Opencoded container_of because the strict type checking
> +	 * in normal container_of cannot deal with char str[0] vs char *str.
> +	 */
> +	return (struct rcu_string *)(str - offsetof(struct rcu_string, str));
> +}
> +
> +void free_rcu_string(const char *str)
> +{
> +	struct rcu_string *rs = str_to_rcustr(str);
> +	call_rcu(&rs->rcu, do_free_rcu_string);
> +}
> +EXPORT_SYMBOL(free_rcu_string);
> +
> +/*
> + * Get a local private copy of a RCU protected string.
> + * Mostly useful to get a string that is stable while sleeping.
> + * Caller must free returned string.
> + */
> +char *access_rcu_string(const char *str, int size, gfp_t gfp)
> +{
> +	char *copy = kmalloc(size, gfp);
> +	if (!str)
> +		return NULL;

Assuming that "str" points to the "str" field of a struct rcu_string,
what prevents a grace period from elapsing at this point, freeing the
"str" out from under us?

> +	rcu_read_lock();
> +	strlcpy(copy, str, size);
> +	rcu_read_unlock();
> +	return copy;
> +}
> +EXPORT_SYMBOL(access_rcu_string);
> Index: linux-2.6.33-rc1-ak/lib/Makefile
> ===================================================================
> --- linux-2.6.33-rc1-ak.orig/lib/Makefile
> +++ linux-2.6.33-rc1-ak/lib/Makefile
> @@ -12,7 +12,8 @@ lib-y := ctype.o string.o vsprintf.o cmd
>  	 idr.o int_sqrt.o extable.o prio_tree.o \
>  	 sha1.o irq_regs.o reciprocal_div.o argv_split.o \
>  	 proportions.o prio_heap.o ratelimit.o show_mem.o \
> -	 is_single_threaded.o plist.o decompress.o flex_array.o
> +	 is_single_threaded.o plist.o decompress.o flex_array.o \
> +	 rcustring.o
> 
>  lib-$(CONFIG_MMU) += ioremap.o
>  lib-$(CONFIG_SMP) += cpumask.o
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

  reply	other threads:[~2009-12-22  2:46 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-12-21  1:20 [PATCH] [0/11] SYSCTL: Use RCU to avoid races with string sysctls Andi Kleen
2009-12-21  1:20 ` [PATCH] [1/11] Add rcustring ADT for RCU protected strings Andi Kleen
2009-12-22  2:46   ` Paul E. McKenney [this message]
2009-12-22 10:05     ` Andi Kleen
2009-12-22 20:59       ` Paul E. McKenney
2009-12-21  1:20 ` [PATCH] [2/11] Add a kernel_address() that works for data too Andi Kleen
2009-12-21  1:20 ` [PATCH] [3/11] SYSCTL: Add proc_rcu_string to manage sysctls using rcu strings Andi Kleen
2009-12-22  2:51   ` Paul E. McKenney
2009-12-22  3:00     ` Eric W. Biederman
2009-12-22  7:44       ` Paul E. McKenney
2009-12-21  1:20 ` [PATCH] [4/11] SYSCTL: Use RCU strings for core_pattern sysctl Andi Kleen
2009-12-21  1:20 ` [PATCH] [5/11] SYSCTL: Add call_usermodehelper_cleanup() Andi Kleen
2009-12-21  1:20 ` [PATCH] [6/11] SYSCTL: Convert modprobe_path to proc_rcu_string() Andi Kleen
2009-12-21  1:20 ` [PATCH] [7/11] SYSCTL: Convert poweroff_command to proc_rcu_string Andi Kleen
2009-12-21  1:20 ` [PATCH] [8/11] SYSCTL: Convert hotplug helper string to proc_rcu_string() Andi Kleen
2009-12-22 19:03   ` Greg KH
2009-12-21  1:20 ` [PATCH] [9/11] SYSCTL: Add a mutex to the page_alloc zone order sysctl Andi Kleen
2009-12-21  1:20 ` [PATCH] [10/11] SYSCTL: Use RCU protected sysctl for ocfs group add helper Andi Kleen
2009-12-21  1:20 ` [PATCH] [11/11] SYSCTL: Convert IRDA text sysctl to RCU Andi Kleen
2009-12-21  1:59 ` [PATCH] [0/11] SYSCTL: Use RCU to avoid races with string sysctls Eric W. Biederman
2009-12-21  2:04   ` Andi Kleen
2009-12-21  2:31     ` Eric W. Biederman
2009-12-21  3:21       ` Andi Kleen

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=20091222024635.GA9279@linux.vnet.ibm.com \
    --to=paulmck@linux.vnet.ibm.com \
    --cc=andi@firstfloor.org \
    --cc=ebiederm@xmission.com \
    --cc=linux-kernel@vger.kernel.org \
    /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.