From: Stathis Kamperis Date: Sun, 22 Nov 2009 16:54:57 +0000 (+0200) Subject: Allow null mounts to accept -o update X-Git-Url: https://gitweb.dragonflybsd.org/~polachok/dragonfly.git/commitdiff_plain/8b02b69a65f3a7c5d344957f9ee3162b20077c93 Allow null mounts to accept -o update Dragonfly-bug: Reviewed-by: dillon@, y0netan1@, swildner@ Final patch contains modifications proposed by y0netan1@. --- diff --git a/sbin/mount_null/mount_null.8 b/sbin/mount_null/mount_null.8 index d7b613c65b..5a70b00cf3 100644 --- a/sbin/mount_null/mount_null.8 +++ b/sbin/mount_null/mount_null.8 @@ -49,6 +49,10 @@ .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 @@ -85,6 +89,10 @@ flag followed by a comma separated string of options. 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. diff --git a/sbin/mount_null/mount_null.c b/sbin/mount_null/mount_null.c index ec23bd9839..9e02b6d607 100644 --- a/sbin/mount_null/mount_null.c +++ b/sbin/mount_null/mount_null.c @@ -54,6 +54,7 @@ struct mntopt mopts[] = { MOPT_STDOPTS, + MOPT_UPDATE, MOPT_NULL }; @@ -69,12 +70,16 @@ main(int argc, char **argv) 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(); @@ -82,13 +87,21 @@ main(int argc, char **argv) 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 @@ -96,7 +109,6 @@ main(int argc, char **argv) * 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")) { @@ -118,5 +130,7 @@ usage(void) { fprintf(stderr, "usage: mount_null [-o options] target_fs mount_point\n"); + fprintf(stderr, + " mount_null -u [-o options] mount_point\n"); exit(1); } diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index 4a1bfd0ed6..b8f19f3d4e 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -118,7 +118,7 @@ sys_mount(struct mount_args *uap) 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; @@ -161,6 +161,14 @@ sys_mount(struct mount_args *uap) return (error); } + /* + * 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 */ @@ -184,6 +192,16 @@ sys_mount(struct mount_args *uap) } 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 */ @@ -193,7 +211,14 @@ sys_mount(struct mount_args *uap) 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; /* @@ -258,11 +283,6 @@ sys_mount(struct mount_args *uap) 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; diff --git a/sys/vfs/nullfs/null.h b/sys/vfs/nullfs/null.h index c227244859..623128c252 100644 --- a/sys/vfs/nullfs/null.h +++ b/sys/vfs/nullfs/null.h @@ -41,6 +41,7 @@ struct null_args { char *target; /* Target of loopback */ + struct export_args export; /* Network export information */ }; #if defined(_KERNEL) || defined(_KERNEL_STRUCTURES) diff --git a/sys/vfs/nullfs/null_vfsops.c b/sys/vfs/nullfs/null_vfsops.c index 113c44e322..25bf2e15e4 100644 --- a/sys/vfs/nullfs/null_vfsops.c +++ b/sys/vfs/nullfs/null_vfsops.c @@ -81,18 +81,22 @@ nullfs_mount(struct mount *mp, char *path, caddr_t data, struct ucred *cred) 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