From nobody@FreeBSD.org  Fri Jun 22 08:44:06 2007
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52])
	by hub.freebsd.org (Postfix) with ESMTP id EAC4916A421
	for <freebsd-gnats-submit@FreeBSD.org>; Fri, 22 Jun 2007 08:44:06 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (www.freebsd.org [69.147.83.33])
	by mx1.freebsd.org (Postfix) with ESMTP id DAE4813C4B7
	for <freebsd-gnats-submit@FreeBSD.org>; Fri, 22 Jun 2007 08:44:06 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (localhost [127.0.0.1])
	by www.freebsd.org (8.13.1/8.13.1) with ESMTP id l5M8i6vP059151
	for <freebsd-gnats-submit@FreeBSD.org>; Fri, 22 Jun 2007 08:44:06 GMT
	(envelope-from nobody@www.freebsd.org)
Received: (from nobody@localhost)
	by www.freebsd.org (8.13.1/8.13.1/Submit) id l5M8i6Il059150;
	Fri, 22 Jun 2007 08:44:06 GMT
	(envelope-from nobody)
Message-Id: <200706220844.l5M8i6Il059150@www.freebsd.org>
Date: Fri, 22 Jun 2007 08:44:06 GMT
From: Konrad Heuer <kheuer2@gwdg.de>
To: freebsd-gnats-submit@FreeBSD.org
Subject: Linux (e.g.) ls hangs on named pipes in 6.2-RELEASE
X-Send-Pr-Version: www-3.0

>Number:         113939
>Category:       kern
>Synopsis:       [named-pipes] Linux (e.g.) ls hangs on named pipes in 6.2-RELEASE [regression]
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    freebsd-bugs
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Fri Jun 22 08:50:02 GMT 2007
>Closed-Date:    Sun Jun 21 19:08:46 UTC 2009
>Last-Modified:  Sun Jun 21 19:10:01 UTC 2009
>Originator:     Konrad Heuer
>Release:        6.2-RELEASE-p5
>Organization:
GWDG
>Environment:
FreeBSD myhost.mydomain 6.2-RELEASE-p5 FreeBSD 6.2-RELEASE-p5 #3: Tue Jun 12 16:25:12 CEST 2007     kheuer@gwdu111.gwdg.de:/usr/obj/usr/src/sys/MYKERNEL  i386
>Description:
Linux binaries scanning directories like ls hang when encountering named
pipes, thus backup software like TSM too - backup doesn't work anymore!

In 6.1-RELEASE-p14, everything worked well.

% ktrace -f kd.out /usr/compat/linux/bin/ls -l test-fifo
^C
% kdump -f kd.out | tail -6

 29927 ls       RET   ioctl 0
 29927 ls       CALL  getdirentries(0xbfbfec88,0x805e0d4,0x281c1ff4)
 29927 ls       NAMI  "test-fifo"
 29927 ls       NAMI  "test-fifo"
 29927 ls       RET   getdirentries 0
 29927 ls       PSIG  SIGINT SIG_DFL



>How-To-Repeat:
% /usr/sbin/pkg_info | grep linux_base
linux_base-fc-4_9   Base set of packages needed in Linux mode (for i386/amd64)

% mkfifo test-fifo

% ls -l test-fifo
prw-r--r--  1 kheuer  wheel  0 Jun 22 10:27 test-fifo

% /usr/compat/linux/bin/ls -l test-fifo
^C

>Fix:


