Print this page
NEX-9755 Race in libshare can cause zfs set sharenfs to fail
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>

Split Close
Expand all
Collapse all
          --- old/usr/src/lib/libshare/common/plugin.c
          +++ new/usr/src/lib/libshare/common/plugin.c
↓ open down ↓ 45 lines elided ↑ open up ↑
  46   46   * protocol plugin interface
  47   47   *
  48   48   * finds plugins and makes them accessible. This is only "used" by
  49   49   * libshare.so.
  50   50   */
  51   51  
  52   52  struct sa_proto_plugin *sap_proto_list;
  53   53  
  54   54  static struct sa_proto_handle sa_proto_handle;
  55   55  
       56 +extern mutex_t sa_global_lock;
       57 +
  56   58  void proto_plugin_fini();
  57   59  
       60 +static void proto_plugin_fini_impl(boolean_t);
       61 +
  58   62  /*
  59   63   * Returns true if name is "." or "..", otherwise returns false.
  60   64   */
  61   65  static boolean_t
  62   66  proto_is_dot_or_dotdot(const char *name)
  63   67  {
  64   68          if (*name != '.')
  65   69                  return (B_FALSE);
  66   70  
  67   71          if ((name[1] == '\0') || (name[1] == '.' && name[2] == '\0'))
↓ open down ↓ 20 lines elided ↑ open up ↑
  88   92          struct sa_proto_plugin *proto;
  89   93          int num_protos = 0;
  90   94          struct sa_plugin_ops *plugin_ops;
  91   95          void *dlhandle;
  92   96          DIR *dir;
  93   97          struct dirent *dent;
  94   98          int ret = SA_OK;
  95   99          struct stat st;
  96  100          char isa[MAXISALEN];
  97  101  
      102 +        assert(MUTEX_HELD(&sa_global_lock));
      103 +
  98  104  #if defined(_LP64)
  99  105          if (sysinfo(SI_ARCHITECTURE_64, isa, MAXISALEN) == -1)
 100  106                  isa[0] = '\0';
 101  107  #else
 102  108          isa[0] = '\0';
 103  109  #endif
      110 +        if (sap_proto_list != NULL && sa_proto_handle.sa_proto != NULL) {
      111 +                sa_proto_handle.sa_ref_count++;
      112 +                return (SA_OK);
      113 +        }
 104  114  
 105  115          if ((dir = opendir(SA_LIB_DIR)) == NULL)
 106  116                  return (SA_OK);
 107  117  
 108  118          while ((dent = readdir(dir)) != NULL) {
 109  119                  char path[MAXPATHLEN];
 110  120  
 111  121                  if (proto_is_dot_or_dotdot(dent->d_name))
 112  122                          continue;
 113  123  
↓ open down ↓ 34 lines elided ↑ open up ↑
 148  158  
 149  159                  proto->plugin_ops = plugin_ops;
 150  160                  proto->plugin_handle = dlhandle;
 151  161                  num_protos++;
 152  162                  proto->plugin_next = sap_proto_list;
 153  163                  sap_proto_list = proto;
 154  164          }
 155  165  
 156  166          (void) closedir(dir);
 157  167  
 158      -        if (num_protos != 0) {
      168 +        if (num_protos != 0 && sa_proto_handle.sa_proto == NULL) {
 159  169                  sa_proto_handle.sa_proto =
 160  170                      (char **)calloc(num_protos, sizeof (char *));
 161  171                  sa_proto_handle.sa_ops =
 162  172                      (struct sa_plugin_ops **)calloc(num_protos,
 163  173                      sizeof (struct sa_plugin_ops *));
 164  174                  if (sa_proto_handle.sa_proto != NULL &&
 165  175                      sa_proto_handle.sa_ops != NULL) {
 166  176                          int i;
 167  177                          struct sa_proto_plugin *tmp;
 168  178  
↓ open down ↓ 18 lines elided ↑ open up ↑
 187  197                                  }
 188  198                          }
 189  199                  } else {
 190  200                          ret = SA_NO_MEMORY;
 191  201                  }
 192  202          }
 193  203  
 194  204          /*
 195  205           * There was an error, so cleanup prior to return of failure.
 196  206           */
 197      -        if (ret != SA_OK)
 198      -                proto_plugin_fini();
      207 +        if (ret != SA_OK) {
      208 +                proto_plugin_fini_impl(B_TRUE);
      209 +        } else {
      210 +                assert(sa_proto_handle.sa_ref_count >= 0);
      211 +                sa_proto_handle.sa_ref_count++;
      212 +        }
 199  213  
 200  214          return (ret);
 201  215  }
 202  216  
 203  217  /*
 204  218   * proto_plugin_fini()
 205  219   *
 206  220   * Uninitialize all the plugin modules.
 207  221   */
 208  222  
 209  223  void
 210  224  proto_plugin_fini()
 211  225  {
      226 +        assert(MUTEX_HELD(&sa_global_lock));
      227 +
      228 +        proto_plugin_fini_impl(B_FALSE);
      229 +}
      230 +
      231 +static void
      232 +proto_plugin_fini_impl(boolean_t forcefini)
      233 +{
 212  234          struct sa_proto_plugin *p;
 213  235  
      236 +        assert(MUTEX_HELD(&sa_global_lock));
      237 +
      238 +        sa_proto_handle.sa_ref_count--;
 214  239          /*
      240 +         * If another thread has a reference to the proto list,
      241 +         * we don't want to clear it out while they're using it
      242 +         * or find_protocol() could fail.
      243 +         */
      244 +        if (!forcefini && sa_proto_handle.sa_ref_count > 0) {
      245 +                return;
      246 +        } else {
      247 +                sa_proto_handle.sa_ref_count = 0;
      248 +        }
      249 +
      250 +        /*
 215  251           * Protocols may call this framework during _fini
 216  252           * (the smbfs plugin is known to do this) so do
 217  253           * two passes: 1st call _fini; 2nd free, dlclose.
 218  254           */
 219  255          for (p = sap_proto_list; p != NULL; p = p->plugin_next)
 220  256                  p->plugin_ops->sa_fini();
 221  257  
 222  258          while ((p = sap_proto_list) != NULL) {
 223  259                  sap_proto_list = p->plugin_next;
 224  260  
 225  261                  if (p->plugin_handle != NULL)
 226  262                          (void) dlclose(p->plugin_handle);
 227  263                  free(p);
 228  264          }
      265 +        if (sap_proto_list != NULL)
      266 +                sap_proto_list = NULL;
 229  267          if (sa_proto_handle.sa_ops != NULL) {
 230  268                  free(sa_proto_handle.sa_ops);
 231  269                  sa_proto_handle.sa_ops = NULL;
 232  270          }
 233  271          if (sa_proto_handle.sa_proto != NULL) {
 234  272                  free(sa_proto_handle.sa_proto);
 235  273                  sa_proto_handle.sa_proto = NULL;
 236  274          }
 237  275          sa_proto_handle.sa_num_proto = 0;
 238  276  }
↓ open down ↓ 3 lines elided ↑ open up ↑
 242  280   *
 243  281   * Search the plugin list for the specified protocol and return the
 244  282   * ops vector.  NULL if protocol is not defined.
 245  283   */
 246  284  
 247  285  static struct sa_plugin_ops *
 248  286  find_protocol(char *proto)
 249  287  {
 250  288          int i;
 251  289          struct sa_plugin_ops *ops = NULL;
 252      -        extern mutex_t sa_global_lock;
 253  290  
 254  291          (void) mutex_lock(&sa_global_lock);
 255  292          if (proto != NULL) {
 256  293                  for (i = 0; i < sa_proto_handle.sa_num_proto; i++) {
 257  294                          if (strcmp(proto, sa_proto_handle.sa_proto[i]) == 0) {
 258  295                                  ops = sa_proto_handle.sa_ops[i];
 259  296                                  break;
 260  297                          }
 261  298                  }
 262  299          }
↓ open down ↓ 447 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX