Subject: kern/5603: NULLFS and UMAPFS export
To: None <gnats-bugs@gnats.netbsd.org>
From: None <perseant@hitl.washington.edu>
List: netbsd-bugs
Date: 06/17/1998 16:44:20
>Number:         5603
>Category:       kern
>Synopsis:       It would be nice to allow exports of NULLFS-derived filesystems
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people (Kernel Bug People)
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Wed Jun 17 16:50:00 1998
>Last-Modified:
>Originator:     Konrad Schroder
>Organization:
 Konrad Schroder           http://www.hitl.washington.edu/people/perseant/
 System Administrator                         perseant@hitl.washington.edu
 Human Interface Technology Lab                      Voice: (206) 616-1478
 Box 352142, University of Washington, 98195, USA      FAX: (206) 543-5380
>Release:        1.3.2, though AFAICT nullfs and umapfs haven't changed since
>Environment:
System: NetBSD scratchy 1.3.2 NetBSD 1.3.2 (HITL_GENERIC) #11: Wed Jun 17 11:59:35 PDT 1998     perseant@ftp:/usr/src/sys/arch/sparc/compile/HITL_GENERIC sparc

>Description:
	It would be nice if nullfs and friends, particularly umap, could
	be exported.

	We have a need to export Umap filesystems between departments
	which represent different administrative domains (and so inevitably
	different sets of UID/GIDs).  This is essentially the same
	scenario as one of the main examples of umap in the Red Daemon Book,
	and the patch to allow this is relatively simple.

	Currently, we are using an exported umapfs in production; though
	I have successfully copied kernel sources into and successfully
	done a "make depend && make" on an exported nullfs, I have not
	done further testing.

	The patch below can only determine stale filehandles correctly if
	the underlying filesystem is an FFS, which, although sufficient
	for my site, is a gross hack.  Breaking out the determination
	of filehandle staleness (or possibly of filesystem mountedness) from
	VFS_FHTOVP into, say, VOP_STALE would provide a more general solution.
	I'd be happy to implement that, if it is desired.

	Union would also be desirable to export, though I've left that
	for later.
>How-To-Repeat:
>Fix:

*** sys/miscfs/umapfs.dist/umap.h	Mon Oct  6 04:26:46 1997
--- sys/miscfs/umapfs/umap.h	Tue Jun  9 13:07:58 1998
***************
*** 47,50 ****
--- 47,52 ----
  struct umap_args {
  	char		*target;	/* Target of loopback  */
+ 	/* XXX It is a silent requirement of mountd that this be second */
+         struct  export_args export;     /* network export information */
  	int 		nentries;       /* # of entries in user map array */
  	int 		gnentries;	/* # of entries in group map array */
***************
*** 53,56 ****
--- 55,59 ----
  };
  
+ #ifdef _KERNEL
  struct umap_mount {
  	struct mount	*umapm_vfs;
***************
*** 62,68 ****
  	u_long		info_gmapdata[GMAPFILEENTRIES][2]; /*mapping data for 
  	    group mapping in ficus */
  };
  
- #ifdef _KERNEL
  /*
   * A cache of vnode references
--- 65,71 ----
  	u_long		info_gmapdata[GMAPFILEENTRIES][2]; /*mapping data for 
  	    group mapping in ficus */
+ 	struct  netexport umapm_export;            /* export information */
  };
  
  /*
   * A cache of vnode references
*** sys/miscfs/umapfs.dist/umap_subr.c	Thu Sep 11 04:20:58 1997
--- sys/miscfs/umapfs/umap_subr.c	Tue Jun  9 11:57:10 1998
***************
*** 434,446 ****
  		structure. */
  
! 	i = 0;
! 	while (credp->cr_groups[i] != 0) {
  		gid = (gid_t) umap_findid(credp->cr_groups[i],
  					  groupmap, gnentries);
- 
  		if (gid != -1)
! 			credp->cr_groups[i++] = gid;
  		else
! 			credp->cr_groups[i++] = NULLGROUP;
  	}
  }
--- 434,444 ----
  		structure. */
  
