svn commit: r194599 - in stable/6/sys: . compat/linux contrib/pf dev/cxgb

Dmitry Chagin dchagin at FreeBSD.org
Sun Jun 21 19:02:33 UTC 2009


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);


More information about the svn-src-stable mailing list