* fs_sync() and free_vnode() now use the file system's fsync() hook to write back

changes made to a file instead of directly using vm_cache_write_modified() -
  besides making the file system more independent from the file cache, this also
  works around a possible dead lock (that is to be fixed in a later commit).
* fs_sync() no longer uses vnodes from the mount's vnode list directly to write
  back the changes made to them, but gets them via ID instead - this makes sure
  the vnode is in a valid state and fixes a race condition with free_vnode().


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17059 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2006-04-10 21:22:24 +00:00
parent 39cdae74a7
commit 675c19c9cf

View File

@ -653,8 +653,8 @@ free_vnode(struct vnode *vnode, bool reenter)
// if the vnode won't be deleted, in which case the changes
// will be discarded
if (vnode->cache && !vnode->remove)
vm_cache_write_modified(vnode->cache);
if (!vnode->remove && FS_CALL(vnode, fsync) != NULL)
FS_CALL(vnode, fsync)(vnode->mount->cookie, vnode->private_node);
if (!vnode->unpublished) {
if (vnode->remove)
@ -1236,8 +1236,9 @@ normalize_flock(struct file_descriptor *descriptor, struct flock *flock)
}
/** Disconnects all file descriptors that go the \a vnodeToDisconnect, or
* if this is NULL, all vnodes of the specified \a mount object.
/** Disconnects all file descriptors that are associated with the
* \a vnodeToDisconnect, or if this is NULL, all vnodes of the specified
* \a mount object.
*
* Note, after you've called this function, there might still be ongoing
* accesses - they won't be interrupted if they already happened before.
@ -5491,16 +5492,41 @@ fs_sync(dev_t device)
mutex_unlock(&sMountMutex);
// synchronize all vnodes
recursive_lock_lock(&mount->rlock);
struct vnode *vnode = NULL;
while ((vnode = (struct vnode *)list_get_next_item(&mount->vnodes, vnode)) != NULL) {
if (vnode->cache)
vm_cache_write_modified(vnode->cache);
struct vnode *previousVnode = NULL;
while (true) {
// synchronize access to vnode list
recursive_lock_lock(&mount->rlock);
struct vnode *vnode = (struct vnode *)list_get_next_item(&mount->vnodes,
previousVnode);
vnode_id id = -1;
if (vnode != NULL)
id = vnode->id;
recursive_lock_unlock(&mount->rlock);
if (vnode == NULL)
break;
// acquire a reference to the vnode
if (get_vnode(mount->id, id, &vnode, true) == B_OK) {
if (previousVnode != NULL)
put_vnode(previousVnode);
if (FS_CALL(vnode, fsync) != NULL)
FS_CALL(vnode, fsync)(vnode->mount->cookie, vnode->private_node);
// 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;
}
}
recursive_lock_unlock(&mount->rlock);
if (previousVnode != NULL)
put_vnode(previousVnode);
put_mount(mount);
return status;
}