* 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:
@@ -82,12 +82,14 @@ struct FUSENode : RWLockable, HashTableLink<FUSENode> {
|
|||||||
FUSEEntryList entries;
|
FUSEEntryList entries;
|
||||||
int type;
|
int type;
|
||||||
int32 refCount;
|
int32 refCount;
|
||||||
|
bool dirty;
|
||||||
|
|
||||||
FUSENode(ino_t id, int type)
|
FUSENode(ino_t id, int type)
|
||||||
:
|
:
|
||||||
id(id),
|
id(id),
|
||||||
type(type),
|
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_UNMOUNT, true);
|
||||||
|
|
||||||
fVolumeCapabilities.Set(FS_VOLUME_CAPABILITY_READ_FS_INFO, fFS->ops.statfs);
|
fVolumeCapabilities.Set(FS_VOLUME_CAPABILITY_READ_FS_INFO, fFS->ops.statfs);
|
||||||
// fVolumeCapabilities.Set(FS_VOLUME_CAPABILITY_WRITE_FS_INFO,
|
// missing: FS_VOLUME_CAPABILITY_WRITE_FS_INFO
|
||||||
// fFS->ops.wfsstat);
|
fVolumeCapabilities.Set(FS_VOLUME_CAPABILITY_SYNC, fFS->ops.fsync);
|
||||||
// fVolumeCapabilities.Set(FS_VOLUME_CAPABILITY_SYNC, fFS->ops.sync);
|
// emulated via fsync()
|
||||||
|
|
||||||
fVolumeCapabilities.Set(FS_VOLUME_CAPABILITY_GET_VNODE, true);
|
fVolumeCapabilities.Set(FS_VOLUME_CAPABILITY_GET_VNODE, true);
|
||||||
// emulated
|
// emulated
|
||||||
|
|||||||
@@ -722,9 +722,47 @@ printf("FUSEVolume::Unmount()\n");
|
|||||||
status_t
|
status_t
|
||||||
FUSEVolume::Sync()
|
FUSEVolume::Sync()
|
||||||
{
|
{
|
||||||
// TODO: Implement!
|
PRINT(("FUSEVolume::Sync()\n"));
|
||||||
// NOTE: There's no hook for sync'ing the whole FS.
|
|
||||||
return B_UNSUPPORTED;
|
// 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
|
// #pragma mark - vnodes
|
||||||
|
|
||||||
|
|
||||||
@@ -885,21 +915,28 @@ FUSEVolume::FSync(void* _node)
|
|||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
RETURN_ERROR(error);
|
RETURN_ERROR(error);
|
||||||
|
|
||||||
|
// mark the node not dirty
|
||||||
|
bool dirty = node->dirty;
|
||||||
|
node->dirty = false;
|
||||||
|
|
||||||
locker.Unlock();
|
locker.Unlock();
|
||||||
|
|
||||||
// open, sync, and close the node
|
// open, sync, and close the node
|
||||||
FileCookie cookie(O_RDONLY);
|
FileCookie cookie(O_RDONLY);
|
||||||
int fuseError = fuse_fs_open(fFS, path, &cookie);
|
int fuseError = fuse_fs_open(fFS, path, &cookie);
|
||||||
if (fuseError != 0)
|
if (fuseError == 0) {
|
||||||
RETURN_ERROR(fuseError);
|
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);
|
if (fuseError != 0) {
|
||||||
// full sync, not only data
|
// sync'ing failed -- mark the node dirty again
|
||||||
if (fuseError != 0)
|
locker.Lock();
|
||||||
|
node->dirty |= dirty;
|
||||||
RETURN_ERROR(fuseError);
|
RETURN_ERROR(fuseError);
|
||||||
|
}
|
||||||
fuse_fs_flush(fFS, path, &cookie);
|
|
||||||
fuse_fs_release(fFS, path, &cookie);
|
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
@@ -967,11 +1004,15 @@ dir->id, name, target, mode));
|
|||||||
|
|
||||||
locker.Unlock();
|
locker.Unlock();
|
||||||
|
|
||||||
// create the dir
|
// create the symlink
|
||||||
int fuseError = fuse_fs_symlink(fFS, target, path);
|
int fuseError = fuse_fs_symlink(fFS, target, path);
|
||||||
if (fuseError != 0)
|
if (fuseError != 0)
|
||||||
RETURN_ERROR(fuseError);
|
RETURN_ERROR(fuseError);
|
||||||
|
|
||||||
|
// mark the dir dirty
|
||||||
|
locker.Lock();
|
||||||
|
dir->dirty = true;
|
||||||
|
|
||||||
// TODO: Set the mode?!
|
// TODO: Set the mode?!
|
||||||
|
|
||||||
// TODO: Node monitoring!
|
// TODO: Node monitoring!
|
||||||
@@ -1016,6 +1057,11 @@ node, node->id));
|
|||||||
if (fuseError != 0)
|
if (fuseError != 0)
|
||||||
RETURN_ERROR(fuseError);
|
RETURN_ERROR(fuseError);
|
||||||
|
|
||||||
|
// mark the dir and the node dirty
|
||||||
|
locker.Lock();
|
||||||
|
dir->dirty = true;
|
||||||
|
node->dirty = true;
|
||||||
|
|
||||||
// TODO: Node monitoring!
|
// TODO: Node monitoring!
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -1053,6 +1099,9 @@ PRINT(("FUSEVolume::Unlink(%p (%lld), \"%s\")\n", dir, dir->id, name));
|
|||||||
locker.Lock();
|
locker.Lock();
|
||||||
_RemoveEntry(dir, name);
|
_RemoveEntry(dir, name);
|
||||||
|
|
||||||
|
// mark the dir dirty
|
||||||
|
dir->dirty = true;
|
||||||
|
|
||||||
// TODO: Node monitoring!
|
// TODO: Node monitoring!
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -1099,6 +1148,10 @@ oldDir->id, oldName, newDir, newDir->id, newName));
|
|||||||
locker.Lock();
|
locker.Lock();
|
||||||
_RenameEntry(oldDir, oldName, newDir, newName);
|
_RenameEntry(oldDir, oldName, newDir, newName);
|
||||||
|
|
||||||
|
// mark the dirs dirty
|
||||||
|
oldDir->dirty = true;
|
||||||
|
newDir->dirty = true;
|
||||||
|
|
||||||
// TODO: Node monitoring!
|
// TODO: Node monitoring!
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -1240,6 +1293,10 @@ mask));
|
|||||||
RETURN_ERROR(fuseError);
|
RETURN_ERROR(fuseError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mark the node dirty
|
||||||
|
locker.Lock();
|
||||||
|
node->dirty = true;
|
||||||
|
|
||||||
// TODO: Node monitoring!
|
// TODO: Node monitoring!
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -1298,6 +1355,11 @@ openMode, mode));
|
|||||||
RETURN_ERROR(error);
|
RETURN_ERROR(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mark the dir and the node dirty
|
||||||
|
locker.Lock();
|
||||||
|
dir->dirty = true;
|
||||||
|
node->dirty = true;
|
||||||
|
|
||||||
cookieDeleter.Detach();
|
cookieDeleter.Detach();
|
||||||
*_cookie = cookie;
|
*_cookie = cookie;
|
||||||
*_vnid = node->id;
|
*_vnid = node->id;
|
||||||
@@ -1350,6 +1412,11 @@ PRINT(("FUSEVolume::Open(%p (%lld), %#x)\n", node, node->id, openMode));
|
|||||||
fuse_fs_release(fFS, path, cookie);
|
fuse_fs_release(fFS, path, cookie);
|
||||||
RETURN_ERROR(fuseError);
|
RETURN_ERROR(fuseError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mark the node dirty
|
||||||
|
locker.Lock();
|
||||||
|
node->dirty = true;
|
||||||
|
|
||||||
// TODO: Node monitoring!
|
// TODO: Node monitoring!
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1499,6 +1566,10 @@ FUSEVolume::Write(void* _node, void* _cookie, off_t pos, const void* buffer,
|
|||||||
if (bytesWritten < 0)
|
if (bytesWritten < 0)
|
||||||
return bytesWritten;
|
return bytesWritten;
|
||||||
|
|
||||||
|
// mark the node dirty
|
||||||
|
locker.Lock();
|
||||||
|
node->dirty = true;
|
||||||
|
|
||||||
// TODO: Node monitoring?
|
// TODO: Node monitoring?
|
||||||
|
|
||||||
*_bytesWritten = bytesWritten;
|
*_bytesWritten = bytesWritten;
|
||||||
@@ -1537,6 +1608,10 @@ mode));
|
|||||||
if (fuseError != 0)
|
if (fuseError != 0)
|
||||||
RETURN_ERROR(fuseError);
|
RETURN_ERROR(fuseError);
|
||||||
|
|
||||||
|
// mark the dir dirty
|
||||||
|
locker.Lock();
|
||||||
|
dir->dirty = true;
|
||||||
|
|
||||||
// TODO: Node monitoring!
|
// TODO: Node monitoring!
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -1574,6 +1649,10 @@ PRINT(("FUSEVolume::RemoveDir(%p (%lld), \"%s\")\n", dir, dir->id, name));
|
|||||||
locker.Lock();
|
locker.Lock();
|
||||||
_RemoveEntry(dir, name);
|
_RemoveEntry(dir, name);
|
||||||
|
|
||||||
|
// mark the parent dir dirty
|
||||||
|
locker.Lock();
|
||||||
|
dir->dirty = true;
|
||||||
|
|
||||||
// TODO: Node monitoring!
|
// TODO: Node monitoring!
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|||||||
@@ -37,8 +37,6 @@ public:
|
|||||||
virtual status_t Unmount();
|
virtual status_t Unmount();
|
||||||
virtual status_t Sync();
|
virtual status_t Sync();
|
||||||
virtual status_t ReadFSInfo(fs_info* info);
|
virtual status_t ReadFSInfo(fs_info* info);
|
||||||
virtual status_t WriteFSInfo(const struct fs_info* info,
|
|
||||||
uint32 mask);
|
|
||||||
|
|
||||||
// vnodes
|
// vnodes
|
||||||
virtual status_t Lookup(void* dir, const char* entryName,
|
virtual status_t Lookup(void* dir, const char* entryName,
|
||||||
|
|||||||
Reference in New Issue
Block a user