Only call sigdeferstop() for NFS.

Use bypass to catch any NFS VOP dispatch and route it through the
wrapper which does sigdeferstop() and then dispatches original
VOP. NFS does not need a bypass below it, which is not supported.

The vop offset in the vop_vector is added since otherwise it is
impossible to get vop_op_t from the internal table, and I did not
wanted to create the layered fs only to wrap NFS VOPs.

VFS_OP()s wrap is straightforward.

Requested and reviewed by:	mjg (previous version)
Tested by:	pho
Sponsored by:	The FreeBSD Foundation
Differential revision:	https://reviews.freebsd.org/D17658
This commit is contained in:
kib 2018-10-23 21:43:41 +00:00
parent ce1bca43e9
commit 5994728f36
7 changed files with 285 additions and 58 deletions

View File

@ -147,7 +147,8 @@ static vop_set_text_t nfs_set_text;
/*
* Global vfs data structures for nfs
*/
struct vop_vector newnfs_vnodeops = {
static struct vop_vector newnfs_vnodeops_nosig = {
.vop_default = &default_vnodeops,
.vop_access = nfs_access,
.vop_advlock = nfs_advlock,
@ -182,7 +183,19 @@ struct vop_vector newnfs_vnodeops = {
.vop_set_text = nfs_set_text,
};
struct vop_vector newnfs_fifoops = {
static int
nfs_vnodeops_bypass(struct vop_generic_args *a)
{
return (vop_sigdefer(&newnfs_vnodeops_nosig, a));
}
struct vop_vector newnfs_vnodeops = {
.vop_default = &default_vnodeops,
.vop_bypass = nfs_vnodeops_bypass,
};
static struct vop_vector newnfs_fifoops_nosig = {
.vop_default = &fifo_specops,
.vop_access = nfsspec_access,
.vop_close = nfsfifo_close,
@ -197,6 +210,18 @@ struct vop_vector newnfs_fifoops = {
.vop_write = nfsfifo_write,
};
static int
nfs_fifoops_bypass(struct vop_generic_args *a)
{
return (vop_sigdefer(&newnfs_fifoops_nosig, a));
}
struct vop_vector newnfs_fifoops = {
.vop_default = &default_vnodeops,
.vop_bypass = nfs_fifoops_bypass,
};
static int nfs_mknodrpc(struct vnode *dvp, struct vnode **vpp,
struct componentname *cnp, struct vattr *vap);
static int nfs_removerpc(struct vnode *dvp, struct vnode *vp, char *name,

View File

@ -1322,4 +1322,37 @@ vfs_stdsysctl(mp, op, req)
return (EOPNOTSUPP);
}
/* end of vfs default ops */
static vop_bypass_t *
bp_by_off(struct vop_vector *vop, struct vop_generic_args *a)
{
return (*(vop_bypass_t **)((char *)vop + a->a_desc->vdesc_vop_offset));
}
int
vop_sigdefer(struct vop_vector *vop, struct vop_generic_args *a)
{
vop_bypass_t *bp;
int prev_stops, rc;
for (; vop != NULL; vop = vop->vop_default) {
bp = bp_by_off(vop, a);
if (bp != NULL)
break;
/*
* Bypass is not really supported. It is done for
* fallback to unimplemented vops in the default
* vector.
*/
bp = vop->vop_bypass;
if (bp != NULL)
break;
}
MPASS(bp != NULL);
prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT);
rc = bp(a);
sigallowstop(prev_stops);
return (rc);
}

View File

@ -165,6 +165,198 @@ vfs_byname_kld(const char *fstype, struct thread *td, int *error)
return (vfsp);
}
static int
vfs_mount_sigdefer(struct mount *mp)
{
int prev_stops, rc;
TSRAW(curthread, TS_ENTER, "VFS_MOUNT", mp->mnt_vfc->vfc_name);
prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT);
rc = (*mp->mnt_vfc->vfc_vfsops_sd->vfs_mount)(mp);
sigallowstop(prev_stops);
TSRAW(curthread, TS_EXIT, "VFS_MOUNT", mp->mnt_vfc->vfc_name);
return (rc);
}
static int
vfs_unmount_sigdefer(struct mount *mp, int mntflags)
{
int prev_stops, rc;
prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT);
rc = (*mp->mnt_vfc->vfc_vfsops_sd->vfs_unmount)(mp, mntflags);
sigallowstop(prev_stops);
return (rc);
}
static int
vfs_root_sigdefer(struct mount *mp, int flags, struct vnode **vpp)
{
int prev_stops, rc;
prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT);
rc = (*mp->mnt_vfc->vfc_vfsops_sd->vfs_root)(mp, flags, vpp);
sigallowstop(prev_stops);
return (rc);
}
static int
vfs_quotactl_sigdefer(struct mount *mp, int cmd, uid_t uid, void *arg)
{
int prev_stops, rc;
prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT);
rc = (*mp->mnt_vfc->vfc_vfsops_sd->vfs_quotactl)(mp, cmd, uid, arg);
sigallowstop(prev_stops);
return (rc);
}
static int
vfs_statfs_sigdefer(struct mount *mp, struct statfs *sbp)
{
int prev_stops, rc;
prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT);
rc = (*mp->mnt_vfc->vfc_vfsops_sd->vfs_statfs)(mp, sbp);
sigallowstop(prev_stops);
return (rc);
}
static int
vfs_sync_sigdefer(struct mount *mp, int waitfor)
{
int prev_stops, rc;
prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT);
rc = (*mp->mnt_vfc->vfc_vfsops_sd->vfs_sync)(mp, waitfor);
sigallowstop(prev_stops);
return (rc);
}
static int
vfs_vget_sigdefer(struct mount *mp, ino_t ino, int flags, struct vnode **vpp)
{
int prev_stops, rc;
prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT);
rc = (*mp->mnt_vfc->vfc_vfsops_sd->vfs_vget)(mp, ino, flags, vpp);
sigallowstop(prev_stops);
return (rc);
}
static int
vfs_fhtovp_sigdefer(struct mount *mp, struct fid *fidp, int flags,
struct vnode **vpp)
{
int prev_stops, rc;
prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT);
rc = (*mp->mnt_vfc->vfc_vfsops_sd->vfs_fhtovp)(mp, fidp, flags, vpp);
sigallowstop(prev_stops);
return (rc);
}
static int
vfs_checkexp_sigdefer(struct mount *mp, struct sockaddr *nam, int *exflg,
struct ucred **credp, int *numsecflavors, int **secflavors)
{
int prev_stops, rc;
prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT);
rc = (*mp->mnt_vfc->vfc_vfsops_sd->vfs_checkexp)(mp, nam, exflg, credp,
numsecflavors, secflavors);
sigallowstop(prev_stops);
return (rc);
}
static int
vfs_extattrctl_sigdefer(struct mount *mp, int cmd, struct vnode *filename_vp,
int attrnamespace, const char *attrname)
{
int prev_stops, rc;
prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT);
rc = (*mp->mnt_vfc->vfc_vfsops_sd->vfs_extattrctl)(mp, cmd,
filename_vp, attrnamespace, attrname);
sigallowstop(prev_stops);
return (rc);
}
static int
vfs_sysctl_sigdefer(struct mount *mp, fsctlop_t op, struct sysctl_req *req)
{
int prev_stops, rc;
prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT);
rc = (*mp->mnt_vfc->vfc_vfsops_sd->vfs_sysctl)(mp, op, req);
sigallowstop(prev_stops);
return (rc);
}
static void
vfs_susp_clean_sigdefer(struct mount *mp)
{
int prev_stops;
if (*mp->mnt_vfc->vfc_vfsops_sd->vfs_susp_clean == NULL)
return;
prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT);
(*mp->mnt_vfc->vfc_vfsops_sd->vfs_susp_clean)(mp);
sigallowstop(prev_stops);
}
static void
vfs_reclaim_lowervp_sigdefer(struct mount *mp, struct vnode *vp)
{
int prev_stops;
if (*mp->mnt_vfc->vfc_vfsops_sd->vfs_reclaim_lowervp == NULL)
return;
prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT);
(*mp->mnt_vfc->vfc_vfsops_sd->vfs_reclaim_lowervp)(mp, vp);
sigallowstop(prev_stops);
}
static void
vfs_unlink_lowervp_sigdefer(struct mount *mp, struct vnode *vp)
{
int prev_stops;
if (*mp->mnt_vfc->vfc_vfsops_sd->vfs_unlink_lowervp == NULL)
return;
prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT);
(*(mp)->mnt_vfc->vfc_vfsops_sd->vfs_unlink_lowervp)(mp, vp);
sigallowstop(prev_stops);
}
static void
vfs_purge_sigdefer(struct mount *mp)
{
int prev_stops;
prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT);
(*mp->mnt_vfc->vfc_vfsops_sd->vfs_purge)(mp);
sigallowstop(prev_stops);
}
static struct vfsops vfsops_sigdefer = {
.vfs_mount = vfs_mount_sigdefer,
.vfs_unmount = vfs_unmount_sigdefer,
.vfs_root = vfs_root_sigdefer,
.vfs_quotactl = vfs_quotactl_sigdefer,
.vfs_statfs = vfs_statfs_sigdefer,
.vfs_sync = vfs_sync_sigdefer,
.vfs_vget = vfs_vget_sigdefer,
.vfs_fhtovp = vfs_fhtovp_sigdefer,
.vfs_checkexp = vfs_checkexp_sigdefer,
.vfs_extattrctl = vfs_extattrctl_sigdefer,
.vfs_sysctl = vfs_sysctl_sigdefer,
.vfs_susp_clean = vfs_susp_clean_sigdefer,
.vfs_reclaim_lowervp = vfs_reclaim_lowervp_sigdefer,
.vfs_unlink_lowervp = vfs_unlink_lowervp_sigdefer,
.vfs_purge = vfs_purge_sigdefer,
};
/* Register a new filesystem type in the global table */
static int
@ -278,13 +470,21 @@ vfs_register(struct vfsconf *vfc)
if (vfsops->vfs_sysctl == NULL)
vfsops->vfs_sysctl = vfs_stdsysctl;
if ((vfc->vfc_flags & VFCF_SBDRY) != 0) {
vfc->vfc_vfsops_sd = vfc->vfc_vfsops;
vfc->vfc_vfsops = &vfsops_sigdefer;
}
if (vfc->vfc_flags & VFCF_JAIL)
prison_add_vfs(vfc);
/*
* Call init function for this VFS...
*/
(*(vfc->vfc_vfsops->vfs_init))(vfc);
if ((vfc->vfc_flags & VFCF_SBDRY) != 0)
vfc->vfc_vfsops_sd->vfs_init(vfc);
else
vfc->vfc_vfsops->vfs_init(vfc);
vfsconf_unlock();
/*
@ -329,12 +529,18 @@ vfs_unregister(struct vfsconf *vfc)
vfsconf_unlock();
return (EBUSY);
}
if (vfc->vfc_vfsops->vfs_uninit != NULL) {
error = (*vfc->vfc_vfsops->vfs_uninit)(vfsp);
if (error != 0) {
vfsconf_unlock();
return (error);
}
error = 0;
if ((vfc->vfc_flags & VFCF_SBDRY) != 0) {
if (vfc->vfc_vfsops_sd->vfs_uninit != NULL)
error = vfc->vfc_vfsops_sd->vfs_uninit(vfsp);
} else {
if (vfc->vfc_vfsops->vfs_uninit != NULL) {
error = vfc->vfc_vfsops->vfs_uninit(vfsp);
}
if (error != 0) {
vfsconf_unlock();
return (error);
}
}
TAILQ_REMOVE(&vfsconf, vfsp, vfc_list);
maxtypenum = VFS_GENERIC;

View File

@ -808,7 +808,8 @@ sys_mount(struct thread *td, struct mount_args *uap)
free(fstype, M_TEMP);
if (vfsp == NULL)
return (ENOENT);
if (vfsp->vfc_vfsops->vfs_cmount == NULL)
if (vfsp->vfc_vfsops->vfs_cmount == NULL || ((vfsp->vfc_flags &
VFCF_SBDRY) != 0 && (vfsp->vfc_vfsops_sd->vfs_cmount == NULL)))
return (EOPNOTSUPP);
ma = mount_argsu(ma, "fstype", uap->type, MFSNAMELEN);
@ -817,8 +818,9 @@ sys_mount(struct thread *td, struct mount_args *uap)
ma = mount_argb(ma, !(flags & MNT_NOSUID), "nosuid");
ma = mount_argb(ma, !(flags & MNT_NOEXEC), "noexec");
error = vfsp->vfc_vfsops->vfs_cmount(ma, uap->data, flags);
return (error);
if ((vfsp->vfc_flags & VFCF_SBDRY) != 0)
return (vfsp->vfc_vfsops_sd->vfs_cmount(ma, uap->data, flags));
return (vfsp->vfc_vfsops->vfs_cmount(ma, uap->data, flags));
}
/*

View File

@ -513,6 +513,7 @@ struct vfsconf {
u_int vfc_version; /* ABI version number */
char vfc_name[MFSNAMELEN]; /* filesystem type name */
struct vfsops *vfc_vfsops; /* filesystem operations vector */
struct vfsops *vfc_vfsops_sd; /* ... signal-deferred */
int vfc_typenum; /* historic filesystem type number */
int vfc_refcount; /* number mounted of this type */
int vfc_flags; /* permanent flags */
@ -694,139 +695,96 @@ struct vfsops {
vfs_statfs_t __vfs_statfs;
#define VFS_PROLOGUE(MP) do { \
struct mount *mp__; \
int _prev_stops; \
\
mp__ = (MP); \
_prev_stops = sigdeferstop((mp__ != NULL && \
(mp__->mnt_vfc->vfc_flags & VFCF_SBDRY) != 0) ? \
SIGDEFERSTOP_SILENT : SIGDEFERSTOP_NOP);
#define VFS_EPILOGUE(MP) \
sigallowstop(_prev_stops); \
} while (0)
#define VFS_MOUNT(MP) ({ \
int _rc; \
\
TSRAW(curthread, TS_ENTER, "VFS_MOUNT", (MP)->mnt_vfc->vfc_name);\
VFS_PROLOGUE(MP); \
_rc = (*(MP)->mnt_op->vfs_mount)(MP); \
VFS_EPILOGUE(MP); \
TSRAW(curthread, TS_EXIT, "VFS_MOUNT", (MP)->mnt_vfc->vfc_name);\
_rc; })
#define VFS_UNMOUNT(MP, FORCE) ({ \
int _rc; \
\
VFS_PROLOGUE(MP); \
_rc = (*(MP)->mnt_op->vfs_unmount)(MP, FORCE); \
VFS_EPILOGUE(MP); \
_rc; })
#define VFS_ROOT(MP, FLAGS, VPP) ({ \
int _rc; \
\
VFS_PROLOGUE(MP); \
_rc = (*(MP)->mnt_op->vfs_root)(MP, FLAGS, VPP); \
VFS_EPILOGUE(MP); \
_rc; })
#define VFS_QUOTACTL(MP, C, U, A) ({ \
int _rc; \
\
VFS_PROLOGUE(MP); \
_rc = (*(MP)->mnt_op->vfs_quotactl)(MP, C, U, A); \
VFS_EPILOGUE(MP); \
_rc; })
#define VFS_STATFS(MP, SBP) ({ \
int _rc; \
\
VFS_PROLOGUE(MP); \
_rc = __vfs_statfs((MP), (SBP)); \
VFS_EPILOGUE(MP); \
_rc; })
#define VFS_SYNC(MP, WAIT) ({ \
int _rc; \
\
VFS_PROLOGUE(MP); \
_rc = (*(MP)->mnt_op->vfs_sync)(MP, WAIT); \
VFS_EPILOGUE(MP); \
_rc; })
#define VFS_VGET(MP, INO, FLAGS, VPP) ({ \
int _rc; \
\
VFS_PROLOGUE(MP); \
_rc = (*(MP)->mnt_op->vfs_vget)(MP, INO, FLAGS, VPP); \
VFS_EPILOGUE(MP); \
_rc; })
#define VFS_FHTOVP(MP, FIDP, FLAGS, VPP) ({ \
int _rc; \
\
VFS_PROLOGUE(MP); \
_rc = (*(MP)->mnt_op->vfs_fhtovp)(MP, FIDP, FLAGS, VPP); \
VFS_EPILOGUE(MP); \
_rc; })
#define VFS_CHECKEXP(MP, NAM, EXFLG, CRED, NUMSEC, SEC) ({ \
int _rc; \
\
VFS_PROLOGUE(MP); \
_rc = (*(MP)->mnt_op->vfs_checkexp)(MP, NAM, EXFLG, CRED, NUMSEC,\
SEC); \
VFS_EPILOGUE(MP); \
_rc; })
#define VFS_EXTATTRCTL(MP, C, FN, NS, N) ({ \
int _rc; \
\
VFS_PROLOGUE(MP); \
_rc = (*(MP)->mnt_op->vfs_extattrctl)(MP, C, FN, NS, N); \
VFS_EPILOGUE(MP); \
_rc; })
#define VFS_SYSCTL(MP, OP, REQ) ({ \
int _rc; \
\
VFS_PROLOGUE(MP); \
_rc = (*(MP)->mnt_op->vfs_sysctl)(MP, OP, REQ); \
VFS_EPILOGUE(MP); \
_rc; })
#define VFS_SUSP_CLEAN(MP) do { \
if (*(MP)->mnt_op->vfs_susp_clean != NULL) { \
VFS_PROLOGUE(MP); \
(*(MP)->mnt_op->vfs_susp_clean)(MP); \
VFS_EPILOGUE(MP); \
} \
} while (0)
#define VFS_RECLAIM_LOWERVP(MP, VP) do { \
if (*(MP)->mnt_op->vfs_reclaim_lowervp != NULL) { \
VFS_PROLOGUE(MP); \
(*(MP)->mnt_op->vfs_reclaim_lowervp)((MP), (VP)); \
VFS_EPILOGUE(MP); \
} \
} while (0)
#define VFS_UNLINK_LOWERVP(MP, VP) do { \
if (*(MP)->mnt_op->vfs_unlink_lowervp != NULL) { \
VFS_PROLOGUE(MP); \
(*(MP)->mnt_op->vfs_unlink_lowervp)((MP), (VP)); \
VFS_EPILOGUE(MP); \
} \
} while (0)
#define VFS_PURGE(MP) do { \
if (*(MP)->mnt_op->vfs_purge != NULL) { \
VFS_PROLOGUE(MP); \
(*(MP)->mnt_op->vfs_purge)(MP); \
VFS_EPILOGUE(MP); \
} \
} while (0)

