Changeset View
Standalone View
sys/kern/vfs_mount.c
Show All 36 Lines | |||||
*/ | */ | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/conf.h> | #include <sys/conf.h> | ||||
#include <sys/smp.h> | #include <sys/smp.h> | ||||
#include <sys/bus.h> | |||||
kib: Perhaps devd events stuff could be split in dedicated header, as a followup. | |||||
#include <sys/eventhandler.h> | #include <sys/eventhandler.h> | ||||
#include <sys/fcntl.h> | #include <sys/fcntl.h> | ||||
#include <sys/jail.h> | #include <sys/jail.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/ktr.h> | #include <sys/ktr.h> | ||||
#include <sys/libkern.h> | #include <sys/libkern.h> | ||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/mount.h> | #include <sys/mount.h> | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | |||||
/* For any iteration/modification of mountlist */ | /* For any iteration/modification of mountlist */ | ||||
struct mtx mountlist_mtx; | struct mtx mountlist_mtx; | ||||
MTX_SYSINIT(mountlist, &mountlist_mtx, "mountlist", MTX_DEF); | MTX_SYSINIT(mountlist, &mountlist_mtx, "mountlist", MTX_DEF); | ||||
EVENTHANDLER_LIST_DEFINE(vfs_mounted); | EVENTHANDLER_LIST_DEFINE(vfs_mounted); | ||||
EVENTHANDLER_LIST_DEFINE(vfs_unmounted); | EVENTHANDLER_LIST_DEFINE(vfs_unmounted); | ||||
static void mount_devctl_event(const char *type, struct mount *mp, bool donew); | |||||
Done Inline ActionsNot sure this is the right name to use, so would be interested in feedback. imp: Not sure this is the right name to use, so would be interested in feedback.
| |||||
/* | /* | ||||
* Global opts, taken by all filesystems | * Global opts, taken by all filesystems | ||||
*/ | */ | ||||
static const char *global_opts[] = { | static const char *global_opts[] = { | ||||
"errmsg", | "errmsg", | ||||
"fstype", | "fstype", | ||||
"fspath", | "fspath", | ||||
"ro", | "ro", | ||||
▲ Show 20 Lines • Show All 903 Lines • ▼ Show 20 Lines | vfs_domount_first( | ||||
mtx_lock(&mountlist_mtx); | mtx_lock(&mountlist_mtx); | ||||
TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); | TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); | ||||
mtx_unlock(&mountlist_mtx); | mtx_unlock(&mountlist_mtx); | ||||
vfs_event_signal(NULL, VQ_MOUNT, 0); | vfs_event_signal(NULL, VQ_MOUNT, 0); | ||||
vn_lock(newdp, LK_EXCLUSIVE | LK_RETRY); | vn_lock(newdp, LK_EXCLUSIVE | LK_RETRY); | ||||
VOP_UNLOCK(vp); | VOP_UNLOCK(vp); | ||||
EVENTHANDLER_DIRECT_INVOKE(vfs_mounted, mp, newdp, td); | EVENTHANDLER_DIRECT_INVOKE(vfs_mounted, mp, newdp, td); | ||||
VOP_UNLOCK(newdp); | VOP_UNLOCK(newdp); | ||||
mount_devctl_event("MOUNT", mp, false); | |||||
mountcheckdirs(vp, newdp); | mountcheckdirs(vp, newdp); | ||||
vn_seqc_write_end(vp); | vn_seqc_write_end(vp); | ||||
vn_seqc_write_end(newdp); | vn_seqc_write_end(newdp); | ||||
vrele(newdp); | vrele(newdp); | ||||
if ((mp->mnt_flag & MNT_RDONLY) == 0) | if ((mp->mnt_flag & MNT_RDONLY) == 0) | ||||
vfs_allocate_syncvnode(mp); | vfs_allocate_syncvnode(mp); | ||||
vfs_op_exit(mp); | vfs_op_exit(mp); | ||||
vfs_unbusy(mp); | vfs_unbusy(mp); | ||||
▲ Show 20 Lines • Show All 185 Lines • ▼ Show 20 Lines | if ((mp->mnt_flag & MNT_ASYNC) != 0 && | ||||
mp->mnt_kern_flag |= MNTK_ASYNC; | mp->mnt_kern_flag |= MNTK_ASYNC; | ||||
else | else | ||||
mp->mnt_kern_flag &= ~MNTK_ASYNC; | mp->mnt_kern_flag &= ~MNTK_ASYNC; | ||||
MNT_IUNLOCK(mp); | MNT_IUNLOCK(mp); | ||||
if (error != 0) | if (error != 0) | ||||
goto end; | goto end; | ||||
mount_devctl_event("REMOUNT", mp, true); | |||||
if (mp->mnt_opt != NULL) | if (mp->mnt_opt != NULL) | ||||
vfs_freeopts(mp->mnt_opt); | vfs_freeopts(mp->mnt_opt); | ||||
mp->mnt_opt = mp->mnt_optnew; | mp->mnt_opt = mp->mnt_optnew; | ||||
*optlist = NULL; | *optlist = NULL; | ||||
(void)VFS_STATFS(mp, &mp->mnt_stat); | (void)VFS_STATFS(mp, &mp->mnt_stat); | ||||
/* | /* | ||||
* Prevent external consumers of mount options from reading | * Prevent external consumers of mount options from reading | ||||
* mnt_optnew. | * mnt_optnew. | ||||
▲ Show 20 Lines • Show All 599 Lines • ▼ Show 20 Lines | if (rootvp != NULL) { | ||||
vdrop(rootvp); | vdrop(rootvp); | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
mtx_lock(&mountlist_mtx); | mtx_lock(&mountlist_mtx); | ||||
TAILQ_REMOVE(&mountlist, mp, mnt_list); | TAILQ_REMOVE(&mountlist, mp, mnt_list); | ||||
mtx_unlock(&mountlist_mtx); | mtx_unlock(&mountlist_mtx); | ||||
EVENTHANDLER_DIRECT_INVOKE(vfs_unmounted, mp, td); | EVENTHANDLER_DIRECT_INVOKE(vfs_unmounted, mp, td); | ||||
if (coveredvp != NULL) { | if (coveredvp != NULL) { | ||||
Not Done Inline Actionscoveredvp is still locked there. That said, I am not sure that it is reasonable to report mount options for unmount event. kib: coveredvp is still locked there.
That said, I am not sure that it is reasonable to report… | |||||
Done Inline ActionsWon't they communicate how the system was last mounted? imp: Won't they communicate how the system was last mounted?
| |||||
Not Done Inline ActionsIs it useful ? Also the operation of unmounting could mangle options in the process. From very quick view, for instance UFS clears MNT_LOCAL. Why ? I do not know. kib: Is it useful ? Also the operation of unmounting could mangle options in the process. From… | |||||
Done Inline ActionsAh, fair point. I'll create a followup. imp: Ah, fair point. I'll create a followup. | |||||
Done Inline ActionsI added to umount, I just realized, to allow us to see if the umount was forced or not, which I know now isn't cleared... should we have a different mechanism to communicate that? imp: I added to umount, I just realized, to allow us to see if the umount was forced or not, which I… | |||||
Not Done Inline ActionsI think that this communication mechanism is fine. mckusick: I think that this communication mechanism is fine. | |||||
coveredvp->v_mountedhere = NULL; | coveredvp->v_mountedhere = NULL; | ||||
vn_seqc_write_end(coveredvp); | vn_seqc_write_end(coveredvp); | ||||
VOP_UNLOCK(coveredvp); | VOP_UNLOCK(coveredvp); | ||||
vdrop(coveredvp); | vdrop(coveredvp); | ||||
} | } | ||||
mount_devctl_event("UNMOUNT", mp, false); | |||||
if (rootvp != NULL) { | if (rootvp != NULL) { | ||||
vn_seqc_write_end(rootvp); | vn_seqc_write_end(rootvp); | ||||
vdrop(rootvp); | vdrop(rootvp); | ||||
} | } | ||||
vfs_event_signal(NULL, VQ_UNMOUNT, 0); | vfs_event_signal(NULL, VQ_UNMOUNT, 0); | ||||
if (rootvnode != NULL && mp == rootvnode->v_mount) { | if (rootvnode != NULL && mp == rootvnode->v_mount) { | ||||
vrele(rootvnode); | vrele(rootvnode); | ||||
rootvnode = NULL; | rootvnode = NULL; | ||||
▲ Show 20 Lines • Show All 564 Lines • ▼ Show 20 Lines | if (cp == NULL) | ||||
break; | break; | ||||
vp = va_arg(ap, const void *); | vp = va_arg(ap, const void *); | ||||
ma = mount_arg(ma, cp, vp, (vp != NULL ? -1 : 0)); | ma = mount_arg(ma, cp, vp, (vp != NULL ? -1 : 0)); | ||||
} | } | ||||
va_end(ap); | va_end(ap); | ||||
error = kernel_mount(ma, flags); | error = kernel_mount(ma, flags); | ||||
return (error); | return (error); | ||||
} | |||||
/* Map from mount options to printable formats. */ | |||||
static struct mntoptnames optnames[] = { | |||||
MNTOPT_NAMES | |||||
}; | |||||
static void | |||||
mount_devctl_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 | |||||
mount_devctl_event(const char *type, struct mount *mp, bool donew) | |||||
Not Done Inline ActionsI suggest mount_devd_event() kib: I suggest mount_devd_event() | |||||
Done Inline Actionselsewhere we use 'devctl' rather than 'devd' so I'll use mount_devctl_event imp: elsewhere we use 'devctl' rather than 'devd' so I'll use mount_devctl_event | |||||
{ | |||||
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) | |||||
kibUnsubmitted Not Done Inline Actionsbuf cannot be null. kib: buf cannot be null. | |||||
impAuthorUnsubmitted Done Inline ActionsI'd intended to use M_NOWAIT... imp: I'd intended to use M_NOWAIT... | |||||
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, '"'); | |||||
mount_devctl_event_mntopt(&sb, "opt", mp->mnt_opt); | |||||
if (donew) | |||||
mount_devctl_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); | |||||
} | } |
Perhaps devd events stuff could be split in dedicated header, as a followup.