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 30, 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 30, 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/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, }; @@ -174,10 +176,11 @@ vp = fd->fd_vnode; VI_LOCK(vp); mtx_unlock(&fdesc_hashmtx); - if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) + error = vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td); + if (error != 0) goto loop; *vpp = vp; - return (0); + goto out; } } mtx_unlock(&fdesc_hashmtx); @@ -230,7 +233,7 @@ if (error) vp2 = NULLVP; *vpp = vp2; - return (error); + goto out; } } @@ -238,7 +241,11 @@ LIST_INSERT_HEAD(fc, fd, fd_hash); mtx_unlock(&fdesc_hashmtx); *vpp = vp; - return (0); + +out: + if (error == 0 && ftype == Fdesc && (fmp->flags & FMNT_LINRDLNKF) != 0) + (*vpp)->v_vflag |= VV_READLINK; + return (error); } struct fdesc_get_ino_args { @@ -420,7 +427,7 @@ break; case Fdesc: - vap->va_type = VCHR; + vap->va_type = (vp->v_vflag & VV_READLINK) == 0 ? VCHR : VLNK; vap->va_nlink = 1; vap->va_size = 0; vap->va_rdev = makedev(0, vap->va_fileid); @@ -490,6 +497,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 +507,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 +539,9 @@ break; dp->d_namlen = sprintf(dp->d_name, "%d", fcnt); dp->d_reclen = UIO_MX; - dp->d_type = DT_CHR; + dp->d_type = + (VFSTOFDESC(mp)->flags & FMNT_LINRDLNKF) == 0 ? + DT_CHR : DT_LNK; dp->d_fileno = i + FD_DESC; break; } @@ -567,3 +578,52 @@ vp->v_data = NULL; return (0); } + +static int +fdesc_readlink(struct vop_readlink_args *va) +{ + struct vnode *vp, *vn; + cap_rights_t rights; + struct thread *td; + struct uio *uio; + struct file *fp; + char *freepath, *fullpath; + size_t pathlen; + int lockflags, fd_fd; + int error; + + freepath = NULL; + vn = va->a_vp; + if (VTOFDESC(vn)->fd_type != Fdesc) + panic("fdesc_readlink: not fdescfs link"); + fd_fd = ((struct fdescnode *)vn->v_data)->fd_fd; + lockflags = VOP_ISLOCKED(vn); + VOP_UNLOCK(vn, 0); + + td = curthread; + error = fget_cap(td, fd_fd, cap_rights_init(&rights), &fp, NULL); + if (error != 0) + goto out; + + switch (fp->f_type) { + case DTYPE_VNODE: + vp = fp->f_vnode; + error = vn_fullpath(td, vp, &fullpath, &freepath); + break; + default: + fullpath = "anon_inode:[unknown]"; + break; + } + if (error == 0) { + uio = va->a_uio; + pathlen = strlen(fullpath); + error = uiomove(fullpath, pathlen, uio); + } + if (freepath != NULL) + free(freepath, M_TEMP); + fdrop(fp, td); + +out: + vn_lock(vn, lockflags | LK_RETRY); + return (error); +} 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_vflag & VV_READLINK) == 0) error = EINVAL; else { aiov.iov_base = buf; Index: sys/sys/vnode.h =================================================================== --- sys/sys/vnode.h +++ sys/sys/vnode.h @@ -250,6 +250,7 @@ #define VV_DELETED 0x0400 /* should be removed */ #define VV_MD 0x0800 /* vnode backs the md device */ #define VV_FORCEINSMQ 0x1000 /* force the insmntque to succeed */ +#define VV_READLINK 0x2000 /* fdescfs linux vnode */ #define VMP_TMPMNTFREELIST 0x0001 /* Vnode is on mnt's tmp free list */