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