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=537555 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 _at__at_ -171,8 +171,7 _at__at_ devfs_free(struct cdev *cdev) cdp = cdev2priv(cdev); if (cdev->si_cred != 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) free(cdp->cdp_dirents, M_DEVFS2); free(cdp, M_CDEVP); _at__at_ -394,7 +393,7 _at__at_ devfs_delete(struct devfs_mount *dm, struct devfs_dirent *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 = 0; } if (DEVFS_DE_DROP(de)) _at__at_ -685,6 +684,21 _at__at_ devfs_destroy(struct cdev *dev) devfs_generation++; } +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 _at__at_ -93,6 +93,7 _at__at_ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/conf.h> #include <sys/fcntl.h> #include <sys/file.h> #include <sys/filedesc.h> _at__at_ -224,6 +225,8 _at__at_ static int pipe_zone_init(void *mem, int size, int flags); static void pipe_zone_fini(void *mem, int size); static uma_zone_t pipe_zone; +static struct unrhdr *pipeino_unr; +static ino_t pipedev_ino; SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_ANY, pipeinit, NULL); _at__at_ -235,6 +238,10 _at__at_ pipeinit(void *dummy __unused) pipe_zone_ctor, NULL, pipe_zone_init, pipe_zone_fini, UMA_ALIGN_PTR, 0); KASSERT(pipe_zone != NULL, ("pipe_zone not initialized")); + pipeino_unr = new_unrhdr(1, INT32_MAX, NULL); + KASSERT(pipeino_unr != NULL, ("pipe fake inodes not initialized")); + pipedev_ino = devfs_alloc_cdp_inode(); + KASSERT(pipedev_ino > 0, ("pipe dev inode not initialized")); } static int _at__at_ -562,6 +569,12 _at__at_ pipe_create(pipe, backing) /* If we're not backing this pipe, no need to do anything. */ error = 0; } + if (error == 0) { + pipe->pipe_ino = alloc_unr(pipeino_unr); + if (pipe->pipe_ino == -1) + /* pipeclose will clear allocated kva */ + error = ENOMEM; + } return (error); } _at__at_ -1408,9 +1421,10 _at__at_ pipe_stat(fp, ub, active_cred, td) ub->st_ctim = pipe->pipe_ctime; ub->st_uid = fp->f_cred->cr_uid; ub->st_gid = fp->f_cred->cr_gid; + ub->st_dev = pipedev_ino; + ub->st_ino = 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); } _at__at_ -1463,6 +1477,7 _at__at_ pipeclose(cpipe) { struct pipepair *pp; struct pipe *ppipe; + ino_t ino; KASSERT(cpipe != NULL, ("pipeclose: cpipe == NULL")); _at__at_ -1521,6 +1536,12 _at__at_ pipeclose(cpipe) knlist_destroy(&cpipe->pipe_sel.si_note); /* + * Postpone the destroy of the fake inode number allocated for + * our end, until pipe mtx is unlocked. + */ + ino = cpipe->pipe_ino; + + /* * If both endpoints are now closed, release the memory for the * pipe pair. If not, unlock. */ _at__at_ -1532,6 +1553,9 _at__at_ pipeclose(cpipe) uma_zfree(pipe_zone, cpipe->pipe_pair); } else PIPE_UNLOCK(cpipe); + + if (ino > 0) + free_unr(pipeino_unr, cpipe->pipe_ino); } /*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 _at__at_ -301,6 +301,9 _at__at_ 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 */ +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 _at__at_ -112,6 +112,7 _at__at_ 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) */ }; /*
This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:40:18 UTC