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