linux Module loading fails due to attempt to double-register compat class

The first time the extcon-class module is loaded it registers a compatibility class "switch", which creates "/class/switch" in sysfs. When the module is unloaded, however, this class is not deregistered. Therefore, the second attempt to load the module fails as it tries to register an already registered compatibility class.
Bug fixed by commit 0dc77b6dabe
Type DoubleOpOnResource
Config "EXTCON && SYSFS && ANDROID" (3rd degree)
Fix-in code
Location drivers/extcon/
#ifdef CONFIG_ANDROID
#define CONFIG_SYSFS
#endif

#define ENOMEM      12  /* Out of memory */
#define EEXIST      17  /* File exists */

#define NULL (void*)0

extern void *malloc (unsigned long __size) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__malloc__)) ;

extern void free (void *__ptr) __attribute__ ((__nothrow__ , __leaf__));

extern int strcmp (const char *__s1, const char *__s2)
     __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__pure__)) __attribute__ ((__nonnull__ (1, 2)));

#ifdef CONFIG_SYSFS
static const char *linked = NULL;

int sysfs_link_sibling(const char *s_name)
{
  if (linked != NULL)
    return (!strcmp(s_name,linked)) ? -EEXIST : -ENOMEM;

  linked = s_name;
  return 0;
}

void sysfs_unlink_sibling(const char *s_name)
{
  if (linked != NULL && !strcmp(s_name,linked))
    linked = NULL;
}

int sysfs_create_dir(const char *name)
{
  return sysfs_link_sibling(name); // (6,13) ERROR
}

int kobject_add(const char *name)
{
  return sysfs_create_dir(name);
}

int *kobject_create_and_add(const char *name)
{
  int *kobj =(int*) malloc(sizeof(int));
  if (!kobj)
    return NULL;

  int retval = kobject_add(name); // (5,12)
  if (retval)
  {
    free(kobj);
    kobj = NULL;
  }

  return kobj;
}

int *class_compat_register(const char *name)
{
  int *kobj;

  kobj = kobject_create_and_add(name); // (4,11)
  if (!kobj)
    return NULL;

  return kobj;
}

void class_compat_unregister(const char *name)
{
  free(name);
}
#endif

#ifdef CONFIG_EXTCON
#if defined(CONFIG_ANDROID)
static int *switch_class;
#endif /* CONFIG_ANDROID */

int create_extcon_class(void)
{
#if defined(CONFIG_ANDROID)
    switch_class = class_compat_register("switch"); // (3,10)
    if (!switch_class)
      return -ENOMEM;
#endif /* CONFIG_ANDROID */
  return 0;
}

int extcon_class_init(void)
{
  return create_extcon_class(); // (2,9)
}

void extcon_class_exit(void)
{
  return;
}
#endif

int main(void)
{
#ifdef CONFIG_EXTCON
  extcon_class_init(); // (1)
  extcon_class_exit(); // (7)
  extcon_class_init(); // (8)
#endif
  return 0;
}

diff --git a/simple/0dc77b6.c b/simple/0dc77b6.c
--- a/simple/0dc77b6.c
+++ b/simple/0dc77b6.c
@@ -98,6 +98,9 @@
 
 void extcon_class_exit(void)
 {
+#if defined(CONFIG_ANDROID)
+    class_compat_unregister("switch");
+#endif
   return;
 }
 #endif
#ifdef CONFIG_ANDROID
#define CONFIG_SYSFS
#endif

#include <errno.h>
#include <stdlib.h>
#include <string.h>

#ifdef CONFIG_SYSFS
static const char *linked = NULL;

struct kobject {
  int __foo;
};

static struct kobject the_kobj;

struct class_compat {
  struct kobject *kobj;
};

static struct class_compat the_cls;
#endif

int main(int argc, char** argv)
{
#ifdef CONFIG_EXTCON
//  extcon_class_init();
#if defined(CONFIG_ANDROID)
  //switch_class = class_compat_register("switch");
  #ifdef CONFIG_SYSFS
  struct class_compat *cls;

  cls = &the_cls;
  //cls->kobj = kobject_create_and_add(name);
  struct kobject *kobj = &the_kobj;
  //int retval = kobject_add(name);
  if (linked != NULL)
    return (!strcmp("switch",linked)) ? -EEXIST : -ENOMEM;

  linked = s_name;
  
  int retval = 0;
  if (retval)
    kobj = NULL;

  cls->kobj = kobj;
  if (!cls->kobj)
    return NULL;

  switch_class = cls;
  #endif
  
  if (!switch_class)
    return -ENOMEM;
#endif /* CONFIG_ANDROID */
//  extcon_class_exit();
  //return;
//  extcon_class_init();
#if defined(CONFIG_ANDROID)
  //switch_class = class_compat_register("switch");
  #ifdef CONFIG_SYSFS
  cls = &the_cls;
  //cls->kobj = kobject_create_and_add(name);
  *kobj = &the_kobj;
  //int retval = kobject_add(name);
  if (linked != NULL)
    return (!strcmp("switch",linked)) ? -EEXIST : -ENOMEM;

  linked = s_name;
  
  retval = 0;
  if (retval)
    kobj = NULL;

  cls->kobj = kobj;
  if (!cls->kobj)
    return NULL;

  switch_class = cls;
  #endif
  
  if (!switch_class)
    return -ENOMEM;
#endif /* CONFIG_ANDROID */
#endif
  return 0;
}

. call drivers/extcon/extcon-class.c:814:extcon_class_init()
. 816: create_extcon_class();
.. call drivers/extcon/extcon-class.c:530:create_extcon_class()
.. // if ANDROID is enabled
.. 539: switch_class = class_compat_register("switch");
... call drivers/base/class.c:519:class_compat_register()
... 526: cls->kobj = kobject_create_and_add(name, &class_kset->kobj);
.... call lib/kobject.c:645:kobject_create_and_add()
.... 654: retval = kobject_add(kobj, parent, "%s", name);
..... call lib/kobject.c:336:kobject_add()
...... call lib/kobject.c:156:kobject_add_internal()
...... 185: error = create_dir(kobj);
....... call lib/kobject.c:47:create_dir()
....... 50: error = sysfs_create_dir(kobj);
........ call fs/sysfs/dir.c:746:sysfs_create_dir()
........ 767: error = create_dir(kobj, parent_sd, type, ns, kobject_name(kobj), &sd);
......... 679: create_dir()
......... 699: rc = sysfs_add_one(&acxt, sd);
.......... call fs/sysfs/dir.c:525:sysfs_add_one()
........... call fs/sysfs/dir.c:456:__sysfs_add_one()
........... 471: ret = sysfs_link_sibling(sd);
........... 473: return ret;
...... 192: if (error == -EEXIST)
...... 204: return error;
.... 659: kobj = NULL;
.... 661: return kobj;
... 529: return NULL;
.. ERROR 541: return -ENOMEM;