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>


  36 #include <sys/stat.h>
  37 #include <dirent.h>
  38 #include <libintl.h>
  39 #include <sys/systeminfo.h>
  40 #include <thread.h>
  41 #include <synch.h>
  42 
  43 #define MAXISALEN       257     /* based on sysinfo(2) man page */
  44 
  45 /*
  46  * protocol plugin interface
  47  *
  48  * finds plugins and makes them accessible. This is only "used" by
  49  * libshare.so.
  50  */
  51 
  52 struct sa_proto_plugin *sap_proto_list;
  53 
  54 static struct sa_proto_handle sa_proto_handle;
  55 


  56 void proto_plugin_fini();
  57 


  58 /*
  59  * Returns true if name is "." or "..", otherwise returns false.
  60  */
  61 static boolean_t
  62 proto_is_dot_or_dotdot(const char *name)
  63 {
  64         if (*name != '.')
  65                 return (B_FALSE);
  66 
  67         if ((name[1] == '\0') || (name[1] == '.' && name[2] == '\0'))
  68                 return (B_TRUE);
  69 
  70         return (B_FALSE);
  71 }
  72 
  73 /*
  74  * proto_plugin_init()
  75  *
  76  * Initialize the protocol specific plugin modules.
  77  *
  78  * Walk /usr/lib/fs/\* for libshare_*.so modules, for example,
  79  * /usr/lib/fs/nfs/libshare_nfs.so. A protocol specific directory
  80  * would have modules with names of the form libshare_<proto>.so.
  81  * For each protocol found, initialize it and add it to the internal
  82  * list of protocols. These are used for protocol specific operations.
  83  */
  84 
  85 int
  86 proto_plugin_init()
  87 {
  88         struct sa_proto_plugin *proto;
  89         int num_protos = 0;
  90         struct sa_plugin_ops *plugin_ops;
  91         void *dlhandle;
  92         DIR *dir;
  93         struct dirent *dent;
  94         int ret = SA_OK;
  95         struct stat st;
  96         char isa[MAXISALEN];
  97 


  98 #if defined(_LP64)
  99         if (sysinfo(SI_ARCHITECTURE_64, isa, MAXISALEN) == -1)
 100                 isa[0] = '\0';
 101 #else
 102         isa[0] = '\0';
 103 #endif




 104 
 105         if ((dir = opendir(SA_LIB_DIR)) == NULL)
 106                 return (SA_OK);
 107 
 108         while ((dent = readdir(dir)) != NULL) {
 109                 char path[MAXPATHLEN];
 110 
 111                 if (proto_is_dot_or_dotdot(dent->d_name))
 112                         continue;
 113 
 114                 (void) snprintf(path, MAXPATHLEN,
 115                     "%s/%s/%s/libshare_%s.so.1", SA_LIB_DIR,
 116                     dent->d_name, isa, dent->d_name);
 117 
 118                 /*
 119                  * If file doesn't exist, don't try to map it
 120                  */
 121                 if (stat(path, &st) < 0)
 122                         continue;
 123 


 138                         continue;
 139                 }
 140 
 141                 proto = (struct sa_proto_plugin *)
 142                     calloc(1, sizeof (struct sa_proto_plugin));
 143                 if (proto == NULL) {
 144                         (void) dlclose(dlhandle);
 145                         ret = SA_NO_MEMORY;
 146                         continue;
 147                 }
 148 
 149                 proto->plugin_ops = plugin_ops;
 150                 proto->plugin_handle = dlhandle;
 151                 num_protos++;
 152                 proto->plugin_next = sap_proto_list;
 153                 sap_proto_list = proto;
 154         }
 155 
 156         (void) closedir(dir);
 157 
 158         if (num_protos != 0) {
 159                 sa_proto_handle.sa_proto =
 160                     (char **)calloc(num_protos, sizeof (char *));
 161                 sa_proto_handle.sa_ops =
 162                     (struct sa_plugin_ops **)calloc(num_protos,
 163                     sizeof (struct sa_plugin_ops *));
 164                 if (sa_proto_handle.sa_proto != NULL &&
 165                     sa_proto_handle.sa_ops != NULL) {
 166                         int i;
 167                         struct sa_proto_plugin *tmp;
 168 
 169                         for (i = 0, tmp = sap_proto_list;
 170                             i < num_protos && tmp != NULL;
 171                             tmp = tmp->plugin_next) {
 172                                 int err;
 173                                 err = SA_OK;
 174                                 if (tmp->plugin_ops->sa_init != NULL)
 175                                         err = tmp->plugin_ops->sa_init();
 176                                 if (err == SA_OK) {
 177                                         /*
 178                                          * Only include if the init
 179                                          * succeeded or was NULL
 180                                          */
 181                                         sa_proto_handle.sa_num_proto++;
 182                                         sa_proto_handle.sa_ops[i] =
 183                                             tmp->plugin_ops;
 184                                         sa_proto_handle.sa_proto[i] =
 185                                             tmp->plugin_ops->sa_protocol;
 186                                         i++;
 187                                 }
 188                         }
 189                 } else {
 190                         ret = SA_NO_MEMORY;
 191                 }
 192         }
 193 
 194         /*
 195          * There was an error, so cleanup prior to return of failure.
 196          */
 197         if (ret != SA_OK)
 198                 proto_plugin_fini();




 199 
 200         return (ret);
 201 }
 202 
 203 /*
 204  * proto_plugin_fini()
 205  *
 206  * Uninitialize all the plugin modules.
 207  */
 208 
 209 void
 210 proto_plugin_fini()
 211 {








 212         struct sa_proto_plugin *p;
 213 



 214         /*











 215          * Protocols may call this framework during _fini
 216          * (the smbfs plugin is known to do this) so do
 217          * two passes: 1st call _fini; 2nd free, dlclose.
 218          */
 219         for (p = sap_proto_list; p != NULL; p = p->plugin_next)
 220                 p->plugin_ops->sa_fini();
 221 
 222         while ((p = sap_proto_list) != NULL) {
 223                 sap_proto_list = p->plugin_next;
 224 
 225                 if (p->plugin_handle != NULL)
 226                         (void) dlclose(p->plugin_handle);
 227                 free(p);
 228         }


 229         if (sa_proto_handle.sa_ops != NULL) {
 230                 free(sa_proto_handle.sa_ops);
 231                 sa_proto_handle.sa_ops = NULL;
 232         }
 233         if (sa_proto_handle.sa_proto != NULL) {
 234                 free(sa_proto_handle.sa_proto);
 235                 sa_proto_handle.sa_proto = NULL;
 236         }
 237         sa_proto_handle.sa_num_proto = 0;
 238 }
 239 
 240 /*
 241  * find_protocol(proto)
 242  *
 243  * Search the plugin list for the specified protocol and return the
 244  * ops vector.  NULL if protocol is not defined.
 245  */
 246 
 247 static struct sa_plugin_ops *
 248 find_protocol(char *proto)
 249 {
 250         int i;
 251         struct sa_plugin_ops *ops = NULL;
 252         extern mutex_t sa_global_lock;
 253 
 254         (void) mutex_lock(&sa_global_lock);
 255         if (proto != NULL) {
 256                 for (i = 0; i < sa_proto_handle.sa_num_proto; i++) {
 257                         if (strcmp(proto, sa_proto_handle.sa_proto[i]) == 0) {
 258                                 ops = sa_proto_handle.sa_ops[i];
 259                                 break;
 260                         }
 261                 }
 262         }
 263         (void) mutex_unlock(&sa_global_lock);
 264         return (ops);
 265 }
 266 
 267 /*
 268  * sa_proto_share(proto, share)
 269  *
 270  * Activate a share for the specified protocol.
 271  */
 272 




  36 #include <sys/stat.h>
  37 #include <dirent.h>
  38 #include <libintl.h>
  39 #include <sys/systeminfo.h>
  40 #include <thread.h>
  41 #include <synch.h>
  42 
  43 #define MAXISALEN       257     /* based on sysinfo(2) man page */
  44 
  45 /*
  46  * protocol plugin interface
  47  *
  48  * finds plugins and makes them accessible. This is only "used" by
  49  * libshare.so.
  50  */
  51 
  52 struct sa_proto_plugin *sap_proto_list;
  53 
  54 static struct sa_proto_handle sa_proto_handle;
  55 
  56 extern mutex_t sa_global_lock;
  57 
  58 void proto_plugin_fini();
  59 
  60 static void proto_plugin_fini_impl(boolean_t);
  61 
  62 /*
  63  * Returns true if name is "." or "..", otherwise returns false.
  64  */
  65 static boolean_t
  66 proto_is_dot_or_dotdot(const char *name)
  67 {
  68         if (*name != '.')
  69                 return (B_FALSE);
  70 
  71         if ((name[1] == '\0') || (name[1] == '.' && name[2] == '\0'))
  72                 return (B_TRUE);
  73 
  74         return (B_FALSE);
  75 }
  76 
  77 /*
  78  * proto_plugin_init()
  79  *
  80  * Initialize the protocol specific plugin modules.
  81  *
  82  * Walk /usr/lib/fs/\* for libshare_*.so modules, for example,
  83  * /usr/lib/fs/nfs/libshare_nfs.so. A protocol specific directory
  84  * would have modules with names of the form libshare_<proto>.so.
  85  * For each protocol found, initialize it and add it to the internal
  86  * list of protocols. These are used for protocol specific operations.
  87  */
  88 
  89 int
  90 proto_plugin_init()
  91 {
  92         struct sa_proto_plugin *proto;
  93         int num_protos = 0;
  94         struct sa_plugin_ops *plugin_ops;
  95         void *dlhandle;
  96         DIR *dir;
  97         struct dirent *dent;
  98         int ret = SA_OK;
  99         struct stat st;
 100         char isa[MAXISALEN];
 101 
 102         assert(MUTEX_HELD(&sa_global_lock));
 103 
 104 #if defined(_LP64)
 105         if (sysinfo(SI_ARCHITECTURE_64, isa, MAXISALEN) == -1)
 106                 isa[0] = '\0';
 107 #else
 108         isa[0] = '\0';
 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         }
 114 
 115         if ((dir = opendir(SA_LIB_DIR)) == NULL)
 116                 return (SA_OK);
 117 
 118         while ((dent = readdir(dir)) != NULL) {
 119                 char path[MAXPATHLEN];
 120 
 121                 if (proto_is_dot_or_dotdot(dent->d_name))
 122                         continue;
 123 
 124                 (void) snprintf(path, MAXPATHLEN,
 125                     "%s/%s/%s/libshare_%s.so.1", SA_LIB_DIR,
 126                     dent->d_name, isa, dent->d_name);
 127 
 128                 /*
 129                  * If file doesn't exist, don't try to map it
 130                  */
 131                 if (stat(path, &st) < 0)
 132                         continue;
 133 


 148                         continue;
 149                 }
 150 
 151                 proto = (struct sa_proto_plugin *)
 152                     calloc(1, sizeof (struct sa_proto_plugin));
 153                 if (proto == NULL) {
 154                         (void) dlclose(dlhandle);
 155                         ret = SA_NO_MEMORY;
 156                         continue;
 157                 }
 158 
 159                 proto->plugin_ops = plugin_ops;
 160                 proto->plugin_handle = dlhandle;
 161                 num_protos++;
 162                 proto->plugin_next = sap_proto_list;
 163                 sap_proto_list = proto;
 164         }
 165 
 166         (void) closedir(dir);
 167 
 168         if (num_protos != 0 && sa_proto_handle.sa_proto == NULL) {
 169                 sa_proto_handle.sa_proto =
 170                     (char **)calloc(num_protos, sizeof (char *));
 171                 sa_proto_handle.sa_ops =
 172                     (struct sa_plugin_ops **)calloc(num_protos,
 173                     sizeof (struct sa_plugin_ops *));
 174                 if (sa_proto_handle.sa_proto != NULL &&
 175                     sa_proto_handle.sa_ops != NULL) {
 176                         int i;
 177                         struct sa_proto_plugin *tmp;
 178 
 179                         for (i = 0, tmp = sap_proto_list;
 180                             i < num_protos && tmp != NULL;
 181                             tmp = tmp->plugin_next) {
 182                                 int err;
 183                                 err = SA_OK;
 184                                 if (tmp->plugin_ops->sa_init != NULL)
 185                                         err = tmp->plugin_ops->sa_init();
 186                                 if (err == SA_OK) {
 187                                         /*
 188                                          * Only include if the init
 189                                          * succeeded or was NULL
 190                                          */
 191                                         sa_proto_handle.sa_num_proto++;
 192                                         sa_proto_handle.sa_ops[i] =
 193                                             tmp->plugin_ops;
 194                                         sa_proto_handle.sa_proto[i] =
 195                                             tmp->plugin_ops->sa_protocol;
 196                                         i++;
 197                                 }
 198                         }
 199                 } else {
 200                         ret = SA_NO_MEMORY;
 201                 }
 202         }
 203 
 204         /*
 205          * There was an error, so cleanup prior to return of failure.
 206          */
 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         }
 213 
 214         return (ret);
 215 }
 216 
 217 /*
 218  * proto_plugin_fini()
 219  *
 220  * Uninitialize all the plugin modules.
 221  */
 222 
 223 void
 224 proto_plugin_fini()
 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 {
 234         struct sa_proto_plugin *p;
 235 
 236         assert(MUTEX_HELD(&sa_global_lock));
 237 
 238         sa_proto_handle.sa_ref_count--;
 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         /*
 251          * Protocols may call this framework during _fini
 252          * (the smbfs plugin is known to do this) so do
 253          * two passes: 1st call _fini; 2nd free, dlclose.
 254          */
 255         for (p = sap_proto_list; p != NULL; p = p->plugin_next)
 256                 p->plugin_ops->sa_fini();
 257 
 258         while ((p = sap_proto_list) != NULL) {
 259                 sap_proto_list = p->plugin_next;
 260 
 261                 if (p->plugin_handle != NULL)
 262                         (void) dlclose(p->plugin_handle);
 263                 free(p);
 264         }
 265         if (sap_proto_list != NULL)
 266                 sap_proto_list = NULL;
 267         if (sa_proto_handle.sa_ops != NULL) {
 268                 free(sa_proto_handle.sa_ops);
 269                 sa_proto_handle.sa_ops = NULL;
 270         }
 271         if (sa_proto_handle.sa_proto != NULL) {
 272                 free(sa_proto_handle.sa_proto);
 273                 sa_proto_handle.sa_proto = NULL;
 274         }
 275         sa_proto_handle.sa_num_proto = 0;
 276 }
 277 
 278 /*
 279  * find_protocol(proto)
 280  *
 281  * Search the plugin list for the specified protocol and return the
 282  * ops vector.  NULL if protocol is not defined.
 283  */
 284 
 285 static struct sa_plugin_ops *
 286 find_protocol(char *proto)
 287 {
 288         int i;
 289         struct sa_plugin_ops *ops = NULL;

 290 
 291         (void) mutex_lock(&sa_global_lock);
 292         if (proto != NULL) {
 293                 for (i = 0; i < sa_proto_handle.sa_num_proto; i++) {
 294                         if (strcmp(proto, sa_proto_handle.sa_proto[i]) == 0) {
 295                                 ops = sa_proto_handle.sa_ops[i];
 296                                 break;
 297                         }
 298                 }
 299         }
 300         (void) mutex_unlock(&sa_global_lock);
 301         return (ops);
 302 }
 303 
 304 /*
 305  * sa_proto_share(proto, share)
 306  *
 307  * Activate a share for the specified protocol.
 308  */
 309