Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 3 Oct 2011 01:04:05 +0300
From:      Kostik Belousov <kostikbel@gmail.com>
To:        standards@freebsd.org
Cc:        current@freebsd.org
Subject:   st_dev and st_ino for pipes
Message-ID:  <20111002220405.GN1511@deviant.kiev.zoral.com.ua>

next in thread | raw e-mail | index | archive | help

--g0gRMcGSHhC9oFXc
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

Our implementation of pipes does not provide useful values for st_dev
and st_ino when stat(2) is done on an anonymous pipe. It was noted by the
people outside the project, e.g. Perl contains a workaround in one
of its modules, submitted by Debian/kFreeBSD developers, see
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=3D537555
and the commit 16f708c9bc0dc48713b200 in the Perl git.

I think this is a non-conformance, since SUSv4 explicitely states
in the description of stat(2)
"For all other file types defined in this volume of POSIX.1-2008, the
structure members st_mode, st_ino, st_dev, st_uid, st_gid, st_atim,
st_ctim, and st_mtim shall have meaningful values ...".

Patch below implements the requirement, by the cost of the small overhead
at the pipe creation time, and slightly bigger cost at the destruction.

Any comments ?

diff --git a/sys/fs/devfs/devfs_devs.c b/sys/fs/devfs/devfs_devs.c
index a2d3222..a111527 100644
--- a/sys/fs/devfs/devfs_devs.c
+++ b/sys/fs/devfs/devfs_devs.c
@@ -171,8 +171,7 @@ devfs_free(struct cdev *cdev)
 	cdp =3D cdev2priv(cdev);
 	if (cdev->si_cred !=3D NULL)
 		crfree(cdev->si_cred);
-	if (cdp->cdp_inode > 0)
-		free_unr(devfs_inos, cdp->cdp_inode);
+	devfs_free_cdp_inode(cdp->cdp_inode);
 	if (cdp->cdp_maxdirent > 0)=20
 		free(cdp->cdp_dirents, M_DEVFS2);
 	free(cdp, M_CDEVP);
@@ -394,7 +393,7 @@ devfs_delete(struct devfs_mount *dm, struct devfs_diren=
t *de, int flags)
 	mac_devfs_destroy(de);
 #endif
 	if (de->de_inode > DEVFS_ROOTINO) {
-		free_unr(devfs_inos, de->de_inode);
+		devfs_free_cdp_inode(de->de_inode);
 		de->de_inode =3D 0;
 	}
 	if (DEVFS_DE_DROP(de))
@@ -685,6 +684,21 @@ devfs_destroy(struct cdev *dev)
 	devfs_generation++;
 }
=20
+ino_t
+devfs_alloc_cdp_inode(void)
+{
+
+	return (alloc_unr(devfs_inos));
+}
+
+void
+devfs_free_cdp_inode(ino_t ino)
+{
+
+	if (ino > 0)
+		free_unr(devfs_inos, ino);
+}
+
 static void
 devfs_devs_init(void *junk __unused)
 {
diff --git a/sys/kern/sys_pipe.c b/sys/kern/sys_pipe.c
index b7ae521..2edecf2 100644
--- a/sys/kern/sys_pipe.c
+++ b/sys/kern/sys_pipe.c
@@ -93,6 +93,7 @@ __FBSDID("$FreeBSD$");
=20
 #include <sys/param.h>
 #include <sys/systm.h>
+#include <sys/conf.h>
 #include <sys/fcntl.h>
 #include <sys/file.h>
 #include <sys/filedesc.h>
@@ -224,6 +225,8 @@ static int	pipe_zone_init(void *mem, int size, int flag=
s);
 static void	pipe_zone_fini(void *mem, int size);
=20
 static uma_zone_t pipe_zone;
+static struct unrhdr *pipeino_unr;
+static ino_t pipedev_ino;
=20
 SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_ANY, pipeinit, NULL);
=20
@@ -235,6 +238,10 @@ pipeinit(void *dummy __unused)
 	    pipe_zone_ctor, NULL, pipe_zone_init, pipe_zone_fini,
 	    UMA_ALIGN_PTR, 0);
 	KASSERT(pipe_zone !=3D NULL, ("pipe_zone not initialized"));
