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