Add a VFS::absolutePath(InodeIdentifier).

This is pretty inefficient for ext2fs. We walk the entire block group
containing the inode, searching through every directory for an entry
referencing this inode.

It might be a good idea to cache this information somehow. I'm not sure
how often we'll be searching for it.

Obviously there are multiple caching layers missing in the file system.
This commit is contained in:
Andreas Kling 2018-10-28 12:20:25 +01:00
parent 3f050c1972
commit 1d4af51250
11 changed files with 116 additions and 18 deletions

View file

@ -43,7 +43,8 @@ ELFLOADER_OBJS = \
AK_OBJS = \
../AK/String.o \
../AK/StringImpl.o
../AK/StringImpl.o \
../AK/StringBuilder.o
OBJS = $(KERNEL_OBJS) $(VFS_OBJS) $(AK_OBJS) $(ELFLOADER_OBJS)

View file

@ -234,7 +234,7 @@ Task* Task::createUserTask(const String& path, uid_t uid, gid_t gid, pid_t paren
cwd = parentTask->m_cwd.copyRef();
}
auto handle = VirtualFileSystem::the().open(path, cwd.ptr());
auto handle = VirtualFileSystem::the().open(path, cwd ? cwd->inode : InodeIdentifier());
if (!handle) {
error = -ENOENT; // FIXME: Get a more detailed error from VFS.
return nullptr;
@ -785,7 +785,7 @@ int Task::sys$close(int fd)
int Task::sys$lstat(const char* path, Unix::stat* statbuf)
{
VALIDATE_USER_BUFFER(statbuf, sizeof(Unix::stat));
auto handle = VirtualFileSystem::the().open(move(path), m_cwd.ptr());
auto handle = VirtualFileSystem::the().open(move(path), cwdInode());
if (!handle)
return -1;
handle->stat(statbuf);
@ -795,7 +795,7 @@ int Task::sys$lstat(const char* path, Unix::stat* statbuf)
int Task::sys$chdir(const char* path)
{
VALIDATE_USER_BUFFER(path, strlen(path));
auto handle = VirtualFileSystem::the().open(path, m_cwd.ptr());
auto handle = VirtualFileSystem::the().open(path, cwdInode());
if (!handle)
return -ENOENT; // FIXME: More detailed error.
if (!handle->isDirectory())
@ -819,7 +819,7 @@ int Task::sys$open(const char* path, size_t pathLength)
VALIDATE_USER_BUFFER(path, pathLength);
if (m_fileHandles.size() >= m_maxFileHandles)
return -EMFILE;
auto handle = VirtualFileSystem::the().open(String(path, pathLength), m_cwd.ptr());
auto handle = VirtualFileSystem::the().open(String(path, pathLength), cwdInode());
if (!handle)
return -ENOENT; // FIXME: Detailed error.
int fd = m_fileHandles.size();

View file

@ -133,6 +133,8 @@ public:
bool isValidAddressForKernel(LinearAddress) const;
bool isValidAddressForUser(LinearAddress) const;
InodeIdentifier cwdInode() const { return m_cwd ? m_cwd->inode : InodeIdentifier(); }
private:
friend class MemoryManager;
friend bool scheduleNewTask();

View file

@ -943,3 +943,35 @@ InodeIdentifier Ext2FileSystem::createInode(InodeIdentifier parentInode, const S
return { id(), inode };
}
InodeIdentifier Ext2FileSystem::findParentOfInode(InodeIdentifier inode) const
{
ASSERT(inode.fileSystemID() == id());
unsigned groupIndex = groupIndexFromInode(inode.index());
unsigned firstInodeInGroup = inodesPerGroup() * (groupIndex - 1);
Vector<InodeIdentifier> directoriesInGroup;
for (unsigned i = 0; i < inodesPerGroup(); ++i) {
auto e2inode = lookupExt2Inode(firstInodeInGroup + i);
if (!e2inode)
continue;
if (isDirectory(e2inode->i_mode)) {
directoriesInGroup.append({ id(), firstInodeInGroup + i });
}
}
InodeIdentifier foundParent;
for (auto& directory : directoriesInGroup) {
enumerateDirectoryInode(directory, [inode, directory, &foundParent] (auto& entry) {
if (entry.inode == inode) {
foundParent = directory;
return false;
}
return true;
});
if (foundParent.isValid())
break;
}
return foundParent;
}

View file

@ -46,6 +46,7 @@ private:
virtual InodeIdentifier createInode(InodeIdentifier parentInode, const String& name, Unix::mode_t, unsigned size) override;
virtual Unix::ssize_t readInodeBytes(InodeIdentifier, Unix::off_t offset, Unix::size_t count, byte* buffer, FileHandle*) const override;
virtual InodeIdentifier makeDirectory(InodeIdentifier parentInode, const String& name, Unix::mode_t) override;
virtual InodeIdentifier findParentOfInode(InodeIdentifier) const override;
bool isDirectoryInode(unsigned) const;
unsigned allocateInode(unsigned preferredGroup, unsigned expectedSize);

View file

@ -50,6 +50,20 @@ InodeIdentifier FileSystem::childOfDirectoryInodeWithName(InodeIdentifier inode,
return foundInode;
}
String FileSystem::nameOfChildInDirectory(InodeIdentifier parent, InodeIdentifier child) const
{
String name;
bool success = enumerateDirectoryInode(parent, [&] (auto& entry) {
if (entry.inode == child) {
name = entry.name;
return false;
}
return true;
});
ASSERT(success);
return name;
}
ByteBuffer FileSystem::readEntireInode(InodeIdentifier inode, FileHandle* handle) const
{
ASSERT(inode.fileSystemID() == id());

View file

@ -45,8 +45,11 @@ public:
virtual InodeIdentifier createInode(InodeIdentifier parentInode, const String& name, Unix::mode_t, unsigned size) = 0;
virtual InodeIdentifier makeDirectory(InodeIdentifier parentInode, const String& name, Unix::mode_t) = 0;
virtual InodeIdentifier findParentOfInode(InodeIdentifier) const = 0;
InodeIdentifier childOfDirectoryInodeWithName(InodeIdentifier, const String& name) const;
ByteBuffer readEntireInode(InodeIdentifier, FileHandle* = nullptr) const;
String nameOfChildInDirectory(InodeIdentifier parent, InodeIdentifier child) const;
protected:
FileSystem();

View file

@ -199,7 +199,7 @@ Unix::ssize_t SyntheticFileSystem::readInodeBytes(InodeIdentifier inode, Unix::o
#endif
ASSERT(offset >= 0);
ASSERT(buffer);
\
auto it = m_inodes.find(inode.index());
if (it == m_inodes.end())
return false;
@ -235,3 +235,11 @@ auto SyntheticFileSystem::generateInodeIndex() -> InodeIndex
{
return m_nextInodeIndex++;
}
InodeIdentifier SyntheticFileSystem::findParentOfInode(InodeIdentifier inode) const
{
auto it = m_inodes.find(inode.index());
if (it == m_inodes.end())
return { };
return (*it).value->parent;
}

View file

@ -19,6 +19,7 @@ public:
virtual InodeIdentifier createInode(InodeIdentifier parentInode, const String& name, Unix::mode_t, unsigned size) override;
virtual Unix::ssize_t readInodeBytes(InodeIdentifier, Unix::off_t offset, Unix::size_t count, byte* buffer, FileHandle*) const override;
virtual InodeIdentifier makeDirectory(InodeIdentifier parentInode, const String& name, Unix::mode_t) override;
virtual InodeIdentifier findParentOfInode(InodeIdentifier) const override;
protected:
typedef unsigned InodeIndex;

View file

@ -1,6 +1,7 @@
#include "VirtualFileSystem.h"
#include "FileHandle.h"
#include "FileSystem.h"
#include <AK/StringBuilder.h>
#include <AK/kmalloc.h>
#include <AK/kstdio.h>
#include <AK/ktime.h>
@ -169,7 +170,7 @@ void VirtualFileSystem::freeNode(Node* node)
m_nodeFreeList.append(move(node));
}
bool VirtualFileSystem::isDirectory(const String& path, Node* base)
bool VirtualFileSystem::isDirectory(const String& path, InodeIdentifier base)
{
auto inode = resolvePath(path, base);
if (!inode.isValid())
@ -356,7 +357,7 @@ bool VirtualFileSystem::touch(const String& path)
return inode.fileSystem()->setModificationTime(inode, ktime(nullptr));
}
OwnPtr<FileHandle> VirtualFileSystem::open(const String& path, Node* base)
OwnPtr<FileHandle> VirtualFileSystem::open(const String& path, InodeIdentifier base)
{
Locker locker(VirtualFileSystem::lock());
@ -369,7 +370,7 @@ OwnPtr<FileHandle> VirtualFileSystem::open(const String& path, Node* base)
return make<FileHandle>(move(vnode));
}
OwnPtr<FileHandle> VirtualFileSystem::create(const String& path, Node* base)
OwnPtr<FileHandle> VirtualFileSystem::create(const String& path, InodeIdentifier base)
{
Locker locker(VirtualFileSystem::lock());
@ -379,7 +380,7 @@ OwnPtr<FileHandle> VirtualFileSystem::create(const String& path, Node* base)
return nullptr;
}
OwnPtr<FileHandle> VirtualFileSystem::mkdir(const String& path, Node* base)
OwnPtr<FileHandle> VirtualFileSystem::mkdir(const String& path, InodeIdentifier base)
{
Locker locker(VirtualFileSystem::lock());
@ -399,7 +400,41 @@ InodeIdentifier VirtualFileSystem::resolveSymbolicLink(const String& basePath, I
return resolvePath(buf);
}
InodeIdentifier VirtualFileSystem::resolvePath(const String& path, Node* base)
String VirtualFileSystem::absolutePath(InodeIdentifier inode)
{
Locker locker(VirtualFileSystem::lock());
if (!inode.isValid())
return String();
Vector<InodeIdentifier> lineage;
while (inode != m_rootNode->inode) {
if (auto* mount = findMountForGuest(inode))
lineage.append(mount->host());
else
lineage.append(inode);
if (inode.metadata().isDirectory()) {
inode = resolvePath("..", inode);
} else
inode = inode.fileSystem()->findParentOfInode(inode);
ASSERT(inode.isValid());
}
if (lineage.isEmpty())
return "/";
lineage.append(m_rootNode->inode);
StringBuilder builder;
for (size_t i = lineage.size() - 1; i >= 1; --i) {
auto& child = lineage[i - 1];
auto parent = lineage[i];
if (auto* mount = findMountForHost(parent))
parent = mount->guest();
builder.append('/');
builder.append(parent.fileSystem()->nameOfChildInDirectory(parent, child));
}
return builder.build();
}
InodeIdentifier VirtualFileSystem::resolvePath(const String& path, InodeIdentifier base)
{
if (path.isEmpty())
return { };
@ -410,7 +445,7 @@ InodeIdentifier VirtualFileSystem::resolvePath(const String& path, Node* base)
if (path[0] == '/')
inode = m_rootNode->inode;
else
inode = base ? base->inode : m_rootNode->inode;
inode = base.isValid() ? base : m_rootNode->inode;
for (unsigned i = 0; i < parts.size(); ++i) {
bool wasRootInodeAtHeadOfLoop = inode.isRootInode();

View file

@ -66,7 +66,7 @@ public:
VirtualFileSystem();
~VirtualFileSystem();
bool isDirectory(const String& path, Node* base = nullptr);
bool isDirectory(const String& path, InodeIdentifier base = InodeIdentifier());
void listDirectory(const String& path);
void listDirectoryRecursively(const String& path);
@ -79,9 +79,9 @@ public:
bool mountRoot(RetainPtr<FileSystem>&&);
bool mount(RetainPtr<FileSystem>&&, const String& path);
OwnPtr<FileHandle> open(const String& path, Node* base = nullptr);
OwnPtr<FileHandle> create(const String& path, Node* base = nullptr);
OwnPtr<FileHandle> mkdir(const String& path, Node* base = nullptr);
OwnPtr<FileHandle> open(const String& path, InodeIdentifier base = InodeIdentifier());
OwnPtr<FileHandle> create(const String& path, InodeIdentifier base = InodeIdentifier());
OwnPtr<FileHandle> mkdir(const String& path, InodeIdentifier base = InodeIdentifier());
bool isRoot(InodeIdentifier) const;
@ -92,12 +92,13 @@ public:
size_t mountCount() const { return m_mounts.size(); }
void forEachMount(Function<void(const Mount&)>) const;
String absolutePath(InodeIdentifier);
private:
friend class FileHandle;
void enumerateDirectoryInode(InodeIdentifier, Function<bool(const FileSystem::DirectoryEntry&)>);
String absolutePath(InodeIdentifier);
InodeIdentifier resolvePath(const String& path, Node* base = nullptr);
InodeIdentifier resolvePath(const String& path, InodeIdentifier base = InodeIdentifier());
InodeIdentifier resolveSymbolicLink(const String& basePath, InodeIdentifier symlinkInode);
RetainPtr<Node> allocateNode();