! 	for(i=0; i<credp->cr_ngroups; i++) {
  		gid = (gid_t) umap_findid(credp->cr_groups[i],
  					groupmap, gnentries);
  		if(gid != -1)
! 			credp->cr_groups[i] = gid;
  		else
! 			credp->cr_groups[i] = NULLGROUP;
  	}
  }
*** sys/miscfs/umapfs.dist/umap_vfsops.c	Mon Oct  6 04:26:46 1997
--- sys/miscfs/umapfs/umap_vfsops.c	Tue Jun  9 13:07:33 1998
***************
*** 55,58 ****
--- 55,64 ----
  #include <miscfs/umapfs/umap.h>
  
+ #include <ufs/ufs/quota.h>
+ #include <ufs/ufs/ufsmount.h>
+ #include <ufs/ufs/inode.h>
+ #include <ufs/ufs/dir.h>
+ #include <ufs/ufs/ufs_extern.h>
+ 
  int	umapfs_mount __P((struct mount *, const char *, void *,
  			  struct nameidata *, struct proc *));
***************
*** 86,103 ****
  	size_t size;
  	int error;
- 
  #ifdef UMAPFS_DIAGNOSTIC
  	printf("umapfs_mount(mp = %p)\n", mp);
  #endif
  
  	/*
- 	 * Update is a no-op
- 	 */
- 	if (mp->mnt_flag & MNT_UPDATE) {
- 		return (EOPNOTSUPP);
- 		/* return (VFS_MOUNT(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, path, data, ndp, p));*/
- 	}
- 
- 	/*
  	 * Get argument
  	 */
--- 92,102 ----
  	size_t size;
  	int error;
  #ifdef UMAPFS_DIAGNOSTIC
+ 	int i;
+ 
  	printf("umapfs_mount(mp = %p)\n", mp);
  #endif
  
  	/*
  	 * Get argument
  	 */
***************
*** 107,110 ****
--- 106,123 ----
  
  	/*
+ 	 * Update is a no-op, unless it is an export and we're allowing those
+ 	 */
+ 	if (mp->mnt_flag & MNT_UPDATE) {
+ 		if(args.target == 0) {
+ #ifdef UMAPFS_DIAGNOSTIC
+ 			printf("target = 0, processing export\n");
+ #endif /* UMAPFS_DIAGNOSTIC */
+ 			return (vfs_export(mp, &(MOUNTTOUMAPMOUNT(mp)->umapm_export), &args.export));
+ 		}
+ 		return (EOPNOTSUPP);
+ 		/* return (VFS_MOUNT(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, path, data, ndp, p));*/
+ 	}
+ 
+ 	/*
  	 * Find lower node
  	 */
***************
*** 154,158 ****
  	printf("umap_mount:nentries %d\n",args.nentries);
  	for (i = 0; i < args.nentries; i++)
! 		printf("   %d maps to %d\n", amp->info_mapdata[i][0],
  	 	    amp->info_mapdata[i][1]);
  #endif
--- 167,171 ----
  	printf("umap_mount:nentries %d\n",args.nentries);
  	for (i = 0; i < args.nentries; i++)
! 		printf("   %ld maps to %ld\n", amp->info_mapdata[i][0],
  	 	    amp->info_mapdata[i][1]);
  #endif
***************
*** 166,170 ****
  	printf("umap_mount:gnentries %d\n",args.gnentries);
  	for (i = 0; i < args.gnentries; i++)
! 		printf("\tgroup %d maps to %d\n", 
  		    amp->info_gmapdata[i][0],
  	 	    amp->info_gmapdata[i][1]);
--- 179,183 ----
  	printf("umap_mount:gnentries %d\n",args.gnentries);
  	for (i = 0; i < args.gnentries; i++)
! 		printf("\tgroup %ld maps to %ld\n", 
  		    amp->info_gmapdata[i][0],
  	 	    amp->info_gmapdata[i][1]);
***************
*** 384,389 ****
  	struct vnode **vpp;
  {
  	
! 	return (VFS_VGET(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, ino, vpp));
  }
  