View File

@ -484,6 +484,7 @@ typedef int vop_bypass_t(struct vop_generic_args *);
struct vnodeop_desc {
char *vdesc_name; /* a readable name for debugging */
int vdesc_flags; /* VDESC_* flags */
int vdesc_vop_offset;
vop_bypass_t *vdesc_call; /* Function to call */
/*
@ -785,6 +786,7 @@ void vop_rmdir_post(void *a, int rc);
void vop_setattr_post(void *a, int rc);
void vop_setextattr_post(void *a, int rc);
void vop_symlink_post(void *a, int rc);
int vop_sigdefer(struct vop_vector *vop, struct vop_generic_args *a);
#ifdef DEBUG_VFS_LOCKS
void vop_strategy_pre(void *a);

View File

@ -181,6 +181,7 @@ if (cfile) {
"struct vnodeop_desc vop_default_desc = {\n" \
" \"default\",\n" \
" 0,\n" \
" 0,\n" \
" (vop_bypass_t *)vop_panic,\n" \
" NULL,\n" \
" VDESC_NO_OFFSET,\n" \
@ -366,12 +367,10 @@ while ((getline < srcfile) > 0) {
add_debug_code(name, args[i], "Entry", "\t");
printc("\tKTR_START" ctrstr);
add_pre(name);
printc("\tVFS_PROLOGUE(a->a_" args[0]"->v_mount);")
printc("\tif (vop->"name" != NULL)")
printc("\t\trc = vop->"name"(a);")
printc("\telse")
printc("\t\trc = vop->vop_bypass(&a->a_gen);")
printc("\tVFS_EPILOGUE(a->a_" args[0]"->v_mount);")
printc("\tSDT_PROBE3(vfs, vop, " name ", return, a->a_" args[0] ", a, rc);\n");
printc("\tif (rc == 0) {");
for (i = 0; i < numargs; ++i)
@ -402,6 +401,8 @@ while ((getline < srcfile) > 0) {
releflags = "0";
printc("\t" releflags vppwillrele ",");
# index in struct vop_vector
printc("\t__offsetof(struct vop_vector, " name "),");
# function to call
printc("\t(vop_bypass_t *)" uname "_AP,");
# vp offsets