>Release-Note:
>Audit-Trail:
State-Changed-From-To: open->closed 
State-Changed-By: dchagin 
State-Changed-When: Sun Jun 21 19:06:30 UTC 2009 
State-Changed-Why:  
MFC to stable/7 done. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=113939 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/113939: commit references a PR
Date: Sun, 21 Jun 2009 19:02:43 +0000 (UTC)

 Author: dchagin
 Date: Sun Jun 21 19:02:32 2009
 New Revision: 194599
 URL: http://svn.freebsd.org/changeset/base/194599
 
 Log:
   MFC r164890 (by jkim):
   Fixes for 'blocking in fifoor state' problem of LTP tests.
   linux_*stat*() functions were opening files with O_RDONLY to get
   major/minor pair for char/block special files.  Unfortunately,
   when these functions are used against fifo, it is blocked forever
   because there is no writer.  Instead, we only open char/block special
   files for major/minor conversion.  We have to get rid of kern_open()
   entirely from translate_path_major_minor() but today is not the day.
   While I am here, add checks for errors before calling
   translate_path_major_minor().
   
   MFC r179651:
   
   d_ino member of linux_dirent structure should be unsigned long.
   
   MFC r182892:
   
   Getdents requires padding with 2 bytes instead of 1 byte
   as with getdents64. The last byte is used for storing
   the d_type, add this to plain getdents case where it was
   missing before. Also change the code to use strlcpy instead
   of plain strcpy.
   
   MFC r188572:
   
   Fix an edge-case of the linux readdir: We need the size of a linux
   dirent structure, not the size of a pointer to it.
   
   PR:		kern/113939
   Approved by:	kib (mentor)
 
 Modified:
   stable/6/sys/   (props changed)
   stable/6/sys/compat/linux/linux_file.c
   stable/6/sys/compat/linux/linux_stats.c
   stable/6/sys/contrib/pf/   (props changed)
   stable/6/sys/dev/cxgb/   (props changed)
 
 Modified: stable/6/sys/compat/linux/linux_file.c
 ==============================================================================
 --- stable/6/sys/compat/linux/linux_file.c	Sun Jun 21 17:35:04 2009	(r194598)
 +++ stable/6/sys/compat/linux/linux_file.c	Sun Jun 21 19:02:32 2009	(r194599)
 @@ -232,7 +232,7 @@ linux_readdir(struct thread *td, struct 
   */
  
  struct l_dirent {
 -	l_long		d_ino;
 +	l_ulong		d_ino;
  	l_off_t		d_off;
  	l_ushort	d_reclen;
  	char		d_name[LINUX_NAME_MAX + 1];
 @@ -246,9 +246,20 @@ struct l_dirent64 {
  	char		d_name[LINUX_NAME_MAX + 1];
  };
  
 -#define LINUX_RECLEN(de,namlen) \
 -    ALIGN((((char *)&(de)->d_name - (char *)de) + (namlen) + 1))
 +/*
 + * Linux uses the last byte in the dirent buffer to store d_type,
 + * at least glibc-2.7 requires it. That is why l_dirent is padded with 2 bytes.
 + */
 +#define LINUX_RECLEN(namlen)						\
 +    roundup((offsetof(struct l_dirent, d_name) + (namlen) + 2),		\
 +    sizeof(l_ulong))
 +
 +#define LINUX_RECLEN64(namlen)						\
 +    roundup((offsetof(struct l_dirent64, d_name) + (namlen) + 1),	\
 +    sizeof(uint64_t))
  
 +#define LINUX_MAXRECLEN		max(LINUX_RECLEN(LINUX_NAME_MAX),	\
 +				    LINUX_RECLEN64(LINUX_NAME_MAX))
  #define	LINUX_DIRBLKSIZ		512
  
  static int
 @@ -261,12 +272,13 @@ getdents_common(struct thread *td, struc
  	int len, reclen;		/* BSD-format */
  	caddr_t outp;			/* Linux-format */
  	int resid, linuxreclen=0;	/* Linux-format */
 +	caddr_t lbuf;			/* Linux-format */
  	struct file *fp;
  	struct uio auio;
  	struct iovec aiov;
  	off_t off;
 -	struct l_dirent linux_dirent;
 -	struct l_dirent64 linux_dirent64;
 +	struct l_dirent *linux_dirent;
 +	struct l_dirent64 *linux_dirent64;
  	int buflen, error, eofflag, nbytes, justone;
  	u_long *cookies = NULL, *cookiep;
  	int ncookies, vfslocked;
 @@ -276,7 +288,7 @@ getdents_common(struct thread *td, struc
  		/* readdir(2) case. Always struct dirent. */
  		if (is64bit)
  			return (EINVAL);
 -		nbytes = sizeof(linux_dirent);
 +		nbytes = sizeof(*linux_dirent);
  		justone = 1;
  	} else
  		justone = 0;
 @@ -302,6 +314,7 @@ getdents_common(struct thread *td, struc
  	buflen = max(LINUX_DIRBLKSIZ, nbytes);
  	buflen = min(buflen, MAXBSIZE);
  	buf = malloc(buflen, M_TEMP, M_WAITOK);
 +	lbuf = malloc(LINUX_MAXRECLEN, M_TEMP, M_WAITOK | M_ZERO);
  	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
  
  again:
 @@ -379,8 +392,8 @@ again:
  		}
  
  		linuxreclen = (is64bit)
 -		    ? LINUX_RECLEN(&linux_dirent64, bdp->d_namlen)
 -		    : LINUX_RECLEN(&linux_dirent, bdp->d_namlen);
 +		    ? LINUX_RECLEN64(bdp->d_namlen)
 +		    : LINUX_RECLEN(bdp->d_namlen);
  
  		if (reclen > len || resid < linuxreclen) {
  			outp++;
 @@ -389,34 +402,41 @@ again:
  
  		if (justone) {
  			/* readdir(2) case. */
 -			linux_dirent.d_ino = (l_long)bdp->d_fileno;
 -			linux_dirent.d_off = (l_off_t)linuxreclen;
 -			linux_dirent.d_reclen = (l_ushort)bdp->d_namlen;
 -			strcpy(linux_dirent.d_name, bdp->d_name);
 -			error = copyout(&linux_dirent, outp, linuxreclen);
 -		} else {
 -			if (is64bit) {
 -				linux_dirent64.d_ino = bdp->d_fileno;
 -				linux_dirent64.d_off = (cookiep)
 -				    ? (l_off_t)*cookiep
 -				    : (l_off_t)(off + reclen);
 -				linux_dirent64.d_reclen =
 -				    (l_ushort)linuxreclen;
 -				linux_dirent64.d_type = bdp->d_type;
 -				strcpy(linux_dirent64.d_name, bdp->d_name);
 -				error = copyout(&linux_dirent64, outp,
 -				    linuxreclen);
 -			} else {
 -				linux_dirent.d_ino = bdp->d_fileno;
 -				linux_dirent.d_off = (cookiep)
 -				    ? (l_off_t)*cookiep
 -				    : (l_off_t)(off + reclen);
 -				linux_dirent.d_reclen = (l_ushort)linuxreclen;
 -				strcpy(linux_dirent.d_name, bdp->d_name);
 -				error = copyout(&linux_dirent, outp,
 -				    linuxreclen);
 -			}
 +			linux_dirent = (struct l_dirent*)lbuf;
 +			linux_dirent->d_ino = bdp->d_fileno;
 +			linux_dirent->d_off = (l_off_t)linuxreclen;
 +			linux_dirent->d_reclen = (l_ushort)bdp->d_namlen;
 +			strlcpy(linux_dirent->d_name, bdp->d_name,
 +			    linuxreclen - offsetof(struct l_dirent, d_name));
 +			error = copyout(linux_dirent, outp, linuxreclen);
  		}
 +		if (is64bit) {
 +			linux_dirent64 = (struct l_dirent64*)lbuf;
 +			linux_dirent64->d_ino = bdp->d_fileno;
 +			linux_dirent64->d_off = (cookiep)
 +			    ? (l_off_t)*cookiep
 +			    : (l_off_t)(off + reclen);
 +			linux_dirent64->d_reclen = (l_ushort)linuxreclen;
 +			linux_dirent64->d_type = bdp->d_type;
 +			strlcpy(linux_dirent64->d_name, bdp->d_name,
 +			    linuxreclen - offsetof(struct l_dirent64, d_name));
 +			error = copyout(linux_dirent64, outp, linuxreclen);
 +		} else if (!justone) {
 +			linux_dirent = (struct l_dirent*)lbuf;
 +			linux_dirent->d_ino = bdp->d_fileno;
 +			linux_dirent->d_off = (cookiep)
 +			    ? (l_off_t)*cookiep
 +			    : (l_off_t)(off + reclen);
 +			linux_dirent->d_reclen = (l_ushort)linuxreclen;
 +			/*
 +			 * Copy d_type to last byte of l_dirent buffer
 +			 */
 +			lbuf[linuxreclen-1] = bdp->d_type;
 +			strlcpy(linux_dirent->d_name, bdp->d_name,
 +			    linuxreclen - offsetof(struct l_dirent, d_name)-1);
 +			error = copyout(linux_dirent, outp, linuxreclen);
 +		}
 +
  		if (error)
  			goto out;
  
 @@ -452,6 +472,7 @@ out:
  	VFS_UNLOCK_GIANT(vfslocked);
  	fdrop(fp, td);
  	free(buf, M_TEMP);
 +	free(lbuf, M_TEMP);
  	return (error);
  }
  
 
 Modified: stable/6/sys/compat/linux/linux_stats.c
 ==============================================================================
 --- stable/6/sys/compat/linux/linux_stats.c	Sun Jun 21 17:35:04 2009	(r194598)
 +++ stable/6/sys/compat/linux/linux_stats.c	Sun Jun 21 19:02:32 2009	(r194599)
 @@ -99,23 +99,16 @@ static void
  translate_fd_major_minor(struct thread *td, int fd, struct stat *buf)
  {
  	struct file *fp;
 -	int error;
  	int major, minor;
  
 -	if ((error = fget(td, fd, &fp)) != 0)
 +	if ((!S_ISCHR(buf->st_mode) && !S_ISBLK(buf->st_mode)) ||
 +	    fget(td, fd, &fp) != 0)
  		return;
 -	if (fp->f_vnode) {
 -		if (fp->f_vnode->v_type == VCHR
 -		    || fp->f_vnode->v_type == VBLK) {
 -			if (fp->f_vnode->v_un.vu_cdev) {
 -				if (linux_driver_get_major_minor(
 -				    fp->f_vnode->v_un.vu_cdev->si_name,
 -				    &major, &minor) == 0) {
 -					buf->st_rdev = (major << 8 | minor);
 -				}
 -			}
 -		}
 -	}
 +	if (fp->f_vnode != NULL &&
 +	    fp->f_vnode->v_un.vu_cdev != NULL &&
 +	    linux_driver_get_major_minor(fp->f_vnode->v_un.vu_cdev->si_name,
 +					 &major, &minor) == 0)
 +		buf->st_rdev = (major << 8 | minor);
  	fdrop(fp, td);
  }
  
 @@ -128,6 +121,8 @@ translate_path_major_minor(struct thread
  	int fd;
  	int temp;
  
 +	if (!S_ISCHR(buf->st_mode) && !S_ISBLK(buf->st_mode))
 +		return;
  	temp = td->td_retval[0];
  	if (kern_open(td, path, UIO_SYSSPACE, O_RDONLY, 0) != 0)
  		return;
 @@ -178,18 +173,19 @@ linux_newstat(struct thread *td, struct 
  #endif
  
  	error = kern_stat(td, path, UIO_SYSSPACE, &buf);
 -	  if (!error && strlen(path) > strlen("/dev/pts/") &&
 -	      !strncmp(path, "/dev/pts/", strlen("/dev/pts/"))
 -	      && path[9] >= '0' && path[9] <= '9') {
 -		  /*
 -		   * Linux checks major and minors of the slave device to make
 -		   * sure it's a pty device, so let's make him believe it is.
 -		   */
 -		  buf.st_rdev = (136 << 8);
 -	  }
 -
 -	translate_path_major_minor(td, path, &buf);
 -
 +	if (!error) {
 +		if (strlen(path) > strlen("/dev/pts/") &&
 +		    !strncmp(path, "/dev/pts/", strlen("/dev/pts/")) &&
 +		    path[9] >= '0' && path[9] <= '9') {
 +			/*
 +			 * Linux checks major and minors of the slave device
 +			 * to make sure it's a pty device, so let's make him
 +			 * believe it is.
 +			 */
 +			buf.st_rdev = (136 << 8);
 +		} else
 +			translate_path_major_minor(td, path, &buf);
 +	}
  	LFREEPATH(path);
  	if (error)
  		return (error);
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
>Unformatted:
