1*b4cb3fe0SToomas Soome /*-
2*b4cb3fe0SToomas Soome * Copyright 2021 Toomas Soome <tsoome@me.com>
3*b4cb3fe0SToomas Soome *
4*b4cb3fe0SToomas Soome * Redistribution and use in source and binary forms, with or without
5*b4cb3fe0SToomas Soome * modification, are permitted provided that the following conditions
6*b4cb3fe0SToomas Soome * are met:
7*b4cb3fe0SToomas Soome * 1. Redistributions of source code must retain the above copyright
8*b4cb3fe0SToomas Soome * notice, this list of conditions and the following disclaimer.
9*b4cb3fe0SToomas Soome * 2. Redistributions in binary form must reproduce the above copyright
10*b4cb3fe0SToomas Soome * notice, this list of conditions and the following disclaimer in the
11*b4cb3fe0SToomas Soome * documentation and/or other materials provided with the distribution.
12*b4cb3fe0SToomas Soome *
13*b4cb3fe0SToomas Soome * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14*b4cb3fe0SToomas Soome * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15*b4cb3fe0SToomas Soome * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16*b4cb3fe0SToomas Soome * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17*b4cb3fe0SToomas Soome * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18*b4cb3fe0SToomas Soome * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19*b4cb3fe0SToomas Soome * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20*b4cb3fe0SToomas Soome * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21*b4cb3fe0SToomas Soome * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22*b4cb3fe0SToomas Soome * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23*b4cb3fe0SToomas Soome * SUCH DAMAGE.
24*b4cb3fe0SToomas Soome */
25*b4cb3fe0SToomas Soome
26*b4cb3fe0SToomas Soome #include <stand.h>
27*b4cb3fe0SToomas Soome #include <sys/queue.h>
28*b4cb3fe0SToomas Soome
29*b4cb3fe0SToomas Soome /*
30*b4cb3fe0SToomas Soome * While setting "currdev" environment variable, alse "mount" the
31*b4cb3fe0SToomas Soome * new root file system. This is done to hold disk device open
32*b4cb3fe0SToomas Soome * in between file accesses, and thus preserve block cache for
33*b4cb3fe0SToomas Soome * this device. Additionally, this allows us to optimize filesystem
34*b4cb3fe0SToomas Soome * access by sharing filesystem metadata (like superblock).
35*b4cb3fe0SToomas Soome */
36*b4cb3fe0SToomas Soome
37*b4cb3fe0SToomas Soome typedef STAILQ_HEAD(mnt_info_list, mnt_info) mnt_info_list_t;
38*b4cb3fe0SToomas Soome
39*b4cb3fe0SToomas Soome typedef struct mnt_info {
40*b4cb3fe0SToomas Soome STAILQ_ENTRY(mnt_info) mnt_link; /* link in mount list */
41*b4cb3fe0SToomas Soome const struct fs_ops *mnt_fs;
42*b4cb3fe0SToomas Soome char *mnt_dev;
43*b4cb3fe0SToomas Soome char *mnt_path;
44*b4cb3fe0SToomas Soome unsigned mnt_refcount;
45*b4cb3fe0SToomas Soome void *mnt_data; /* Private state */
46*b4cb3fe0SToomas Soome } mnt_info_t;
47*b4cb3fe0SToomas Soome
48*b4cb3fe0SToomas Soome /* list of mounted filesystems. */
49*b4cb3fe0SToomas Soome static mnt_info_list_t mnt_list = STAILQ_HEAD_INITIALIZER(mnt_list);
50*b4cb3fe0SToomas Soome
51*b4cb3fe0SToomas Soome static void
free_mnt(mnt_info_t * mnt)52*b4cb3fe0SToomas Soome free_mnt(mnt_info_t *mnt)
53*b4cb3fe0SToomas Soome {
54*b4cb3fe0SToomas Soome free(mnt->mnt_dev);
55*b4cb3fe0SToomas Soome free(mnt->mnt_path);
56*b4cb3fe0SToomas Soome free(mnt);
57*b4cb3fe0SToomas Soome }
58*b4cb3fe0SToomas Soome
59*b4cb3fe0SToomas Soome static int
add_mnt_info(struct fs_ops * fs,const char * dev,const char * path,void * data)60*b4cb3fe0SToomas Soome add_mnt_info(struct fs_ops *fs, const char *dev, const char *path, void *data)
61*b4cb3fe0SToomas Soome {
62*b4cb3fe0SToomas Soome mnt_info_t *mnt;
63*b4cb3fe0SToomas Soome
64*b4cb3fe0SToomas Soome mnt = malloc(sizeof(*mnt));
65*b4cb3fe0SToomas Soome if (mnt == NULL)
66*b4cb3fe0SToomas Soome return (ENOMEM);
67*b4cb3fe0SToomas Soome
68*b4cb3fe0SToomas Soome mnt->mnt_fs = fs;
69*b4cb3fe0SToomas Soome mnt->mnt_dev = strdup(dev);
70*b4cb3fe0SToomas Soome mnt->mnt_path = strdup(path);
71*b4cb3fe0SToomas Soome mnt->mnt_data = data;
72*b4cb3fe0SToomas Soome mnt->mnt_refcount = 1;
73*b4cb3fe0SToomas Soome
74*b4cb3fe0SToomas Soome if (mnt->mnt_dev == NULL || mnt->mnt_path == NULL) {
75*b4cb3fe0SToomas Soome free_mnt(mnt);
76*b4cb3fe0SToomas Soome return (ENOMEM);
77*b4cb3fe0SToomas Soome }
78*b4cb3fe0SToomas Soome STAILQ_INSERT_TAIL(&mnt_list, mnt, mnt_link);
79*b4cb3fe0SToomas Soome return (0);
80*b4cb3fe0SToomas Soome }
81*b4cb3fe0SToomas Soome
82*b4cb3fe0SToomas Soome static void
delete_mnt_info(mnt_info_t * mnt)83*b4cb3fe0SToomas Soome delete_mnt_info(mnt_info_t *mnt)
84*b4cb3fe0SToomas Soome {
85*b4cb3fe0SToomas Soome STAILQ_REMOVE(&mnt_list, mnt, mnt_info, mnt_link);
86*b4cb3fe0SToomas Soome free_mnt(mnt);
87*b4cb3fe0SToomas Soome }
88*b4cb3fe0SToomas Soome
89*b4cb3fe0SToomas Soome int
mount(const char * dev,const char * path,int flags __unused,void * data)90*b4cb3fe0SToomas Soome mount(const char *dev, const char *path, int flags __unused, void *data)
91*b4cb3fe0SToomas Soome {
92*b4cb3fe0SToomas Soome mnt_info_t *mnt;
93*b4cb3fe0SToomas Soome int rc = -1;
94*b4cb3fe0SToomas Soome
95*b4cb3fe0SToomas Soome /* Is it already mounted? */
96*b4cb3fe0SToomas Soome STAILQ_FOREACH(mnt, &mnt_list, mnt_link) {
97*b4cb3fe0SToomas Soome if (strcmp(dev, mnt->mnt_dev) == 0 &&
98*b4cb3fe0SToomas Soome strcmp(path, mnt->mnt_path) == 0) {
99*b4cb3fe0SToomas Soome mnt->mnt_refcount++;
100*b4cb3fe0SToomas Soome return (0);
101*b4cb3fe0SToomas Soome }
102*b4cb3fe0SToomas Soome }
103*b4cb3fe0SToomas Soome
104*b4cb3fe0SToomas Soome for (int i = 0; file_system[i] != NULL; i++) {
105*b4cb3fe0SToomas Soome struct fs_ops *fs;
106*b4cb3fe0SToomas Soome
107*b4cb3fe0SToomas Soome fs = file_system[i];
108*b4cb3fe0SToomas Soome if (fs->fo_mount == NULL)
109*b4cb3fe0SToomas Soome continue;
110*b4cb3fe0SToomas Soome
111*b4cb3fe0SToomas Soome if (fs->fo_mount(dev, path, &data) != 0)
112*b4cb3fe0SToomas Soome continue;
113*b4cb3fe0SToomas Soome
114*b4cb3fe0SToomas Soome rc = add_mnt_info(fs, dev, path, data);
115*b4cb3fe0SToomas Soome if (rc != 0 && mnt->mnt_fs->fo_unmount != NULL) {
116*b4cb3fe0SToomas Soome printf("failed to mount %s: %s\n", dev,
117*b4cb3fe0SToomas Soome strerror(rc));
118*b4cb3fe0SToomas Soome (void)mnt->mnt_fs->fo_unmount(dev, data);
119*b4cb3fe0SToomas Soome }
120*b4cb3fe0SToomas Soome break;
121*b4cb3fe0SToomas Soome }
122*b4cb3fe0SToomas Soome
123*b4cb3fe0SToomas Soome
124*b4cb3fe0SToomas Soome /*
125*b4cb3fe0SToomas Soome * if rc is -1, it means we have no file system with fo_mount()
126*b4cb3fe0SToomas Soome * callback, or all fo_mount() calls failed. As long as we
127*b4cb3fe0SToomas Soome * have missing fo_mount() callbacks, we allow mount() to return 0.
128*b4cb3fe0SToomas Soome */
129*b4cb3fe0SToomas Soome if (rc == -1)
130*b4cb3fe0SToomas Soome rc = 0;
131*b4cb3fe0SToomas Soome
132*b4cb3fe0SToomas Soome return (rc);
133*b4cb3fe0SToomas Soome }
134*b4cb3fe0SToomas Soome
135*b4cb3fe0SToomas Soome int
unmount(const char * dev,int flags __unused)136*b4cb3fe0SToomas Soome unmount(const char *dev, int flags __unused)
137*b4cb3fe0SToomas Soome {
138*b4cb3fe0SToomas Soome mnt_info_t *mnt;
139*b4cb3fe0SToomas Soome int rv;
140*b4cb3fe0SToomas Soome
141*b4cb3fe0SToomas Soome rv = 0;
142*b4cb3fe0SToomas Soome STAILQ_FOREACH(mnt, &mnt_list, mnt_link) {
143*b4cb3fe0SToomas Soome if (strcmp(dev, mnt->mnt_dev) == 0) {
144*b4cb3fe0SToomas Soome if (mnt->mnt_refcount > 1) {
145*b4cb3fe0SToomas Soome mnt->mnt_refcount--;
146*b4cb3fe0SToomas Soome break;
147*b4cb3fe0SToomas Soome }
148*b4cb3fe0SToomas Soome
149*b4cb3fe0SToomas Soome if (mnt->mnt_fs->fo_unmount != NULL)
150*b4cb3fe0SToomas Soome rv = mnt->mnt_fs->fo_unmount(dev,
151*b4cb3fe0SToomas Soome mnt->mnt_data);
152*b4cb3fe0SToomas Soome delete_mnt_info(mnt);
153*b4cb3fe0SToomas Soome break;
154*b4cb3fe0SToomas Soome }
155*b4cb3fe0SToomas Soome }
156*b4cb3fe0SToomas Soome
157*b4cb3fe0SToomas Soome if (rv != 0)
158*b4cb3fe0SToomas Soome printf("failed to unmount %s: %d\n", dev, rv);
159*b4cb3fe0SToomas Soome return (0);
160*b4cb3fe0SToomas Soome }
161