--- 397,410 ----
  	struct vnode **vpp;
  {
+         int ret;
+         struct vnode *nvp;
   
!         ret = VFS_VGET(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, ino, &nvp);
!         /*
!          * XXX - This only works because locking gets transparently
!          * passed on to the lower layer!  --ks
!          */
!         umap_node_create(mp,nvp,vpp); 
!         return ret;
  }
  
***************
*** 397,402 ****
  	struct ucred**credanonp;
  {
  
! 	return (EOPNOTSUPP);
  }
  
--- 418,457 ----
  	struct ucred**credanonp;
  {
+ 	int error;
+         struct netcred *np;
+         struct vnode *nvp;
  
! 	/* adapted from ufs_check_export */
! 	
!         np = vfs_export_lookup(mp, &(MOUNTTOUMAPMOUNT(mp)->umapm_export), nam);
!         if (np == NULL)
!                 return (EACCES);
!         if ((error = VFS_VGET(MOUNTTOUMAPMOUNT(mp)->umapm_vfs,
! 	    ((struct ufid *)fidp)->ufid_ino, &nvp)) != 0) {
!                 *vpp = NULLVP;
!                 return (error);
!         }
! 	/* XXXX - KS - this is a kludge; we really want a VOP_STALE instead */
! 	if(nvp->v_tag == VT_UFS || nvp->v_tag == VT_LFS) {
! 		struct inode *ip;
! 
! 	        ip = VTOI(nvp);
! 		if (ip->i_ffs_mode == 0 || ip->i_ffs_gen != ((struct ufid *)fidp)->ufid_gen) {
! 			vput(nvp);
! 			*vpp = NULLVP;
! #ifdef UMAPFS_DIAGNOSTIC
! 			printf("ffs_mode = %d,",ip->i_ffs_mode);
! 			printf(" ffs_gen = %d, nfs_gen = %d\n",
! 			       ip->i_ffs_gen, ((struct ufid *)fidp)->ufid_gen);
! #endif
! 			return (ESTALE);
! 		}
! 	}
! 
! 	umap_node_create(mp,nvp,vpp);
!         *exflagsp = np->netc_exflags;
!         *credanonp = &np->netc_anon;
! 
! 	return 0;
  }
  
***************
*** 406,411 ****
  	struct fid *fhp;
  {
  
! 	return (EOPNOTSUPP);
  }
  
--- 461,468 ----
  	struct fid *fhp;
  {
+ 	int ret;
  
! 	ret = VFS_VPTOFH(UMAPVPTOLOWERVP(vp), fhp);
! 	return ret;
  }
  
*** sys/miscfs/umapfs.dist/umap_vnops.c	Mon Oct  6 04:26:46 1997
--- sys/miscfs/umapfs/umap_vnops.c	Thu Jun  4 10:03:01 1998
***************
*** 151,163 ****
  		 */
  
! 		if (i && (*this_vp_p)->v_op != umap_vnodeop_p) {
  			old_vps[i] = NULL;
  		} else {
  			old_vps[i] = *this_vp_p;
  			*(vps_p[i]) = UMAPVPTOLOWERVP(*this_vp_p);
! 			if (reles & 1)
  				VREF(*this_vp_p);
  		}
! 			
  	}
  
--- 151,163 ----
  		 */
  
! 		if (i && ((*this_vp_p) == NULLVP || (*this_vp_p)->v_op != umap_vnodeop_p)) {
  			old_vps[i] = NULL;
  		} else {
  			old_vps[i] = *this_vp_p;
  			*(vps_p[i]) = UMAPVPTOLOWERVP(*this_vp_p);
! 			if (reles & 1) {
  				VREF(*this_vp_p);
  			}
! 		}
  	}
  
***************
*** 178,184 ****
  		credp = *credpp;
  
! 		if (umap_bug_bypass && credp->cr_uid != 0)
! 			printf("umap_bypass: user was %d, group %d\n", 
  			    credp->cr_uid, credp->cr_gid);
  
  		/* Map all ids in the credential structure. */
--- 178,190 ----
  		credp = *credpp;
  
! 		if (umap_bug_bypass && credp->cr_uid != 0) {
! 			printf("umap_bypass: user was %d, group %d (", 
  			    credp->cr_uid, credp->cr_gid);
+ 			for(i=0; i<credp->cr_ngroups; i++) {
+ 				printf("%d%s", credp->cr_groups[i],
+ 					(i==credp->cr_ngroups-1?"":","));
+ 			}
+ 			printf(")\n");
+ 		}
  
  		/* Map all ids in the credential structure. */
***************
*** 186,192 ****
  		umap_mapids(vp1->v_mount, credp);
  
! 		if (umap_bug_bypass && credp->cr_uid != 0)
  			printf("umap_bypass: user now %d, group %d\n", 
  			    credp->cr_uid, credp->cr_gid);
  	}
  
--- 192,204 ----
  		umap_mapids(vp1->v_mount, credp);
  
! 		if (umap_bug_bypass && credp->cr_uid != 0) {
  			printf("umap_bypass: user now %d, group %d\n", 
  			    credp->cr_uid, credp->cr_gid);
+ 			for(i=0; i<credp->cr_ngroups; i++) {
+ 				printf("%d%s", credp->cr_groups[i],
+ 					(i==credp->cr_ngroups-1?"":","));
+ 			}
+ 			printf(")\n");
+ 		}
  	}
  
*** sys/miscfs/nullfs.dist/null.h	Wed Jun 17 11:15:19 1998
--- sys/miscfs/nullfs/null.h	Wed Jun 17 11:54:49 1998
***************
*** 42,45 ****
--- 42,47 ----
  struct null_args {
  	char		*target;	/* Target of loopback  */
+ 	/* XXX It is a silent requirement of mountd that this be second */
+         struct  export_args export;     /* network export information */
  };
  
***************
*** 47,56 ****
  	struct mount	*nullm_vfs;
  	struct vnode	*nullm_rootvp;	/* Reference to root null_node */
  };
  
- #ifdef _KERNEL
  /*
   * A cache of vnode references
   */
  struct null_node {
  	LIST_ENTRY(null_node)	null_hash;	/* Hash list */
--- 49,59 ----
  	struct mount	*nullm_vfs;
  	struct vnode	*nullm_rootvp;	/* Reference to root null_node */
+         struct  netexport nullm_export;            /* export information */
  };
  
  /*
   * A cache of vnode references
   */
