xref: /minix3/minix/servers/vfs/vmnt.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1*433d6423SLionel Sambuc /* Virtual mount table related routines.
2*433d6423SLionel Sambuc  *
3*433d6423SLionel Sambuc  */
4*433d6423SLionel Sambuc 
5*433d6423SLionel Sambuc #include "fs.h"
6*433d6423SLionel Sambuc #include "vmnt.h"
7*433d6423SLionel Sambuc #include <assert.h>
8*433d6423SLionel Sambuc #include <string.h>
9*433d6423SLionel Sambuc 
10*433d6423SLionel Sambuc static int is_vmnt_locked(struct vmnt *vmp);
11*433d6423SLionel Sambuc static void clear_vmnt(struct vmnt *vmp);
12*433d6423SLionel Sambuc 
13*433d6423SLionel Sambuc /* Is vmp pointer reasonable? */
14*433d6423SLionel Sambuc #define SANEVMP(v) ((((v) >= &vmnt[0] && (v) < &vmnt[NR_MNTS])))
15*433d6423SLionel Sambuc #define BADVMP(v, f, l) printf("%s:%d: bad vmp %p\n", f, l, v)
16*433d6423SLionel Sambuc /* vp check that panics */
17*433d6423SLionel Sambuc #define ASSERTVMP(v) if(!SANEVMP(v)) { \
18*433d6423SLionel Sambuc 	BADVMP(v, __FILE__, __LINE__); panic("bad vmp"); }
19*433d6423SLionel Sambuc 
20*433d6423SLionel Sambuc #if LOCK_DEBUG
21*433d6423SLionel Sambuc /*===========================================================================*
22*433d6423SLionel Sambuc  *				check_vmnt_locks_by_me			     *
23*433d6423SLionel Sambuc  *===========================================================================*/
24*433d6423SLionel Sambuc void check_vmnt_locks_by_me(struct fproc *rfp)
25*433d6423SLionel Sambuc {
26*433d6423SLionel Sambuc /* Check whether this thread still has locks held on vmnts */
27*433d6423SLionel Sambuc   struct vmnt *vmp;
28*433d6423SLionel Sambuc 
29*433d6423SLionel Sambuc   for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; vmp++) {
30*433d6423SLionel Sambuc 	if (tll_locked_by_me(&vmp->m_lock))
31*433d6423SLionel Sambuc 		panic("Thread %d still holds vmnt lock on vmp %p call_nr=%d\n",
32*433d6423SLionel Sambuc 		      mthread_self(), vmp, job_call_nr);
33*433d6423SLionel Sambuc   }
34*433d6423SLionel Sambuc 
35*433d6423SLionel Sambuc   if (rfp->fp_vmnt_rdlocks != 0)
36*433d6423SLionel Sambuc 	panic("Thread %d still holds read locks on a vmnt (%d) call_nr=%d\n",
37*433d6423SLionel Sambuc 	      mthread_self(), rfp->fp_vmnt_rdlocks, job_call_nr);
38*433d6423SLionel Sambuc }
39*433d6423SLionel Sambuc #endif
40*433d6423SLionel Sambuc 
41*433d6423SLionel Sambuc /*===========================================================================*
42*433d6423SLionel Sambuc  *				check_vmnt_locks			     *
43*433d6423SLionel Sambuc  *===========================================================================*/
44*433d6423SLionel Sambuc void check_vmnt_locks()
45*433d6423SLionel Sambuc {
46*433d6423SLionel Sambuc   struct vmnt *vmp;
47*433d6423SLionel Sambuc   int count = 0;
48*433d6423SLionel Sambuc 
49*433d6423SLionel Sambuc   for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; vmp++)
50*433d6423SLionel Sambuc 	if (is_vmnt_locked(vmp)) {
51*433d6423SLionel Sambuc 		count++;
52*433d6423SLionel Sambuc 		printf("vmnt %p is %s, fs_e=%d dev=%llx\n", vmp, (tll_islocked(&vmp->m_lock) ? "locked":"pending locked"), vmp->m_fs_e, vmp->m_dev);
53*433d6423SLionel Sambuc 	}
54*433d6423SLionel Sambuc 
55*433d6423SLionel Sambuc   if (count) panic("%d locked vmnts\n", count);
56*433d6423SLionel Sambuc #if 0
57*433d6423SLionel Sambuc   printf("check_vmnt_locks OK\n");
58*433d6423SLionel Sambuc #endif
59*433d6423SLionel Sambuc }
60*433d6423SLionel Sambuc 
61*433d6423SLionel Sambuc /*===========================================================================*
62*433d6423SLionel Sambuc  *                             mark_vmnt_free				     *
63*433d6423SLionel Sambuc  *===========================================================================*/
64*433d6423SLionel Sambuc void mark_vmnt_free(struct vmnt *vmp)
65*433d6423SLionel Sambuc {
66*433d6423SLionel Sambuc   ASSERTVMP(vmp);
67*433d6423SLionel Sambuc 
68*433d6423SLionel Sambuc   vmp->m_fs_e = NONE;
69*433d6423SLionel Sambuc   vmp->m_dev = NO_DEV;
70*433d6423SLionel Sambuc }
71*433d6423SLionel Sambuc 
72*433d6423SLionel Sambuc /*===========================================================================*
73*433d6423SLionel Sambuc  *                             clear_vmnt				     *
74*433d6423SLionel Sambuc  *===========================================================================*/
75*433d6423SLionel Sambuc static void clear_vmnt(struct vmnt *vmp)
76*433d6423SLionel Sambuc {
77*433d6423SLionel Sambuc /* Reset vmp to initial parameters */
78*433d6423SLionel Sambuc   ASSERTVMP(vmp);
79*433d6423SLionel Sambuc 
80*433d6423SLionel Sambuc   vmp->m_fs_e = NONE;
81*433d6423SLionel Sambuc   vmp->m_dev = NO_DEV;
82*433d6423SLionel Sambuc   vmp->m_flags = 0;
83*433d6423SLionel Sambuc   vmp->m_mounted_on = NULL;
84*433d6423SLionel Sambuc   vmp->m_root_node = NULL;
85*433d6423SLionel Sambuc   vmp->m_label[0] = '\0';
86*433d6423SLionel Sambuc   vmp->m_comm.c_max_reqs = 1;
87*433d6423SLionel Sambuc   vmp->m_comm.c_cur_reqs = 0;
88*433d6423SLionel Sambuc   vmp->m_comm.c_req_queue = NULL;
89*433d6423SLionel Sambuc }
90*433d6423SLionel Sambuc 
91*433d6423SLionel Sambuc /*===========================================================================*
92*433d6423SLionel Sambuc  *                             get_free_vmnt				     *
93*433d6423SLionel Sambuc  *===========================================================================*/
94*433d6423SLionel Sambuc struct vmnt *get_free_vmnt(void)
95*433d6423SLionel Sambuc {
96*433d6423SLionel Sambuc   struct vmnt *vmp;
97*433d6423SLionel Sambuc 
98*433d6423SLionel Sambuc   for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; ++vmp) {
99*433d6423SLionel Sambuc 	if (vmp->m_dev == NO_DEV) {
100*433d6423SLionel Sambuc 		clear_vmnt(vmp);
101*433d6423SLionel Sambuc 		return(vmp);
102*433d6423SLionel Sambuc 	}
103*433d6423SLionel Sambuc   }
104*433d6423SLionel Sambuc 
105*433d6423SLionel Sambuc   return(NULL);
106*433d6423SLionel Sambuc }
107*433d6423SLionel Sambuc 
108*433d6423SLionel Sambuc /*===========================================================================*
109*433d6423SLionel Sambuc  *                             find_vmnt				     *
110*433d6423SLionel Sambuc  *===========================================================================*/
111*433d6423SLionel Sambuc struct vmnt *find_vmnt(endpoint_t fs_e)
112*433d6423SLionel Sambuc {
113*433d6423SLionel Sambuc /* Find the vmnt belonging to an FS with endpoint 'fs_e' iff it's in use */
114*433d6423SLionel Sambuc   struct vmnt *vp;
115*433d6423SLionel Sambuc 
116*433d6423SLionel Sambuc   for (vp = &vmnt[0]; vp < &vmnt[NR_MNTS]; ++vp)
117*433d6423SLionel Sambuc 	if (vp->m_fs_e == fs_e && vp->m_dev != NO_DEV)
118*433d6423SLionel Sambuc 		return(vp);
119*433d6423SLionel Sambuc 
120*433d6423SLionel Sambuc   return(NULL);
121*433d6423SLionel Sambuc }
122*433d6423SLionel Sambuc 
123*433d6423SLionel Sambuc /*===========================================================================*
124*433d6423SLionel Sambuc  *                             init_vmnts				     *
125*433d6423SLionel Sambuc  *===========================================================================*/
126*433d6423SLionel Sambuc void init_vmnts(void)
127*433d6423SLionel Sambuc {
128*433d6423SLionel Sambuc /* Initialize vmnt table */
129*433d6423SLionel Sambuc   struct vmnt *vmp;
130*433d6423SLionel Sambuc 
131*433d6423SLionel Sambuc   for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; vmp++) {
132*433d6423SLionel Sambuc 	clear_vmnt(vmp);
133*433d6423SLionel Sambuc 	tll_init(&vmp->m_lock);
134*433d6423SLionel Sambuc   }
135*433d6423SLionel Sambuc }
136*433d6423SLionel Sambuc 
137*433d6423SLionel Sambuc /*===========================================================================*
138*433d6423SLionel Sambuc  *                             is_vmnt_locked				     *
139*433d6423SLionel Sambuc  *===========================================================================*/
140*433d6423SLionel Sambuc static int is_vmnt_locked(struct vmnt *vmp)
141*433d6423SLionel Sambuc {
142*433d6423SLionel Sambuc   ASSERTVMP(vmp);
143*433d6423SLionel Sambuc   return(tll_islocked(&vmp->m_lock) || tll_haspendinglock(&vmp->m_lock));
144*433d6423SLionel Sambuc }
145*433d6423SLionel Sambuc 
146*433d6423SLionel Sambuc /*===========================================================================*
147*433d6423SLionel Sambuc  *                             lock_vmnt				     *
148*433d6423SLionel Sambuc  *===========================================================================*/
149*433d6423SLionel Sambuc int lock_vmnt(struct vmnt *vmp, tll_access_t locktype)
150*433d6423SLionel Sambuc {
151*433d6423SLionel Sambuc   int r;
152*433d6423SLionel Sambuc   tll_access_t initial_locktype;
153*433d6423SLionel Sambuc 
154*433d6423SLionel Sambuc   ASSERTVMP(vmp);
155*433d6423SLionel Sambuc 
156*433d6423SLionel Sambuc   initial_locktype = (locktype == VMNT_EXCL) ? VMNT_WRITE : locktype;
157*433d6423SLionel Sambuc 
158*433d6423SLionel Sambuc   if (vmp->m_fs_e == who_e) return(EDEADLK);
159*433d6423SLionel Sambuc 
160*433d6423SLionel Sambuc   r = tll_lock(&vmp->m_lock, initial_locktype);
161*433d6423SLionel Sambuc 
162*433d6423SLionel Sambuc   if (r == EBUSY) return(r);
163*433d6423SLionel Sambuc 
164*433d6423SLionel Sambuc   if (initial_locktype != locktype) {
165*433d6423SLionel Sambuc 	upgrade_vmnt_lock(vmp);
166*433d6423SLionel Sambuc   }
167*433d6423SLionel Sambuc 
168*433d6423SLionel Sambuc #if LOCK_DEBUG
169*433d6423SLionel Sambuc   if (locktype == VMNT_READ)
170*433d6423SLionel Sambuc 	fp->fp_vmnt_rdlocks++;
171*433d6423SLionel Sambuc #endif
172*433d6423SLionel Sambuc 
173*433d6423SLionel Sambuc   return(OK);
174*433d6423SLionel Sambuc }
175*433d6423SLionel Sambuc 
176*433d6423SLionel Sambuc /*===========================================================================*
177*433d6423SLionel Sambuc  *                             vmnt_unmap_by_endpoint			     *
178*433d6423SLionel Sambuc  *===========================================================================*/
179*433d6423SLionel Sambuc void vmnt_unmap_by_endpt(endpoint_t proc_e)
180*433d6423SLionel Sambuc {
181*433d6423SLionel Sambuc   struct vmnt *vmp;
182*433d6423SLionel Sambuc 
183*433d6423SLionel Sambuc   if ((vmp = find_vmnt(proc_e)) != NULL) {
184*433d6423SLionel Sambuc 	mark_vmnt_free(vmp);
185*433d6423SLionel Sambuc 	fs_cancel(vmp);
186*433d6423SLionel Sambuc 	invalidate_filp_by_endpt(proc_e);
187*433d6423SLionel Sambuc 	if (vmp->m_mounted_on) {
188*433d6423SLionel Sambuc 		/* Only put mount point when it was actually used as mount
189*433d6423SLionel Sambuc 		 * point. That is, the mount was succesful. */
190*433d6423SLionel Sambuc 		put_vnode(vmp->m_mounted_on);
191*433d6423SLionel Sambuc 	}
192*433d6423SLionel Sambuc   }
193*433d6423SLionel Sambuc }
194*433d6423SLionel Sambuc 
195*433d6423SLionel Sambuc /*===========================================================================*
196*433d6423SLionel Sambuc  *                             unlock_vmnt				     *
197*433d6423SLionel Sambuc  *===========================================================================*/
198*433d6423SLionel Sambuc void unlock_vmnt(struct vmnt *vmp)
199*433d6423SLionel Sambuc {
200*433d6423SLionel Sambuc   ASSERTVMP(vmp);
201*433d6423SLionel Sambuc 
202*433d6423SLionel Sambuc #if LOCK_DEBUG
203*433d6423SLionel Sambuc   /* Decrease read-only lock counter when not locked as VMNT_WRITE or
204*433d6423SLionel Sambuc    * VMNT_EXCL */
205*433d6423SLionel Sambuc   if (!tll_locked_by_me(&vmp->m_lock))
206*433d6423SLionel Sambuc 	fp->fp_vmnt_rdlocks--;
207*433d6423SLionel Sambuc #endif
208*433d6423SLionel Sambuc 
209*433d6423SLionel Sambuc   tll_unlock(&vmp->m_lock);
210*433d6423SLionel Sambuc 
211*433d6423SLionel Sambuc #if LOCK_DEBUG
212*433d6423SLionel Sambuc   assert(!tll_locked_by_me(&vmp->m_lock));
213*433d6423SLionel Sambuc #endif
214*433d6423SLionel Sambuc 
215*433d6423SLionel Sambuc }
216*433d6423SLionel Sambuc 
217*433d6423SLionel Sambuc /*===========================================================================*
218*433d6423SLionel Sambuc  *                             downgrade_vmnt_lock			     *
219*433d6423SLionel Sambuc  *===========================================================================*/
220*433d6423SLionel Sambuc void downgrade_vmnt_lock(struct vmnt *vmp)
221*433d6423SLionel Sambuc {
222*433d6423SLionel Sambuc   ASSERTVMP(vmp);
223*433d6423SLionel Sambuc   tll_downgrade(&vmp->m_lock);
224*433d6423SLionel Sambuc 
225*433d6423SLionel Sambuc #if LOCK_DEBUG
226*433d6423SLionel Sambuc   /* If we're no longer the owner of a lock, we downgraded to VMNT_READ */
227*433d6423SLionel Sambuc   if (!tll_locked_by_me(&vmp->m_lock)) {
228*433d6423SLionel Sambuc 	fp->fp_vmnt_rdlocks++;
229*433d6423SLionel Sambuc   }
230*433d6423SLionel Sambuc #endif
231*433d6423SLionel Sambuc }
232*433d6423SLionel Sambuc 
233*433d6423SLionel Sambuc /*===========================================================================*
234*433d6423SLionel Sambuc  *                             upgrade_vmnt_lock			     *
235*433d6423SLionel Sambuc  *===========================================================================*/
236*433d6423SLionel Sambuc void upgrade_vmnt_lock(struct vmnt *vmp)
237*433d6423SLionel Sambuc {
238*433d6423SLionel Sambuc   ASSERTVMP(vmp);
239*433d6423SLionel Sambuc   tll_upgrade(&vmp->m_lock);
240*433d6423SLionel Sambuc }
241*433d6423SLionel Sambuc 
242*433d6423SLionel Sambuc /*===========================================================================*
243*433d6423SLionel Sambuc  *                             fetch_vmnt_paths				     *
244*433d6423SLionel Sambuc  *===========================================================================*/
245*433d6423SLionel Sambuc void fetch_vmnt_paths(void)
246*433d6423SLionel Sambuc {
247*433d6423SLionel Sambuc   struct vmnt *vmp;
248*433d6423SLionel Sambuc   struct vnode *cur_wd;
249*433d6423SLionel Sambuc   char orig_path[PATH_MAX];
250*433d6423SLionel Sambuc 
251*433d6423SLionel Sambuc   cur_wd = fp->fp_wd;
252*433d6423SLionel Sambuc 
253*433d6423SLionel Sambuc   for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; vmp++) {
254*433d6423SLionel Sambuc 	if (vmp->m_dev == NO_DEV)
255*433d6423SLionel Sambuc 		continue;
256*433d6423SLionel Sambuc 	if (vmp->m_fs_e == PFS_PROC_NR)
257*433d6423SLionel Sambuc 		continue;
258*433d6423SLionel Sambuc 
259*433d6423SLionel Sambuc 	strlcpy(orig_path, vmp->m_mount_path, PATH_MAX);
260*433d6423SLionel Sambuc 
261*433d6423SLionel Sambuc 	/* Find canonical path */
262*433d6423SLionel Sambuc 	if (canonical_path(vmp->m_mount_path, fp) != OK) {
263*433d6423SLionel Sambuc 		/* We failed to find it (moved somewhere else?). Let's try
264*433d6423SLionel Sambuc 		 * again by starting at the node on which we are mounted:
265*433d6423SLionel Sambuc 		 * pretend that node is our working directory and look for the
266*433d6423SLionel Sambuc 		 * canonical path of the relative path to the mount point
267*433d6423SLionel Sambuc 		 * (which should be in our 'working directory').
268*433d6423SLionel Sambuc 		 */
269*433d6423SLionel Sambuc 		char *mp;
270*433d6423SLionel Sambuc 		int len;
271*433d6423SLionel Sambuc 
272*433d6423SLionel Sambuc 		fp->fp_wd = vmp->m_mounted_on;	/* Change our working dir */
273*433d6423SLionel Sambuc 
274*433d6423SLionel Sambuc 		/* Isolate the mount point name of the full path */
275*433d6423SLionel Sambuc 		len = strlen(vmp->m_mount_path);
276*433d6423SLionel Sambuc 		if (vmp->m_mount_path[len - 1] == '/') {
277*433d6423SLionel Sambuc 			vmp->m_mount_path[len - 1] = '\0';
278*433d6423SLionel Sambuc 		}
279*433d6423SLionel Sambuc 		mp = strrchr(vmp->m_mount_path, '/');
280*433d6423SLionel Sambuc 		strlcpy(vmp->m_mount_path, mp+1, NAME_MAX+1);
281*433d6423SLionel Sambuc 
282*433d6423SLionel Sambuc 		if (canonical_path(vmp->m_mount_path, fp) != OK) {
283*433d6423SLionel Sambuc 			/* Our second try failed too. Maybe an FS has crashed
284*433d6423SLionel Sambuc 			 * and we're missing part of the tree. Revert path.
285*433d6423SLionel Sambuc 			 */
286*433d6423SLionel Sambuc 			strlcpy(vmp->m_mount_path, orig_path, PATH_MAX);
287*433d6423SLionel Sambuc 		}
288*433d6423SLionel Sambuc 		fp->fp_wd = cur_wd;		/* Revert working dir */
289*433d6423SLionel Sambuc 	}
290*433d6423SLionel Sambuc   }
291*433d6423SLionel Sambuc }
292