kern/125149: [zfs][nfs] changing into .zfs dir from nfs clientcauses endless panic loop

Weldon Godfrey wgodfrey at ena.com
Thu Oct 9 16:30:04 UTC 2008


The following reply was made to PR kern/125149; it has been noted by GNATS.

From: "Weldon Godfrey" <wgodfrey at ena.com>
To: "Jaakko Heinonen" <jh at saunalahti.fi>,
	"Volker Werth" <vwe at freebsd.org>
Cc: <bug-followup at freebsd.org>
Subject: RE: kern/125149: [zfs][nfs] changing into .zfs dir from nfs clientcauses endless panic loop
Date: Thu, 9 Oct 2008 11:23:12 -0500

 Is this patch based on 8-CURRENT or 7-RELEASE?  If 8-CURRENT, I don't
 know if I can test as I would like to stick with 7-RELEASE for now.
 However, I would like to move to ZFS11 so if there is a patch for 7 for
 ZFS11 (assuming your patch is based in the v11 code), I would like to
 apply that.
 
 
 
 /usr/src/sys/modules/zfs/../../cddl/contrib/opensolaris/uts/common/fs/zf
 s/zfs_ctldir.c:1073:33: error: macro "vn_lock" requires 3 arguments, but
 only 2 given
 /usr/src/sys/modules/zfs/../../cddl/contrib/opensolaris/uts/common/fs/zf
 s/zfs_ctldir.c: In function 'zfsctl_vget':
 /usr/src/sys/modules/zfs/../../cddl/contrib/opensolaris/uts/common/fs/zf
 s/zfs_ctldir.c:1073: error: 'vn_lock' undeclared (first use in this
 function)
 /usr/src/sys/modules/zfs/../../cddl/contrib/opensolaris/uts/common/fs/zf
 s/zfs_ctldir.c:1073: error: (Each undeclared identifier is reported only
 once
 /usr/src/sys/modules/zfs/../../cddl/contrib/opensolaris/uts/common/fs/zf
 s/zfs_ctldir.c:1073: error: for each function it appears in.)
 /usr/src/sys/modules/zfs/../../cddl/contrib/opensolaris/uts/common/fs/zf
 s/zfs_ctldir.c:1093:22: error: macro "vn_lock" requires 3 arguments, but
 only 2 given
 
 Weldon
 
 -----Original Message-----
 From: Jaakko Heinonen [mailto:jh at saunalahti.fi]=20
 Sent: Tuesday, October 07, 2008 10:37 AM
 To: Volker Werth
 Cc: Weldon Godfrey; bug-followup at freebsd.org
 Subject: Re: kern/125149: [zfs][nfs] changing into .zfs dir from nfs
 clientcauses endless panic loop
 
 
 Hi,
 
 On 2008-10-02, Volker Werth wrote:
 > > #8  0xffffffff804f06fa in vput (vp=3D0x0) at atomic.h:142
 > > #9  0xffffffff8060670d in nfsrv_readdirplus
 (nfsd=3D0xffffff000584f100,
 > > slp=3D0xffffff0005725900,=20
 > >     td=3D0xffffff00059a0340, mrq=3D0xffffffffdf761af0) at
 > > /usr/src/sys/nfsserver/nfs_serv.c:3613
 > > #10 0xffffffff80615a5d in nfssvc (td=3DVariable "td" is not =
 available.
 > > ) at /usr/src/sys/nfsserver/nfs_syscalls.c:461
 > > #11 0xffffffff8072f377 in syscall (frame=3D0xffffffffdf761c70) at
 > > /usr/src/sys/amd64/amd64/trap.c:852
 > > #12 0xffffffff807158bb in Xfast_syscall () at
 > > /usr/src/sys/amd64/amd64/exception.S:290
 > > #13 0x000000080068746c in ?? ()
 > > Previous frame inner to this frame (corrupt stack?)
 >=20
 > I think the problem is the NULL pointer to vput. A maintainer needs to
 > check how nvp can get a NULL pointer (judging by assuming my fresh
 > codebase is not too different from yours).
 
 The bug is reproducible with nfs clients using readdirplus. FreeBSD
 client doesn't use readdirplus by default but you can enable it with -l
 mount option. Here are steps to reproduce the panic with FreeBSD nfs
 client:
 
 - nfs export a zfs file system
 - on client mount the file system with -l mount option and list the
   zfs control directory
 # mount_nfs -l x.x.x.x:/tank /mnt
 # ls /mnt/.zfs
 
 I see two bugs here:
 
 1) nfsrv_readdirplus() doesn't check VFS_VGET() error status properly.
    It only checks for EOPNOTSUPP but other errors are ignored. This is
 the
    final reason for the panic and in theory it could happen for other
    file systems too. In this case VFS_VGET() returns EINVAL and results
    NULL nvp.
 2) zfs VFS_VGET() returns EINVAL for .zfs control directory entries.
    Looking at zfs_vget() it tries find corresponding znode to fulfill
    the request. However control directory entries don't have backing
    znodes.
 
 Here is a patch which fixes 1). The patch prevents system from panicing
 but a fix for 2) is needed to make readdirplus work with .zfs directory.
 
 %%%
 Index: sys/nfsserver/nfs_serv.c
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
 --- sys/nfsserver/nfs_serv.c	(revision 183511)
 +++ sys/nfsserver/nfs_serv.c	(working copy)
 @@ -3597,9 +3597,12 @@ again:
  	 * Probe one of the directory entries to see if the filesystem
  	 * supports VGET.
  	 */
 -	if (VFS_VGET(vp->v_mount, dp->d_fileno, LK_EXCLUSIVE, &nvp) =3D=3D
 -	    EOPNOTSUPP) {
 -		error =3D NFSERR_NOTSUPP;
 +	error =3D VFS_VGET(vp->v_mount, dp->d_fileno, LK_EXCLUSIVE, &nvp);
 +	if (error) {
 +		if (error =3D=3D EOPNOTSUPP)
 +			error =3D NFSERR_NOTSUPP;
 +		else
 +			error =3D NFSERR_SERVERFAULT;
  		vrele(vp);
  		vp =3D NULL;
  		free((caddr_t)cookies, M_TEMP);
 %%%
 
 And here's an attempt to add support for .zfs control directory entries
 (bug 2)) in zfs_vget(). The patch is very experimental and it only works
 for snapshots which are already active (mounted).
 
 %%%
 Index: sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
 --- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c
 (revision 183587)
 +++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c	(working
 copy)
 @@ -759,9 +759,10 @@ zfs_vget(vfs_t *vfsp, ino_t ino, int fla
  		VN_RELE(ZTOV(zp));
  		err =3D EINVAL;
  	}
 -	if (err !=3D 0)
 -		*vpp =3D NULL;
 -	else {
 +	if (err !=3D 0) {
 +		/* try .zfs control directory */
 +		err =3D zfsctl_vget(vfsp, ino, flags, vpp);
 +	} else {
  		*vpp =3D ZTOV(zp);
  		vn_lock(*vpp, flags);
  	}
 Index: sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
 --- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c
 (revision 183587)
 +++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c	(working
 copy)
 @@ -1047,6 +1047,63 @@ zfsctl_lookup_objset(vfs_t *vfsp, uint64
  	return (error);
  }
 =20
 +int
 +zfsctl_vget(vfs_t *vfsp, uint64_t nodeid, int flags, vnode_t **vpp)
 +{
 +	zfsvfs_t *zfsvfs =3D vfsp->vfs_data;
 +	vnode_t *dvp, *vp;
 +	zfsctl_snapdir_t *sdp;
 +	zfsctl_node_t *zcp;
 +	zfs_snapentry_t *sep;
 +	int error;
 +
 +	*vpp =3D NULL;
 +
 +	ASSERT(zfsvfs->z_ctldir !=3D NULL);
 +	error =3D zfsctl_root_lookup(zfsvfs->z_ctldir, "snapshot", &dvp,
 +	    NULL, 0, NULL, kcred);
 +	if (error !=3D 0)
 +		return (error);
 +
 +	if (nodeid =3D=3D ZFSCTL_INO_ROOT || nodeid =3D=3D ZFSCTL_INO_SNAPDIR) =
 {
 +		if (nodeid =3D=3D ZFSCTL_INO_SNAPDIR)
 +			*vpp =3D dvp;
 +		else {
 +			VN_RELE(dvp);
 +			*vpp =3D zfsvfs->z_ctldir;
 +			VN_HOLD(*vpp);
 +		}
 +		/* XXX: LK_RETRY? */
 +		vn_lock(*vpp, flags | LK_RETRY);
 +		return (0);
 +	}
 +	=09
 +	sdp =3D dvp->v_data;
 +
 +	mutex_enter(&sdp->sd_lock);
 +	sep =3D avl_first(&sdp->sd_snaps);
 +	while (sep !=3D NULL) {
 +		vp =3D sep->se_root;
 +		zcp =3D vp->v_data;
 +		if (zcp->zc_id =3D=3D nodeid)
 +			break;
 +
 +		sep =3D AVL_NEXT(&sdp->sd_snaps, sep);
 +	}
 +
 +	if (sep !=3D NULL) {
 +		VN_HOLD(vp);
 +		*vpp =3D vp;
 +		vn_lock(*vpp, flags);
 +	} else
 +		error =3D EINVAL;
 +
 +	mutex_exit(&sdp->sd_lock);
 +
 +	VN_RELE(dvp);
 +
 +	return (error);
 +}
  /*
   * Unmount any snapshots for the given filesystem.  This is called from
   * zfs_umount() - if we have a ctldir, then go through and unmount all
 the
 Index: sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_ctldir.h
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
 --- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_ctldir.h
 (revision 183587)
 +++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_ctldir.h
 (working copy)
 @@ -60,6 +60,7 @@ int zfsctl_root_lookup(vnode_t *dvp, cha
      int flags, vnode_t *rdir, cred_t *cr);
 =20
  int zfsctl_lookup_objset(vfs_t *vfsp, uint64_t objsetid, zfsvfs_t
 **zfsvfsp);
 +int zfsctl_vget(vfs_t *vfsp, uint64_t nodeid, int flags, vnode_t
 **vpp);
 =20
  #define	ZFSCTL_INO_ROOT		0x1
  #define	ZFSCTL_INO_SNAPDIR	0x2
 %%%
 
 --=20
 Jaakko


More information about the freebsd-fs mailing list