kern/113939: commit references a PR

dfilter service dfilter at FreeBSD.ORG
Sun Jun 21 19:10:06 UTC 2009


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

From: dfilter at FreeBSD.ORG (dfilter service)
To: bug-followup at 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 at freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe at freebsd.org"
 


More information about the freebsd-bugs mailing list