+	pipeino_unr =3D new_unrhdr(1, INT32_MAX, NULL);
+	KASSERT(pipeino_unr !=3D NULL, ("pipe fake inodes not initialized"));
+	pipedev_ino =3D devfs_alloc_cdp_inode();
+	KASSERT(pipedev_ino > 0, ("pipe dev inode not initialized"));
 }
=20
 static int
@@ -562,6 +569,12 @@ pipe_create(pipe, backing)
 		/* If we're not backing this pipe, no need to do anything. */
 		error =3D 0;
 	}
+	if (error =3D=3D 0) {
+		pipe->pipe_ino =3D alloc_unr(pipeino_unr);
+		if (pipe->pipe_ino =3D=3D -1)
+			/* pipeclose will clear allocated kva */
+			error =3D ENOMEM;
+	}
 	return (error);
 }
=20
@@ -1408,9 +1421,10 @@ pipe_stat(fp, ub, active_cred, td)
 	ub->st_ctim =3D pipe->pipe_ctime;
 	ub->st_uid =3D fp->f_cred->cr_uid;
 	ub->st_gid =3D fp->f_cred->cr_gid;
+	ub->st_dev =3D pipedev_ino;
+	ub->st_ino =3D pipe->pipe_ino;
 	/*
-	 * Left as 0: st_dev, st_ino, st_nlink, st_rdev, st_flags, st_gen.
-	 * XXX (st_dev, st_ino) should be unique.
+	 * Left as 0: st_nlink, st_rdev, st_flags, st_gen.
 	 */
 	return (0);
 }
@@ -1463,6 +1477,7 @@ pipeclose(cpipe)
 {
 	struct pipepair *pp;
 	struct pipe *ppipe;
+	ino_t ino;
=20
 	KASSERT(cpipe !=3D NULL, ("pipeclose: cpipe =3D=3D NULL"));
=20
@@ -1521,6 +1536,12 @@ pipeclose(cpipe)
 	knlist_destroy(&cpipe->pipe_sel.si_note);
=20
 	/*
+	 * Postpone the destroy of the fake inode number allocated for
+	 * our end, until pipe mtx is unlocked.
+	 */
+	ino =3D cpipe->pipe_ino;
+
+	/*
 	 * If both endpoints are now closed, release the memory for the
 	 * pipe pair.  If not, unlock.
 	 */
@@ -1532,6 +1553,9 @@ pipeclose(cpipe)
 		uma_zfree(pipe_zone, cpipe->pipe_pair);
 	} else
 		PIPE_UNLOCK(cpipe);
+
+	if (ino > 0)
+		free_unr(pipeino_unr, cpipe->pipe_ino);
 }
=20
 /*ARGSUSED*/
diff --git a/sys/sys/conf.h b/sys/sys/conf.h
index 08e1582..7acd2e0 100644
--- a/sys/sys/conf.h
+++ b/sys/sys/conf.h
@@ -301,6 +301,9 @@ int	devfs_set_cdevpriv(void *priv, cdevpriv_dtr_t dtr);
 void	devfs_clear_cdevpriv(void);
 void	devfs_fpdrop(struct file *fp);	/* XXX This is not public KPI */
=20
+ino_t	devfs_alloc_cdp_inode(void);
+void	devfs_free_cdp_inode(ino_t ino);
+
 #define		UID_ROOT	0
 #define		UID_BIN		3
 #define		UID_UUCP	66
diff --git a/sys/sys/pipe.h b/sys/sys/pipe.h
index 2592a8d..20b1092 100644
--- a/sys/sys/pipe.h
+++ b/sys/sys/pipe.h
@@ -112,6 +112,7 @@ struct pipe {
 	u_int	pipe_state;		/* pipe status info */
 	int	pipe_busy;		/* busy flag, mostly to handle rundown sanely */
 	int	pipe_present;		/* still present? */
+	ino_t	pipe_ino;		/* fake inode for stat(2) */
 };
=20
 /*

--g0gRMcGSHhC9oFXc
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.18 (FreeBSD)

iEYEARECAAYFAk6I39UACgkQC3+MBN1Mb4gRTACfRK3JmXb/vJNRgg72XDbgxt2O
sUMAmwdkGYERkFDj+9NJzYNDGT5TPFhm
=olkY
-----END PGP SIGNATURE-----

--g0gRMcGSHhC9oFXc--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20111002220405.GN1511>