Subject: a workaround for mountd.
To: None <tech-userlevel@netbsd.org>
From: enami tsugutomo <enami@sm.sony.co.jp>
List: tech-userlevel
Date: 02/01/2000 19:55:23
The -current mountd has a bug or at least doesn't acts as before.  If
a file system is exported to everyone, the mountd fails to export
again (on SIGHUP).  Or, user modifed some export option of currently
exported file system, it failes to export on SIGHUP.

One workaround is unexport and retry when failed to export first time.
This is workaround since it introduces race condition, but is better
than failed to export.

Any throughts?

enami.
Index: mountd.c
===================================================================
RCS file: /cvsroot/basesrc/usr.sbin/mountd/mountd.c,v
retrieving revision 1.58
diff -c -r1.58 mountd.c
*** mountd.c	1999/11/14 14:37:16	1.58
--- mountd.c	2000/02/01 06:16:37
***************
*** 176,181 ****
--- 176,189 ----
  	nfsfh_t         fhr_fh;
  };
  
+ union mount_args {
+ 	struct ufs_args ua;
+ 	struct iso_args ia;
+ 	struct mfs_args ma;
+ 	struct msdosfs_args da;
+ 	struct adosfs_args aa;
+ };
+ 
  /* Global defs */
  static char    *add_expdir __P((struct dirlist **, char *, int));
  static void add_dlist __P((struct dirlist **, struct dirlist *,
***************
*** 191,196 ****
--- 199,207 ----
  static int do_opt __P((const char *, size_t, char **, char **,
      struct exportlist *, struct grouplist *, int *, int *, struct ucred *));
  static struct exportlist *ex_search __P((fsid_t *));
+ static int mount_export __P((char *, int, struct statfs *,
+     union mount_args *));
+ static int mount_unexport __P((struct statfs *));
  static int parse_directory __P((const char *, size_t, struct grouplist *,
      int, char *, struct exportlist **, struct statfs *));
  static int parse_host_netgroup __P((const char *, size_t, struct exportlist *,
***************
*** 1013,1026 ****
  	 *      instead of just MOUNT_FFS.
  	 */
  	for (i = 0; i < num; i++, fsp++) {
- 		union {
- 			struct ufs_args ua;
- 			struct iso_args ia;
- 			struct mfs_args ma;
- 			struct msdosfs_args da;
- 			struct adosfs_args aa;
- 		} targs;
- 
  		if (debug)
  			(void)fprintf(stderr,
  			    "seeing if we want to delete %s.\n",
--- 1024,1029 ----
***************
*** 1032,1060 ****
  		if (ex_search(&fsp->f_fsid))
  			continue;
  
! 		if (!strncmp(fsp->f_fstypename, MOUNT_MFS, MFSNAMELEN) ||
! 		    !strncmp(fsp->f_fstypename, MOUNT_FFS, MFSNAMELEN) ||
! 		    !strncmp(fsp->f_fstypename, MOUNT_EXT2FS, MFSNAMELEN) ||
! 		    !strncmp(fsp->f_fstypename, MOUNT_MSDOS, MFSNAMELEN) ||
! 		    !strncmp(fsp->f_fstypename, MOUNT_ADOSFS, MFSNAMELEN) ||
! 		    !strncmp(fsp->f_fstypename, MOUNT_NULL, MFSNAMELEN) ||
! 		    !strncmp(fsp->f_fstypename, MOUNT_UMAP, MFSNAMELEN) ||
! 		    !strncmp(fsp->f_fstypename, MOUNT_UNION, MFSNAMELEN) ||
! 		    !strncmp(fsp->f_fstypename, MOUNT_CD9660, MFSNAMELEN) ||
! 		    !strncmp(fsp->f_fstypename, MOUNT_NTFS, MFSNAMELEN)) {
! 			if (debug)
! 				(void)fprintf(stderr,
! 				    "Deleting export for mount %s.\n",
! 				    fsp->f_mntonname);
! 
! 			bzero((char *) &targs, sizeof(targs));
! 			targs.ua.fspec = NULL;
! 			targs.ua.export.ex_flags = MNT_DELEXPORT;
! 			if (mount(fsp->f_fstypename, fsp->f_mntonname,
! 			    fsp->f_flags | MNT_UPDATE, &targs) == -1)
! 				syslog(LOG_ERR, "Can't delete exports for %s",
! 				    fsp->f_mntonname);
! 		}
  	}
  }
  
--- 1035,1043 ----
  		if (ex_search(&fsp->f_fsid))
  			continue;
  
! 		if (mount_unexport(fsp) == -1)
! 			syslog(LOG_ERR, "Can't delete exports for %s",
! 			    fsp->f_mntonname);
  	}
  }
  
***************
*** 1674,1679 ****
--- 1657,1742 ----
  	return n;
  }
  
+ static int
+ mount_unexport(fsp)
+ 	struct statfs *fsp;
+ {
+ 	union mount_args targs;
+ 
+ 	if (!strncmp(fsp->f_fstypename, MOUNT_MFS, MFSNAMELEN) ||
+ 	    !strncmp(fsp->f_fstypename, MOUNT_FFS, MFSNAMELEN) ||
+ 	    !strncmp(fsp->f_fstypename, MOUNT_EXT2FS, MFSNAMELEN) ||
+ 	    !strncmp(fsp->f_fstypename, MOUNT_MSDOS, MFSNAMELEN) ||
+ 	    !strncmp(fsp->f_fstypename, MOUNT_ADOSFS, MFSNAMELEN) ||
+ 	    !strncmp(fsp->f_fstypename, MOUNT_NULL, MFSNAMELEN) ||
+ 	    !strncmp(fsp->f_fstypename, MOUNT_UMAP, MFSNAMELEN) ||
+ 	    !strncmp(fsp->f_fstypename, MOUNT_UNION, MFSNAMELEN) ||
+ 	    !strncmp(fsp->f_fstypename, MOUNT_CD9660, MFSNAMELEN) ||
+ 	    !strncmp(fsp->f_fstypename, MOUNT_NTFS, MFSNAMELEN)) {
+ 		if (debug)
+ 			(void)fprintf(stderr,
+ 			    "Deleting export for mount %s.\n",
+ 			    fsp->f_mntonname);
+ 
+ 		memset(&targs, 0, sizeof(targs));
+ 		targs.ua.fspec = NULL;
+ 		targs.ua.export.ex_flags = MNT_DELEXPORT;
+ 		return (mount(fsp->f_fstypename, fsp->f_mntonname,
+ 		    fsp->f_flags | MNT_UPDATE, &targs));
+ 	}
+ 
+ 	return (0);
+ }
+ 
+ static int
+ mount_export(dirp, dirplen, fsb, mntargs)
+ 	char *dirp;
+ 	int dirplen;
+ 	struct statfs *fsb;
+ 	union mount_args *mntargs;
+ {
+ 	int error;
+ 	char *cp, savedc;
+ 
+ 	cp = dirp + dirplen;		/* First, cp points terminating NUL. */
+ 	savedc = *cp;
+ 
+ 	/*
+ 	 * XXX:
+ 	 * Maybe I should just use the fsb->f_mntonname path instead
+ 	 * of looping back up the dirp to the mount point??
+ 	 * Also, needs to know how to export all types of local
+ 	 * exportable file systems and not just MOUNT_FFS.
+ 	 */
+ 	while ((error = mount(fsb->f_fstypename, dirp,
+ 	    fsb->f_flags | MNT_UPDATE, mntargs)) == -1) {
+ 		if (errno == EPERM ||
+ 		    (opt_flags & OP_ALLDIRS) != 0)
+ 			break;
+ 
+ 		*cp-- = savedc;
+ 		/* back up over the last component */
+ 		while (cp > dirp && *cp != '/')
+ 			cp--;
+ 		while (cp > dirp && *(cp - 1) != '/')
+ 			cp--;
+ 		if (cp == dirp) {
+ 			if (debug)
+ 				(void)fprintf(stderr, "mnt unsucc\n");
+ 			errno = 0;	/* This is not a system error. XXX */
+ 			goto out;	/* Don't restore the savedc. */
+ 		}
+ 		/* Now, cp points the first slash. */
+ 		savedc = *cp;
+ 		*cp = '\0';
+ 	}
+ 
+ 	*cp = savedc;
+ 
+  out:
+ 	return (error);
+ }
+ 
  /*
   * Do the mount syscall with the update flag to push the export info into
   * the kernel.
***************
*** 1690,1707 ****
  	int dirplen;
  	struct statfs *fsb;
  {
- 	char *cp = NULL;
  	u_int32_t **addrp;
! 	int done;
! 	char savedc = '\0';
  	struct sockaddr_in sin, imask;
! 	union {
! 		struct ufs_args ua;
! 		struct iso_args ia;
! 		struct mfs_args ma;
! 		struct msdosfs_args da;
! 		struct adosfs_args aa;
! 	} args;
  	u_int32_t net;
  
  	args.ua.fspec = 0;
--- 1753,1762 ----
  	int dirplen;
  	struct statfs *fsb;
  {
  	u_int32_t **addrp;
! 	int done, saved_errno;
  	struct sockaddr_in sin, imask;
! 	union mount_args args;
  	u_int32_t net;
  
  	args.ua.fspec = 0;
***************
*** 1766,1822 ****
  		default:
  			syslog(LOG_ERR, "\"%s\", line %ld: Bad netgroup type",
  			    line, (unsigned long)lineno);
- 			if (cp)
- 				*cp = savedc;
  			return (1);
  		};
  
! 		/*
! 		 * XXX:
! 		 * Maybe I should just use the fsb->f_mntonname path instead
! 		 * of looping back up the dirp to the mount point??
! 		 * Also, needs to know how to export all types of local
! 		 * exportable file systems and not just MOUNT_FFS.
! 		 */
! 		while (mount(fsb->f_fstypename, dirp,
! 		    fsb->f_flags | MNT_UPDATE, &args) == -1) {
! 			if (cp)
! 				*cp-- = savedc;
! 			else
! 				cp = dirp + dirplen - 1;
! 			if (errno == EPERM) {
! 				syslog(LOG_ERR,
! 		    "\"%s\", line %ld: Can't change attributes for %s to %s",
! 				    line, (unsigned long)lineno,
! 				    dirp, (grp->gr_type == GT_HOST) ?
! 				    grp->gr_ptr.gt_hostent->h_name :
! 				    (grp->gr_type == GT_NET) ?
! 				    grp->gr_ptr.gt_net.nt_name :
! 				    "Unknown");
! 				return (1);
! 			}
! 			if (opt_flags & OP_ALLDIRS) {
! 				syslog(LOG_ERR,
! 				"\"%s\", line %ld: Could not remount %s: %m",
! 				    line, (unsigned long)lineno,
! 				    dirp);
! 				return (1);
! 			}
! 			/* back up over the last component */
! 			while (*cp == '/' && cp > dirp)
! 				cp--;
! 			while (*(cp - 1) != '/' && cp > dirp)
! 				cp--;
! 			if (cp == dirp) {
! 				if (debug)
! 					(void)fprintf(stderr, "mnt unsucc\n");
! 				syslog(LOG_ERR, 
! 				    "\"%s\", line %ld: Can't export %s",
! 				    line, (unsigned long)lineno, dirp);
  				return (1);
  			}
- 			savedc = *cp;
- 			*cp = '\0';
  		}
  		if (addrp) {
  			++addrp;
--- 1821,1861 ----
  		default:
  			syslog(LOG_ERR, "\"%s\", line %ld: Bad netgroup type",
  			    line, (unsigned long)lineno);
  			return (1);
  		};
  
! 		if (mount_export(dirp, dirplen, fsb, &args) == -1) {
! 			saved_errno = errno;
! 			/*
! 			 * It may be just some export options are modified.
! 			 * Unexport and retry.
! 			 */
! 			if (mount_unexport(fsb) == -1 ||
! 			    mount_export(dirp, dirplen, fsb, &args) == -1) {
! 				errno = saved_errno;
! 				if (errno == EPERM)
! 					syslog(LOG_ERR,
! 					    "\"%s\", line %ld: "
! 					    "Can't change attributes for %s "
! 					    "to %s",
! 					    line, (unsigned long)lineno,
! 					    dirp, (grp->gr_type == GT_HOST) ?
! 					    grp->gr_ptr.gt_hostent->h_name :
! 					    (grp->gr_type == GT_NET) ?
! 					    grp->gr_ptr.gt_net.nt_name :
! 					    "Unknown");
! 				else if (errno != 0)
! 					syslog(LOG_ERR,
! 					    "\"%s\", line %ld: "
! 					    "Could not remount %s: %m",
! 					    line, (unsigned long)lineno, dirp);
! 				else
! 					syslog(LOG_ERR, 
! 					    "\"%s\", line %ld: "
! 					    "Can't export %s",
! 					    line, (unsigned long)lineno, dirp);
  				return (1);
  			}
  		}
  		if (addrp) {
  			++addrp;
***************
*** 1825,1832 ****
  		} else
  			done = TRUE;
  	}
- 	if (cp)
- 		*cp = savedc;
  	return (0);
  }
  
--- 1864,1869 ----