* Removed WriteFSInfo(). It's used only for changing the volume name and we

can't implement that with the FUSE interface.
* We now mark nodes dirty after a write operation.
* Implemented Sync() by fsync()ing all dirty nodes.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@29746 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2009-03-27 15:56:52 +00:00
parent fb886ec014
commit c8722a1e82
4 changed files with 105 additions and 26 deletions
@@ -82,12 +82,14 @@ struct FUSENode : RWLockable, HashTableLink<FUSENode> {
FUSEEntryList entries;
int type;
int32 refCount;
bool dirty;
FUSENode(ino_t id, int type)
:
id(id),
type(type),
refCount(1)
refCount(1),
dirty(false)
{
}
@@ -338,9 +338,9 @@ FUSEFileSystem::_InitCapabilities()
fVolumeCapabilities.Set(FS_VOLUME_CAPABILITY_UNMOUNT, true);
fVolumeCapabilities.Set(FS_VOLUME_CAPABILITY_READ_FS_INFO, fFS->ops.statfs);
// fVolumeCapabilities.Set(FS_VOLUME_CAPABILITY_WRITE_FS_INFO,
// fFS->ops.wfsstat);
// fVolumeCapabilities.Set(FS_VOLUME_CAPABILITY_SYNC, fFS->ops.sync);
// missing: FS_VOLUME_CAPABILITY_WRITE_FS_INFO
fVolumeCapabilities.Set(FS_VOLUME_CAPABILITY_SYNC, fFS->ops.fsync);
// emulated via fsync()
fVolumeCapabilities.Set(FS_VOLUME_CAPABILITY_GET_VNODE, true);
// emulated
@@ -722,9 +722,47 @@ printf("FUSEVolume::Unmount()\n");
status_t
FUSEVolume::Sync()
{
// TODO: Implement!
// NOTE: There's no hook for sync'ing the whole FS.
return B_UNSUPPORTED;
PRINT(("FUSEVolume::Sync()\n"));
// There's no FUSE hook for sync'ing the whole FS. We need to individually
// fsync all nodes that have been marked dirty. To keep things simple, we
// hold the volume lock the whole time. That's a concurrency killer, but
// usually sync isn't invoked that often.
AutoLocker<Locker> _(fLock);
// iterate through all nodes
FUSENodeTable::Iterator it = fNodes.GetIterator();
while (FUSENode* node = it.Next()) {
if (!node->dirty)
continue;
// node is dirty -- we have to sync it
// get a path for the node
char path[B_PATH_NAME_LENGTH];
size_t pathLen;
status_t error = _BuildPath(node, path, pathLen);
if (error != B_OK)
continue;
// open, sync, and close the node
FileCookie cookie(O_RDONLY);
int fuseError = fuse_fs_open(fFS, path, &cookie);
if (fuseError == 0) {
fuseError = fuse_fs_fsync(fFS, path, 0, &cookie);
// full sync, not only data
fuse_fs_flush(fFS, path, &cookie);
fuse_fs_release(fFS, path, &cookie);
}
if (fuseError == 0) {
// sync'ing successful -- mark the node not dirty
node->dirty = false;
}
}
return B_OK;
}
@@ -753,14 +791,6 @@ FUSEVolume::ReadFSInfo(fs_info* info)
}
status_t
FUSEVolume::WriteFSInfo(const struct fs_info* info, uint32 mask)
{
// TODO: Implement!
return B_UNSUPPORTED;
}
// #pragma mark - vnodes
@@ -885,21 +915,28 @@ FUSEVolume::FSync(void* _node)
if (error != B_OK)
RETURN_ERROR(error);
// mark the node not dirty
bool dirty = node->dirty;
node->dirty = false;
locker.Unlock();
// open, sync, and close the node
FileCookie cookie(O_RDONLY);
int fuseError = fuse_fs_open(fFS, path, &cookie);
if (fuseError != 0)
RETURN_ERROR(fuseError);
if (fuseError == 0) {
fuseError = fuse_fs_fsync(fFS, path, 0, &cookie);
// full sync, not only data
fuse_fs_flush(fFS, path, &cookie);
fuse_fs_release(fFS, path, &cookie);
}
fuseError = fuse_fs_fsync(fFS, path, 0, &cookie);
// full sync, not only data
if (fuseError != 0)
if (fuseError != 0) {
// sync'ing failed -- mark the node dirty again
locker.Lock();
node->dirty |= dirty;
RETURN_ERROR(fuseError);
fuse_fs_flush(fFS, path, &cookie);
fuse_fs_release(fFS, path, &cookie);
}
return B_OK;
}
@@ -967,11 +1004,15 @@ dir->id, name, target, mode));
locker.Unlock();
// create the dir
// create the symlink
int fuseError = fuse_fs_symlink(fFS, target, path);
if (fuseError != 0)
RETURN_ERROR(fuseError);
// mark the dir dirty
locker.Lock();
dir->dirty = true;
// TODO: Set the mode?!
// TODO: Node monitoring!
@@ -1016,6 +1057,11 @@ node, node->id));
if (fuseError != 0)
RETURN_ERROR(fuseError);
// mark the dir and the node dirty
locker.Lock();
dir->dirty = true;
node->dirty = true;
// TODO: Node monitoring!
return B_OK;
@@ -1053,6 +1099,9 @@ PRINT(("FUSEVolume::Unlink(%p (%lld), \"%s\")\n", dir, dir->id, name));
locker.Lock();
_RemoveEntry(dir, name);
// mark the dir dirty
dir->dirty = true;
// TODO: Node monitoring!
return B_OK;
@@ -1099,6 +1148,10 @@ oldDir->id, oldName, newDir, newDir->id, newName));
locker.Lock();
_RenameEntry(oldDir, oldName, newDir, newName);
// mark the dirs dirty
oldDir->dirty = true;
newDir->dirty = true;
// TODO: Node monitoring!
return B_OK;
@@ -1240,6 +1293,10 @@ mask));
RETURN_ERROR(fuseError);
}
// mark the node dirty
locker.Lock();
node->dirty = true;
// TODO: Node monitoring!
return B_OK;
@@ -1298,6 +1355,11 @@ openMode, mode));
RETURN_ERROR(error);
}
// mark the dir and the node dirty
locker.Lock();
dir->dirty = true;
node->dirty = true;
cookieDeleter.Detach();
*_cookie = cookie;
*_vnid = node->id;
@@ -1350,6 +1412,11 @@ PRINT(("FUSEVolume::Open(%p (%lld), %#x)\n", node, node->id, openMode));
fuse_fs_release(fFS, path, cookie);
RETURN_ERROR(fuseError);
}
// mark the node dirty
locker.Lock();
node->dirty = true;
// TODO: Node monitoring!
}
@@ -1499,6 +1566,10 @@ FUSEVolume::Write(void* _node, void* _cookie, off_t pos, const void* buffer,
if (bytesWritten < 0)
return bytesWritten;
// mark the node dirty
locker.Lock();
node->dirty = true;
// TODO: Node monitoring?
*_bytesWritten = bytesWritten;
@@ -1537,6 +1608,10 @@ mode));
if (fuseError != 0)
RETURN_ERROR(fuseError);
// mark the dir dirty
locker.Lock();
dir->dirty = true;
// TODO: Node monitoring!
return B_OK;
@@ -1574,6 +1649,10 @@ PRINT(("FUSEVolume::RemoveDir(%p (%lld), \"%s\")\n", dir, dir->id, name));
locker.Lock();
_RemoveEntry(dir, name);
// mark the parent dir dirty
locker.Lock();
dir->dirty = true;
// TODO: Node monitoring!
return B_OK;
@@ -37,8 +37,6 @@ public:
virtual status_t Unmount();
virtual status_t Sync();
virtual status_t ReadFSInfo(fs_info* info);
virtual status_t WriteFSInfo(const struct fs_info* info,
uint32 mask);
// vnodes
virtual status_t Lookup(void* dir, const char* entryName,