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