2006-02-08 18:48:25

by Greg KH

[permalink] [raw]
Subject: [patch 00/03] EXPORT_SYMBOL_GPL_FUTURE()

Currently we don't have a way to show people that some kernel symbols
will be changed in the future from EXPORT_SYMBOL() to
EXPORT_SYMBOL_GPL(). As we all know, not everyone reads the
Documentation/feature_removal.txt file, so we need a bigger way to
remind people.

Here's a series of three patches that adds this functionality, and
marks the RCU and USB subsystems with them.

I'll be adding these to my kernel trees to have them show up in the -mm
releases for testing.

thanks,

greg k-h


2006-02-08 18:49:29

by Greg KH

[permalink] [raw]
Subject: [patch 01/03] add EXPORT_SYMBOL_GPL_FUTURE()

This patch adds the ability to mark symbols that will be changed in the
future, so that non-GPL usage of them is flagged by the kernel and
printed out to the system log.

Signed-off-by: Greg Kroah-Hartman <[email protected]>

---
include/asm-generic/vmlinux.lds.h | 14 +++++++++++
include/linux/module.h | 8 ++++++
kernel/module.c | 46 ++++++++++++++++++++++++++++++++++++--
3 files changed, 66 insertions(+), 2 deletions(-)

--- gregkh-2.6.orig/include/asm-generic/vmlinux.lds.h
+++ gregkh-2.6/include/asm-generic/vmlinux.lds.h
@@ -58,6 +58,13 @@
VMLINUX_SYMBOL(__stop___ksymtab_gpl) = .; \
} \
\
+ /* Kernel symbol table: GPL-future-only symbols */ \
+ __ksymtab_gpl_future : AT(ADDR(__ksymtab_gpl_future) - LOAD_OFFSET) { \
+ VMLINUX_SYMBOL(__start___ksymtab_gpl_future) = .; \
+ *(__ksymtab_gpl_future) \
+ VMLINUX_SYMBOL(__stop___ksymtab_gpl_future) = .; \
+ } \
+ \
/* Kernel symbol table: Normal symbols */ \
__kcrctab : AT(ADDR(__kcrctab) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___kcrctab) = .; \
@@ -72,6 +79,13 @@
VMLINUX_SYMBOL(__stop___kcrctab_gpl) = .; \
} \
\
+ /* Kernel symbol table: GPL-future-only symbols */ \
+ __kcrctab_gpl_future : AT(ADDR(__kcrctab_gpl_future) - LOAD_OFFSET) { \
+ VMLINUX_SYMBOL(__start___kcrctab_gpl_future) = .; \
+ *(__kcrctab_gpl_future) \
+ VMLINUX_SYMBOL(__stop___kcrctab_gpl_future) = .; \
+ } \
+ \
/* Kernel symbol table: strings */ \
__ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) { \
*(__ksymtab_strings) \
--- gregkh-2.6.orig/include/linux/module.h
+++ gregkh-2.6/include/linux/module.h
@@ -198,6 +198,9 @@ void *__symbol_get_gpl(const char *symbo
#define EXPORT_SYMBOL_GPL(sym) \
__EXPORT_SYMBOL(sym, "_gpl")

+#define EXPORT_SYMBOL_GPL_FUTURE(sym) \
+ __EXPORT_SYMBOL(sym, "_gpl_future")
+
#endif

struct module_ref
@@ -255,6 +258,11 @@ struct module
unsigned int num_gpl_syms;
const unsigned long *gpl_crcs;

+ /* symbols that will be GPL-only in the near future. */
+ const struct kernel_symbol *gpl_future_syms;
+ unsigned int num_gpl_future_syms;
+ const unsigned long *gpl_future_crcs;
+
/* Exception table */
unsigned int num_exentries;
const struct exception_table_entry *extable;
--- gregkh-2.6.orig/kernel/module.c
+++ gregkh-2.6/kernel/module.c
@@ -126,8 +126,11 @@ extern const struct kernel_symbol __star
extern const struct kernel_symbol __stop___ksymtab[];
extern const struct kernel_symbol __start___ksymtab_gpl[];
extern const struct kernel_symbol __stop___ksymtab_gpl[];
+extern const struct kernel_symbol __start___ksymtab_gpl_future[];
+extern const struct kernel_symbol __stop___ksymtab_gpl_future[];
extern const unsigned long __start___kcrctab[];
extern const unsigned long __start___kcrctab_gpl[];
+extern const unsigned long __start___kcrctab_gpl_future[];

#ifndef CONFIG_MODVERSIONS
#define symversion(base, idx) NULL
@@ -159,6 +162,21 @@ static unsigned long __find_symbol(const
return __start___ksymtab_gpl[i].value;
}
}
+ for (i = 0; __start___ksymtab_gpl_future+i < __stop___ksymtab_gpl_future; i++) {
+ if (strcmp(__start___ksymtab_gpl_future[i].name, name) == 0) {
+ *crc = symversion(__start___kcrctab_gpl_future, i);
+ if (!gplok) {
+ printk(KERN_WARNING "Symbol %s is being used "
+ "by a non-GPL module, which will not "
+ "be allowed in the future\n", name);
+ printk(KERN_WARNING "Please see the file, "
+ "Documentation/feature-removal-schedule.txt, "
+ "in the kernel source tree, for more "
+ "details.\n");
+ }
+ return __start___ksymtab_gpl_future[i].value;
+ }
+ }

/* Now try modules. */
list_for_each_entry(mod, &modules, list) {
@@ -177,6 +195,21 @@ static unsigned long __find_symbol(const
}
}
}
+ for (i = 0; i < mod->num_gpl_future_syms; i++) {
+ if (strcmp(mod->gpl_future_syms[i].name, name) == 0) {
+ *crc = symversion(mod->gpl_future_crcs, i);
+ if (!gplok) {
+ printk(KERN_WARNING "Symbol %s is being used "
+ "by a non-GPL module, which will not "
+ "be allowed in the future\n", name);
+ printk(KERN_WARNING "Please see the file, "
+ "Documentation/feature-removal-schedule.txt, "
+ "in the kernel source tree, for more "
+ "details.\n");
+ }
+ return mod->gpl_future_syms[i].value;
+ }
+ }
}
DEBUGP("Failed to find symbol %s\n", name);
return 0;
@@ -1537,7 +1570,8 @@ static struct module *load_module(void _
char *secstrings, *args, *modmagic, *strtab = NULL;
unsigned int i, symindex = 0, strindex = 0, setupindex, exindex,
exportindex, modindex, obsparmindex, infoindex, gplindex,
- crcindex, gplcrcindex, versindex, pcpuindex;
+ crcindex, gplcrcindex, versindex, pcpuindex, gplfutureindex,
+ gplfuturecrcindex;
long arglen;
struct module *mod;
long err = 0;
@@ -1618,8 +1652,10 @@ static struct module *load_module(void _
/* Optional sections */
exportindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab");
gplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl");
+ gplfutureindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl_future");
crcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab");
gplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl");
+ gplfuturecrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl_future");
setupindex = find_sec(hdr, sechdrs, secstrings, "__param");
exindex = find_sec(hdr, sechdrs, secstrings, "__ex_table");
obsparmindex = find_sec(hdr, sechdrs, secstrings, "__obsparm");
@@ -1775,10 +1811,16 @@ static struct module *load_module(void _
mod->gpl_syms = (void *)sechdrs[gplindex].sh_addr;
if (gplcrcindex)
mod->gpl_crcs = (void *)sechdrs[gplcrcindex].sh_addr;
+ mod->num_gpl_future_syms = sechdrs[gplfutureindex].sh_size /
+ sizeof(*mod->gpl_future_syms);
+ mod->gpl_future_syms = (void *)sechdrs[gplfutureindex].sh_addr;
+ if (gplfuturecrcindex)
+ mod->gpl_future_crcs = (void *)sechdrs[gplfuturecrcindex].sh_addr;

#ifdef CONFIG_MODVERSIONS
if ((mod->num_syms && !crcindex) ||
- (mod->num_gpl_syms && !gplcrcindex)) {
+ (mod->num_gpl_syms && !gplcrcindex) ||
+ (mod->num_gpl_future_syms && !gplfuturecrcindex)) {
printk(KERN_WARNING "%s: No versions for exported symbols."
" Tainting kernel.\n", mod->name);
add_taint(TAINT_FORCED_MODULE);

2006-02-08 18:50:20

by Greg KH

[permalink] [raw]
Subject: [patch 02/03] add EXPORT_SYMBOL_GPL_FUTURE() to RCU subsystem

As the RCU symbols are going to be changed to GPL in the near future,
let us warn users that this is going to happen.

Cc: Dipankar Sarma <[email protected]>
Cc: Paul McKenney <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
kernel/rcupdate.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)

--- gregkh-2.6.orig/kernel/rcupdate.c
+++ gregkh-2.6/kernel/rcupdate.c
@@ -569,7 +569,7 @@ void synchronize_kernel(void)

module_param(maxbatch, int, 0);
EXPORT_SYMBOL_GPL(rcu_batches_completed);
-EXPORT_SYMBOL(call_rcu); /* WARNING: GPL-only in April 2006. */
-EXPORT_SYMBOL(call_rcu_bh); /* WARNING: GPL-only in April 2006. */
+EXPORT_SYMBOL_GPL_FUTURE(call_rcu); /* WARNING: GPL-only in April 2006. */
+EXPORT_SYMBOL_GPL_FUTURE(call_rcu_bh); /* WARNING: GPL-only in April 2006. */
EXPORT_SYMBOL_GPL(synchronize_rcu);
-EXPORT_SYMBOL(synchronize_kernel); /* WARNING: GPL-only in April 2006. */
+EXPORT_SYMBOL_GPL_FUTURE(synchronize_kernel); /* WARNING: GPL-only in April 2006. */

2006-02-08 18:51:23

by Greg KH

[permalink] [raw]
Subject: [patch 03/03] add EXPORT_SYMBOL_GPL_FUTURE() to USB subsystem

The USB core symbols will be converted to GPL-only in a few years. Mark
this as such and update the documentation explaining why, and provide a
pointer for developers to receive help if they need it.

Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
Documentation/feature-removal-schedule.txt | 19 +++++++++++++++++++
drivers/usb/core/driver.c | 6 +++---
2 files changed, 22 insertions(+), 3 deletions(-)

--- gregkh-2.6.orig/drivers/usb/core/driver.c
+++ gregkh-2.6/drivers/usb/core/driver.c
@@ -381,7 +381,7 @@ const struct usb_device_id *usb_match_id

return NULL;
}
-EXPORT_SYMBOL(usb_match_id);
+EXPORT_SYMBOL_GPL_FUTURE(usb_match_id);

int usb_device_match(struct device *dev, struct device_driver *drv)
{
@@ -449,7 +449,7 @@ int usb_register_driver(struct usb_drive

return retval;
}
-EXPORT_SYMBOL(usb_register_driver);
+EXPORT_SYMBOL_GPL_FUTURE(usb_register_driver);

/**
* usb_deregister - unregister a USB driver
@@ -472,4 +472,4 @@ void usb_deregister(struct usb_driver *d

usbfs_update_special();
}
-EXPORT_SYMBOL(usb_deregister);
+EXPORT_SYMBOL_GPL_FUTURE(usb_deregister);
--- gregkh-2.6.orig/Documentation/feature-removal-schedule.txt
+++ gregkh-2.6/Documentation/feature-removal-schedule.txt
@@ -171,3 +171,22 @@ Why: The ISA interface is faster and sho
probing is also known to cause trouble in at least one case (see
bug #5889.)
Who: Jean Delvare <[email protected]>
+
+---------------------------
+
+What: USB driver API moves to EXPORT_SYMBOL_GPL
+When: Febuary 2008
+Files: include/linux/usb.h, drivers/usb/core/driver.c
+Why: The USB subsystem has changed a lot over time, and it has been
+ possible to create userspace USB drivers using usbfs/libusb/gadgetfs
+ that operate as fast as the USB bus allows. Because of this, the USB
+ subsystem will not be allowing closed source kernel drivers to
+ register with it, after this grace period is over. If anyone needs
+ any help in converting their closed source drivers over to use the
+ userspace filesystems, please contact the
+ [email protected] mailing list, and the developers
+ there will be glad to help you out.
+Who: Greg Kroah-Hartman <[email protected]>
+
+---------------------------
+

2006-02-08 19:32:56

by Dipankar Sarma

[permalink] [raw]
Subject: Re: [patch 02/03] add EXPORT_SYMBOL_GPL_FUTURE() to RCU subsystem

On Wed, Feb 08, 2006 at 10:50:13AM -0800, Greg KH wrote:
> As the RCU symbols are going to be changed to GPL in the near future,
> let us warn users that this is going to happen.
>
> Cc: Dipankar Sarma <[email protected]>
> Cc: Paul McKenney <[email protected]>

Should be Paul McKenney <[email protected]> for you-know-why :)

> Signed-off-by: Greg Kroah-Hartman <[email protected]>

Looks good. Wish we had done this much earlier to alert people.

Thanks
Dipankar

2006-02-08 19:40:35

by Greg KH

[permalink] [raw]
Subject: Re: [patch 02/03] add EXPORT_SYMBOL_GPL_FUTURE() to RCU subsystem

On Thu, Feb 09, 2006 at 01:01:55AM +0530, Dipankar Sarma wrote:
> On Wed, Feb 08, 2006 at 10:50:13AM -0800, Greg KH wrote:
> > As the RCU symbols are going to be changed to GPL in the near future,
> > let us warn users that this is going to happen.
> >
> > Cc: Dipankar Sarma <[email protected]>
> > Cc: Paul McKenney <[email protected]>
>
> Should be Paul McKenney <[email protected]> for you-know-why :)

Then you might want to consider changing the in-kernel comments where
this address is :)

> > Signed-off-by: Greg Kroah-Hartman <[email protected]>
>
> Looks good. Wish we had done this much earlier to alert people.

Glad you like it.

thanks,

greg k-h

2006-02-08 19:49:51

by Sam Ravnborg

[permalink] [raw]
Subject: Re: [patch 01/03] add EXPORT_SYMBOL_GPL_FUTURE()

On Wed, Feb 08, 2006 at 10:49:22AM -0800, Greg KH wrote:
> This patch adds the ability to mark symbols that will be changed in the
> future, so that non-GPL usage of them is flagged by the kernel and
> printed out to the system log.
>
> Signed-off-by: Greg Kroah-Hartman <[email protected]>
The patch duplicate too much code to my taste at least.
May I suggest to consolidate a little in module.c before applying the
GPL_FUTURE stuff.

Have you considered: EXPORT_GPL_SOON()?

Sam

See sample patch for potential consolidation:
[compiletime tested only...]

diff --git a/kernel/module.c b/kernel/module.c
index 618ed6e..e07a22e 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -135,6 +135,18 @@ extern const unsigned long __start___kcr
#define symversion(base, idx) ((base) ? ((base) + (idx)) : NULL)
#endif

+/* lookup symbol in given range of kernel_symbols */
+static int lookup_symbol(const char *name,
+ const struct kernel_symbol *start,
+ const struct kernel_symbol *stop)
+{
+ unsigned int i;
+ for (i = 0; start + i < stop; i++)
+ if (strcmp(start[i].name, name) == 0)
+ return i;
+ return -1;
+}
+
/* Find a symbol, return value, crc and module which owns it */
static unsigned long __find_symbol(const char *name,
struct module **owner,
@@ -142,39 +154,40 @@ static unsigned long __find_symbol(const
int gplok)
{
struct module *mod;
- unsigned int i;
+ int i;

/* Core kernel first. */
*owner = NULL;
- for (i = 0; __start___ksymtab+i < __stop___ksymtab; i++) {
- if (strcmp(__start___ksymtab[i].name, name) == 0) {
- *crc = symversion(__start___kcrctab, i);
- return __start___ksymtab[i].value;
- }
+ i = lookup_symbol(name, __start___ksymtab, __stop___ksymtab);
+ if (i >= 0) {
+ *crc = symversion(__start___kcrctab, i);
+ return __start___ksymtab[i].value;
}
if (gplok) {
- for (i = 0; __start___ksymtab_gpl+i<__stop___ksymtab_gpl; i++)
- if (strcmp(__start___ksymtab_gpl[i].name, name) == 0) {
- *crc = symversion(__start___kcrctab_gpl, i);
- return __start___ksymtab_gpl[i].value;
- }
+ i = lookup_symbol(name, __start___ksymtab_gpl,
+ __stop___ksymtab_gpl);
+ if (i >= 0) {
+ *crc = symversion(__start___kcrctab_gpl, i);
+ return __start___ksymtab_gpl[i].value;
+ }
}

/* Now try modules. */
list_for_each_entry(mod, &modules, list) {
*owner = mod;
- for (i = 0; i < mod->num_syms; i++)
- if (strcmp(mod->syms[i].name, name) == 0) {
- *crc = symversion(mod->crcs, i);
- return mod->syms[i].value;
- }
+ i = lookup_symbol(name, mod->syms, mod->syms + mod->num_syms);
+ if (i >= 0) {
+ *crc = symversion(mod->crcs, i);
+ return mod->syms[i].value;
+ }

if (gplok) {
- for (i = 0; i < mod->num_gpl_syms; i++) {
- if (strcmp(mod->gpl_syms[i].name, name) == 0) {
- *crc = symversion(mod->gpl_crcs, i);
- return mod->gpl_syms[i].value;
- }
+ i = lookup_symbol(name,
+ mod->gpl_syms,
+ mod->gpl_syms + mod->num_gpl_syms);
+ if (i >= 0) {
+ *crc = symversion(mod->gpl_crcs, i);
+ return mod->gpl_syms[i].value;
}
}
}

2006-02-08 20:17:05

by Sam Ravnborg

[permalink] [raw]
Subject: Re: [patch 01/03] add EXPORT_SYMBOL_GPL_FUTURE()

On Wed, Feb 08, 2006 at 08:49:26PM +0100, Sam Ravnborg wrote:
> On Wed, Feb 08, 2006 at 10:49:22AM -0800, Greg KH wrote:
> > This patch adds the ability to mark symbols that will be changed in the
> > future, so that non-GPL usage of them is flagged by the kernel and
> > printed out to the system log.
> >
> > Signed-off-by: Greg Kroah-Hartman <[email protected]>
> The patch duplicate too much code to my taste at least.
> May I suggest to consolidate a little in module.c before applying the
> GPL_FUTURE stuff.
>
> Have you considered: EXPORT_GPL_SOON()?
>
> Sam
>
> See sample patch for potential consolidation:
> [compiletime tested only...]

Better version below...

diff --git a/kernel/module.c b/kernel/module.c
index 618ed6e..a57f92d 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -135,6 +135,18 @@ extern const unsigned long __start___kcr
#define symversion(base, idx) ((base) ? ((base) + (idx)) : NULL)
#endif

+/* lookup symbol in given range of kernel_symbols */
+static const struct kernel_symbol *lookup_symbol(const char *name,
+ const struct kernel_symbol *start,
+ const struct kernel_symbol *stop)
+{
+ const struct kernel_symbol *ks = start;
+ for (; ks < stop; ks++)
+ if (strcmp(ks->name, name) == 0)
+ return ks;
+ return NULL;
+}
+
/* Find a symbol, return value, crc and module which owns it */
static unsigned long __find_symbol(const char *name,
struct module **owner,
@@ -142,39 +154,41 @@ static unsigned long __find_symbol(const
int gplok)
{
struct module *mod;
- unsigned int i;
+ const struct kernel_symbol *ks;

/* Core kernel first. */
*owner = NULL;
- for (i = 0; __start___ksymtab+i < __stop___ksymtab; i++) {
- if (strcmp(__start___ksymtab[i].name, name) == 0) {
- *crc = symversion(__start___kcrctab, i);
- return __start___ksymtab[i].value;
- }
+ ks = lookup_symbol(name, __start___ksymtab, __stop___ksymtab);
+ if (ks) {
+ *crc = symversion(__start___kcrctab, (ks - __start___ksymtab));
+ return ks->value;
}
if (gplok) {
- for (i = 0; __start___ksymtab_gpl+i<__stop___ksymtab_gpl; i++)
- if (strcmp(__start___ksymtab_gpl[i].name, name) == 0) {
- *crc = symversion(__start___kcrctab_gpl, i);
- return __start___ksymtab_gpl[i].value;
- }
+ ks = lookup_symbol(name, __start___ksymtab_gpl,
+ __stop___ksymtab_gpl);
+ if (ks) {
+ *crc = symversion(__start___kcrctab_gpl,
+ (ks - __start___ksymtab_gpl));
+ return ks->value;
+ }
}

/* Now try modules. */
list_for_each_entry(mod, &modules, list) {
*owner = mod;
- for (i = 0; i < mod->num_syms; i++)
- if (strcmp(mod->syms[i].name, name) == 0) {
- *crc = symversion(mod->crcs, i);
- return mod->syms[i].value;
- }
+ ks = lookup_symbol(name, mod->syms, mod->syms + mod->num_syms);
+ if (ks) {
+ *crc = symversion(mod->crcs, (ks - mod->syms));
+ return ks->value;
+ }

if (gplok) {
- for (i = 0; i < mod->num_gpl_syms; i++) {
- if (strcmp(mod->gpl_syms[i].name, name) == 0) {
- *crc = symversion(mod->gpl_crcs, i);
- return mod->gpl_syms[i].value;
- }
+ ks = lookup_symbol(name, mod->gpl_syms,
+ mod->gpl_syms + mod->num_gpl_syms);
+ if (ks) {
+ *crc = symversion(mod->gpl_crcs,
+ (ks - mod->gpl_syms));
+ return ks->value;
}
}
}
@@ -1444,18 +1458,12 @@ static void setup_modinfo(struct module
#ifdef CONFIG_KALLSYMS
int is_exported(const char *name, const struct module *mod)
{
- unsigned int i;
-
- if (!mod) {
- for (i = 0; __start___ksymtab+i < __stop___ksymtab; i++)
- if (strcmp(__start___ksymtab[i].name, name) == 0)
- return 1;
- return 0;
- }
- for (i = 0; i < mod->num_syms; i++)
- if (strcmp(mod->syms[i].name, name) == 0)
+ if (!mod && lookup_symbol(name, __start___ksymtab, __stop___ksymtab))
return 1;
- return 0;
+ else if (lookup_symbol(name, mod->syms, mod->syms + mod->num_syms))
+ return 1;
+ else
+ return 0;
}

/* As per nm */

2006-02-08 22:57:48

by Greg KH

[permalink] [raw]
Subject: Re: [patch 01/03] add EXPORT_SYMBOL_GPL_FUTURE()

On Wed, Feb 08, 2006 at 09:16:45PM +0100, Sam Ravnborg wrote:
> On Wed, Feb 08, 2006 at 08:49:26PM +0100, Sam Ravnborg wrote:
> > On Wed, Feb 08, 2006 at 10:49:22AM -0800, Greg KH wrote:
> > > This patch adds the ability to mark symbols that will be changed in the
> > > future, so that non-GPL usage of them is flagged by the kernel and
> > > printed out to the system log.
> > >
> > > Signed-off-by: Greg Kroah-Hartman <[email protected]>
> > The patch duplicate too much code to my taste at least.
> > May I suggest to consolidate a little in module.c before applying the
> > GPL_FUTURE stuff.
> >
> > Have you considered: EXPORT_GPL_SOON()?

Well, as I'm proposing that the USB symbols be converted in 2 years,
that's not exactly "SOON" :)

> Better version below...

Very nice, I've added this to my tree. I had originally tried to do
something like this, but your version is very nice compared to my bad
hack.

thanks,

greg k-h