Allow null mounts to accept -o update
authorStathis Kamperis <beket@dragonflybsd.org>
Sun, 22 Nov 2009 16:54:57 +0000 (18:54 +0200)
committerStathis Kamperis <beket@dragonflybsd.org>
Sun, 22 Nov 2009 17:39:04 +0000 (19:39 +0200)
Dragonfly-bug: <http://bugs.dragonflybsd.org/issue1537>
Reviewed-by: dillon@, y0netan1@, swildner@
Final patch contains modifications proposed by y0netan1@.

sbin/mount_null/mount_null.8
sbin/mount_null/mount_null.c
sys/kern/vfs_syscalls.c
sys/vfs/nullfs/null.h
sys/vfs/nullfs/null_vfsops.c

index d7b613c..5a70b00 100644 (file)
 .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.
index ec23bd9..9e02b6d 100644 (file)
@@ -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);
 }
index 4a1bfd0..b8f19f3 100644 (file)
@@ -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;
@@ -162,6 +162,14 @@ sys_mount(struct mount_args *uap)
        }
 
        /*
+        * 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;
@@ -185,6 +193,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
         */
        if (uap->flags & MNT_UPDATE) {
@@ -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;
index c227244..623128c 100644 (file)
@@ -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)
index 113c44e..25bf2e1 100644 (file)
@@ -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