Add a custom VOP_PATHCONF method for fdescfs.

The method handles NAME_MAX and LINK_MAX explicitly.  For all other
pathconf variables, the method passes the request down to the underlying
file descriptor.  This requires splitting a kern_fpathconf() syscallsubr
routine out of sys_fpathconf().  Also, to avoid lock order reversals with
vnode locks, the fdescfs vnode is unlocked around the call to
kern_fpathconf(), but with the usecount of the vnode bumped.

MFC after:	1 month
Sponsored by:	Chelsio Communications
This commit is contained in:
jhb 2017-12-19 18:20:38 +00:00
parent fd53ccf393
commit b731672881
3 changed files with 43 additions and 5 deletions

View File

@ -55,6 +55,8 @@
#include <sys/namei.h>
#include <sys/proc.h>
#include <sys/stat.h>
#include <sys/syscallsubr.h>
#include <sys/unistd.h>
#include <sys/vnode.h>
#include <fs/fdescfs/fdesc.h>
@ -70,6 +72,7 @@ struct mtx fdesc_hashmtx;
static vop_getattr_t fdesc_getattr;
static vop_lookup_t fdesc_lookup;
static vop_open_t fdesc_open;
static vop_pathconf_t fdesc_pathconf;
static vop_readdir_t fdesc_readdir;
static vop_readlink_t fdesc_readlink;
static vop_reclaim_t fdesc_reclaim;
@ -82,7 +85,7 @@ static struct vop_vector fdesc_vnodeops = {
.vop_getattr = fdesc_getattr,
.vop_lookup = fdesc_lookup,
.vop_open = fdesc_open,
.vop_pathconf = vop_stdpathconf,
.vop_pathconf = fdesc_pathconf,
.vop_readdir = fdesc_readdir,
.vop_readlink = fdesc_readlink,
.vop_reclaim = fdesc_reclaim,
@ -395,6 +398,33 @@ fdesc_open(struct vop_open_args *ap)
return (ENODEV);
}
static int
fdesc_pathconf(struct vop_pathconf_args *ap)
{
struct vnode *vp = ap->a_vp;
int error;
switch (ap->a_name) {
case _PC_NAME_MAX:
*ap->a_retval = NAME_MAX;
return (0);
case _PC_LINK_MAX:
if (VTOFDESC(vp)->fd_type == Froot)
*ap->a_retval = 2;
else
*ap->a_retval = 1;
return (0);
default:
vref(vp);
VOP_UNLOCK(vp, 0);
error = kern_fpathconf(curthread, VTOFDESC(vp)->fd_fd,
ap->a_name);
vn_lock(vp, LK_SHARED | LK_RETRY);
vunref(vp);
return (error);
}
}
static int
fdesc_getattr(struct vop_getattr_args *ap)
{

View File

@ -1417,27 +1417,34 @@ struct fpathconf_args {
/* ARGSUSED */
int
sys_fpathconf(struct thread *td, struct fpathconf_args *uap)
{
return (kern_fpathconf(td, uap->fd, uap->name));
}
int
kern_fpathconf(struct thread *td, int fd, int name)
{
struct file *fp;
struct vnode *vp;
cap_rights_t rights;
int error;
error = fget(td, uap->fd, cap_rights_init(&rights, CAP_FPATHCONF), &fp);
error = fget(td, fd, cap_rights_init(&rights, CAP_FPATHCONF), &fp);
if (error != 0)
return (error);
if (uap->name == _PC_ASYNC_IO) {
if (name == _PC_ASYNC_IO) {
td->td_retval[0] = _POSIX_ASYNCHRONOUS_IO;
goto out;
}
vp = fp->f_vnode;
if (vp != NULL) {
vn_lock(vp, LK_SHARED | LK_RETRY);
error = VOP_PATHCONF(vp, uap->name, td->td_retval);
error = VOP_PATHCONF(vp, name, td->td_retval);
VOP_UNLOCK(vp, 0);
} else if (fp->f_type == DTYPE_PIPE || fp->f_type == DTYPE_SOCKET) {
if (uap->name != _PC_PIPE_BUF) {
if (name != _PC_PIPE_BUF) {
error = EINVAL;
} else {
td->td_retval[0] = PIPE_BUF;

View File

@ -111,6 +111,7 @@ int kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg);
int kern_fcntl_freebsd(struct thread *td, int fd, int cmd, long arg);
int kern_fhstat(struct thread *td, fhandle_t fh, struct stat *buf);
int kern_fhstatfs(struct thread *td, fhandle_t fh, struct statfs *buf);
int kern_fpathconf(struct thread *td, int fd, int name);
int kern_fstat(struct thread *td, int fd, struct stat *sbp);
int kern_fstatfs(struct thread *td, int fd, struct statfs *buf);
int kern_fsync(struct thread *td, int fd, bool fullsync);