This should fix the recently introduced locking problems:
- locking policy is now: 1) the volume lock, 2) the inode lock, 3) start the transaction (the journal lock) - you don't need all locks, but you have to follow this order when you need more than one of them. - in many cases, this makes our inode read/write lock useless. I am really looking forward to the OpenBeOS VFS layer where we can remove many of these locks again. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@6464 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -971,6 +971,9 @@ BlockAllocator::CheckNextNode(check_control *control)
|
|||||||
// if we are allowed to fix errors, we should remove the file
|
// if we are allowed to fix errors, we should remove the file
|
||||||
if (control->flags & BFS_REMOVE_WRONG_TYPES
|
if (control->flags & BFS_REMOVE_WRONG_TYPES
|
||||||
&& control->flags & BFS_FIX_BITMAP_ERRORS) {
|
&& control->flags & BFS_FIX_BITMAP_ERRORS) {
|
||||||
|
#ifdef UNSAFE_GET_VNODE
|
||||||
|
RecursiveLocker locker(fVolume->Lock());
|
||||||
|
#endif
|
||||||
// it's safe to start a transaction, because Inode::Remove()
|
// it's safe to start a transaction, because Inode::Remove()
|
||||||
// won't touch the block bitmap (which we hold the lock for)
|
// won't touch the block bitmap (which we hold the lock for)
|
||||||
// if we set the INODE_DONT_FREE_SPACE flag - since we fix
|
// if we set the INODE_DONT_FREE_SPACE flag - since we fix
|
||||||
|
|||||||
@@ -36,6 +36,14 @@ struct log_entry : node<log_entry> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Locking policy in BFS: if you need both, the volume lock and the
|
||||||
|
// journal lock, you must lock the volume first - or else you will
|
||||||
|
// end up in a deadlock.
|
||||||
|
// That is, if you start a transaction, and will need to lock the
|
||||||
|
// volume while the transaction is in progress (for the unsafe
|
||||||
|
// get_vnode() call, for example), you must lock the volume before
|
||||||
|
// starting the transaction.
|
||||||
|
|
||||||
class Journal {
|
class Journal {
|
||||||
public:
|
public:
|
||||||
Journal(Volume *);
|
Journal(Volume *);
|
||||||
|
|||||||
@@ -810,6 +810,10 @@ bfs_write_stat(void *_ns, void *_node, struct stat *stat, long mask)
|
|||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
RETURN_ERROR(status);
|
RETURN_ERROR(status);
|
||||||
|
|
||||||
|
#ifdef UNSAFE_GET_VNODE
|
||||||
|
RecursiveLocker locker(volume->Lock());
|
||||||
|
#endif
|
||||||
|
|
||||||
WriteLocked locked(inode->Lock());
|
WriteLocked locked(inode->Lock());
|
||||||
if (locked.IsLocked() < B_OK)
|
if (locked.IsLocked() < B_OK)
|
||||||
RETURN_ERROR(B_ERROR);
|
RETURN_ERROR(B_ERROR);
|
||||||
@@ -901,6 +905,9 @@ bfs_create(void *_ns, void *_directory, const char *name, int omode, int mode,
|
|||||||
cookie->last_size = 0;
|
cookie->last_size = 0;
|
||||||
cookie->last_notification = system_time();
|
cookie->last_notification = system_time();
|
||||||
|
|
||||||
|
#ifdef UNSAFE_GET_VNODE
|
||||||
|
RecursiveLocker locker(volume->Lock());
|
||||||
|
#endif
|
||||||
Transaction transaction(volume, directory->BlockNumber());
|
Transaction transaction(volume, directory->BlockNumber());
|
||||||
|
|
||||||
status = Inode::Create(&transaction, directory, name, S_FILE | (mode & S_IUMSK),
|
status = Inode::Create(&transaction, directory, name, S_FILE | (mode & S_IUMSK),
|
||||||
@@ -939,6 +946,9 @@ bfs_symlink(void *_ns, void *_directory, const char *name, const char *path)
|
|||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
RETURN_ERROR(status);
|
RETURN_ERROR(status);
|
||||||
|
|
||||||
|
#ifdef UNSAFE_GET_VNODE
|
||||||
|
RecursiveLocker locker(volume->Lock());
|
||||||
|
#endif
|
||||||
Transaction transaction(volume, directory->BlockNumber());
|
Transaction transaction(volume, directory->BlockNumber());
|
||||||
|
|
||||||
Inode *link;
|
Inode *link;
|
||||||
@@ -1001,6 +1011,9 @@ bfs_unlink(void *_ns, void *_directory, const char *name)
|
|||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
|
#ifdef UNSAFE_GET_VNODE
|
||||||
|
RecursiveLocker locker(volume->Lock());
|
||||||
|
#endif
|
||||||
Transaction transaction(volume, directory->BlockNumber());
|
Transaction transaction(volume, directory->BlockNumber());
|
||||||
|
|
||||||
off_t id;
|
off_t id;
|
||||||
@@ -1061,8 +1074,8 @@ bfs_rename(void *_ns, void *_oldDir, const char *oldName, void *_newDir, const c
|
|||||||
if (oldDirectory != newDirectory) {
|
if (oldDirectory != newDirectory) {
|
||||||
vnode_id parent = volume->ToVnode(newDirectory->Parent());
|
vnode_id parent = volume->ToVnode(newDirectory->Parent());
|
||||||
vnode_id root = volume->RootNode()->ID();
|
vnode_id root = volume->RootNode()->ID();
|
||||||
while (true)
|
|
||||||
{
|
while (true) {
|
||||||
if (parent == id)
|
if (parent == id)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
else if (parent == root || parent == oldDirectory->ID())
|
else if (parent == root || parent == oldDirectory->ID())
|
||||||
@@ -1228,8 +1241,8 @@ bfs_open(void *_ns, void *_node, int omode, void **_cookie)
|
|||||||
|
|
||||||
// Should we truncate the file?
|
// Should we truncate the file?
|
||||||
if (omode & O_TRUNC) {
|
if (omode & O_TRUNC) {
|
||||||
Transaction transaction(volume, inode->BlockNumber());
|
|
||||||
WriteLocked locked(inode->Lock());
|
WriteLocked locked(inode->Lock());
|
||||||
|
Transaction transaction(volume, inode->BlockNumber());
|
||||||
|
|
||||||
status_t status = inode->SetFileSize(&transaction, 0);
|
status_t status = inode->SetFileSize(&transaction, 0);
|
||||||
if (status < B_OK) {
|
if (status < B_OK) {
|
||||||
@@ -1342,6 +1355,9 @@ bfs_close(void *_ns, void *_node, void *_cookie)
|
|||||||
Inode *inode = (Inode *)_node;
|
Inode *inode = (Inode *)_node;
|
||||||
|
|
||||||
if (cookie->open_mode & O_RWMASK) {
|
if (cookie->open_mode & O_RWMASK) {
|
||||||
|
#ifdef UNSAFE_GET_VNODE
|
||||||
|
RecursiveLocker locker(volume->Lock());
|
||||||
|
#endif
|
||||||
ReadLocked locked(inode->Lock());
|
ReadLocked locked(inode->Lock());
|
||||||
|
|
||||||
// trim the preallocated blocks and update the size,
|
// trim the preallocated blocks and update the size,
|
||||||
@@ -1487,6 +1503,9 @@ bfs_mkdir(void *_ns, void *_directory, const char *name, int mode)
|
|||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
RETURN_ERROR(status);
|
RETURN_ERROR(status);
|
||||||
|
|
||||||
|
#ifdef UNSAFE_GET_VNODE
|
||||||
|
RecursiveLocker locker(volume->Lock());
|
||||||
|
#endif
|
||||||
Transaction transaction(volume, directory->BlockNumber());
|
Transaction transaction(volume, directory->BlockNumber());
|
||||||
|
|
||||||
// Inode::Create() locks the inode if we pass the "id" parameter, but we
|
// Inode::Create() locks the inode if we pass the "id" parameter, but we
|
||||||
@@ -1515,6 +1534,9 @@ bfs_rmdir(void *_ns, void *_directory, const char *name)
|
|||||||
Volume *volume = (Volume *)_ns;
|
Volume *volume = (Volume *)_ns;
|
||||||
Inode *directory = (Inode *)_directory;
|
Inode *directory = (Inode *)_directory;
|
||||||
|
|
||||||
|
#ifdef UNSAFE_GET_VNODE
|
||||||
|
RecursiveLocker locker(volume->Lock());
|
||||||
|
#endif
|
||||||
Transaction transaction(volume, directory->BlockNumber());
|
Transaction transaction(volume, directory->BlockNumber());
|
||||||
|
|
||||||
off_t id;
|
off_t id;
|
||||||
@@ -1738,6 +1760,9 @@ bfs_remove_attr(void *_ns, void *_node, const char *name)
|
|||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
|
#ifdef UNSAFE_GET_VNODE
|
||||||
|
RecursiveLocker locker(volume->Lock());
|
||||||
|
#endif
|
||||||
Transaction transaction(volume, inode->BlockNumber());
|
Transaction transaction(volume, inode->BlockNumber());
|
||||||
|
|
||||||
status = inode->RemoveAttribute(&transaction, name);
|
status = inode->RemoveAttribute(&transaction, name);
|
||||||
@@ -1827,6 +1852,9 @@ bfs_write_attr(void *_ns, void *_node, const char *name, int type, const void *b
|
|||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
|
#ifdef UNSAFE_GET_VNODE
|
||||||
|
RecursiveLocker locker(volume->Lock());
|
||||||
|
#endif
|
||||||
Transaction transaction(volume, inode->BlockNumber());
|
Transaction transaction(volume, inode->BlockNumber());
|
||||||
|
|
||||||
status = inode->WriteAttribute(&transaction, name, type, pos, (const uint8 *)buffer, _length);
|
status = inode->WriteAttribute(&transaction, name, type, pos, (const uint8 *)buffer, _length);
|
||||||
@@ -1947,6 +1975,9 @@ bfs_create_index(void *_ns, const char *name, int type, int flags)
|
|||||||
if (geteuid() != 0)
|
if (geteuid() != 0)
|
||||||
return B_NOT_ALLOWED;
|
return B_NOT_ALLOWED;
|
||||||
|
|
||||||
|
#ifdef UNSAFE_GET_VNODE
|
||||||
|
RecursiveLocker locker(volume->Lock());
|
||||||
|
#endif
|
||||||
Transaction transaction(volume, volume->Indices());
|
Transaction transaction(volume, volume->Indices());
|
||||||
|
|
||||||
Index index(volume);
|
Index index(volume);
|
||||||
@@ -1979,6 +2010,9 @@ bfs_remove_index(void *_ns, const char *name)
|
|||||||
if ((indices = volume->IndicesNode()) == NULL)
|
if ((indices = volume->IndicesNode()) == NULL)
|
||||||
return B_ENTRY_NOT_FOUND;
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
|
#ifdef UNSAFE_GET_VNODE
|
||||||
|
RecursiveLocker locker(volume->Lock());
|
||||||
|
#endif
|
||||||
Transaction transaction(volume, volume->Indices());
|
Transaction transaction(volume, volume->Indices());
|
||||||
|
|
||||||
status_t status = indices->Remove(&transaction, name);
|
status_t status = indices->Remove(&transaction, name);
|
||||||
|
|||||||
Reference in New Issue
Block a user