Index: sbin/mount/mount.c =================================================================== --- sbin/mount/mount.c +++ sbin/mount/mount.c @@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$"); #include +#define _WANT_MNTOPTNAMES #include #include #include @@ -92,36 +93,8 @@ char *flags2opts(int); /* Map from mount options to printable formats. */ -static struct opt { - uint64_t o_opt; - const char *o_name; -} optnames[] = { - { MNT_ASYNC, "asynchronous" }, - { MNT_EXPORTED, "NFS exported" }, - { MNT_LOCAL, "local" }, - { MNT_NOATIME, "noatime" }, - { MNT_NOEXEC, "noexec" }, - { MNT_NOSUID, "nosuid" }, - { MNT_NOSYMFOLLOW, "nosymfollow" }, - { MNT_QUOTA, "with quotas" }, - { MNT_RDONLY, "read-only" }, - { MNT_SYNCHRONOUS, "synchronous" }, - { MNT_UNION, "union" }, - { MNT_NOCLUSTERR, "noclusterr" }, - { MNT_NOCLUSTERW, "noclusterw" }, - { MNT_SUIDDIR, "suiddir" }, - { MNT_SOFTDEP, "soft-updates" }, - { MNT_SUJ, "journaled soft-updates" }, - { MNT_MULTILABEL, "multilabel" }, - { MNT_ACLS, "acls" }, - { MNT_NFS4ACLS, "nfsv4acls" }, - { MNT_GJOURNAL, "gjournal" }, - { MNT_AUTOMOUNTED, "automounted" }, - { MNT_VERIFIED, "verified" }, - { MNT_UNTRUSTED, "untrusted" }, - { MNT_NOCOVER, "nocover" }, - { MNT_EMPTYDIR, "emptydir" }, - { 0, NULL } +static struct mntoptnames optnames[] = { + MNTOPT_NAMES }; /* @@ -664,7 +637,7 @@ { uint64_t flags; unsigned int i; - struct opt *o; + struct mntoptnames *o; struct passwd *pw; (void)printf("%s on %s (%s", sfp->f_mntfromname, sfp->f_mntonname, Index: sys/kern/subr_bus.c =================================================================== --- sys/kern/subr_bus.c +++ sys/kern/subr_bus.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include Index: sys/kern/vfs_mount.c =================================================================== --- sys/kern/vfs_mount.c +++ sys/kern/vfs_mount.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -101,6 +102,8 @@ EVENTHANDLER_LIST_DEFINE(vfs_mounted); EVENTHANDLER_LIST_DEFINE(vfs_unmounted); +static void dev_vfs_event(const char *type, struct mount *mp, bool donew); + /* * Global opts, taken by all filesystems */ @@ -1020,6 +1023,7 @@ VOP_UNLOCK(vp); EVENTHANDLER_DIRECT_INVOKE(vfs_mounted, mp, newdp, td); VOP_UNLOCK(newdp); + dev_vfs_event("MOUNT", mp, false); mountcheckdirs(vp, newdp); vn_seqc_write_end(vp); vn_seqc_write_end(newdp); @@ -1221,6 +1225,7 @@ if (error != 0) goto end; + dev_vfs_event("REMOUNT", mp, true); if (mp->mnt_opt != NULL) vfs_freeopts(mp->mnt_opt); mp->mnt_opt = mp->mnt_optnew; @@ -1836,6 +1841,7 @@ TAILQ_REMOVE(&mountlist, mp, mnt_list); mtx_unlock(&mountlist_mtx); EVENTHANDLER_DIRECT_INVOKE(vfs_unmounted, mp, td); + dev_vfs_event("UNMOUNT", mp, false); if (coveredvp != NULL) { coveredvp->v_mountedhere = NULL; vn_seqc_write_end(coveredvp); @@ -2423,3 +2429,71 @@ error = kernel_mount(ma, flags); return (error); } + +/* Map from mount options to printable formats. */ +static struct mntoptnames optnames[] = { + MNTOPT_NAMES +}; + +static void +dev_vfs_event_mntopt(struct sbuf *sb, const char *what, struct vfsoptlist *opts) +{ + struct vfsopt *opt; + + if (opts == NULL || TAILQ_EMPTY(opts)) + return; + sbuf_printf(sb, " %s=\"", what); + TAILQ_FOREACH(opt, opts, link) { + if (opt->name[0] == '\0' || (opt->len > 0 && *(char *)opt->value == '\0')) + continue; + devctl_safe_quote_sb(sb, opt->name); + if (opt->len > 0) { + sbuf_putc(sb, '='); + devctl_safe_quote_sb(sb, opt->value); + } + sbuf_putc(sb, ';'); + } + sbuf_putc(sb, '"'); +} + +#define DEVCTL_LEN 1024 +static void +dev_vfs_event(const char *type, struct mount *mp, bool donew) +{ + const uint8_t *cp; + struct mntoptnames *fp; + struct sbuf sb; + struct statfs *sfp = &mp->mnt_stat; + char *buf; + + buf = malloc(DEVCTL_LEN, M_MOUNT, M_WAITOK); + if (buf == NULL) + return; + sbuf_new(&sb, buf, DEVCTL_LEN, SBUF_FIXEDLEN); + sbuf_cpy(&sb, "mount-point=\""); + devctl_safe_quote_sb(&sb, sfp->f_mntonname); + sbuf_cat(&sb, "\" mount-dev=\""); + devctl_safe_quote_sb(&sb, sfp->f_mntfromname); + sbuf_cat(&sb, "\" mount-type=\""); + devctl_safe_quote_sb(&sb, sfp->f_fstypename); + sbuf_cat(&sb, "\" fsid=0x"); + cp = (const uint8_t *)&sfp->f_fsid.val[0]; + for (int i = 0; i < sizeof(sfp->f_fsid); i++) + sbuf_printf(&sb, "%02x", cp[i]); + sbuf_printf(&sb, " owner=%u flags=\"", sfp->f_owner); + for (fp = optnames; fp->o_opt != 0; fp++) { + if ((mp->mnt_flag & fp->o_opt) != 0) { + sbuf_cat(&sb, fp->o_name); + sbuf_putc(&sb, ';'); + } + } + sbuf_putc(&sb, '"'); + dev_vfs_event_mntopt(&sb, "opt", mp->mnt_opt); + if (donew) + dev_vfs_event_mntopt(&sb, "optnew", mp->mnt_optnew); + sbuf_finish(&sb); + + devctl_notify("VFS", "FS", type, sbuf_data(&sb)); + sbuf_delete(&sb); + free(buf, M_MOUNT); +} Index: sys/sys/mount.h =================================================================== --- sys/sys/mount.h +++ sys/sys/mount.h @@ -294,6 +294,45 @@ #endif /* _KERNEL */ +#if defined(_WANT_MNTOPTNAMES) || defined(_KERNEL) +struct mntoptnames { + uint64_t o_opt; + const char *o_name; +}; +#define MNTOPT_NAMES \ + { MNT_ASYNC, "asynchronous" }, \ + { MNT_EXPORTED, "NFS exported" }, \ + { MNT_LOCAL, "local" }, \ + { MNT_NOATIME, "noatime" }, \ + { MNT_NOEXEC, "noexec" }, \ + { MNT_NOSUID, "nosuid" }, \ + { MNT_NOSYMFOLLOW, "nosymfollow" }, \ + { MNT_QUOTA, "with quotas" }, \ + { MNT_RDONLY, "read-only" }, \ + { MNT_SYNCHRONOUS, "synchronous" }, \ + { MNT_UNION, "union" }, \ + { MNT_NOCLUSTERR, "noclusterr" }, \ + { MNT_NOCLUSTERW, "noclusterw" }, \ + { MNT_SUIDDIR, "suiddir" }, \ + { MNT_SOFTDEP, "soft-updates" }, \ + { MNT_SUJ, "journaled soft-updates" }, \ + { MNT_MULTILABEL, "multilabel" }, \ + { MNT_ACLS, "acls" }, \ + { MNT_NFS4ACLS, "nfsv4acls" }, \ + { MNT_GJOURNAL, "gjournal" }, \ + { MNT_AUTOMOUNTED, "automounted" }, \ + { MNT_VERIFIED, "verified" }, \ + { MNT_UNTRUSTED, "untrusted" }, \ + { MNT_NOCOVER, "nocover" }, \ + { MNT_EMPTYDIR, "emptydir" }, \ + { MNT_UPDATE, "update" }, \ + { MNT_DELEXPORT, "delexport" }, \ + { MNT_RELOAD, "reload" }, \ + { MNT_FORCE, "force" }, \ + { MNT_SNAPSHOT, "snapshot" }, \ + { 0, NULL } +#endif + /* * User specifiable flags, stored in mnt_flag. */