Changeset 25407
- Timestamp:
- 05/09/08 19:53:13 (4 days ago)
- Files:
-
- haiku/trunk/src/system/kernel/fs/vfs.cpp (modified) (8 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
haiku/trunk/src/system/kernel/fs/vfs.cpp
r25378 r25407 28 28 #include <StorageDefs.h> 29 29 30 #include <AutoDeleter.h> 30 31 #include <block_cache.h> 31 32 #include <boot/kernel_args.h> … … 152 153 sem_id wait_sem; 153 154 LockList locks; 155 156 advisory_locking() 157 : 158 lock(-1), 159 wait_sem(-1) 160 { 161 } 162 163 ~advisory_locking() 164 { 165 if (lock >= 0) 166 delete_sem(lock); 167 if (wait_sem >= 0) 168 delete_sem(wait_sem); 169 } 154 170 }; 155 171 … … 190 206 /*! \brief Guards sVnodeTable. 191 207 192 The holder is allowed to read/write accesssVnodeTable and to208 The holder is allowed read/write access to sVnodeTable and to 193 209 any unbusy vnode in that table, save to the immutable fields (device, id, 194 210 private_node, mount) to which … … 1123 1139 return B_FILE_ERROR; 1124 1140 1125 struct advisory_locking *locking = new(std::nothrow) advisory_locking; 1126 if (locking == NULL) 1127 return B_NO_MEMORY; 1128 1129 status_t status; 1130 1131 locking->wait_sem = create_sem(0, "advisory lock"); 1132 if (locking->wait_sem < B_OK) { 1133 status = locking->wait_sem; 1134 goto err1; 1135 } 1136 1137 locking->lock = create_sem(0, "advisory locking"); 1138 if (locking->lock < B_OK) { 1139 status = locking->lock; 1140 goto err2; 1141 } 1142 1143 // We need to set the locking structure atomically - someone 1144 // else might set one at the same time 1145 do { 1146 if (atomic_pointer_test_and_set(&vnode->advisory_locking, locking, 1147 (advisory_locking*)NULL) == NULL) 1141 ObjectDeleter<advisory_locking> lockingDeleter; 1142 struct advisory_locking *locking = NULL; 1143 1144 while (get_advisory_locking(vnode) == NULL) { 1145 // no locking object set on the vnode yet, create one 1146 if (locking == NULL) { 1147 locking = new(std::nothrow) advisory_locking; 1148 if (locking == NULL) 1149 return B_NO_MEMORY; 1150 lockingDeleter.SetTo(locking); 1151 1152 locking->wait_sem = create_sem(0, "advisory lock"); 1153 if (locking->wait_sem < B_OK) 1154 return locking->wait_sem; 1155 1156 locking->lock = create_sem(0, "advisory locking"); 1157 if (locking->lock < B_OK) 1158 return locking->lock; 1159 } 1160 1161 // set our newly created locking object 1162 MutexLocker _(sVnodeMutex); 1163 if (vnode->advisory_locking == NULL) { 1164 vnode->advisory_locking = locking; 1165 lockingDeleter.Detach(); 1148 1166 return B_OK; 1149 } while (get_advisory_locking(vnode) == NULL); 1150 1151 status = B_OK; 1152 // we delete the one we've just created, but nevertheless, the vnode 1153 // does have a locking structure now 1154 1155 delete_sem(locking->lock); 1156 err2: 1157 delete_sem(locking->wait_sem); 1158 err1: 1159 delete locking; 1160 return status; 1167 } 1168 } 1169 1170 // The vnode already had a locking object. That's just as well. 1171 1172 return B_OK; 1161 1173 } 1162 1174 … … 1288 1300 locking = get_advisory_locking(vnode); 1289 1301 if (locking != NULL) { 1302 MutexLocker locker(sVnodeMutex); 1303 1290 1304 // the locking could have been changed in the mean time 1291 1305 if (locking->locks.IsEmpty()) { 1292 1306 vnode->advisory_locking = NULL; 1307 locker.Unlock(); 1293 1308 1294 1309 // we've detached the locking from the vnode, so we can … … 1299 1314 } else { 1300 1315 // the locking is in use again 1316 locker.Unlock(); 1301 1317 release_sem_etc(locking->lock, 1, B_DO_NOT_RESCHEDULE); 1302 1318 } … … 1329 1345 // TODO: do deadlock detection! 1330 1346 1331 restart: 1332 // if this vnode has an advisory_locking structure attached, 1333 // lock that one and search for any colliding file lock 1334 struct advisory_locking *locking = get_advisory_locking(vnode); 1335 team_id team = team_get_current_team_id(); 1336 sem_id waitForLock = -1; 1337 1338 if (locking != NULL) { 1347 struct advisory_locking *locking; 1348 sem_id waitForLock; 1349 1350 while (true) { 1351 // if this vnode has an advisory_locking structure attached, 1352 // lock that one and search for any colliding file lock 1353 status = create_advisory_locking(vnode); 1354 if (status != B_OK) 1355 return status; 1356 1357 locking = vnode->advisory_locking; 1358 team_id team = team_get_current_team_id(); 1359 waitForLock = -1; 1360 1339 1361 // test for collisions 1340 1362 LockList::Iterator iterator = locking->locks.GetIterator(); 1341 1363 while (iterator.HasNext()) { 1342 1364 struct advisory_lock *lock = iterator.Next(); 1343 1365 1344 1366 // TODO: locks from the same team might be joinable! 1345 1367 if (lock->team != team && advisory_lock_intersects(lock, flock)) { … … 1353 1375 } 1354 1376 1355 if (waitForLock < B_OK || !wait) 1377 if (waitForLock < 0) 1378 break; 1379 1380 // We need to wait. Do that or fail now, if we've been asked not to. 1381 1382 if (!wait) { 1356 1383 put_advisory_locking(locking); 1357 } 1358 1359 // wait for the lock if we have to, or else return immediately 1360 1361 if (waitForLock >= B_OK) { 1362 if (!wait) 1363 status = session != -1 ? B_WOULD_BLOCK : B_PERMISSION_DENIED; 1364 else { 1365 status = switch_sem_etc(locking->lock, waitForLock, 1, 1366 B_CAN_INTERRUPT, 0); 1367 if (status == B_OK) { 1368 // see if we're still colliding 1369 goto restart; 1370 } 1371 } 1372 } 1373 1374 if (status < B_OK) 1375 return status; 1384 return session != -1 ? B_WOULD_BLOCK : B_PERMISSION_DENIED; 1385 } 1386 1387 status = switch_sem_etc(locking->lock, waitForLock, 1, 1388 B_CAN_INTERRUPT, 0); 1389 if (status != B_OK && status != B_BAD_SEM_ID) 1390 return status; 1391 1392 // We have been notified, but we need to re-lock the locking object. So 1393 // go another round... 1394 } 1376 1395 1377 1396 // install new lock 1378 1379 locking = get_advisory_locking(vnode);1380 if (locking == NULL) {1381 // we need to create a new locking object1382 status = create_advisory_locking(vnode);1383 if (status < B_OK)1384 return status;1385 1386 locking = vnode->advisory_locking;1387 // we own the locking object, so it can't go away1388 }1389 1397 1390 1398 struct advisory_lock *lock = (struct advisory_lock *)malloc(
