* 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:
parent
39cdae74a7
commit
675c19c9cf
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user