xref: /freebsd/stand/libsa/mount.c (revision 3e15b01d6914c927e37d1699645783acf286655c)
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