1 /*
2 * Copyright (c) 1997-2006 Erez Zadok
3 * Copyright (c) 1990 Jan-Simon Pendry
4 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
5 * Copyright (c) 1990 The Regents of the University of California.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Jan-Simon Pendry at Imperial College, London.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgment:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 *
39 *
40 * File: am-utils/amd/mntfs.c
41 *
42 */
43
44 #ifdef HAVE_CONFIG_H
45 # include <config.h>
46 #endif /* HAVE_CONFIG_H */
47 #include <am_defs.h>
48 #include <amd.h>
49
50 qelem mfhead = {&mfhead, &mfhead};
51
52 int mntfs_allocated;
53
54
55 mntfs *
dup_mntfs(mntfs * mf)56 dup_mntfs(mntfs *mf)
57 {
58 if (mf->mf_refc == 0) {
59 if (mf->mf_cid)
60 untimeout(mf->mf_cid);
61 mf->mf_cid = 0;
62 }
63 mf->mf_refc++;
64
65 return mf;
66 }
67
68
69 static void
init_mntfs(mntfs * mf,am_ops * ops,am_opts * mo,char * mp,char * info,char * auto_opts,char * mopts,char * remopts)70 init_mntfs(mntfs *mf, am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, char *mopts, char *remopts)
71 {
72 mf->mf_ops = ops;
73 mf->mf_fsflags = ops->nfs_fs_flags;
74 mf->mf_fo = mo;
75 mf->mf_mount = strdup(mp);
76 mf->mf_info = strdup(info);
77 mf->mf_auto = strdup(auto_opts);
78 mf->mf_mopts = strdup(mopts);
79 mf->mf_remopts = strdup(remopts);
80 mf->mf_loopdev = NULL;
81 mf->mf_refc = 1;
82 mf->mf_flags = 0;
83 mf->mf_error = -1;
84 mf->mf_cid = 0;
85 mf->mf_private = 0;
86 mf->mf_prfree = 0;
87
88 if (ops->ffserver)
89 mf->mf_server = (*ops->ffserver) (mf);
90 else
91 mf->mf_server = 0;
92 }
93
94
95 static mntfs *
alloc_mntfs(am_ops * ops,am_opts * mo,char * mp,char * info,char * auto_opts,char * mopts,char * remopts)96 alloc_mntfs(am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, char *mopts, char *remopts)
97 {
98 mntfs *mf = ALLOC(struct mntfs);
99
100 init_mntfs(mf, ops, mo, mp, info, auto_opts, mopts, remopts);
101 ins_que(&mf->mf_q, &mfhead);
102 mntfs_allocated++;
103
104 return mf;
105 }
106
107
108 /* find a matching mntfs in our list */
109 mntfs *
locate_mntfs(am_ops * ops,am_opts * mo,char * mp,char * info,char * auto_opts,char * mopts,char * remopts)110 locate_mntfs(am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, char *mopts, char *remopts)
111 {
112 mntfs *mf;
113
114 dlog("Locating mntfs reference to (%s,%s)", mp, info);
115
116 ITER(mf, mntfs, &mfhead) {
117 /*
118 * For backwards compatibility purposes, we treat already-mounted
119 * filesystems differently and only require a match of their mount point,
120 * not of their server info. After all, there is little we can do if
121 * the user asks us to mount two different things onto the same mount: one
122 * will always cover the other one.
123 */
124 if (STREQ(mf->mf_mount, mp) &&
125 ((mf->mf_flags & MFF_MOUNTED && !(mf->mf_fsflags & FS_DIRECT))
126 || (STREQ(mf->mf_info, info) && mf->mf_ops == ops))) {
127 /*
128 * Handle cases where error ops are involved
129 */
130 if (ops == &amfs_error_ops) {
131 /*
132 * If the existing ops are not amfs_error_ops
133 * then continue...
134 */
135 if (mf->mf_ops != &amfs_error_ops)
136 continue;
137 return dup_mntfs(mf);
138 }
139
140 dlog("mf->mf_flags = %#x", mf->mf_flags);
141 mf->mf_fo = mo;
142 if ((mf->mf_flags & MFF_RESTART) && amd_state < Finishing) {
143 /*
144 * Restart a previously mounted filesystem.
145 */
146 dlog("Restarting filesystem %s", mf->mf_mount);
147
148 /*
149 * If we are restarting an amd internal filesystem,
150 * we need to initialize it a bit.
151 *
152 * We know it's internal because it is marked as toplvl.
153 */
154 if (mf->mf_ops == &amfs_toplvl_ops) {
155 mf->mf_ops = ops;
156 mf->mf_info = strealloc(mf->mf_info, info);
157 ops->mounted(mf); /* XXX: not right, but will do for now */
158 }
159
160 return mf;
161 }
162
163 if (!(mf->mf_flags & (MFF_MOUNTED | MFF_MOUNTING | MFF_UNMOUNTING))) {
164 fserver *fs;
165 mf->mf_flags &= ~MFF_ERROR;
166 mf->mf_error = -1;
167 mf->mf_auto = strealloc(mf->mf_auto, auto_opts);
168 mf->mf_mopts = strealloc(mf->mf_mopts, mopts);
169 mf->mf_remopts = strealloc(mf->mf_remopts, remopts);
170 mf->mf_info = strealloc(mf->mf_info, info);
171
172 if (mf->mf_private && mf->mf_prfree) {
173 mf->mf_prfree(mf->mf_private);
174 mf->mf_private = 0;
175 }
176
177 fs = ops->ffserver ? (*ops->ffserver) (mf) : (fserver *) NULL;
178 if (mf->mf_server)
179 free_srvr(mf->mf_server);
180 mf->mf_server = fs;
181 }
182 return dup_mntfs(mf);
183 } /* end of "if (STREQ(mf-> ..." */
184 } /* end of ITER */
185
186 return 0;
187 }
188
189
190 /* find a matching mntfs in our list, create a new one if none is found */
191 mntfs *
find_mntfs(am_ops * ops,am_opts * mo,char * mp,char * info,char * auto_opts,char * mopts,char * remopts)192 find_mntfs(am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, char *mopts, char *remopts)
193 {
194 mntfs *mf = locate_mntfs(ops, mo, mp, info, auto_opts, mopts, remopts);
195 if (mf)
196 return mf;
197
198 return alloc_mntfs(ops, mo, mp, info, auto_opts, mopts, remopts);
199 }
200
201
202 mntfs *
new_mntfs(void)203 new_mntfs(void)
204 {
205 return alloc_mntfs(&amfs_error_ops, (am_opts *) 0, "//nil//", ".", "", "", "");
206 }
207
208
209 static void
uninit_mntfs(mntfs * mf)210 uninit_mntfs(mntfs *mf)
211 {
212 if (mf->mf_auto)
213 XFREE(mf->mf_auto);
214 if (mf->mf_mopts)
215 XFREE(mf->mf_mopts);
216 if (mf->mf_remopts)
217 XFREE(mf->mf_remopts);
218 if (mf->mf_info)
219 XFREE(mf->mf_info);
220 if (mf->mf_private && mf->mf_prfree)
221 (*mf->mf_prfree) (mf->mf_private);
222
223 if (mf->mf_mount)
224 XFREE(mf->mf_mount);
225
226 /*
227 * Clean up the file server
228 */
229 if (mf->mf_server)
230 free_srvr(mf->mf_server);
231
232 /*
233 * Don't do a callback on this mount
234 */
235 if (mf->mf_cid) {
236 untimeout(mf->mf_cid);
237 mf->mf_cid = 0;
238 }
239 }
240
241
242 static void
discard_mntfs(voidp v)243 discard_mntfs(voidp v)
244 {
245 mntfs *mf = v;
246
247 rem_que(&mf->mf_q);
248
249 /*
250 * Free memory
251 */
252 uninit_mntfs(mf);
253 XFREE(mf);
254
255 --mntfs_allocated;
256 }
257
258
259 void
flush_mntfs(void)260 flush_mntfs(void)
261 {
262 mntfs *mf;
263
264 mf = AM_FIRST(mntfs, &mfhead);
265 while (mf != HEAD(mntfs, &mfhead)) {
266 mntfs *mf2 = mf;
267 mf = NEXT(mntfs, mf);
268 if (mf2->mf_refc == 0 && mf2->mf_cid)
269 discard_mntfs(mf2);
270 }
271 }
272
273
274 void
free_mntfs(opaque_t arg)275 free_mntfs(opaque_t arg)
276 {
277 mntfs *mf = (mntfs *) arg;
278
279 dlog("free_mntfs <%s> type %s mf_refc %d flags %x",
280 mf->mf_mount, mf->mf_ops->fs_type, mf->mf_refc, mf->mf_flags);
281
282 /*
283 * We shouldn't ever be called to free something that has
284 * a non-positive refcount. Something is badly wrong if
285 * we have been! Ignore the request for now...
286 */
287 if (mf->mf_refc <= 0) {
288 plog(XLOG_ERROR, "IGNORING free_mntfs for <%s>: refc %d, flags %x (bug?)",
289 mf->mf_mount, mf->mf_refc, mf->mf_flags);
290 return;
291 }
292
293 /* don't discard last reference of a restarted/kept mntfs */
294 if (mf->mf_refc == 1 && mf->mf_flags & MFF_RSTKEEP) {
295 plog(XLOG_ERROR, "IGNORING free_mntfs for <%s>: refc %d, flags %x (restarted)",
296 mf->mf_mount, mf->mf_refc, mf->mf_flags);
297 return;
298 }
299
300 if (--mf->mf_refc == 0) {
301 if (mf->mf_flags & MFF_MOUNTED) {
302 int quoted;
303 mf->mf_flags &= ~MFF_MOUNTED;
304
305 /*
306 * Record for posterity
307 */
308 quoted = strchr(mf->mf_info, ' ') != 0; /* cheap */
309 plog(XLOG_INFO, "%s%s%s %sed fstype %s from %s",
310 quoted ? "\"" : "",
311 mf->mf_info,
312 quoted ? "\"" : "",
313 mf->mf_error ? "discard" : "unmount",
314 mf->mf_ops->fs_type, mf->mf_mount);
315 }
316
317 if (mf->mf_fsflags & FS_DISCARD) {
318 dlog("Immediately discarding mntfs for %s", mf->mf_mount);
319 discard_mntfs(mf);
320
321 } else {
322
323 if (mf->mf_flags & MFF_RESTART) {
324 dlog("Discarding remount hook for %s", mf->mf_mount);
325 } else {
326 dlog("Discarding last mntfs reference to %s fstype %s",
327 mf->mf_mount, mf->mf_ops->fs_type);
328 }
329 if (mf->mf_flags & (MFF_MOUNTED | MFF_MOUNTING | MFF_UNMOUNTING))
330 dlog("mntfs reference for %s still active", mf->mf_mount);
331 mf->mf_cid = timeout(ALLOWED_MOUNT_TIME, discard_mntfs, (voidp) mf);
332 }
333 }
334 }
335
336
337 mntfs *
realloc_mntfs(mntfs * mf,am_ops * ops,am_opts * mo,char * mp,char * info,char * auto_opts,char * mopts,char * remopts)338 realloc_mntfs(mntfs *mf, am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, char *mopts, char *remopts)
339 {
340 mntfs *mf2;
341
342 if (mf->mf_refc == 1 &&
343 mf->mf_flags & MFF_RESTART &&
344 STREQ(mf->mf_mount, mp)) {
345 /*
346 * If we are inheriting then just return
347 * the same node...
348 */
349 return mf;
350 }
351
352 /*
353 * Re-use the existing mntfs if it is mounted.
354 * This traps a race in nfsx.
355 */
356 if (mf->mf_ops != &amfs_error_ops &&
357 (mf->mf_flags & MFF_MOUNTED) &&
358 !FSRV_ISDOWN(mf->mf_server)) {
359 mf->mf_fo = mo;
360 return mf;
361 }
362
363 mf2 = find_mntfs(ops, mo, mp, info, auto_opts, mopts, remopts);
364 free_mntfs(mf);
365 return mf2;
366 }
367