diff --git a/sys/fs/nfsclient/nfs_clvnops.c b/sys/fs/nfsclient/nfs_clvnops.c index e2c2dc1f442b..056eb271eea6 100644 --- a/sys/fs/nfsclient/nfs_clvnops.c +++ b/sys/fs/nfsclient/nfs_clvnops.c @@ -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, diff --git a/sys/kern/vfs_default.c b/sys/kern/vfs_default.c index ac000241009c..84b2471b3571 100644 --- a/sys/kern/vfs_default.c +++ b/sys/kern/vfs_default.c @@ -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); +} diff --git a/sys/kern/vfs_init.c b/sys/kern/vfs_init.c index 5eb38e6d8f61..58cde434b8f7 100644 --- a/sys/kern/vfs_init.c +++ b/sys/kern/vfs_init.c @@ -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; diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c index 3e325ae7431e..8d98cb199ec3 100644 --- a/sys/kern/vfs_mount.c +++ b/sys/kern/vfs_mount.c @@ -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)); } /* diff --git a/sys/sys/mount.h b/sys/sys/mount.h index c4f4bebfac64..51d709052850 100644 --- a/sys/sys/mount.h +++ b/sys/sys/mount.h @@ -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) diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h index 731381ed9837..4dab541afc13 100644 --- a/sys/sys/vnode.h +++ b/sys/sys/vnode.h @@ -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); diff --git a/sys/tools/vnode_if.awk b/sys/tools/vnode_if.awk index 966d0a951e98..6f1d19270786 100644 --- a/sys/tools/vnode_if.awk +++ b/sys/tools/vnode_if.awk @@ -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