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