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