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