+ #ifdef _KERNEL
  struct null_node {
  	LIST_ENTRY(null_node)	null_hash;	/* Hash list */
*** sys/miscfs/nullfs.dist/null_vfsops.c	Wed Jun 17 11:15:19 1998
--- sys/miscfs/nullfs/null_vfsops.c	Wed Jun 17 11:57:50 1998
***************
*** 56,59 ****
--- 56,65 ----
  #include <miscfs/nullfs/null.h>
  
+ #include <ufs/ufs/quota.h>
+ #include <ufs/ufs/ufsmount.h>
+ #include <ufs/ufs/inode.h>
+ #include <ufs/ufs/dir.h>
+ #include <ufs/ufs/ufs_extern.h>
+ 
  int	nullfs_mount __P((struct mount *, const char *, void *,
  			  struct nameidata *, struct proc *));
***************
*** 92,103 ****
  
  	/*
- 	 * Update is a no-op
- 	 */
- 	if (mp->mnt_flag & MNT_UPDATE) {
- 		return (EOPNOTSUPP);
- 		/* return VFS_MOUNT(MOUNTTONULLMOUNT(mp)->nullm_vfs, path, data, ndp, p);*/
- 	}
- 
- 	/*
  	 * Get argument
  	 */
--- 98,101 ----
***************
*** 107,110 ****
--- 105,122 ----
  
  	/*
+ 	 * Update is a no-op, unless it is an export and we're allowing those
+ 	 */
+ 	if (mp->mnt_flag & MNT_UPDATE) {
+ 		if(args.target == 0) {
+ #ifdef NULLFS_DIAGNOSTIC
+ 			printf("target = 0, processing export\n");
+ #endif /* NULLFS_DIAGNOSTIC */
+ 			return (vfs_export(mp, &(MOUNTTONULLMOUNT(mp)->nullm_export), &args.export));
+ 		}
+ 		return (EOPNOTSUPP);
+ 		/* return (VFS_MOUNT(MOUNTTONULLMOUNT(mp)->nullm_vfs, path, data, ndp, p));*/
+ 	}
+ 
+ 	/*
  	 * Find lower node
  	 */
***************
*** 342,347 ****
  	struct vnode **vpp;
  {
  	
! 	return VFS_VGET(MOUNTTONULLMOUNT(mp)->nullm_vfs, ino, vpp);
  }
  
--- 354,363 ----
  	struct vnode **vpp;
  {
+         int ret;
+         struct vnode *nvp;
  
!         ret = VFS_VGET(MOUNTTONULLMOUNT(mp)->nullm_vfs, ino, &nvp);
!         null_node_create(mp,nvp,vpp,1);
!         return ret;
  }
  
***************
*** 355,360 ****
  	struct ucred**credanonp;
  {
  
! 	return (EOPNOTSUPP);
  }
  
--- 375,414 ----
  	struct ucred**credanonp;
  {
+ 	int error;
+         struct netcred *np;
+         struct vnode *nvp;
  
! 	/* adapted from ufs_check_export */
! 	
!         np = vfs_export_lookup(mp, &(MOUNTTONULLMOUNT(mp)->nullm_export), nam);
!         if (np == NULL)
!                 return (EACCES);
!         if ((error = VFS_VGET(MOUNTTONULLMOUNT(mp)->nullm_vfs,
! 	    ((struct ufid *)fidp)->ufid_ino, &nvp)) != 0) {
!                 *vpp = NULLVP;
!                 return (error);
!         }
! 	/* XXXX - KS - this is a kludge; we really want a VOP_STALE instead */
! 	if(nvp->v_tag == VT_UFS || nvp->v_tag == VT_LFS) {
! 		struct inode *ip;
! 
! 	        ip = VTOI(nvp);
! 		if (ip->i_ffs_mode == 0 || ip->i_ffs_gen != ((struct ufid *)fidp)->ufid_gen) {
! 			vput(nvp);
! 			*vpp = NULLVP;
! #ifdef NULLFS_DIAGNOSTIC
! 			printf("ffs_mode = %d,",ip->i_ffs_mode);
! 			printf(" ffs_gen = %d, nfs_gen = %d\n",
! 			       ip->i_ffs_gen, ((struct ufid *)fidp)->ufid_gen);
! #endif
! 			return (ESTALE);
! 		}
! 	}
! 
! 	null_node_create(mp,nvp,vpp,1);
!         *exflagsp = np->netc_exflags;
!         *credanonp = &np->netc_anon;
! 
! 	return 0;
  }
  
***************
*** 364,369 ****
  	struct fid *fhp;
  {
  
! 	return (EOPNOTSUPP);
  }
  
--- 418,425 ----
  	struct fid *fhp;
  {
+ 	int ret;
  
! 	ret = VFS_VPTOFH(NULLVPTOLOWERVP(vp), fhp);
! 	return ret;
  }

*** usr.sbin/mountd/mountd.c.current	Sun Mar  1 04:24:40 1998
--- usr.sbin/mountd/mountd.c	Tue Jun  9 13:05:34 1998
***************
*** 715,718 ****
--- 708,712 ----
  		    !strncmp(fsp->f_fstypename, MOUNT_MSDOS, MFSNAMELEN) ||
  		    !strncmp(fsp->f_fstypename, MOUNT_ADOSFS, MFSNAMELEN) ||
+ 		    !strncmp(fsp->f_fstypename, MOUNT_UMAP, MFSNAMELEN) ||
  		    !strncmp(fsp->f_fstypename, MOUNT_CD9660, MFSNAMELEN)) {
  			bzero((char *)&targs, sizeof(targs));
>Audit-Trail:
>Unformatted: