xref: /freebsd/stand/libsa/mount.c (revision b4cb3fe0e39a31e60292018dc9fb7510b3de92bf)
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 <sys/cdefs.h>
27*b4cb3fe0SToomas Soome __FBSDID("$FreeBSD$");
28*b4cb3fe0SToomas Soome 
29*b4cb3fe0SToomas Soome #include <stand.h>
30*b4cb3fe0SToomas Soome #include <sys/queue.h>
31*b4cb3fe0SToomas Soome 
32*b4cb3fe0SToomas Soome /*
33*b4cb3fe0SToomas Soome  * While setting "currdev" environment variable, alse "mount" the
34*b4cb3fe0SToomas Soome  * new root file system. This is done to hold disk device open
35*b4cb3fe0SToomas Soome  * in between file accesses, and thus preserve block cache for
36*b4cb3fe0SToomas Soome  * this device. Additionally, this allows us to optimize filesystem
37*b4cb3fe0SToomas Soome  * access by sharing filesystem metadata (like superblock).
38*b4cb3fe0SToomas Soome  */
39*b4cb3fe0SToomas Soome 
40*b4cb3fe0SToomas Soome typedef STAILQ_HEAD(mnt_info_list, mnt_info) mnt_info_list_t;
41*b4cb3fe0SToomas Soome 
42*b4cb3fe0SToomas Soome typedef struct mnt_info {
43*b4cb3fe0SToomas Soome 	STAILQ_ENTRY(mnt_info)	mnt_link;	/* link in mount list */
44*b4cb3fe0SToomas Soome 	const struct fs_ops	*mnt_fs;
45*b4cb3fe0SToomas Soome 	char			*mnt_dev;
46*b4cb3fe0SToomas Soome 	char			*mnt_path;
47*b4cb3fe0SToomas Soome 	unsigned		mnt_refcount;
48*b4cb3fe0SToomas Soome 	void			*mnt_data;	/* Private state */
49*b4cb3fe0SToomas Soome } mnt_info_t;
50*b4cb3fe0SToomas Soome 
51*b4cb3fe0SToomas Soome /* list of mounted filesystems. */
52*b4cb3fe0SToomas Soome static mnt_info_list_t mnt_list = STAILQ_HEAD_INITIALIZER(mnt_list);
53*b4cb3fe0SToomas Soome 
54*b4cb3fe0SToomas Soome static void
55*b4cb3fe0SToomas Soome free_mnt(mnt_info_t *mnt)
56*b4cb3fe0SToomas Soome {
57*b4cb3fe0SToomas Soome 	free(mnt->mnt_dev);
58*b4cb3fe0SToomas Soome 	free(mnt->mnt_path);
59*b4cb3fe0SToomas Soome 	free(mnt);
60*b4cb3fe0SToomas Soome }
61*b4cb3fe0SToomas Soome 
62*b4cb3fe0SToomas Soome static int
63*b4cb3fe0SToomas Soome add_mnt_info(struct fs_ops *fs, const char *dev, const char *path, void *data)
64*b4cb3fe0SToomas Soome {
65*b4cb3fe0SToomas Soome 	mnt_info_t *mnt;
66*b4cb3fe0SToomas Soome 
67*b4cb3fe0SToomas Soome 	mnt = malloc(sizeof(*mnt));
68*b4cb3fe0SToomas Soome 	if (mnt == NULL)
69*b4cb3fe0SToomas Soome 		return (ENOMEM);
70*b4cb3fe0SToomas Soome 
71*b4cb3fe0SToomas Soome 	mnt->mnt_fs = fs;
72*b4cb3fe0SToomas Soome 	mnt->mnt_dev = strdup(dev);
73*b4cb3fe0SToomas Soome 	mnt->mnt_path = strdup(path);
74*b4cb3fe0SToomas Soome 	mnt->mnt_data = data;
75*b4cb3fe0SToomas Soome 	mnt->mnt_refcount = 1;
76*b4cb3fe0SToomas Soome 
77*b4cb3fe0SToomas Soome 	if (mnt->mnt_dev == NULL || mnt->mnt_path == NULL) {
78*b4cb3fe0SToomas Soome 		free_mnt(mnt);
79*b4cb3fe0SToomas Soome 		return (ENOMEM);
80*b4cb3fe0SToomas Soome 	}
81*b4cb3fe0SToomas Soome 	STAILQ_INSERT_TAIL(&mnt_list, mnt, mnt_link);
82*b4cb3fe0SToomas Soome 	return (0);
83*b4cb3fe0SToomas Soome }
84*b4cb3fe0SToomas Soome 
85*b4cb3fe0SToomas Soome static void
86*b4cb3fe0SToomas Soome delete_mnt_info(mnt_info_t *mnt)
87*b4cb3fe0SToomas Soome {
88*b4cb3fe0SToomas Soome 	STAILQ_REMOVE(&mnt_list, mnt, mnt_info, mnt_link);
89*b4cb3fe0SToomas Soome 	free_mnt(mnt);
90*b4cb3fe0SToomas Soome }
91*b4cb3fe0SToomas Soome 
92*b4cb3fe0SToomas Soome int
93*b4cb3fe0SToomas Soome mount(const char *dev, const char *path, int flags __unused, void *data)
94*b4cb3fe0SToomas Soome {
95*b4cb3fe0SToomas Soome 	mnt_info_t *mnt;
96*b4cb3fe0SToomas Soome 	int rc = -1;
97*b4cb3fe0SToomas Soome 
98*b4cb3fe0SToomas Soome 	/* Is it already mounted? */
99*b4cb3fe0SToomas Soome 	STAILQ_FOREACH(mnt, &mnt_list, mnt_link) {
100*b4cb3fe0SToomas Soome 		if (strcmp(dev, mnt->mnt_dev) == 0 &&
101*b4cb3fe0SToomas Soome 		    strcmp(path, mnt->mnt_path) == 0) {
102*b4cb3fe0SToomas Soome 			mnt->mnt_refcount++;
103*b4cb3fe0SToomas Soome 			return (0);
104*b4cb3fe0SToomas Soome 		}
105*b4cb3fe0SToomas Soome 	}
106*b4cb3fe0SToomas Soome 
107*b4cb3fe0SToomas Soome 	for (int i = 0; file_system[i] != NULL; i++) {
108*b4cb3fe0SToomas Soome 		struct fs_ops *fs;
109*b4cb3fe0SToomas Soome 
110*b4cb3fe0SToomas Soome 		fs = file_system[i];
111*b4cb3fe0SToomas Soome 		if (fs->fo_mount == NULL)
112*b4cb3fe0SToomas Soome 			continue;
113*b4cb3fe0SToomas Soome 
114*b4cb3fe0SToomas Soome 		if (fs->fo_mount(dev, path, &data) != 0)
115*b4cb3fe0SToomas Soome 			continue;
116*b4cb3fe0SToomas Soome 
117*b4cb3fe0SToomas Soome 		rc = add_mnt_info(fs, dev, path, data);
118*b4cb3fe0SToomas Soome 		if (rc != 0 && mnt->mnt_fs->fo_unmount != NULL) {
119*b4cb3fe0SToomas Soome 			printf("failed to mount %s: %s\n", dev,
120*b4cb3fe0SToomas Soome 			    strerror(rc));
121*b4cb3fe0SToomas Soome 			(void)mnt->mnt_fs->fo_unmount(dev, data);
122*b4cb3fe0SToomas Soome 		}
123*b4cb3fe0SToomas Soome 		break;
124*b4cb3fe0SToomas Soome 	}
125*b4cb3fe0SToomas Soome 
126*b4cb3fe0SToomas Soome 
127*b4cb3fe0SToomas Soome 	/*
128*b4cb3fe0SToomas Soome 	 * if rc is -1, it means we have no file system with fo_mount()
129*b4cb3fe0SToomas Soome 	 * callback, or all fo_mount() calls failed. As long as we
130*b4cb3fe0SToomas Soome 	 * have missing fo_mount() callbacks, we allow mount() to return 0.
131*b4cb3fe0SToomas Soome 	 */
132*b4cb3fe0SToomas Soome 	if (rc == -1)
133*b4cb3fe0SToomas Soome 		rc = 0;
134*b4cb3fe0SToomas Soome 
135*b4cb3fe0SToomas Soome 	return (rc);
136*b4cb3fe0SToomas Soome }
137*b4cb3fe0SToomas Soome 
138*b4cb3fe0SToomas Soome int
139*b4cb3fe0SToomas Soome unmount(const char *dev, int flags __unused)
140*b4cb3fe0SToomas Soome {
141*b4cb3fe0SToomas Soome 	mnt_info_t *mnt;
142*b4cb3fe0SToomas Soome 	int rv;
143*b4cb3fe0SToomas Soome 
144*b4cb3fe0SToomas Soome 	rv = 0;
145*b4cb3fe0SToomas Soome 	STAILQ_FOREACH(mnt, &mnt_list, mnt_link) {
146*b4cb3fe0SToomas Soome 		if (strcmp(dev, mnt->mnt_dev) == 0) {
147*b4cb3fe0SToomas Soome 			if (mnt->mnt_refcount > 1) {
148*b4cb3fe0SToomas Soome 				mnt->mnt_refcount--;
149*b4cb3fe0SToomas Soome 				break;
150*b4cb3fe0SToomas Soome 			}
151*b4cb3fe0SToomas Soome 
152*b4cb3fe0SToomas Soome 			if (mnt->mnt_fs->fo_unmount != NULL)
153*b4cb3fe0SToomas Soome 				rv = mnt->mnt_fs->fo_unmount(dev,
154*b4cb3fe0SToomas Soome 				    mnt->mnt_data);
155*b4cb3fe0SToomas Soome 			delete_mnt_info(mnt);
156*b4cb3fe0SToomas Soome 			break;
157*b4cb3fe0SToomas Soome 		}
158*b4cb3fe0SToomas Soome 	}
159*b4cb3fe0SToomas Soome 
160*b4cb3fe0SToomas Soome 	if (rv != 0)
161*b4cb3fe0SToomas Soome 		printf("failed to unmount %s: %d\n", dev, rv);
162*b4cb3fe0SToomas Soome 	return (0);
163*b4cb3fe0SToomas Soome }
164