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 *===========================================================================*/
check_vmnt_locks_by_me(struct fproc * rfp)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(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 *===========================================================================*/
mark_vmnt_free(struct vmnt * vmp)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 *===========================================================================*/
clear_vmnt(struct vmnt * vmp)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 *===========================================================================*/
get_free_vmnt(void)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 *===========================================================================*/
find_vmnt(endpoint_t fs_e)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 *===========================================================================*/
init_vmnts(void)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 *===========================================================================*/
is_vmnt_locked(struct vmnt * vmp)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 *===========================================================================*/
lock_vmnt(struct vmnt * vmp,tll_access_t locktype)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 *===========================================================================*/
vmnt_unmap_by_endpt(endpoint_t proc_e)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 *===========================================================================*/
unlock_vmnt(struct vmnt * vmp)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 *===========================================================================*/
downgrade_vmnt_lock(struct vmnt * vmp)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 *===========================================================================*/
upgrade_vmnt_lock(struct vmnt * vmp)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 *===========================================================================*/
fetch_vmnt_paths(void)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