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
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 27 #include <stdio.h>
28 28 #include <stdlib.h>
29 29 #include <string.h>
30 30 #include <libshare.h>
31 31 #include "libshare_impl.h"
32 32 #include <dlfcn.h>
33 33 #include <link.h>
34 34 #include <sys/types.h>
35 35 #include <sys/param.h>
36 36 #include <sys/stat.h>
37 37 #include <dirent.h>
38 38 #include <libintl.h>
39 39 #include <sys/systeminfo.h>
40 40 #include <thread.h>
41 41 #include <synch.h>
42 42
43 43 #define MAXISALEN 257 /* based on sysinfo(2) man page */
44 44
45 45 /*
|
↓ 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'))
68 72 return (B_TRUE);
69 73
70 74 return (B_FALSE);
71 75 }
72 76
73 77 /*
74 78 * proto_plugin_init()
75 79 *
76 80 * Initialize the protocol specific plugin modules.
77 81 *
78 82 * Walk /usr/lib/fs/\* for libshare_*.so modules, for example,
79 83 * /usr/lib/fs/nfs/libshare_nfs.so. A protocol specific directory
80 84 * would have modules with names of the form libshare_<proto>.so.
81 85 * For each protocol found, initialize it and add it to the internal
82 86 * list of protocols. These are used for protocol specific operations.
83 87 */
84 88
85 89 int
86 90 proto_plugin_init()
87 91 {
|
↓ 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
114 124 (void) snprintf(path, MAXPATHLEN,
115 125 "%s/%s/%s/libshare_%s.so.1", SA_LIB_DIR,
116 126 dent->d_name, isa, dent->d_name);
117 127
118 128 /*
119 129 * If file doesn't exist, don't try to map it
120 130 */
121 131 if (stat(path, &st) < 0)
122 132 continue;
123 133
124 134 if ((dlhandle = dlopen(path, RTLD_FIRST|RTLD_LAZY)) == NULL) {
125 135 (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
126 136 "Error in plugin for protocol %s: %s\n"),
127 137 dent->d_name, dlerror());
128 138 continue;
129 139 }
130 140
131 141 plugin_ops = (struct sa_plugin_ops *)
132 142 dlsym(dlhandle, "sa_plugin_ops");
133 143 if (plugin_ops == NULL) {
134 144 (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
135 145 "Error in plugin ops for protocol %s: %s\n"),
136 146 dent->d_name, dlerror());
137 147 (void) dlclose(dlhandle);
138 148 continue;
139 149 }
140 150
141 151 proto = (struct sa_proto_plugin *)
142 152 calloc(1, sizeof (struct sa_proto_plugin));
143 153 if (proto == NULL) {
144 154 (void) dlclose(dlhandle);
145 155 ret = SA_NO_MEMORY;
146 156 continue;
147 157 }
|
↓ 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
169 179 for (i = 0, tmp = sap_proto_list;
170 180 i < num_protos && tmp != NULL;
171 181 tmp = tmp->plugin_next) {
172 182 int err;
173 183 err = SA_OK;
174 184 if (tmp->plugin_ops->sa_init != NULL)
175 185 err = tmp->plugin_ops->sa_init();
176 186 if (err == SA_OK) {
177 187 /*
178 188 * Only include if the init
179 189 * succeeded or was NULL
180 190 */
181 191 sa_proto_handle.sa_num_proto++;
182 192 sa_proto_handle.sa_ops[i] =
183 193 tmp->plugin_ops;
184 194 sa_proto_handle.sa_proto[i] =
185 195 tmp->plugin_ops->sa_protocol;
186 196 i++;
|
↓ 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 }
239 277
240 278 /*
241 279 * find_protocol(proto)
|
↓ 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 }
263 300 (void) mutex_unlock(&sa_global_lock);
264 301 return (ops);
265 302 }
266 303
267 304 /*
268 305 * sa_proto_share(proto, share)
269 306 *
270 307 * Activate a share for the specified protocol.
271 308 */
272 309
273 310 int
274 311 sa_proto_share(char *proto, sa_share_t share)
275 312 {
276 313 struct sa_plugin_ops *ops = find_protocol(proto);
277 314 int ret = SA_INVALID_PROTOCOL;
278 315
279 316 if (ops != NULL && ops->sa_share != NULL)
280 317 ret = ops->sa_share(share);
281 318 return (ret);
282 319 }
283 320
284 321 /*
285 322 * sa_proto_unshare(proto, share)
286 323 *
287 324 * Deactivate (unshare) the share for this protocol.
288 325 */
289 326
290 327 int
291 328 sa_proto_unshare(sa_share_t share, char *proto, char *path)
292 329 {
293 330 struct sa_plugin_ops *ops = find_protocol(proto);
294 331 int ret = SA_INVALID_PROTOCOL;
295 332
296 333 if (ops != NULL && ops->sa_unshare != NULL)
297 334 ret = ops->sa_unshare(share, path);
298 335 return (ret);
299 336 }
300 337
301 338 /*
302 339 * sa_proto_share_resource(char *proto, sa_resource_t resource)
303 340 *
304 341 * For protocols that actually enable at the resource level, do the
305 342 * protocol specific resource enable. If it doesn't, return an error.
306 343 * Note that the resource functions are optional so can return
307 344 * SA_NOT_SUPPORTED.
308 345 */
309 346
310 347 int
311 348 sa_proto_share_resource(char *proto, sa_resource_t resource)
312 349 {
313 350 struct sa_plugin_ops *ops = find_protocol(proto);
314 351 int ret = SA_INVALID_PROTOCOL;
315 352
316 353 if (ops != NULL) {
317 354 if (ops->sa_enable_resource != NULL)
318 355 ret = ops->sa_enable_resource(resource);
319 356 else
320 357 ret = SA_NOT_SUPPORTED;
321 358 }
322 359 return (ret);
323 360 }
324 361
325 362 /*
326 363 * sa_proto_unshare_resource(char *proto, sa_resource_t resource)
327 364 *
328 365 * For protocols that actually disable at the resource level, do the
329 366 * protocol specific resource disable. If it doesn't, return an error.
330 367 */
331 368
332 369 int
333 370 sa_proto_unshare_resource(char *proto, sa_resource_t resource)
334 371 {
335 372 struct sa_plugin_ops *ops = find_protocol(proto);
336 373 int ret = SA_INVALID_PROTOCOL;
337 374
338 375 if (ops != NULL) {
339 376 if (ops->sa_disable_resource != NULL)
340 377 ret = ops->sa_disable_resource(resource);
341 378 else
342 379 ret = SA_NOT_SUPPORTED;
343 380 }
344 381 return (ret);
345 382 }
346 383
347 384 /*
348 385 * sa_proto_valid_prop(handle, proto, prop, opt)
349 386 *
350 387 * Check to see if the specified prop is valid for this protocol.
351 388 */
352 389
353 390 int
354 391 sa_proto_valid_prop(sa_handle_t handle, char *proto, sa_property_t prop,
355 392 sa_optionset_t opt)
356 393 {
357 394 struct sa_plugin_ops *ops = find_protocol(proto);
358 395 int ret = 0;
359 396
360 397 if (ops != NULL && ops->sa_valid_prop != NULL)
361 398 ret = ops->sa_valid_prop(handle, prop, opt);
362 399 return (ret);
363 400 }
364 401
365 402 /*
366 403 * sa_proto_valid_space(proto, space)
367 404 *
368 405 * Check if space is valid optionspace for proto.
369 406 * Protocols that don't implement this don't support spaces.
370 407 */
371 408 int
372 409 sa_proto_valid_space(char *proto, char *token)
373 410 {
374 411 struct sa_plugin_ops *ops = find_protocol(proto);
375 412 int ret = 0;
376 413
377 414 if (ops != NULL && ops->sa_valid_space != NULL)
378 415 ret = ops->sa_valid_space(token);
379 416 return (ret);
380 417 }
381 418
382 419 /*
383 420 * sa_proto_space_alias(proto, space)
384 421 *
385 422 * If the name for space is an alias, return its proper name. This is
386 423 * used to translate "default" values into proper form.
387 424 */
388 425 char *
389 426 sa_proto_space_alias(char *proto, char *space)
390 427 {
391 428 struct sa_plugin_ops *ops = find_protocol(proto);
392 429 char *ret = space;
393 430
394 431 if (ops != NULL && ops->sa_space_alias != NULL)
395 432 ret = ops->sa_space_alias(space);
396 433 return (ret);
397 434 }
398 435
399 436 /*
400 437 * sa_proto_security_prop(proto, token)
401 438 *
402 439 * Check to see if the property name in token is a valid named
403 440 * optionset property.
404 441 */
405 442
406 443 int
407 444 sa_proto_security_prop(char *proto, char *token)
408 445 {
409 446 struct sa_plugin_ops *ops = find_protocol(proto);
410 447 int ret = 0;
411 448
412 449 if (ops != NULL && ops->sa_security_prop != NULL)
413 450 ret = ops->sa_security_prop(token);
414 451 return (ret);
415 452 }
416 453
417 454 /*
418 455 * sa_proto_legacy_opts(proto, grouup, options)
419 456 *
420 457 * Have the protocol specific parser parse the options string and add
421 458 * an appropriate optionset to group.
422 459 */
423 460
424 461 int
425 462 sa_proto_legacy_opts(char *proto, sa_group_t group, char *options)
426 463 {
427 464 struct sa_plugin_ops *ops = find_protocol(proto);
428 465 int ret = SA_INVALID_PROTOCOL;
429 466
430 467 if (ops != NULL && ops->sa_legacy_opts != NULL)
431 468 ret = ops->sa_legacy_opts(group, options);
432 469 return (ret);
433 470 }
434 471
435 472 /*
436 473 * sa_proto_legacy_format(proto, group, hier)
437 474 *
438 475 * Return a legacy format string representing either the group's
439 476 * properties or the groups hierarchical properties.
440 477 */
441 478
442 479 char *
443 480 sa_proto_legacy_format(char *proto, sa_group_t group, int hier)
444 481 {
445 482 struct sa_plugin_ops *ops = find_protocol(proto);
446 483 char *ret = NULL;
447 484
448 485 if (ops != NULL && ops->sa_legacy_format != NULL)
449 486 ret = ops->sa_legacy_format(group, hier);
450 487 return (ret);
451 488 }
452 489
453 490 void
454 491 sa_format_free(char *str)
455 492 {
456 493 free(str);
457 494 }
458 495
459 496 /*
460 497 * sharectl related API functions
461 498 */
462 499
463 500 /*
464 501 * sa_proto_get_properties(proto)
465 502 *
466 503 * Return the set of properties that are specific to the
467 504 * protocol. These are usually in /etc/dfs/<proto> and related files,
468 505 * but only the protocol module knows which ones for sure.
469 506 */
470 507
471 508 sa_protocol_properties_t
472 509 sa_proto_get_properties(char *proto)
473 510 {
474 511 struct sa_plugin_ops *ops = find_protocol(proto);
475 512 sa_protocol_properties_t props = NULL;
476 513
477 514 if (ops != NULL && ops->sa_get_proto_set != NULL)
478 515 props = ops->sa_get_proto_set();
479 516 return (props);
480 517 }
481 518
482 519 /*
483 520 * sa_proto_set_property(proto, prop)
484 521 *
485 522 * Update the protocol specific property.
486 523 */
487 524
488 525 int
489 526 sa_proto_set_property(char *proto, sa_property_t prop)
490 527 {
491 528 struct sa_plugin_ops *ops = find_protocol(proto);
492 529 int ret = SA_OK;
493 530
494 531 if (ops != NULL && ops->sa_set_proto_prop != NULL)
495 532 ret = ops->sa_set_proto_prop(prop);
496 533 return (ret);
497 534 }
498 535
499 536 /*
500 537 * sa_valid_protocol(proto)
501 538 *
502 539 * Check to see if the protocol specified is defined by a
503 540 * plugin. Returns true (1) or false (0)
504 541 */
505 542
506 543 int
507 544 sa_valid_protocol(char *proto)
508 545 {
509 546 struct sa_plugin_ops *ops = find_protocol(proto);
510 547 return (ops != NULL);
511 548 }
512 549
513 550 /*
514 551 * Return the current operational status of the protocol
515 552 */
516 553
517 554 char *
518 555 sa_get_protocol_status(char *proto)
519 556 {
520 557 struct sa_plugin_ops *ops = find_protocol(proto);
521 558 char *ret = NULL;
522 559 if (ops != NULL && ops->sa_get_proto_status != NULL)
523 560 ret = ops->sa_get_proto_status(proto);
524 561 return (ret);
525 562 }
526 563
527 564 /*
528 565 * sa_proto_update_legacy(proto, share)
529 566 *
530 567 * Update the protocol specific legacy files if necessary for the
531 568 * specified share.
532 569 */
533 570
534 571 int
535 572 sa_proto_update_legacy(char *proto, sa_share_t share)
536 573 {
537 574 struct sa_plugin_ops *ops = find_protocol(proto);
538 575 int ret = SA_NOT_IMPLEMENTED;
539 576
540 577 if (ops != NULL) {
541 578 if (ops->sa_update_legacy != NULL)
542 579 ret = ops->sa_update_legacy(share);
543 580 }
544 581 return (ret);
545 582 }
546 583
547 584 /*
548 585 * sa_delete_legacy(proto, share)
549 586 *
550 587 * Remove the specified share from the protocol specific legacy files.
551 588 */
552 589
553 590 int
554 591 sa_proto_delete_legacy(char *proto, sa_share_t share)
555 592 {
556 593 struct sa_plugin_ops *ops = find_protocol(proto);
557 594 int ret = SA_NOT_IMPLEMENTED;
558 595
559 596 if (ops != NULL) {
560 597 if (ops->sa_delete_legacy != NULL)
561 598 ret = ops->sa_delete_legacy(share);
562 599 } else {
563 600 if (proto != NULL)
564 601 ret = SA_NOT_IMPLEMENTED;
565 602 else
566 603 ret = SA_INVALID_PROTOCOL;
567 604 }
568 605 return (ret);
569 606 }
570 607
571 608 /*
572 609 * sa_proto_delete_section(proto, section)
573 610 *
574 611 * Remove the specified section from the protocol specific legacy files,
575 612 * if supported.
576 613 */
577 614
578 615 int
579 616 sa_proto_delete_section(char *proto, char *section)
580 617 {
581 618 struct sa_plugin_ops *ops = find_protocol(proto);
582 619 int ret = SA_OK;
583 620
584 621 if (ops != NULL) {
585 622 if (ops->sa_delete_proto_section != NULL)
586 623 ret = ops->sa_delete_proto_section(section);
587 624 } else {
588 625 if (proto != NULL)
589 626 ret = SA_NOT_IMPLEMENTED;
590 627 else
591 628 ret = SA_INVALID_PROTOCOL;
592 629 }
593 630 return (ret);
594 631 }
595 632
596 633 /*
597 634 * sa_proto_change_notify(share, char *protocol)
598 635 *
599 636 * Notify the protocol that a change has been made to the share
600 637 */
601 638
602 639 int
603 640 sa_proto_change_notify(sa_share_t share, char *proto)
604 641 {
605 642 struct sa_plugin_ops *ops = find_protocol(proto);
606 643 int ret = SA_NOT_IMPLEMENTED;
607 644
608 645 if (ops != NULL) {
609 646 if (ops->sa_change_notify != NULL)
610 647 ret = ops->sa_change_notify(share);
611 648 } else if (proto == NULL) {
612 649
613 650 ret = SA_INVALID_PROTOCOL;
614 651 }
615 652 return (ret);
616 653 }
617 654
618 655 /*
619 656 * sa_proto_notify_resource(resource, char *protocol)
620 657 *
621 658 * Notify the protocol that a change has been made to the share
622 659 */
623 660
624 661 int
625 662 sa_proto_notify_resource(sa_resource_t resource, char *proto)
626 663 {
627 664 struct sa_plugin_ops *ops = find_protocol(proto);
628 665 int ret = SA_NOT_IMPLEMENTED;
629 666
630 667 if (ops != NULL) {
631 668 if (ops->sa_notify_resource != NULL)
632 669 ret = ops->sa_notify_resource(resource);
633 670 } else if (proto == NULL) {
634 671 ret = SA_INVALID_PROTOCOL;
635 672 }
636 673 return (ret);
637 674 }
638 675
639 676 /*
640 677 * sa_proto_get_featureset(protocol)
641 678 *
642 679 * Get bitmask of defined features of the protocol. These are
643 680 * primarily things like SA_FEATURE_RESOURCE (shares are by resource
644 681 * name rather than path) and other operational features that affect
645 682 * behavior.
646 683 */
647 684
648 685 uint64_t
649 686 sa_proto_get_featureset(char *proto)
650 687 {
651 688 struct sa_plugin_ops *ops = find_protocol(proto);
652 689 uint64_t ret = 0;
653 690
654 691 if (ops != NULL) {
655 692 if (ops->sa_features != NULL)
656 693 ret = ops->sa_features();
657 694 }
658 695 /* if not implemented, zero is valid */
659 696 return (ret);
660 697 }
661 698
662 699 /*
663 700 * sa_proto_get_transients(sa_handle_t)
664 701 *
665 702 * Called to get any protocol specific transient shares. NFS doesn't
666 703 * use this since the info is in sharetab which is processed as a
667 704 * common transient store.
668 705 *
669 706 * The protocol plugin should verify that the share isn't in the
670 707 * repository and then add it as a transient.
671 708 *
672 709 * Not having an entry is not a problem. It returns 0 in that case.
673 710 */
674 711
675 712 int
676 713 sa_proto_get_transients(sa_handle_t handle, char *proto)
677 714 {
678 715 struct sa_plugin_ops *ops = find_protocol(proto);
679 716 int ret = 0;
680 717
681 718 if (ops != NULL) {
682 719 if (ops->sa_get_transient_shares != NULL)
683 720 ret = ops->sa_get_transient_shares(handle);
684 721 }
685 722 return (ret);
686 723 }
687 724
688 725 /*
689 726 * sa_proto_rename_resource(sa_handle_t, proto, sa_resource_t, newname)
690 727 *
691 728 * Protocols may need to know when a resource has changed names in
692 729 * order to notify clients. This must be done "before" the name in the
693 730 * resource has been changed. Not being implemented is not a problem.
694 731 */
695 732
696 733 int
697 734 sa_proto_rename_resource(sa_handle_t handle, char *proto,
698 735 sa_resource_t resource, char *newname)
699 736 {
700 737 struct sa_plugin_ops *ops = find_protocol(proto);
701 738 int ret = SA_OK;
702 739
703 740 if (ops != NULL) {
704 741 if (ops->sa_rename_resource != NULL)
705 742 ret = ops->sa_rename_resource(handle, resource,
706 743 newname);
707 744 }
708 745 return (ret);
709 746 }
|
↓ open down ↓ |
447 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX