* fs_sync() now holds the sVnodeMutex while iterating over the mount list.

* This has the advantage that we no longer need to call get_vnode(), and
  instead can use lookup_vnode().
* This means at least most of the "corrupted BFS inode" messages should be
  gone; they were produced when fs_sync() tried to get already deleted vnodes.
  This was actually harmless, but doesn't really help in trusting your system :-)
* Also, it no longer tries to write back removed vnodes.
* And finally, it now uses a marker vnode when iterating over the list, so
  that it doesn't need to break out of the loop anymore, and can always sync
  all willing vnodes.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@28212 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2008-10-17 09:55:34 +00:00
parent c4b429ca1c
commit 552c8edcd1

View File

@ -7142,50 +7142,62 @@ fs_sync(dev_t device)
if (status < B_OK)
return status;
struct vnode marker;
marker.remove = true;
// First, synchronize all file caches
struct vnode *previousVnode = NULL;
while (true) {
MutexLocker locker(sVnodeMutex);
// synchronize access to vnode list
recursive_lock_lock(&mount->rlock);
struct vnode *vnode = previousVnode;
do {
struct vnode *vnode;
if (!marker.remove) {
vnode = (struct vnode *)list_get_next_item(&mount->vnodes, &marker);
list_remove_item(&mount->vnodes, &marker);
marker.remove = true;
} else
vnode = (struct vnode *)list_get_first_item(&mount->vnodes);
while (vnode != NULL && (vnode->cache == NULL
|| vnode->remove || vnode->busy)) {
// TODO: we could track writes (and writable mapped vnodes)
// and have a simple flag that we could test for here
vnode = (struct vnode *)list_get_next_item(&mount->vnodes, vnode);
} while (vnode != NULL && vnode->cache == NULL);
}
ino_t id = -1;
if (vnode != NULL)
id = vnode->id;
if (vnode != NULL) {
// insert marker vnode again
list_insert_item_before(&mount->vnodes,
list_get_next_item(&mount->vnodes, vnode), &marker);
marker.remove = false;
}
recursive_lock_unlock(&mount->rlock);
if (vnode == NULL)
break;
// acquire a reference to the vnode
vnode = lookup_vnode(mount->id, vnode->id);
if (vnode == NULL || vnode->busy)
continue;
if (get_vnode(mount->id, id, &vnode, true, false) == B_OK) {
if (previousVnode != NULL)
put_vnode(previousVnode);
if (vnode->ref_count == 0) {
// this vnode has been unused before
list_remove_item(&sUnusedVnodeList, vnode);
sUnusedVnodes--;
}
inc_vnode_ref_count(vnode);
if (vnode->cache != NULL)
locker.Unlock();
if (vnode->cache != NULL && !vnode->remove)
vnode->cache->WriteModified();
// the next vnode might change until we lock the vnode list again,
// but this vnode won't go away since we keep a reference to it.
previousVnode = vnode;
} else {
dprintf("syncing of mount %ld stopped due to vnode %Ld.\n",
mount->id, id);
break;
put_vnode(vnode);
}
}
if (previousVnode != NULL)
put_vnode(previousVnode);
// And then, let the file systems do their synchronizing work