Persistent module storage

Bjorn Ekwall (bj0rn@blox.se)
Tue, 5 Mar 1996 19:36:37 +0100 (MET)


Hi all!

Here is a kernel patch that makes it possible for modules to save
status information between invocations.

If you are using kerneld (and you _are_, aren't you? :-) ) a module can
be loaded and unloaded at almost any time, with no memory of previous
insmod/rmmod activities.

This patch very useful when you want the module to do something the
first time it gets loaded, but not on later "insmod's".

There are two new kernel functions:

char *get_persist(char *key);
char *set_persist(char *key, char *value, int size);

Each function looks for a "persistent" storage, named by "key",
and returns a pointer to the value stored with the key, or NULL
if there wasn't any value stored with the key.

Note that the key can be _any_ string, solely decided by the caller,
and that the value can be _any_ data type, including a (typecasted) struct.

The "size" parameter is the size (in bytes) of the value.
If set_persist is called with size == 0, the value will be removed
from the storage.

I thought of including a r/w interface to /proc as well, but I will leave
that as an exercise for the reader... :-)

I think that the lp module is a primary target for using these functions
so that the line printer doesn't have to be reset every time the module
gets inserted. I'm sure you can think of other modules as well...

Cheers,

Bjorn <bj0rn@blox.se> <http://www.pi.se/blox/>

--- linux/kernel/module.c.org Tue Mar 5 16:08:57 1996
+++ linux/kernel/module.c Tue Mar 5 18:59:33 1996
@@ -42,6 +42,9 @@
*
* - Use dummy syscall functions for users who disable all
* module support. Similar to kernel/sys.c (Paul Gortmaker)
+ *
+ * 05-Mar-96: Bjorn Ekwall:
+ * Added persistent storage for modules: get_persist/set_persist
*/

#ifdef CONFIG_MODULES /* a *big* #ifdef block... */
@@ -816,7 +819,90 @@
return 0;
}

+/*
+ * handle persistent storage for modules
+ * used to save status between invocations
+ *
+ * usage:
+ * char *get_persist("a key");
+ * char *set_persist("a key", &value, sizeof(value));
+ *
+ * where "value" can be anything, including structs.
+ */
+
+struct persist_val {
+ int size;
+ char value[1];
+};
+
+struct persist_t {
+ struct persist_t *next;
+ struct persist_val *val;
+ char key[1];
+};
+
+static struct persist_t *persist_head;
+
+char *persist(int op, char *key, char *value, int size)
+{
+ struct persist_t *p;
+
+ if (key == (char *)0)
+ return (char *)0;
+
+ for (p = persist_head; p; p = p->next) {
+ if (strcmp(key, p->key) == 0)
+ break;
+ }
+
+ switch (op) {
+ case GET_PERSIST:
+ if (p && p->val->size)
+ return p->val->value;
+ /* else */
+ break;
+
+ case SET_PERSIST:
+ if (p == (struct persist_t *)0) {
+ p = kmalloc(sizeof(struct persist_t) + strlen(key), GFP_KERNEL);
+ if (p == NULL)
+ break;
+ strcpy(p->key, key);
+ p->val = kmalloc(size + sizeof(struct persist_val), GFP_KERNEL);
+ if (p->val == NULL) {
+ kfree(p);
+ break;
+ }
+ p->val->size = size;
+ p->next = persist_head;
+ persist_head = p;
+ }
+ if (p->val->size != size) {
+ kfree(p->val);
+ p->val = kmalloc(size + sizeof(struct persist_val), GFP_KERNEL);
+ if (p->val == NULL)
+ break;
+ p->val->size = size;
+ }
+ if (size && value) {
+ memcpy(p->val->value, value, size);
+ return p->val->value;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return (char *)0;
+}
+
#else /* CONFIG_MODULES */
+
+char *persist(int op, char *key, char *value, int size)
+{
+ return (char *)0;
+}

/* Dummy syscalls for people who don't want modules */

--- linux/kernel/ksyms.c.org Tue Mar 5 16:16:38 1996
+++ linux/kernel/ksyms.c Tue Mar 5 16:42:59 1996
@@ -119,6 +119,7 @@
#ifdef CONFIG_KERNELD
X(kerneld_send),
#endif
+ X(persist),
X(get_options),

/* system info variables */
--- linux/include/linux/module.h.org Tue Mar 5 16:13:52 1996
+++ linux/include/linux/module.h Tue Mar 5 16:46:25 1996
@@ -103,7 +103,6 @@
#if defined(MODVERSIONS) && !defined(__GENKSYMS__)
int Using_Versions; /* gcc will handle this global (used as a flag) correctly */
#endif
-
#else

#define MOD_INC_USE_COUNT do { } while (0)
@@ -111,5 +110,27 @@
#define MOD_IN_USE 1

#endif
+
+/*
+ * Persistent storage for modules (see kernel/module.c)
+ *
+ * char *get_persist("a key");
+ * char *get_persist("a key", &value, sizeof(value));
+ */
+
+#define GET_PERSIST 0
+#define SET_PERSIST 1
+
+extern char *persist(int op, char *key, char *value, int size);
+
+static inline char *get_persist(char *key)
+{
+ return persist(GET_PERSIST, key, 0, 0);
+}
+
+static inline char *set_persist(char *key, char *value, int size)
+{
+ return persist(SET_PERSIST, key, value, size);
+}

#endif