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