OSDev.org

The Place to Start for Operating System Developers
It is currently Fri Apr 19, 2024 1:05 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 5 posts ] 
Author Message
 Post subject: VFS: How d you guys handle mountpoints?
PostPosted: Wed Apr 22, 2015 6:49 am 
Offline
Member
Member

Joined: Sat Oct 16, 2010 3:38 pm
Posts: 587
Glidix currently has a VFS with all the typical UNIX features (except symlinks, which are to be implemented soon). However, I'm starting to think that my implementation is not the best.

The main problem with it is that it may not necessarily be the most efficient, and this stems mainly from how it stores mountpoints. When you mount a filesystem, it is assigned a "prefix"; for example, if I might my CD-ROM at /media/cdrom, the kernel will add the following structure to a linked list:

Code:
typedef struct _MountPoint
{
   char         prefix[512];
   FileSystem      *fs;
   struct _MountPoint   *prev;
   struct _MountPoint   *next;
} MountPoint;


Where "prefix" will be "/media/cdrom/" (i.e. all paths starting with "/media/cdrom/" are on this filesystem). When trying to resolve the path "/media/cdrom/my_files/hello.txt", it will see that it begins with "/media/cdrom/" and therefore successfully detect that it is on that filesystem; then, the rest of the path, "my_files/hello.txt" is followed, by calling fs->openroot(), which returns a "Dir" structure, and the system will repeadetly call dir->next() until "my_files" is found, then it will call dir->opendir() which returns another Dir, and eventually it finds the file (if it exists of course).

But this means that the only way processes can have working directories is if they just store their paths, and that path must be strcat()ed with every relative path used, and a lot of pointless directory-traversing will then happen... but otherwise, of course, it wouldn't know which filesystem to go on, if a subdirectory of the working directory is a mountpoint.

How does your OS store mountpoints? I can think of another way: to just store the device (st_dev) and inode (st_inode) of each mountpoint, and redirect all operations on such inodes to the root of the filesystem. But the problem would be that /initrd, /dev, etc must be mounted before the root filesystem, but they are on the root filesystem. I could mount some kind of "ramfs" on the root, then unmount everything and mount the proper filesystems.

But before doing this I wanted to see how other OSes do this. I can't find any information on how linux stores this either.


Top
 Profile  
 
 Post subject: Re: VFS: How d you guys handle mountpoints?
PostPosted: Wed Apr 22, 2015 10:26 am 
Offline
Member
Member

Joined: Tue Aug 14, 2012 8:51 am
Posts: 92
Hi,

Lookup the JamesM tutorial on filesystems, it has a quite elegant way of doing that AFAIK


Top
 Profile  
 
 Post subject: Re: VFS: How d you guys handle mountpoints?
PostPosted: Wed Apr 22, 2015 10:55 am 
Offline
Member
Member

Joined: Sat Oct 16, 2010 3:38 pm
Posts: 587
JamesM's tutorial marks some inodes with a flag (FS_MOUNTPOINT), this is clearly not a good idea; either you'd have to save that flag to disk and each filesystem driver would have to support it, or you'd have to have a list of mounted dev-inode pairs anyway.


Top
 Profile  
 
 Post subject: Re: VFS: How d you guys handle mountpoints?
PostPosted: Wed Apr 22, 2015 12:27 pm 
Offline
Member
Member
User avatar

Joined: Mon Mar 05, 2012 11:23 am
Posts: 616
Location: Germany
In Ghost, a node contains
- type
- virtual id
- physical fs id
- name
- delegate
- parent
- list of children

When the type of the node is "mountpoint", the node additionally has a "delegate" set. Whenever anyone tries to open a file, list a directory, read from a file etc. the delegate is used.

For example, a process wants to open "/examplefs/documents/test.txt":
1. find the node "examplefs" by searching the list of children in the root; if its not found, ask the root's delegate to discover the node
2. find the node "documents" by searching the list of children in the found node; if its not found, the delegate for "examplefs" is asked to discover the node
3. find the node "test.txt" ... using the delegate of "examplefs" as before

