Index: share/man/man4/linux.4 =================================================================== --- share/man/man4/linux.4 +++ share/man/man4/linux.4 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd February 8, 2010 +.Dd July 25, 2017 .Dt LINUX 4 .Os .Sh NAME @@ -127,9 +127,11 @@ module is statically linked into the kernel or loaded as a module. .Sh FILES -.Bl -tag -width /compat/linux/proc -compact +.Bl -tag -width /compat/linux/dev/fd -compact .It Pa /compat/linux minimal Linux run-time environment +.It Pa /compat/linux/dev/fd +limited Linux file-descriptor file system .It Pa /compat/linux/proc limited Linux process file system .It Pa /compat/linux/sys @@ -138,6 +140,7 @@ .Sh SEE ALSO .Xr brandelf 1 , .Xr elf 5 , +.Xr fdescfs 5 , .Xr linprocfs 5 , .Xr linsysfs 5 .Sh HISTORY Index: share/man/man5/fdescfs.5 =================================================================== --- share/man/man5/fdescfs.5 +++ share/man/man5/fdescfs.5 @@ -34,7 +34,7 @@ .\" .\" $FreeBSD$ .\" -.Dd September 18, 2010 +.Dd July 25, 2017 .Dt FDESCFS 5 .Os .Sh NAME @@ -92,6 +92,14 @@ files are created by default when devfs alone is mounted. .Nm creates entries for all file descriptors opened by the process. +.Pp +For +.Xr Linux 4 +ABI compatibility mount +.Nm +volume with +.Cm linrdlnk +option. .Sh FILES .Bl -tag -width /dev/stderr -compact .It Pa /dev/fd/# @@ -103,6 +111,12 @@ .Pa /dev/fd : .Pp .Dl "mount -t fdescfs null /dev/fd" +.Pp +For +.Xr Linux 4 +ABI compatibility: +.Pp +.Dl "mount -t fdescfs -o linrdlnk null /compat/linux/dev/fd" .Sh SEE ALSO .Xr devfs 5 , .Xr mount 8 Index: sys/fs/cd9660/cd9660_vnops.c =================================================================== --- sys/fs/cd9660/cd9660_vnops.c +++ sys/fs/cd9660/cd9660_vnops.c @@ -110,6 +110,7 @@ case VNON: case VBAD: case VMARKER: + case VREADLNK: return (0); } } Index: sys/fs/fdescfs/fdesc.h =================================================================== --- sys/fs/fdescfs/fdesc.h +++ sys/fs/fdescfs/fdesc.h @@ -38,7 +38,9 @@ #define _FS_FDESC_H_ /* Private mount flags for fdescfs. */ -#define FMNT_UNMOUNTF 0x01 +#define FMNT_UNMOUNTF 0x01 +#define FMNT_LINRDLNKF 0x02 + struct fdescmount { struct vnode *f_root; /* Root node */ int flags; Index: sys/fs/fdescfs/fdesc_vfsops.c =================================================================== --- sys/fs/fdescfs/fdesc_vfsops.c +++ sys/fs/fdescfs/fdesc_vfsops.c @@ -101,6 +101,8 @@ */ mp->mnt_data = fmp; fmp->flags = 0; + if (vfs_getopt(mp->mnt_optnew, "linrdlnk", NULL, NULL) == 0) + fmp->flags |= FMNT_LINRDLNKF; error = fdesc_allocvp(Froot, -1, FD_ROOT, mp, &rvp); if (error) { free(fmp, M_FDESCMNT); Index: sys/fs/fdescfs/fdesc_vnops.c =================================================================== --- sys/fs/fdescfs/fdesc_vnops.c +++ sys/fs/fdescfs/fdesc_vnops.c @@ -69,6 +69,7 @@ static vop_lookup_t fdesc_lookup; static vop_open_t fdesc_open; static vop_readdir_t fdesc_readdir; +static vop_readlink_t fdesc_readlink; static vop_reclaim_t fdesc_reclaim; static vop_setattr_t fdesc_setattr; @@ -81,6 +82,7 @@ .vop_open = fdesc_open, .vop_pathconf = vop_stdpathconf, .vop_readdir = fdesc_readdir, + .vop_readlink = fdesc_readlink, .vop_reclaim = fdesc_reclaim, .vop_setattr = fdesc_setattr, }; @@ -272,6 +274,7 @@ { struct vnode **vpp = ap->a_vpp; struct vnode *dvp = ap->a_dvp; + struct mount *mp; struct componentname *cnp = ap->a_cnp; char *pname = cnp->cn_nameptr; struct thread *td = cnp->cn_thread; @@ -361,6 +364,9 @@ if (error) goto bad; + mp = fvp->v_mount; + if (VFSTOFDESC(mp)->flags & FMNT_LINRDLNKF) + fvp->v_type = VREADLNK; *vpp = fvp; return (0); @@ -393,6 +399,7 @@ fdesc_getattr(struct vop_getattr_args *ap) { struct vnode *vp = ap->a_vp; + struct mount *mp; struct vattr *vap = ap->a_vap; struct timeval boottime; @@ -411,6 +418,7 @@ vap->va_bytes = 0; vap->va_filerev = 0; + mp = vp->v_mount; switch (VTOFDESC(vp)->fd_type) { case Froot: vap->va_type = VDIR; @@ -420,7 +428,10 @@ break; case Fdesc: - vap->va_type = VCHR; + if ((VFSTOFDESC(mp)->flags & FMNT_LINRDLNKF) == 0) + vap->va_type = VCHR; + else + vap->va_type = VLNK; vap->va_nlink = 1; vap->va_size = 0; vap->va_rdev = makedev(0, vap->va_fileid); @@ -490,6 +501,7 @@ static int fdesc_readdir(struct vop_readdir_args *ap) { + struct mount *mp; struct uio *uio = ap->a_uio; struct filedesc *fdp; struct dirent d; @@ -499,6 +511,7 @@ if (VTOFDESC(ap->a_vp)->fd_type != Froot) panic("fdesc_readdir: not dir"); + mp = ap->a_vp->v_mount; if (ap->a_ncookies != NULL) *ap->a_ncookies = 0; @@ -530,7 +543,10 @@ break; dp->d_namlen = sprintf(dp->d_name, "%d", fcnt); dp->d_reclen = UIO_MX; - dp->d_type = DT_CHR; + if (VFSTOFDESC(mp)->flags & FMNT_LINRDLNKF) + dp->d_type = DT_LNK; + else + dp->d_type = DT_CHR; dp->d_fileno = i + FD_DESC; break; } @@ -567,3 +583,57 @@ vp->v_data = NULL; return (0); } + +static int +fdesc_readlink(struct vop_readlink_args *va) +{ + struct vnode *vp, *vn = va->a_vp; + struct fdescnode *fd = vn->v_data; + struct thread *td = curthread; + struct uio *uio = va->a_uio; + struct filedesc *fdp; + cap_rights_t rights; + struct file *fp; + char *freepath, *fullpath; + size_t pathlen; + int error, locked; + + if (VTOFDESC(vn)->fd_type != Fdesc) + panic("linfdesc_readlink: not fdescfs link"); + + vhold(vn); + locked = VOP_ISLOCKED(vn); + VOP_UNLOCK(vn, 0); + + fdp = td->td_proc->p_fd; + error = fget_unlocked(fdp, fd->fd_fd, + cap_rights_init(&rights), &fp, NULL); + if (error != 0) + goto out; + + freepath = NULL; + switch (fp->f_type) { + case DTYPE_VNODE: + vp = fp->f_vnode; + vref(vp); + error = vn_fullpath(td, vp, &fullpath, &freepath); + vrele(vp); + break; + default: + fullpath = "anon_inode:[unknown]"; + break; + } + + if (error == 0) { + pathlen = strnlen(fullpath, MAXPATHLEN); + error = uiomove(fullpath, pathlen, uio); + } + if (freepath != NULL) + free(freepath, M_TEMP); + fdrop(fp, td); + +out: + vn_lock(vn, locked | LK_RETRY); + vdrop(vn); + return (error); +} Index: sys/fs/udf/udf_vnops.c =================================================================== --- sys/fs/udf/udf_vnops.c +++ sys/fs/udf/udf_vnops.c @@ -358,6 +358,7 @@ case VNON: case VBAD: case VMARKER: + case VREADLNK: return (0); } } Index: sys/kern/kern_descrip.c =================================================================== --- sys/kern/kern_descrip.c +++ sys/kern/kern_descrip.c @@ -3720,6 +3720,7 @@ { VDIR, KF_VTYPE_VDIR }, { VFIFO, KF_VTYPE_VFIFO }, { VLNK, KF_VTYPE_VLNK }, + { VREADLNK, KF_VTYPE_VLNK }, { VNON, KF_VTYPE_VNON }, { VREG, KF_VTYPE_VREG }, { VSOCK, KF_VTYPE_VSOCK } Index: sys/kern/vfs_subr.c =================================================================== --- sys/kern/vfs_subr.c +++ sys/kern/vfs_subr.c @@ -3435,7 +3435,7 @@ */ static char *typename[] = {"VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD", - "VMARKER"}; + "VMARKER", "VREADLNK"}; void vn_printf(struct vnode *vp, const char *fmt, ...) @@ -3957,6 +3957,7 @@ case VREG: case VDIR: case VLNK: + case VREADLNK: break; case VBLK: case VCHR: Index: sys/kern/vfs_syscalls.c =================================================================== --- sys/kern/vfs_syscalls.c +++ sys/kern/vfs_syscalls.c @@ -2484,7 +2484,7 @@ return (error); } #endif - if (vp->v_type != VLNK) + if (vp->v_type != VLNK && (vp->v_type & VREADLNK) == 0) error = EINVAL; else { aiov.iov_base = buf; Index: sys/kern/vfs_vnops.c =================================================================== --- sys/kern/vfs_vnops.c +++ sys/kern/vfs_vnops.c @@ -1426,6 +1426,7 @@ mode |= S_IFCHR; break; case VLNK: + case VREADLNK: mode |= S_IFLNK; break; case VSOCK: Index: sys/sys/vnode.h =================================================================== --- sys/sys/vnode.h +++ sys/sys/vnode.h @@ -54,7 +54,7 @@ * Vnode types. VNON means no type. */ enum vtype { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO, VBAD, - VMARKER }; + VMARKER, VREADLNK }; /* * Each underlying filesystem allocates its own private area and hangs