.Op Fl o Ar options
.Ar target
.Ar mount-point
+.Nm
+.Fl u
+.Op Fl o Ar options
+.Ar mount-point
.Sh DESCRIPTION
The
.Nm
See the
.Xr mount 8
man page for possible options and their meanings.
+.It Fl u
+Update the mount point.
+This is typically used to upgrade a mount to
+read-write or downgrade it to read-only.
.El
.Pp
The null layer has three purposes.
struct mntopt mopts[] = {
MOPT_STDOPTS,
+ MOPT_UPDATE,
MOPT_NULL
};
struct vfsconf vfc;
int error;
+ bzero(&args, sizeof(args));
mntflags = 0;
- while ((ch = getopt(argc, argv, "o:")) != -1)
+ while ((ch = getopt(argc, argv, "o:u")) != -1)
switch(ch) {
case 'o':
getmntopts(optarg, mopts, &mntflags, 0);
break;
+ case 'u':
+ mntflags |= MNT_UPDATE;
+ break;
case '?':
default:
usage();
argc -= optind;
argv += optind;
- if (argc != 2)
+ /*
+ * Resolve target and source with realpath(3). Only the mount point
+ * needs be specified in update mode, but mount(8) passes us two
+ * arguments, the second of which is the source directory.
+ */
+ if ((mntflags & MNT_UPDATE) && argc == 1) {
+ args.target = NULL;
+ checkpath(argv[0], source);
+ } else if (argc == 2) {
+ args.target = target;
+ checkpath(argv[0], target);
+ checkpath(argv[1], source);
+ } else
usage();
- /* resolve target and source with realpath(3) */
- checkpath(argv[0], target);
- checkpath(argv[1], source);
-
/*
* Mount points that did not use distinct paths (e.g. / on /mnt)
* used to be disallowed because mount linkages were stored in
* stores mount linkages in the namecache topology and does not
* have this problem, so paths no longer need to be distinct.
*/
- args.target = target;
error = getvfsbyname("null", &vfc);
if (error && vfsisloadable("null")) {
{
fprintf(stderr,
"usage: mount_null [-o options] target_fs mount_point\n");
+ fprintf(stderr,
+ " mount_null -u [-o options] mount_point\n");
exit(1);
}
struct proc *p = td->td_proc;
struct vnode *vp;
struct nchandle nch;
- struct mount *mp;
+ struct mount *mp, *nullmp;
struct vfsconf *vfsp;
int error, flag = 0, flag2 = 0;
int hasmount;
}
/*
+ * If the target filesystem is resolved via a nullfs mount, then
+ * nd.nl_nch.mount will be pointing to the nullfs mount structure
+ * instead of the target file system. We need it in case we are
+ * doing an update.
+ */
+ nullmp = nd.nl_nch.mount;
+
+ /*
* Extract the locked+refd ncp and cleanup the nd structure
*/
nch = nd.nl_nch;
cache_unlock(&nch);
/*
+ * Extract the file system type. We need to know this early, to take
+ * appropriate actions if we are dealing with a nullfs.
+ */
+ if ((error = copyinstr(uap->type, fstypename, MFSNAMELEN, NULL)) != 0) {
+ cache_drop(&nch);
+ vput(vp);
+ return (error);
+ }
+
+ /*
* Now we have an unlocked ref'd nch and a locked ref'd vp
*/
if (uap->flags & MNT_UPDATE) {
vput(vp);
return (EINVAL);
}
- mp = vp->v_mount;
+
+ if (strncmp(fstypename, "null", 5) == 0) {
+ KKASSERT(nullmp);
+ mp = nullmp;
+ } else {
+ mp = vp->v_mount;
+ }
+
flag = mp->mnt_flag;
flag2 = mp->mnt_kern_flag;
/*
vput(vp);
return (EPERM);
}
- if ((error = copyinstr(uap->type, fstypename, MFSNAMELEN, NULL)) != 0) {
- cache_drop(&nch);
- vput(vp);
- return (error);
- }
vfsp = vfsconf_find_by_name(fstypename);
if (vfsp == NULL) {
linker_file_t lf;
struct null_args {
char *target; /* Target of loopback */
+ struct export_args export; /* Network export information */
};
#if defined(_KERNEL) || defined(_KERNEL_STRUCTURES)
NULLFSDEBUG("nullfs_mount(mp = %p)\n", (void *)mp);
/*
- * Update is a no-op
+ * Get argument
*/
- if (mp->mnt_flag & MNT_UPDATE) {
- return (EOPNOTSUPP);
- }
+ error = copyin(data, (caddr_t)&args, sizeof(struct null_args));
+ if (error)
+ return (error);
/*
- * Get argument
+ * XXX: Should we process mount export info ?
+ * If not, returning zero here is enough as the actual ro/rw update is
+ * being done in sys_mount().
*/
- error = copyin(data, (caddr_t)&args, sizeof(struct null_args));
- if (error)
+ if (mp->mnt_flag & MNT_UPDATE) {
+ xmp = MOUNTTONULLMOUNT(mp);
+ error = vfs_export(mp, &xmp->export, &args.export);
return (error);
+ }
/*
* Find lower node