"Discovering" here means, searching on the actual physical filesystem/whatever to search for a specific node.
You probably also want to have processes to be filesystem drivers: for this, there is the "task delegate". Whenever this delegate is asked to do anything, it sends a message to the process that registered itself to be the driver for that mountpoint, sets the requesting task asleep, and waits until the action is finished. The filesystem driver process receives this message, does whatever is necessary to do the requested action (like using system calls to create the virtual filesystem nodes etc.) and then tells the kernel that the transaction is finished. The requesting process is the woken up and can continue as if nothing happened.

The root node is just a node with no name, that has a special delegate (the root delegate) that just lists all mounpoints created in root.

Thats how I do it. In short, mounpoints have a delegate that have an implementation to access a specific filesystem.

_________________
Ghost OS - GitHub


Top
 Profile  
 
 Post subject: Re: VFS: How d you guys handle mountpoints?
PostPosted: Wed Apr 22, 2015 10:43 pm 
Offline
Member
Member
User avatar

Joined: Mon Jun 16, 2014 5:33 pm
Posts: 213
Location: Costa Rica
I'll share my VFS's design on what mountpoints respect.

First of all, some important data structures and functions (Spoiler, C++11 is involved!):
Code:
namespace VFS {
   enum class InodeType {
      File,
      Directory,
      SymbolicLink,
      ProtocolFile, // i.e: socket
      NamedPipe,
      TrapFile, // i.e: "special" files
      Gateway // Let's leave this for another forum thread...
   };
   
   struct Inode {
      Size      id; // As far as the underlying filesystem knows
      UID      owner;
      Size      refs; // (Hard-links)
      Size      openRefs; // (Open file descriptors)
      UInt16   access;
      Size      size;
      InodeType   type;
      Bool      mayBeUncached;
   };
   
   class Directory;
   
   struct File {
      Byte      name[256];
      Size      mount;
      Size      inode;
      Directory*   parent;
      File*      next;
      InodeType   type;
   };
   
   class Directory : public File {
      public:
         File*   children;
         
         ErrorCode   getChild   (String name, File **file);
   };
   
   ErrorCode   Mount   (String source, String target, Bool bindMount);
   ErrorCode   Unmount   (String root);
}


Some BTWs:
  • typedef unsigned long Size; // For x86
  • class ErrorCode; // ...
  • typedef bool Bool; // This *has* its reasons
  • typedef const char* String; // Did you though it was something like std::string?

The job of VFS::Mount() is very simple:

If bindMount is true, then source shall be a path pointing to a valid, present directory. That directory and its children shall be copied into a new, fresh tree. The address of that new directory structure is stored in a example pointer named sourceDir. The bind-mounted directory structure itself may not be copied, it's innecessary.

Else, the trap file pointed to by source is loaded into kernel memory and its internal filesystem is parsed into the common tree structure in kernel memory. The directory representation of the root of the loaded filesystem is stored in the previously mentioned sourceDir pointer.

Whatever *sourceDir contains, the target directory, target, shall be empty for everything to work correctly. There will be a single change in the original filesystem tree, that is, all first-level nodes from the root (i.e: /usr counts but /usr/local doesn't) shall have their parent changed to the directory pointed to by target, as well as target shall change its childs pointer member changed to the address of the first element of the mounted filesystem.

The reverse process, VFS::Unmount() is even simpler. It just flushes all data in the mounted filesystem, removes it from kernel memory, and sets the host root's childs pointer member to nullptr.

This model is simple, yet it addresses bind mounting, nested mounts, and multiple mounts of a single filesystem. BTW, obviously, there is a hidden mountpoint list that avoids VFS::Unmount()'ing of non-mountpoints, and there are several minimal, but important details that I didn't said here, specially with the "multiple mounts of a single filesystem" feature.

_________________
Happy New Code!
Hello World in Brainfuck :D:
Code:
++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 5 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: SemrushBot [Bot] and 37 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group