1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * Portions of this source code were derived from Berkeley 4.3 BSD 32 * under license from the Regents of the University of California. 33 */ 34 35 #pragma ident "%Z%%M% %I% %E% SMI" 36 37 /* 38 * 39 * mount.c 40 * 41 * Cachefs mount program. 42 */ 43 44 #include <locale.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <strings.h> 49 #include <stdarg.h> 50 #include <unistd.h> 51 #include <limits.h> 52 #include <errno.h> 53 #include <wait.h> 54 #include <ctype.h> 55 #include <fcntl.h> 56 #include <fslib.h> 57 #include <sys/types.h> 58 #include <sys/time.h> 59 #include <sys/param.h> 60 #include <sys/stat.h> 61 #include <sys/fcntl.h> 62 #include <sys/mount.h> 63 #include <sys/mntent.h> 64 #include <sys/mnttab.h> 65 #include <sys/mntio.h> 66 #include <sys/fs/cachefs_fs.h> 67 #include <sys/utsname.h> 68 #include <rpc/rpc.h> 69 #include <kstat.h> 70 #undef MAX 71 #include <nfs/nfs.h> 72 #include <nfs/nfs_clnt.h> 73 #include <sys/mkdev.h> 74 #include "../common/subr.h" 75 #include "../common/cachefsd.h" 76 77 char *cfs_opts[] = { 78 #define CFSOPT_BACKFSTYPE 0 79 "backfstype", 80 #define CFSOPT_CACHEDIR 1 81 "cachedir", 82 #define CFSOPT_CACHEID 2 83 "cacheid", 84 #define CFSOPT_BACKPATH 3 85 "backpath", 86 87 #define CFSOPT_WRITEAROUND 4 88 "write-around", 89 #define CFSOPT_NONSHARED 5 90 "non-shared", 91 92 #define CFSOPT_DISCONNECTABLE 6 93 "disconnectable", 94 #define CFSOPT_SOFT 7 95 "soft", 96 97 #define CFSOPT_NOCONST 8 98 "noconst", 99 #define CFSOPT_CODCONST 9 100 "demandconst", 101 102 #define CFSOPT_LOCALACCESS 10 103 "local-access", 104 #define CFSOPT_LAZYMOUNT 11 105 "lazy-mount", 106 107 #define CFSOPT_RW 12 108 "rw", 109 #define CFSOPT_RO 13 110 "ro", 111 #define CFSOPT_SUID 14 112 "suid", 113 #define CFSOPT_NOSUID 15 114 "nosuid", 115 #define CFSOPT_REMOUNT 16 116 "remount", 117 #define CFSOPT_FGSIZE 17 118 "fgsize", 119 #define CFSOPT_POPSIZE 18 120 "popsize", 121 #define CFSOPT_ACREGMIN 19 122 "acregmin", 123 #define CFSOPT_ACREGMAX 20 124 "acregmax", 125 #define CFSOPT_ACDIRMIN 21 126 "acdirmin", 127 #define CFSOPT_ACDIRMAX 22 128 "acdirmax", 129 #define CFSOPT_ACTIMEO 23 130 "actimeo", 131 #define CFSOPT_SLIDE 24 132 "slide", 133 #define CFSOPT_NOSETSEC 25 134 "nosec", /* XXX should we use MNTOPT_NOTSETSEC? */ 135 #define CFSOPT_LLOCK 26 136 "llock", 137 #define CFSOPT_NONOTIFY 27 138 "nonotify", 139 #define CFSOPT_SNR 28 140 "snr", 141 #define CFSOPT_NOFILL 29 142 "nofill", 143 #ifdef CFS_NFSV3_PASSTHROUGH 144 #define CFSOPT_NFSV3PASSTHROUGH 30 145 "nfsv3pass", 146 #endif /* CFS_NFSV3_PASSTHROUGH */ 147 NULL 148 }; 149 150 #define MNTTYPE_CFS "cachefs" /* XXX - to be added to mntent.h */ 151 /* XXX - and should be cachefs */ 152 #define CFS_DEF_DIR "/cache" /* XXX - should be added to cfs.h */ 153 154 #define bad(val) (val == NULL || !isdigit(*val)) 155 156 #define VFS_PATH "/usr/lib/fs" 157 #define ALT_PATH "/etc/fs" 158 159 /* forward references */ 160 void usage(char *msgp); 161 void pr_err(char *fmt, ...); 162 int set_cfs_args(char *optionp, struct cachefs_mountargs *margsp, int *mflagp, 163 char **backfstypepp, char **reducepp, int *notifyp, int *nfsv3pass); 164 int get_mount_point(char *cachedirp, char *specp, char **pathpp); 165 int dobackmnt(struct cachefs_mountargs *margsp, char *reducep, char *specp, 166 char *backfstypep, char *mynamep, int readonly); 167 void doexec(char *fstype, char **newargv, char *myname); 168 char *get_back_fsid(char *specp); 169 char *get_cacheid(char *, char *); 170 void record_mount(char *mntp, char *specp, char *backfsp, char *backfstypep, 171 char *cachedirp, char *cacheidp, char *optionp, char *reducep); 172 int daemon_notify(char *cachedirp, char *cacheidp); 173 int pingserver(char *backmntp); 174 int check_cache(char *cachedirp); 175 uint32_t cachefs_get_back_nfsvers(char *cfs_backfs, int nomnttab); 176 int cfs_nfsv4_build_opts(char *optionp, char *cfs_nfsv4ops); 177 178 int nomnttab; 179 int quiet; 180 /* 181 * 182 * main 183 * 184 * Description: 185 * Main routine for the cachefs mount program. 186 * Arguments: 187 * argc number of command line arguments 188 * argv list of command line arguments 189 * Returns: 190 * Returns 0 for success, 1 an error was encountered. 191 * Preconditions: 192 */ 193 194 int 195 main(int argc, char **argv) 196 { 197 char *myname; 198 char *optionp; 199 char *opigp; 200 int mflag; 201 int readonly; 202 struct cachefs_mountargs margs; 203 char *backfstypep; 204 char *reducep; 205 char *specp; 206 int xx; 207 int stat_loc; 208 char *newargv[20]; 209 char *mntp; 210 pid_t pid; 211 int mounted; 212 int c; 213 int lockid; 214 int Oflg; 215 char *strp; 216 char servname[33]; 217 int notify = 1; 218 struct stat64 statb; 219 struct mnttagdesc mtdesc; 220 char mops[MAX_MNTOPT_STR]; 221 char cfs_nfsv4ops[MAX_MNTOPT_STR]; 222 uint32_t nfsvers = 0; 223 uint32_t nfsvers_error = FALSE; 224 int nfsv3pass = 0; 225 (void) setlocale(LC_ALL, ""); 226 #if !defined(TEXT_DOMAIN) 227 #define TEXT_DOMAIN "SYS_TEST" 228 #endif 229 (void) textdomain(TEXT_DOMAIN); 230 231 if (argv[0]) { 232 myname = strrchr(argv[0], '/'); 233 if (myname) 234 myname++; 235 else 236 myname = argv[0]; 237 } else { 238 myname = "path unknown"; 239 } 240 241 optionp = NULL; 242 nomnttab = 0; 243 quiet = 0; 244 readonly = 0; 245 Oflg = 0; 246 cfs_nfsv4ops[0] = '\0'; 247 248 /* process command line options */ 249 while ((c = getopt(argc, argv, "mo:Orq")) != EOF) { 250 switch (c) { 251 case 'm': /* no entry in /etc/mnttab */ 252 nomnttab = 1; 253 break; 254 255 case 'o': 256 optionp = optarg; 257 break; 258 259 case 'O': 260 Oflg++; 261 break; 262 263 case 'r': /* read only mount */ 264 readonly = 1; 265 break; 266 267 case 'q': 268 quiet = 1; 269 break; 270 271 default: 272 usage("invalid option"); 273 return (1); 274 } 275 } 276 277 /* if -o not specified */ 278 if (optionp == NULL) { 279 usage(gettext("\"-o backfstype\" must be specified")); 280 return (1); 281 } 282 283 /* verify special device and mount point are specified */ 284 if (argc - optind < 2) { 285 usage(gettext("must specify special device and mount point")); 286 return (1); 287 } 288 289 /* Store mount point and special device. */ 290 specp = argv[argc - 2]; 291 mntp = argv[argc - 1]; 292 293 /* Initialize default mount values */ 294 margs.cfs_options.opt_flags = CFS_ACCESS_BACKFS; 295 margs.cfs_options.opt_popsize = DEF_POP_SIZE; 296 margs.cfs_options.opt_fgsize = DEF_FILEGRP_SIZE; 297 margs.cfs_fsid = NULL; 298 memset(margs.cfs_cacheid, 0, sizeof (margs.cfs_cacheid)); 299 margs.cfs_cachedir = CFS_DEF_DIR; 300 margs.cfs_backfs = NULL; 301 margs.cfs_acregmin = 0; 302 margs.cfs_acregmax = 0; 303 margs.cfs_acdirmin = 0; 304 margs.cfs_acdirmax = 0; 305 mflag = MS_OPTIONSTR; 306 if (nomnttab) 307 mflag |= MS_NOMNTTAB; 308 backfstypep = NULL; 309 310 /* process -o options */ 311 xx = set_cfs_args(optionp, &margs, &mflag, &backfstypep, &reducep, 312 ¬ify, &nfsv3pass); 313 if (xx) { 314 return (1); 315 } 316 strcpy(mops, optionp); 317 318 /* backfstype has to be specified */ 319 if (backfstypep == NULL) { 320 usage(gettext("\"-o backfstype\" must be specified")); 321 return (1); 322 } 323 324 if ((strcmp(backfstypep, "nfs") != 0) && 325 (strcmp(backfstypep, "hsfs") != 0)) { 326 pr_err(gettext("%s as backfstype is not supported."), 327 backfstypep); 328 return (1); 329 } 330 331 /* set default write mode if not specified */ 332 if ((margs.cfs_options.opt_flags & 333 (CFS_WRITE_AROUND|CFS_NONSHARED)) == 0) { 334 margs.cfs_options.opt_flags |= CFS_WRITE_AROUND; 335 if (strcmp(backfstypep, "hsfs") == 0) 336 mflag |= MS_RDONLY; 337 } 338 339 /* if read-only was specified with the -r option */ 340 if (readonly) { 341 mflag |= MS_RDONLY; 342 } 343 344 /* if overlay was specified with -O option */ 345 if (Oflg) { 346 mflag |= MS_OVERLAY; 347 } 348 349 /* get the fsid of the backfs and the cacheid */ 350 margs.cfs_fsid = get_back_fsid(specp); 351 if (margs.cfs_fsid == NULL) { 352 pr_err(gettext("out of memory")); 353 return (1); 354 } 355 356 /* 357 * If using this cachedir to mount a file system for the first time 358 * after reboot, the ncheck for the sanity of the cachedir 359 */ 360 if (first_time_ab(margs.cfs_cachedir)) 361 if (check_cache(margs.cfs_cachedir)) 362 return (1); 363 364 /* get the front file system cache id if necessary */ 365 if (margs.cfs_cacheid[0] == '\0') { 366 char *cacheid = get_cacheid(margs.cfs_fsid, mntp); 367 368 if (cacheid == NULL) { 369 pr_err(gettext("default cacheid too long")); 370 return (1); 371 } 372 373 strcpy(margs.cfs_cacheid, cacheid); 374 } 375 376 /* lock the cache directory shared */ 377 lockid = cachefs_dir_lock(margs.cfs_cachedir, 1); 378 if (lockid == -1) { 379 /* exit if could not get the lock */ 380 return (1); 381 } 382 383 /* if no mount point was specified and we are not remounting */ 384 mounted = 0; 385 if ((margs.cfs_backfs == NULL) && 386 (((mflag & MS_REMOUNT) == 0) || 387 (margs.cfs_options.opt_flags & CFS_SLIDE))) { 388 /* if a disconnectable mount */ 389 xx = 0; 390 if (margs.cfs_options.opt_flags & CFS_DISCONNECTABLE) { 391 /* see if the server is alive */ 392 xx = pingserver(specp); 393 } 394 395 /* attempt to mount the back file system */ 396 if (xx == 0) { 397 xx = dobackmnt(&margs, reducep, specp, backfstypep, 398 myname, readonly); 399 /* 400 * nfs mount exits with a value of 32 if a timeout 401 * error occurs trying the mount. 402 */ 403 if (xx && (xx != 32)) { 404 cachefs_dir_unlock(lockid); 405 rmdir(margs.cfs_backfs); 406 return (1); 407 } 408 if (xx == 0) 409 mounted = 1; 410 } 411 } 412 413 /* 414 * At this point the back file system should be mounted. 415 * Get NFS version information for the back filesystem if 416 * it is NFS. The version information is required 417 * because NFS version 4 is incompatible with cachefs 418 * and we provide pass-through support for NFS version 4 419 * with cachefs, aka the cachefs mount is installed but 420 * there is no caching. This is indicated to the kernel 421 * during the mount by setting the CFS_BACKFS_NFSV4 flag. 422 */ 423 if (margs.cfs_backfs != NULL && strcmp(backfstypep, "nfs") == 0) { 424 425 nfsvers = cachefs_get_back_nfsvers(margs.cfs_backfs, nomnttab); 426 switch (nfsvers) { 427 case 2: 428 break; 429 430 case 3: 431 if (nfsv3pass) { 432 /* Force pass through (for debugging) */ 433 margs.cfs_options.opt_flags = CFS_BACKFS_NFSV4; 434 if (cfs_nfsv4_build_opts(optionp, 435 cfs_nfsv4ops) != 0) { 436 nfsvers_error = TRUE; 437 goto clean_backmnt; 438 } 439 } 440 break; 441 442 case 4: 443 /* 444 * overwrite old option flags with NFSv4 flag. 445 * Note that will also operate in strict 446 * consistency mode. Clean up the option string 447 * to get rid of the cachefs-specific options 448 * to be in sync with the opt flags, otherwise 449 * these can make it into the mnttab and cause 450 * problems (esp. the disconnected option). 451 */ 452 margs.cfs_options.opt_flags = CFS_BACKFS_NFSV4; 453 if (cfs_nfsv4_build_opts(optionp, cfs_nfsv4ops) != 0) { 454 nfsvers_error = TRUE; 455 goto clean_backmnt; 456 } 457 break; 458 459 default: 460 /* error, unknown version */ 461 nfsvers_error = TRUE; 462 goto clean_backmnt; 463 } 464 } 465 466 /* 467 * Grab server name from special file arg if it is there or set 468 * server name to "server unknown". 469 */ 470 margs.cfs_hostname = servname; 471 strncpy(servname, specp, sizeof (servname)); 472 servname[sizeof (servname) - 1] = '\0'; 473 strp = strchr(servname, ':'); 474 if (strp == NULL) { 475 margs.cfs_hostname = "server unknown"; 476 margs.cfs_backfsname = specp; 477 } else { 478 *strp = '\0'; 479 /* 480 * The rest of the special file arg is the name of 481 * the back filesystem. 482 */ 483 strp++; 484 margs.cfs_backfsname = strp; 485 } 486 487 /* mount the cache file system */ 488 xx = mount((margs.cfs_backfs != NULL) ? margs.cfs_backfs : "nobackfs", 489 mntp, mflag | MS_DATA, MNTTYPE_CFS, 490 &margs, sizeof (margs), 491 (cfs_nfsv4ops[0] == '\0' ? mops : cfs_nfsv4ops), 492 MAX_MNTOPT_STR); 493 clean_backmnt: 494 if (xx == -1 || nfsvers_error) { 495 if (nfsvers_error) { 496 pr_err(gettext("nfs version error.")); 497 } else if (errno == ESRCH) { 498 pr_err(gettext("mount failed, options do not match.")); 499 } else if ((errno == EAGAIN) && (margs.cfs_backfs == NULL)) { 500 pr_err(gettext("mount failed, server not responding.")); 501 } else { 502 pr_err(gettext("mount failed %s"), strerror(errno)); 503 } 504 505 /* try to unmount the back file system if we mounted it */ 506 if (mounted) { 507 xx = 1; 508 newargv[xx++] = "umount"; 509 newargv[xx++] = margs.cfs_backfs; 510 newargv[xx++] = NULL; 511 512 /* fork */ 513 if ((pid = fork()) == -1) { 514 pr_err(gettext("could not fork: %s"), 515 strerror(errno)); 516 cachefs_dir_unlock(lockid); 517 return (1); 518 } 519 520 /* if the child */ 521 if (pid == 0) { 522 /* do the unmount */ 523 doexec(backfstypep, newargv, "umount"); 524 } 525 526 /* else if the parent */ 527 else { 528 wait(0); 529 } 530 rmdir(margs.cfs_backfs); 531 } 532 533 cachefs_dir_unlock(lockid); 534 return (1); 535 } 536 537 /* release the lock on the cache directory */ 538 cachefs_dir_unlock(lockid); 539 540 /* record the mount information in the fscache directory */ 541 record_mount(mntp, specp, margs.cfs_backfs, backfstypep, 542 margs.cfs_cachedir, margs.cfs_cacheid, 543 (cfs_nfsv4ops[0] == '\0' ? optionp : cfs_nfsv4ops), reducep); 544 545 /* notify the daemon of the mount */ 546 if (notify) 547 daemon_notify(margs.cfs_cachedir, margs.cfs_cacheid); 548 549 /* update mnttab file if necessary */ 550 if (!nomnttab) { 551 /* 552 * If we added the back file system, tag it with ignore, 553 * however, don't fail the mount after its done 554 * if the tag can't be added (eg., this would cause 555 * automounter problems). 556 */ 557 if (mounted) { 558 FILE *mt; 559 struct extmnttab mnt; 560 561 if ((mt = fopen(MNTTAB, "r")) == NULL) 562 return (1); 563 while (getextmntent(mt, &mnt, sizeof (mnt)) != -1) { 564 if (mnt.mnt_mountp != NULL && 565 strcmp(margs.cfs_backfs, 566 mnt.mnt_mountp) == 0) { 567 /* found it, do tag ioctl */ 568 mtdesc.mtd_major = mnt.mnt_major; 569 mtdesc.mtd_minor = mnt.mnt_minor; 570 mtdesc.mtd_mntpt = margs.cfs_backfs; 571 mtdesc.mtd_tag = MNTOPT_IGNORE; 572 573 (void) ioctl(fileno(mt), 574 MNTIOC_SETTAG, &mtdesc); 575 break; 576 } 577 } 578 fclose(mt); 579 } 580 } 581 582 /* return success */ 583 return (0); 584 } 585 586 587 /* 588 * 589 * usage 590 * 591 * Description: 592 * Prints a short usage message. 593 * Arguments: 594 * msgp message to include with the usage message 595 * Returns: 596 * Preconditions: 597 */ 598 599 void 600 usage(char *msgp) 601 { 602 if (msgp) { 603 pr_err(gettext("%s"), msgp); 604 } 605 606 fprintf(stderr, 607 gettext("Usage: mount -F cachefs [generic options] " 608 "-o backfstype=file_system_type[FSTypespecific_options] " 609 "special mount_point\n")); 610 } 611 612 /* 613 * 614 * pr_err 615 * 616 * Description: 617 * Prints an error message to stderr. 618 * Arguments: 619 * fmt printf style format 620 * ... arguments for fmt 621 * Returns: 622 * Preconditions: 623 * precond(fmt) 624 */ 625 626 void 627 pr_err(char *fmt, ...) 628 { 629 va_list ap; 630 631 va_start(ap, fmt); 632 (void) fprintf(stderr, gettext("mount -F cachefs: ")); 633 (void) vfprintf(stderr, fmt, ap); 634 (void) fprintf(stderr, "\n"); 635 va_end(ap); 636 } 637 638 /* 639 * 640 * set_cfs_args 641 * 642 * Description: 643 * Parse the comma delimited set of options specified by optionp 644 * and puts the results in margsp, mflagp, and backfstypepp. 645 * A string is constructed of options which are not specific to 646 * cfs and is placed in reducepp. 647 * Pointers to strings are invalid if this routine is called again. 648 * No initialization is done on margsp, mflagp, or backfstypepp. 649 * Arguments: 650 * optionp string of comma delimited options 651 * margsp option results for the mount dataptr arg 652 * mflagp option results for the mount mflag arg 653 * backfstypepp set to name of back file system type 654 * reducepp set to the option string without cfs specific options 655 * Returns: 656 * Returns 0 for success, -1 for an error. 657 * Preconditions: 658 * precond(optionp) 659 * precond(margsp) 660 * precond(mflagp) 661 * precond(backfstypepp) 662 * precond(reducepp) 663 */ 664 665 int 666 set_cfs_args(char *optionp, struct cachefs_mountargs *margsp, int *mflagp, 667 char **backfstypepp, char **reducepp, int *notifyp, int *nfsv3pass) 668 { 669 static char *optstrp = NULL; 670 static char *reducep = NULL; 671 char *savep, *strp, *valp; 672 int badopt; 673 int ret; 674 int o_backpath = 0; 675 int o_writemode = 0; 676 int xx; 677 uint_t yy; 678 struct stat64 sinfo; 679 char *pbuf; 680 681 /* free up any previous options */ 682 free(optstrp); 683 optstrp = NULL; 684 free(reducep); 685 reducep = NULL; 686 687 /* make a copy of the options so we can modify it */ 688 optstrp = strp = strdup(optionp); 689 reducep = malloc(strlen(optionp) + 1000); 690 if ((strp == NULL) || (reducep == NULL)) { 691 pr_err(gettext("out of memory")); 692 return (-1); 693 } 694 *reducep = '\0'; 695 696 /* parse the options */ 697 badopt = 0; 698 ret = 0; 699 while (*strp) { 700 savep = strp; 701 switch (getsubopt(&strp, cfs_opts, &valp)) { 702 703 case CFSOPT_BACKFSTYPE: 704 if (valp == NULL) 705 badopt = 1; 706 else 707 *backfstypepp = valp; 708 break; 709 710 case CFSOPT_CACHEDIR: 711 if (valp == NULL) 712 badopt = 1; 713 else { 714 margsp->cfs_cachedir = valp; 715 if (valp[0] != '/') { 716 pbuf = (char *)malloc(MAXPATHLEN + 717 strlen(valp) + 3); 718 if (pbuf == NULL) { 719 pr_err(gettext("out of memory")); 720 badopt = 1; 721 break; 722 } 723 if (getcwd(pbuf, MAXPATHLEN+1) == NULL) { 724 pr_err(gettext("cachedir too long")); 725 badopt = 1; 726 break; 727 } 728 if (pbuf[strlen(pbuf)-1] != '/') 729 strcat(pbuf, "/"); 730 strcat(pbuf, valp); 731 margsp->cfs_cachedir = pbuf; 732 } 733 } 734 break; 735 736 case CFSOPT_CACHEID: 737 if (valp == NULL) { 738 badopt = 1; 739 break; 740 } 741 742 if (strlen(valp) >= (size_t)C_MAX_MOUNT_FSCDIRNAME) { 743 pr_err(gettext("cacheid too long")); 744 badopt = 1; 745 break; 746 } 747 748 memset(margsp->cfs_cacheid, 0, C_MAX_MOUNT_FSCDIRNAME); 749 strcpy(margsp->cfs_cacheid, valp); 750 break; 751 752 case CFSOPT_BACKPATH: 753 if (valp == NULL) 754 badopt = 1; 755 else { 756 margsp->cfs_backfs = valp; 757 o_backpath = 1; 758 } 759 break; 760 761 case CFSOPT_WRITEAROUND: 762 margsp->cfs_options.opt_flags |= CFS_WRITE_AROUND; 763 o_writemode++; 764 break; 765 766 case CFSOPT_NONSHARED: 767 margsp->cfs_options.opt_flags |= CFS_NONSHARED; 768 o_writemode++; 769 break; 770 771 case CFSOPT_NOCONST: 772 margsp->cfs_options.opt_flags |= CFS_NOCONST_MODE; 773 break; 774 775 case CFSOPT_CODCONST: 776 margsp->cfs_options.opt_flags |= CFS_CODCONST_MODE; 777 break; 778 779 case CFSOPT_LOCALACCESS: 780 margsp->cfs_options.opt_flags &= ~CFS_ACCESS_BACKFS; 781 break; 782 783 case CFSOPT_NOSETSEC: 784 margsp->cfs_options.opt_flags |= CFS_NOACL; 785 break; 786 787 case CFSOPT_LLOCK: 788 margsp->cfs_options.opt_flags |= CFS_LLOCK; 789 strcat(reducep, ","); 790 strcat(reducep, savep); 791 break; 792 793 case CFSOPT_REMOUNT: 794 *mflagp |= MS_REMOUNT; 795 break; 796 797 case CFSOPT_SLIDE: 798 margsp->cfs_options.opt_flags |= CFS_SLIDE; 799 break; 800 801 case CFSOPT_FGSIZE: 802 if (bad(valp)) 803 badopt = 1; 804 else 805 margsp->cfs_options.opt_fgsize = atoi(valp); 806 break; 807 808 case CFSOPT_POPSIZE: 809 if (bad(valp)) 810 badopt = 1; 811 else 812 margsp->cfs_options.opt_popsize = 813 atoi(valp) * 1024; 814 break; 815 816 case CFSOPT_ACREGMIN: 817 if (bad(valp)) 818 badopt = 1; 819 else 820 margsp->cfs_acregmin = atoi(valp); 821 break; 822 823 case CFSOPT_ACREGMAX: 824 if (bad(valp)) 825 badopt = 1; 826 else 827 margsp->cfs_acregmax = atoi(valp); 828 break; 829 830 case CFSOPT_ACDIRMIN: 831 if (bad(valp)) 832 badopt = 1; 833 else 834 margsp->cfs_acdirmin = atoi(valp); 835 break; 836 837 case CFSOPT_ACDIRMAX: 838 if (bad(valp)) 839 badopt = 1; 840 else 841 margsp->cfs_acdirmax = atoi(valp); 842 break; 843 844 case CFSOPT_ACTIMEO: 845 if (bad(valp)) 846 badopt = 1; 847 else { 848 yy = atoi(valp); 849 margsp->cfs_acregmin = yy; 850 margsp->cfs_acregmax = yy; 851 margsp->cfs_acdirmin = yy; 852 margsp->cfs_acdirmax = yy; 853 } 854 /* 855 * Note that we do not pass the actimeo options 856 * to the back file system. This change was 857 * made for Chart. Chart needs noac or actimeo=0 858 * so it makes no sense to pass these options on. 859 * In theory it should be okay to not pass these 860 * options on for regular cachefs mounts since 861 * cachefs perform the required attribute caching. 862 */ 863 break; 864 865 #if 0 866 case CFSOPT_LAZYMOUNT: 867 margsp->cfs_options.opt_flags |= CFS_LAZYMOUNT; 868 break; 869 #endif 870 871 case CFSOPT_DISCONNECTABLE: 872 case CFSOPT_SNR: 873 margsp->cfs_options.opt_flags |= CFS_DISCONNECTABLE; 874 break; 875 876 case CFSOPT_NOFILL: 877 margsp->cfs_options.opt_flags |= CFS_NOFILL; 878 break; 879 880 case CFSOPT_SOFT: 881 margsp->cfs_options.opt_flags |= CFS_SOFT; 882 break; 883 884 case CFSOPT_NONOTIFY: 885 *notifyp = 0; 886 break; 887 888 #ifdef CFS_NFSV3_PASSTHROUGH 889 case CFSOPT_NFSV3PASSTHROUGH: 890 *nfsv3pass = 1; 891 break; 892 #endif /* CFS_NFSV3_PASSTHROUGH */ 893 894 default: 895 /* 896 * unknown or vfs layer option, save for the back 897 * file system 898 */ 899 strcat(reducep, ","); 900 strcat(reducep, savep); 901 break; 902 } 903 904 /* if a lexical error occurred */ 905 if (badopt) { 906 pr_err(gettext("invalid argument to option: \"%s\""), 907 savep); 908 badopt = 0; 909 ret = -1; 910 } 911 } 912 913 /* 914 * Should mount backfs soft if disconnectable & non-shared options 915 * are used. NFS soft option allows reads and writes to TIMEOUT 916 * when the server is not responding, which is crucial for 917 * disconnectable option to work all the time in non-shared mode. 918 * 919 * Should mount backfs semisoft if disconnectable & write-around 920 * are used. NFS semisoft option allows reads to TIMEOUT and 921 * write to block when the server is not responding, which is 922 * good for write around option because it is shared. 923 * 924 * Since disconnectable and strict options are conflicting, 925 * when disconnectable option is used, default option is set to 926 * demandconst. 927 */ 928 929 if (margsp->cfs_options.opt_flags & (CFS_DISCONNECTABLE | CFS_SOFT)) 930 if (margsp->cfs_options.opt_flags & CFS_NONSHARED) { 931 strcat(reducep, ",soft,noprint"); 932 margsp->cfs_options.opt_flags |= CFS_CODCONST_MODE; 933 } 934 else 935 strcat(reducep, ",semisoft,noprint"); 936 937 if (!(margsp->cfs_options.opt_flags & CFS_DISCONNECTABLE)) { 938 /* not snr, no need to notify the cachefsd */ 939 *notifyp = 0; 940 } 941 942 /* additional nfs options needed so disconnectable will work */ 943 if (margsp->cfs_options.opt_flags & CFS_DISCONNECTABLE) { 944 /* 945 * retry=0 so cachefs can mount if nfs mount fails 946 * even with this nfs takes 3 minutes to give up 947 * actimeo=0 because NFS does not pick up new ctime after 948 * rename 949 */ 950 strcat(reducep, ",retry=0"); 951 if (margsp->cfs_options.opt_flags & CFS_NONSHARED) 952 strcat(reducep, ",actimeo=0"); 953 } 954 955 /* check for conflicting options */ 956 xx = margsp->cfs_options.opt_flags; 957 if (o_backpath & (xx & CFS_DISCONNECTABLE)) { 958 pr_err(gettext("backpath cannot be used with disconnectable")); 959 ret = -1; 960 } 961 if (margsp->cfs_acregmin > margsp->cfs_acregmax) { 962 pr_err(gettext("acregmin cannot be greater than acregmax")); 963 ret = -1; 964 } 965 if (margsp->cfs_acdirmin > margsp->cfs_acdirmax) { 966 pr_err(gettext("acdirmin cannot be greater than acdirmax")); 967 ret = -1; 968 } 969 970 xx = CFS_NOCONST_MODE | CFS_CODCONST_MODE; 971 if ((margsp->cfs_options.opt_flags & xx) == xx) { 972 pr_err(gettext("only one of noconst and demandconst" 973 " may be specified")); 974 ret = -1; 975 } 976 977 if (o_writemode > 1) { 978 pr_err(gettext( 979 "only one of write-around or non-shared" 980 " may be specified")); 981 ret = -1; 982 } 983 984 /* if an error occured */ 985 if (ret) 986 return (-1); 987 988 /* if there are any options which are not mount specific */ 989 if (*reducep) 990 *reducepp = reducep + 1; 991 else 992 *reducepp = NULL; 993 994 /* return success */ 995 return (0); 996 } 997 998 /* 999 * 1000 * get_mount_point 1001 * 1002 * Description: 1003 * Makes a suitable mount point for the back file system. 1004 * The name of the mount point created is stored in a malloced 1005 * buffer in pathpp 1006 * Arguments: 1007 * cachedirp the name of the cache directory 1008 * specp the special name of the device for the file system 1009 * pathpp where to store the mount point 1010 * Returns: 1011 * Returns 0 for success, -1 for an error. 1012 * Preconditions: 1013 * precond(cachedirp) 1014 * precond(specp) 1015 * precond(pathpp) 1016 */ 1017 1018 int 1019 get_mount_point(char *cachedirp, char *specp, char **pathpp) 1020 { 1021 char *strp; 1022 char *namep; 1023 struct stat64 stat1, stat2; 1024 int xx; 1025 int index; 1026 int max; 1027 1028 /* make a copy of the special device name */ 1029 specp = strdup(specp); 1030 if (specp == NULL) { 1031 pr_err(gettext("out of memory")); 1032 return (-1); 1033 } 1034 1035 /* convert the special device name into a file name */ 1036 strp = specp; 1037 while (strp = strchr(strp, '/')) { 1038 *strp = '_'; 1039 } 1040 1041 /* get some space for the path name */ 1042 strp = malloc(MAXPATHLEN); 1043 if (strp == NULL) { 1044 pr_err(gettext("out of memory")); 1045 return (-1); 1046 } 1047 1048 /* see if the mount directory is valid */ 1049 /* backfs can contain large files */ 1050 sprintf(strp, "%s/%s", cachedirp, BACKMNT_NAME); 1051 xx = stat64(strp, &stat1); 1052 if ((xx == -1) || !S_ISDIR(stat1.st_mode)) { 1053 pr_err(gettext("%s is not a valid cache."), strp); 1054 return (-1); 1055 } 1056 1057 /* find a directory name we can use */ 1058 max = 10000; 1059 namep = strp + strlen(strp); 1060 for (index = 1; index < max; index++) { 1061 1062 /* construct a directory name to consider */ 1063 if (index == 1) 1064 sprintf(namep, "/%s", specp); 1065 else 1066 sprintf(namep, "/%s_%d", specp, index); 1067 1068 /* try to create the directory */ 1069 xx = mkdir(strp, 0755); 1070 if (xx == 0) { 1071 /* done if the create succeeded */ 1072 break; 1073 } 1074 } 1075 1076 /* if the search failed */ 1077 if (index >= max) { 1078 pr_err(gettext("could not create a directory")); 1079 return (-1); 1080 } 1081 1082 /* return success */ 1083 *pathpp = strp; 1084 return (0); 1085 } 1086 1087 1088 int 1089 dobackmnt(struct cachefs_mountargs *margsp, char *reducep, char *specp, 1090 char *backfstypep, char *mynamep, int readonly) 1091 { 1092 int xx; 1093 pid_t pid; 1094 char *newargv[20]; 1095 int stat_loc; 1096 1097 /* get a suitable mount point */ 1098 xx = get_mount_point(margsp->cfs_cachedir, specp, &margsp->cfs_backfs); 1099 if (xx) 1100 return (1); 1101 1102 /* construct argument list for mounting the back file system */ 1103 xx = 1; 1104 newargv[xx++] = "mount"; 1105 if (readonly) 1106 newargv[xx++] = "-r"; 1107 if (nomnttab) 1108 newargv[xx++] = "-m"; 1109 if (quiet) 1110 newargv[xx++] = "-q"; 1111 if (reducep) { 1112 newargv[xx++] = "-o"; 1113 newargv[xx++] = reducep; 1114 } 1115 newargv[xx++] = specp; 1116 newargv[xx++] = margsp->cfs_backfs; 1117 newargv[xx++] = NULL; 1118 1119 /* fork */ 1120 if ((pid = fork()) == -1) { 1121 pr_err(gettext("could not fork %s"), strerror(errno)); 1122 return (1); 1123 } 1124 1125 /* if the child */ 1126 if (pid == 0) { 1127 /* do the mount */ 1128 doexec(backfstypep, newargv, mynamep); 1129 } 1130 1131 /* else if the parent */ 1132 else { 1133 /* wait for the child to exit */ 1134 if (wait(&stat_loc) == -1) { 1135 pr_err(gettext("wait failed %s"), strerror(errno)); 1136 return (1); 1137 } 1138 1139 if (!WIFEXITED(stat_loc)) { 1140 pr_err(gettext("back mount did not exit")); 1141 return (1); 1142 } 1143 1144 xx = WEXITSTATUS(stat_loc); 1145 if (xx) { 1146 pr_err(gettext("back mount failed")); 1147 return (xx); 1148 } 1149 } 1150 1151 return (0); 1152 } 1153 1154 /* 1155 * 1156 * doexec 1157 * 1158 * Description: 1159 * Execs the specified program with the specified command line arguments. 1160 * This function never returns. 1161 * Arguments: 1162 * fstype type of file system 1163 * newargv command line arguments 1164 * progp name of program to exec 1165 * Returns: 1166 * Preconditions: 1167 * precond(fstype) 1168 * precond(newargv) 1169 */ 1170 1171 void 1172 doexec(char *fstype, char *newargv[], char *progp) 1173 { 1174 char full_path[PATH_MAX]; 1175 char alter_path[PATH_MAX]; 1176 char *vfs_path = VFS_PATH; 1177 char *alt_path = ALT_PATH; 1178 1179 /* build the full pathname of the fstype dependent command. */ 1180 sprintf(full_path, "%s/%s/%s", vfs_path, fstype, progp); 1181 sprintf(alter_path, "%s/%s/%s", alt_path, fstype, progp); 1182 1183 /* if the program exists */ 1184 if (access(full_path, 0) == 0) { 1185 /* invoke the program */ 1186 execv(full_path, &newargv[1]); 1187 1188 /* if wrong permissions */ 1189 if (errno == EACCES) { 1190 pr_err(gettext("cannot execute %s %s"), 1191 full_path, strerror(errno)); 1192 } 1193 1194 /* if it did not work and the shell might make it */ 1195 if (errno == ENOEXEC) { 1196 newargv[0] = "sh"; 1197 newargv[1] = full_path; 1198 execv("/sbin/sh", &newargv[0]); 1199 } 1200 } 1201 1202 /* try the alternate path */ 1203 execv(alter_path, &newargv[1]); 1204 1205 /* if wrong permissions */ 1206 if (errno == EACCES) { 1207 pr_err(gettext("cannot execute %s %s"), 1208 alter_path, strerror(errno)); 1209 } 1210 1211 /* if it did not work and the shell might make it */ 1212 if (errno == ENOEXEC) { 1213 newargv[0] = "sh"; 1214 newargv[1] = alter_path; 1215 execv("/sbin/sh", &newargv[0]); 1216 } 1217 1218 pr_err(gettext("operation not applicable to FSType %s"), fstype); 1219 exit(1); 1220 } 1221 1222 /* 1223 * 1224 * get_back_fsid 1225 * 1226 * Description: 1227 * Determines a unique identifier for the back file system. 1228 * Arguments: 1229 * specp the special file of the back fs 1230 * Returns: 1231 * Returns a malloc string which is the unique identifer 1232 * or NULL on failure. NULL is only returned if malloc fails. 1233 * Preconditions: 1234 * precond(specp) 1235 */ 1236 1237 char * 1238 get_back_fsid(char *specp) 1239 { 1240 return (strdup(specp)); 1241 } 1242 1243 /* 1244 * 1245 * get_cacheid 1246 * 1247 * Description: 1248 * Determines an identifier for the front file system cache. 1249 * The returned string points to a static buffer which is 1250 * overwritten on each call. 1251 * The length of the returned string is < C_MAX_MOUNT_FSCDIRNAME. 1252 * Arguments: 1253 * fsidp back file system id 1254 * mntp front file system mount point 1255 * Returns: 1256 * Returns a pointer to the string identifier, or NULL if the 1257 * identifier was overflowed. 1258 * Preconditions: 1259 * precond(fsidp) 1260 * precond(mntp) 1261 */ 1262 1263 char * 1264 get_cacheid(char *fsidp, char *mntp) 1265 { 1266 char *c1; 1267 static char buf[PATH_MAX]; 1268 char mnt_copy[PATH_MAX]; 1269 1270 /* strip off trailing space in mountpoint -- autofs fallout */ 1271 if (strlen(mntp) >= sizeof (mnt_copy)) 1272 return (NULL); 1273 (void) strcpy(mnt_copy, mntp); 1274 c1 = mnt_copy + strlen(mnt_copy) - 1; 1275 if (*c1 == ' ') 1276 *c1 = '\0'; 1277 1278 if ((strlen(fsidp) + strlen(mnt_copy) + 2) >= 1279 (size_t)C_MAX_MOUNT_FSCDIRNAME) 1280 return (NULL); 1281 1282 strcpy(buf, fsidp); 1283 strcat(buf, ":"); 1284 strcat(buf, mnt_copy); 1285 c1 = buf; 1286 while ((c1 = strpbrk(c1, "/")) != NULL) 1287 *c1 = '_'; 1288 return (buf); 1289 } 1290 1291 1292 /* 1293 * 1294 * check_cache 1295 * 1296 * Description: 1297 * Checks the cache we are about to use. 1298 * Arguments: 1299 * cachedirp cachedirectory to check 1300 * Returns: 1301 * Returns 0 for success, -1 for an error. 1302 * Preconditions: 1303 */ 1304 int 1305 check_cache(cachedirp) 1306 char *cachedirp; 1307 { 1308 char *fsck_argv[4]; 1309 int status = 0; 1310 pid_t pid; 1311 1312 fsck_argv[1] = "fsck"; 1313 fsck_argv[2] = cachedirp; 1314 fsck_argv[3] = NULL; 1315 1316 /* fork */ 1317 if ((pid = fork()) == -1) { 1318 pr_err(gettext("could not fork %s"), 1319 strerror(errno)); 1320 return (1); 1321 } 1322 1323 if (pid == 0) { 1324 /* do the fsck */ 1325 doexec("cachefs", fsck_argv, "fsck"); 1326 } else { 1327 /* wait for the child to exit */ 1328 if (wait(&status) == -1) { 1329 pr_err(gettext("wait failed %s"), 1330 strerror(errno)); 1331 return (1); 1332 } 1333 1334 if (!WIFEXITED(status)) { 1335 pr_err(gettext("cache fsck did not exit")); 1336 return (1); 1337 } 1338 1339 if (WEXITSTATUS(status) != 0) { 1340 pr_err(gettext("cache fsck mount failed")); 1341 return (1); 1342 } 1343 } 1344 return (0); 1345 } 1346 1347 /* 1348 * 1349 * record_mount 1350 * 1351 * Description: 1352 * Records mount information in a file in the fscache directory. 1353 * Arguments: 1354 * Returns: 1355 * Preconditions: 1356 */ 1357 1358 void 1359 record_mount(char *mntp, char *specp, char *backfsp, char *backfstypep, 1360 char *cachedirp, char *cacheidp, char *optionp, char *reducep) 1361 { 1362 char buf[MAXPATHLEN*2]; 1363 FILE *fout; 1364 time_t tval; 1365 1366 tval = time(NULL); 1367 1368 /* this file is < 2GB */ 1369 sprintf(buf, "%s/%s/%s", cachedirp, cacheidp, CACHEFS_MNT_FILE); 1370 fout = fopen(buf, "w"); 1371 if (fout == NULL) { 1372 pr_err(gettext("could not open %s, %d"), buf, errno); 1373 return; 1374 } 1375 1376 fprintf(fout, "cachedir: %s\n", cachedirp); 1377 fprintf(fout, "mnt_point: %s\n", mntp); 1378 if (specp) { 1379 fprintf(fout, "special: %s\n", specp); 1380 } 1381 if (backfsp) 1382 fprintf(fout, "backpath: %s\n", backfsp); 1383 fprintf(fout, "backfstype: %s\n", backfstypep); 1384 fprintf(fout, "cacheid: %s\n", cacheidp); 1385 fprintf(fout, "cachefs_options: %s\n", optionp); 1386 if (reducep) 1387 fprintf(fout, "backfs_options: %s\n", reducep); 1388 fprintf(fout, "mount_time: %u\n", tval); 1389 1390 fclose(fout); 1391 } 1392 1393 int 1394 daemon_notify(char *cachedirp, char *cacheidp) 1395 { 1396 CLIENT *clnt; 1397 enum clnt_stat retval; 1398 int ret; 1399 int xx; 1400 int result; 1401 char *hostp; 1402 struct utsname info; 1403 struct cachefsd_fs_mounted args; 1404 1405 /* get the host name */ 1406 xx = uname(&info); 1407 if (xx == -1) { 1408 pr_err(gettext("cannot get host name, errno %d"), errno); 1409 return (1); 1410 } 1411 hostp = info.nodename; 1412 1413 /* creat the connection to the daemon */ 1414 clnt = clnt_create(hostp, CACHEFSDPROG, CACHEFSDVERS, "local"); 1415 if (clnt == NULL) { 1416 pr_err(gettext("cachefsd is not running")); 1417 return (1); 1418 } 1419 1420 args.mt_cachedir = cachedirp; 1421 args.mt_cacheid = cacheidp; 1422 retval = cachefsd_fs_mounted_1(&args, NULL, clnt); 1423 if (retval != RPC_SUCCESS) { 1424 clnt_perror(clnt, gettext("cachefsd is not responding")); 1425 clnt_destroy(clnt); 1426 return (1); 1427 } 1428 1429 ret = 0; 1430 1431 clnt_destroy(clnt); 1432 1433 return (ret); 1434 } 1435 1436 /* returns 0 if the server is alive, -1 if an error */ 1437 int 1438 pingserver(char *backmntp) 1439 { 1440 CLIENT *clnt; 1441 static struct timeval TIMEOUT = { 25, 0 }; 1442 enum clnt_stat retval; 1443 int ret; 1444 int xx; 1445 char *hostp; 1446 char buf[MAXPATHLEN]; 1447 char *pc; 1448 1449 /* get the host name */ 1450 strcpy(buf, backmntp); 1451 pc = strchr(buf, ':'); 1452 if (pc == NULL) { 1453 /* no host name, pretend it works */ 1454 return (0); 1455 } 1456 *pc = '\0'; 1457 hostp = buf; 1458 1459 /* create the connection to the mount daemon */ 1460 clnt = clnt_create(hostp, NFS_PROGRAM, NFS_VERSION, "udp"); 1461 if (clnt == NULL) { 1462 return (-1); 1463 } 1464 1465 ret = 0; 1466 1467 /* see if the mountd responds */ 1468 retval = clnt_call(clnt, 0, xdr_void, NULL, xdr_void, NULL, 1469 TIMEOUT); 1470 if (retval != RPC_SUCCESS) { 1471 ret = -1; 1472 } 1473 1474 clnt_destroy(clnt); 1475 1476 return (ret); 1477 } 1478 1479 /* 1480 * first_time_ab : first time after boot - returns non-zero value 1481 * if the cachedir is being used for the first time 1482 * after the system reboot, otherwise zero. 1483 */ 1484 int 1485 first_time_ab(char *buf) 1486 { 1487 struct stat sinfo; 1488 char name[MAXPATHLEN]; 1489 int ufd; 1490 time32_t btime; 1491 1492 sprintf(name, "%s/%s", buf, CACHEFS_UNMNT_FILE); 1493 if (stat(name, &sinfo) != 0) 1494 return (1); 1495 if (sinfo.st_size == 0) 1496 return (1); 1497 if ((ufd = open(name, O_RDONLY)) == -1) 1498 return (1); 1499 if (read(ufd, &btime, sizeof (time32_t)) == -1) 1500 return (1); 1501 close(ufd); 1502 if (get_boottime() != btime) 1503 return (1); 1504 return (0); 1505 } 1506 1507 /* 1508 * cachefs_get_back_nfsvers 1509 * 1510 * Returns: nfs version 1511 * 1512 * Params: 1513 * cfs_backfs - backfile system mountpoint 1514 * nomnttab - mnttab entry does not exist 1515 * 1516 * Uses the kstat interface to extract the nfs version for 1517 * the mount. 1518 */ 1519 uint32_t 1520 cachefs_get_back_nfsvers(char *cfs_backfs, int nomnttab) 1521 { 1522 kstat_ctl_t *kc = NULL; 1523 FILE *mnttab = NULL; 1524 struct extmnttab mnt; 1525 kstat_t *ksp; 1526 dev_t my_fsid = NODEV; 1527 struct mntinfo_kstat mik; 1528 uint32_t nfsvers = 0; 1529 struct stat64 st; 1530 1531 /* 1532 * Initialize kernel statistics facility. 1533 */ 1534 if ((kc = kstat_open()) == NULL) { 1535 pr_err(gettext("kstat_open() can't open /dev/kstat: %s"), 1536 strerror(errno)); 1537 goto end; 1538 } 1539 1540 /* 1541 * Locate the mount information in the mnttab if the nomnttab 1542 * flag is not set, otherwise look for the entry by doing 1543 * stat'ting the mountpoint. 1544 */ 1545 if (!nomnttab) { 1546 if ((mnttab = fopen(MNTTAB, "r")) == NULL) { 1547 pr_err(gettext("can't open /etc/mnttab: %s"), 1548 strerror(errno)); 1549 goto end; 1550 } 1551 1552 while (getextmntent(mnttab, &mnt, sizeof (mnt)) != -1) { 1553 if (mnt.mnt_mountp == NULL || 1554 strcmp(cfs_backfs, mnt.mnt_mountp) != 0) { 1555 continue; 1556 } 1557 my_fsid = makedev(mnt.mnt_major, mnt.mnt_minor); 1558 break; 1559 } 1560 } 1561 1562 if (my_fsid == NODEV) { 1563 if (stat64(cfs_backfs, &st) == -1) { 1564 pr_err(gettext("can't stat mountpoint: %s"), 1565 strerror(errno)); 1566 goto end; 1567 } else { 1568 my_fsid = st.st_dev; 1569 } 1570 1571 } 1572 1573 /* 1574 * Walk the kstat control structures to locate the 1575 * structure that describes the nfs module/mntinfo 1576 * statistics for the mounted backfilesystem. 1577 */ 1578 for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) { 1579 1580 if (ksp->ks_type != KSTAT_TYPE_RAW) 1581 continue; 1582 if (strcmp(ksp->ks_module, "nfs") != 0) 1583 continue; 1584 if (strcmp(ksp->ks_name, "mntinfo") != 0) 1585 continue; 1586 if ((my_fsid & MAXMIN) != ksp->ks_instance) 1587 continue; 1588 1589 /* 1590 * At this point we have located the 1591 * kstat info for the mount, read the 1592 * statistics and return version info. 1593 */ 1594 if (kstat_read(kc, ksp, &mik) == -1) { 1595 pr_err(gettext("kstat_read() can't read %s/%s: %s"), 1596 ksp->ks_module, ksp->ks_name, strerror(errno)); 1597 goto end; 1598 } 1599 1600 nfsvers = mik.mik_vers; 1601 break; 1602 } 1603 1604 end: 1605 if (kc) 1606 kstat_close(kc); 1607 if (mnttab) 1608 fclose(mnttab); 1609 1610 return (nfsvers); 1611 } 1612 1613 /* 1614 * cfs_nfsv4_build_opts 1615 * 1616 * Returns: 0 on success, -1 on failure 1617 * 1618 * Params: 1619 * optionp - original option pointer 1620 * cfs_nfsv4ops - modified options for nfsv4 cachefs mount 1621 * 1622 * Parse the comma delimited set of options specified by optionp 1623 * and clean out options that we don't want to use with NFSv4. 1624 */ 1625 int 1626 cfs_nfsv4_build_opts(char *optionp, char *cfs_nfsv4ops) 1627 { 1628 char *optstrp; 1629 char *strp; 1630 char *savep; 1631 char *valp; 1632 uint32_t first = TRUE; 1633 1634 /* Make a copy of the options so we can modify it */ 1635 optstrp = strp = strdup(optionp); 1636 if (strp == NULL) { 1637 pr_err(gettext("out of memory")); 1638 return (-1); 1639 } 1640 1641 /* Parse the options, cfs_nfsv4ops is initialized in main */ 1642 while (*strp) { 1643 savep = strp; 1644 switch (getsubopt(&strp, cfs_opts, &valp)) { 1645 1646 /* Ignore options that set cfs option flags */ 1647 case CFSOPT_WRITEAROUND: 1648 case CFSOPT_NONSHARED: 1649 case CFSOPT_NOCONST: 1650 case CFSOPT_CODCONST: 1651 case CFSOPT_LOCALACCESS: 1652 case CFSOPT_NOSETSEC: 1653 case CFSOPT_LLOCK: 1654 case CFSOPT_SLIDE: 1655 case CFSOPT_DISCONNECTABLE: 1656 case CFSOPT_SNR: 1657 case CFSOPT_NOFILL: 1658 case CFSOPT_SOFT: 1659 break; 1660 1661 default: 1662 /* 1663 * Copy in option for cachefs nfsv4 mount. 1664 */ 1665 snprintf(cfs_nfsv4ops, MAX_MNTOPT_STR, 1666 "%s%s%s", cfs_nfsv4ops, first ? "" : ",", 1667 savep); 1668 first = FALSE; 1669 break; 1670 } 1671 } 1672 free(optstrp); 1673 1674 return (0); 1675 }