sos-code-article10/sos/fs.h

1141 lines
36 KiB
C

/* Copyright (C) 2005,2006 David Decotigny
Copyright (C) 2000-2005 The KOS Team (Thomas Petazzoni, David
Decotigny, Julien Munier)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
USA.
*/
#ifndef _SOS_FS_H_
#define _SOS_FS_H_
/**
* @file fs.h
*
* (Virtual) Filesystem management.
*
* SOS provides a complete Unix-like file system service. Supported
* features of this service are:
* - mountpoints
* - generic file system support (FS) through object-oriented
* specialization (so-called VFS)
* - hard & symbolic links
* - regular files and directories
* - block and character device special files (from article 9 onward)
* - file mapping
* - basic permission management ("rwx" only, no notion of owner)
* - chroot
* - separation of disk node and namespace notions allowing hard links
* and to move/rename/remove files or directories that are in use
* - basic FS interface (open/read/seek/creat/mkdir/rename/link
* / symlink/chmod/mount/fcntl/ioctl...)
* - deferred writes (ie file caching). @see sync(3)
*
* Among the unsupported features:
* - no user-based permission (uid/gid, ACLS)
* - no modification / access time accounting
* - no Fifo/socket special files (yet)
* - no generic support library for common fcntl commands
* (F_SETOWN/GETLEASE/NOTIFY, etc.)
* - no flock-style functions
*
* Rationale
* =========
* The VFS layer is based on 3 central concepts:
*
* - The meta-information for each file stored on disk: size,
* permissions, ... (struct sos_fs_node for SOS, inode for Unix)
*
* It is sufficient to know where this meta-information is located
* on disk (a simple sector number most of the time) to build the
* corresponding struct sos_fs_node into memory and to retrieve the
* data of the file from the disk
*
* For example, consider that we know a sector that holds the meta
* information is located at sector 64589 on disk. By retrieving
* this meta information directly from disk, we can build the
* struct sos_fs_node, which would (for example) tell that the
* corresponding file spans (for example) over sectors 4345, 5645,
* 4539 and 6575, is 1.7kB long
*
* Everything is stored this way on the disk, even the
* directories. From the disk contents' point of view, a directory
* is simply a file whose contents represent a list of mappings
* "name" -> meta-information location
*
* - One or many nodes in the file hierarchy pointing to this data
* (struct sos_fs_nscache_node for SOS, struct dentry for Linux). This
* tells that the entry "toto" in directory "/home/zorglub"
* corresponds to the given struct sos_fs_node
*
* Actually, with the struct sos_fs_node above, we can reach any
* file in the system. However, dealing with mountpoints requires
* an intermediary data structure because a directory on a disk
* cannot make reference to children struct sos_fs_node on other
* disk. This is one of the reasons why there is this struct
* sos_fs_nscache_node. Another reason is that we kind-of "cache" the
* most used struct sos_fs_node: those that lead from the global
* root ("/") to the files and directories currently being used
* (hence the name "nscache" for "namespace cache"). This speeds-up
* the path-resolving process (aka "lookup"), as the most-used path
* are already in-memory and the struct sos_fs_node are already
* in-memory too.
*
* A struct sos_fs_nscache_node can have at most 1 parent (the ".."
* entry). It can also have 0 parent in case the node is being used
* by a process (file is opened or mapped), but the file is
* actually "removed", ie un-reachable from any directory.
*
* Many such structures can reference the same underlying struct
* sos_fs_node, which enables the support of "hard links".
*
* - The "opened file" strucures. They store the information
* pertaining to a particular usage of a file. The most important
* thing they store is the "file pointer", which holds the
* location in the file where the next read/write operation should
* start
*
* Each process has at least 2 such opened files: its "current
* working directory" (RTFM chdir) and its "process root" (RTFM
* chroot). Those are heritated across fork() and can be changed by
* appropriate syscalls (resp. chdir/chroot). The main "root" of
* the system is the process root of the "init" process. The usual
* opened files (think of open() and opendir()) are stored in the
* file descriptor array (fds[]). This is the index in this array
* that is commonly called a "file descriptor".
*
*
* The whole VFS layer comprises a series of objects that can be
* specialized to implement different FS support (fat, ext2, ffs, ...):
*
* - The notion of "file system manager", which basically is a
* container to a FS name (eg "FAT", "EXT2", etc...) and a series of
* functions responsible for initializing a particular "mounting" of
* a FS (the "mount" method). This is SOS's struct sos_fs_manager_type
*
* - The notion of "file system instance" which contains the data
* proper to a particular mounting of an FS. Its most important job
* is to allocate new struct sos_fs_node on disk, or to retrieve the
* meta-information (ie struct sos_fs_node) located at the given
* location on disk. This is roughly THE primary physical interface
* between the VFS and the disks. This is SOS's struct
* sos_fs_manager_instance, aka the Linux's superblock
*
* For each struct sos_fs_node that it allocates, or that is loads
* from disk into memory, this "instance manager" is responsible
* for inidicating the functions that implement the FS-dedicated
* routine such as read/write/mmap/ioctl/... for this precise node.
*
* The nodes (struct sos_fs_node) of a struct
* sos_fs_manager_instance that are currently loaded in memory are
* stored in a hash-table. The key of this map is the location of the
* meta-information on disk. That way, it is very fast to look for
* the given meta-information whose location on disk is knows: if
* it has already been loaded into memory, its memory address is
* quickly resolved thanks to this hash table.
*/
#include <sos/types.h>
#include <sos/errno.h>
#include <sos/hash.h>
#include <sos/umem_vmm.h>
/* Forward declarations (structures defined in this file) */
struct sos_fs_manager_type;
struct sos_fs_manager_instance;
struct sos_fs_statfs;
struct sos_fs_node;
struct sos_fs_opened_file;
struct sos_fs_stat;
#include "fs_nscache.h"
#include <sos/blkdev.h>
/**
* The type of filesystem object.
*
* Each struct sos_fs_node has a type. Here are the supported types.
*/
typedef enum {
SOS_FS_NODE_REGULAR_FILE = 0x42,
SOS_FS_NODE_DIRECTORY = 0x24,
SOS_FS_NODE_SYMLINK = 0x84,
SOS_FS_NODE_DEVICE_CHAR = 0x48,
SOS_FS_NODE_DEVICE_BLOCK = 0x12
} sos_fs_node_type_t;
#define SOS_FS_MANAGER_NAME_MAXLEN 32
/**
* Description of a supported Filesystem type.
*
* These descriptions are listed in an internal list (see
* fs.c:fs_list), and each time we want to mount a FS, we precise a
* name (eg "FAT", "EXT2", ...). The VFS will look for this name into
* the list of supported filesystem types, and, when found, call its
* sos_fs_manager_type::mount() method.
*
* New filesystem types are registered using sos_fs_register_fs_type()
*/
struct sos_fs_manager_type
{
char name[SOS_FS_MANAGER_NAME_MAXLEN];
/**
* Responsible for making sure the underlying device (if any) really
* stores the correct filesystem format, for creating the hash of fs
* nodes and for calling sos_fs_register_fs_instance
*
* @param device May be NULL
*
* @note mandatory, may block
*/
sos_ret_t (*mount)(struct sos_fs_manager_type * this,
struct sos_fs_node * device,
const char * args,
struct sos_fs_manager_instance ** mounted_fs);
/**
* Responsible for de-allocating the hash of fs nodes and for
* calling sos_fs_unregister_fs_instance
*
* @note mandatory, may block
*/
sos_ret_t (*umount)(struct sos_fs_manager_type * this,
struct sos_fs_manager_instance * mounted_fs);
/** Free of use */
void * custom_data;
/** List of filesystem instances of this type currently mounted
somewhere in the system */
struct sos_fs_manager_instance * instances;
/** Linkage for the list of filesystem types registered in the
system */
struct sos_fs_manager_type *prev, *next;
};
/**
* Data related to a particular "mounting" of a file system. A
* so-called "superblock" under Linux
*
* This holds the FUNDAMENTAL functions responsible for loading struct
* sos_fs_node from disk, or for allocating thom on disk. It also
* holds the hash-table of struct sos_fs_node already loaded into
* memory.
*/
struct sos_fs_manager_instance
{
/**
* @note Publicly readable. Written only by sos_fs_manager_type::mount()
*/
struct sos_fs_manager_type * fs_type;
/**
* Usually, a filesystem relies on a device (disk, network, ram,
* ...) to fetch its data. This is the location of the device.
*
* @note Publicly readable. Written only by fs.c
*/
struct sos_fs_node * device;
#define SOS_FS_MOUNT_SYNC (1 << 0)
#define SOS_FS_MOUNT_READONLY (1 << 1)
#define SOS_FS_MOUNT_NOEXEC (1 << 2)
/**
* Is this FS read-only, without EXEC file permission, write-through
* ? Or-red combination of the SOS_FS_MOUNT_ flags
*
* @note Publicly readable. Written only by fs.c
*/
sos_ui32_t flags;
/**
* The namespace node that is the root of THIS file system mounting
*
* @note Publicly readable. Written only by fs.c
*/
struct sos_fs_nscache_node * root;
/**
* List of dirty nodes. These are the nodes that need to be written
* back to disk. With FS supporting deferred-writes, the
* sos_fs_sync() function will use this list to flush the dirty
* nodes back to disk.
*
* @note Reserved to fs.c
*/
struct sos_fs_node * dirty_nodes;
/**
* Build a fresh new FS node at the given location. This implies
* the allocation of a new sos_fs_node structure in memory
*
* @note Mandatory, may block. Appropriate locking MUST be implemented
*/
sos_ret_t (*fetch_node_from_disk)(struct sos_fs_manager_instance * this,
sos_ui64_t storage_location,
struct sos_fs_node ** result);
/**
* Build a fresh new FS node ON THE DISK of the given type (dir,
* plain file, symlink, ...), completely empty ; return a newly
* allocated IN-MEMORY node structure representing it
*
* @param open_creat_flags is the open_flags parameter passed to
* sos_fs_open() when O_CREAT is set. 0 when allocated trough
* creat/mkdir/mknod/symlink
*
* @note Mandatory, may block. Appropriate locking MUST be implemented
*/
sos_ret_t (*allocate_new_node)(struct sos_fs_manager_instance * this,
sos_fs_node_type_t type,
const struct sos_process * creator,
sos_ui32_t access_rights,
sos_ui32_t open_creat_flags,
struct sos_fs_node ** result);
/**
* Return filesystem status (RTFM df)
*
* @note Optional, may block. Appropriate locking MUST be implemented
*/
sos_ret_t (*statfs)(struct sos_fs_manager_instance * this,
struct sos_fs_statfs * result);
/**
* Comparison callback called when looking for file/dirs in the
* namespace cache. Normally, a usual lexicographical comparison is
* done (when this function points to NULL). But for some FS, it
* might be useful to use another comparison function (eg for
* case-insensitive FS)
*
* @note Optional (may be NULL), must NOT block
*/
sos_bool_t (*nsnode_same_name)(const char * name1, sos_ui16_t namelen1,
const char * name2, sos_ui16_t namelen2);
/**
* Hash table of the struct sos_fs_node of this filesystem instance
* loaded in memory: key=storage_location, element=sos_fs_node
*/
struct sos_hash_table * nodecache;
/**
* Unique identifier of this FS (used in sync method, updated by
* fs.c). This enables sync_all_fs to be resilient to mount/umount
* and (un)register_fs_type/instance
*/
sos_ui64_t uid;
void * custom_data;
/** Linkage for the list of instances for the underlying fs type */
struct sos_fs_manager_instance * prev, * next;
};
/**
* The CENTRAL data structure of the whole thing. A so-called "inode"
*
* This represents the meta-information related to a file on disk: its
* permission, where its data is located. Actually, in SOS, these
* information are not stored in this structure. Instead, we define a
* series of methods in this structure that MUST be implemented by the
* FS and that realize the higher level operations needed by the
* OS. These operations will rely on the meta-information that the FS
* code MUST define and manage by itself (hence the
* sos_fs_node::custom_data field).
*/
struct sos_fs_node
{
/**
* An struct sos_fs_node always belong to exactly ONE file system
*/
struct sos_fs_manager_instance * fs;
/**
* The so-called "inode": location of this node inside the FS
* instance. Updated by struct
* sos_fs_manager_instance::fetch_node_from_disk()
*/
sos_ui64_t storage_location;
/**
* Number of ON-DISK links to this node.
*
* - For everything but directories: the number of hard links to the file
* - For directories: 1 + the number of children nodes
*
* @note Publicly readable. Written only by
* sos_fs_node_ops_dir::link() and sos_fs_node_ops_dir::unlink()
*/
sos_count_t ondisk_lnk_cnt;
/**
* Number of IN-MEMORY nscache_nodes referencing this FS node.
*
* Corresponds to the number of struct sos_fs_nscache_node pointing
* to this node. This could be as much as ondisk_lnk_cnt + 1, but is
* usually less
*
* @note Reserved to fs.c
*/
sos_count_t inmem_ref_cnt;
/**
* Directory, symlink, ...
*
* @see sos_fs_node_type_t
*
* @note Publicly readable. Written only by fs.c
*/
sos_fs_node_type_t type;
#define SOS_FS_READABLE 00400
#define SOS_FS_WRITABLE 00200
#define SOS_FS_EXECUTABLE 00100
/**
* read/write, ... @see the SOS_FS_*ABLE flags
* @note Publicly readable. Written only by fs.c
*/
sos_ui32_t access_rights;
/**
* @note Reserved to fs.c
*/
sos_bool_t dirty;
/**
* Incremented each time one of the opened files for this node is
* modified
* @note Publicly readable. Written only by fs.c
*/
sos_lcount_t generation;
/**
* @note Available only for device files (char/block)
* @note Publicly readable. Written only by
* sos_fs_manager_instance::fetch_node_from_disk() and mknod()
*/
struct sos_fs_dev_id_t
{
sos_ui32_t device_class; /**< aka "major" */
sos_ui32_t device_instance; /**< aka "minor" */
} dev_id;
/** Operations common to all node types */
struct sos_fs_node_ops_file *ops_file;
/** Operations specific to some node types */
union
{
/** when type == SOS_FS_NODE_DIRECTORY */
struct sos_fs_node_ops_dir *ops_dir;
/**
* when type == SOS_FS_NODE_DEVICE_BLOCK
* The FS node has a link to some data pertaining to the device,
* not to any special operations
* @see blkdev.c for a definition of this structure
*/
struct sos_blockdev_instance *block_device;
/** when type == SOS_FS_NODE_SYMLINK */
struct sos_fs_node_ops_symlink *ops_symlink;
}; /* Anonymous union (gcc extension) */
/**
* Simply free this FS node from the kernel memory: it does NOT
* mean that the corresponding on-disk node is free ! Actually, the
* corresponding ON-DISK node is free iff ondisk_lnk_cnt == 0. No
* need to sync anything to disk, as the VFS will sync the node
* before calling this method
*
* @note Mandatory, may block, no special locking needed
*/
sos_ret_t (*destructor)(struct sos_fs_node * this);
/**
* Called when a process opens the node
*
* @note Mandatory, may block. Appropriate locking MUST be implemented
* @note FS-specific EXCEPT for device special files (char &
* block) because they are handled in an uniform way by the
* chardev/blockdev subsystems
* @note As a consequence, FS code can safely assume that "this" is
* never a character or block device
*/
sos_ret_t (*new_opened_file)(struct sos_fs_node * this,
const struct sos_process * owner,
sos_ui32_t open_flags,
struct sos_fs_opened_file ** result_of);
/**
* Called when a process closes the node
*
* @note Mandatory, may block. Appropriate locking MUST be implemented
* @note FS-specific EXCEPT for device special files (char &
* block) because they are handled in an uniform way by the
* chardev/blockdev subsystems
* @note As a consequence, FS code can safely assume that "this" is
* never a character or block device
*/
sos_ret_t (*close_opened_file)(struct sos_fs_node * this,
struct sos_fs_opened_file * of);
/**
* This should hold the meta information for this node as needed by
* the FS instance.
*/
void * custom_data;
/** Hash linkage entry for this FS node in the nodecache
dictionary */
struct sos_hash_linkage hlink_nodecache;
/** Linkage to list the dirty nodes of the given FS */
struct sos_fs_node *prev_dirty, *next_dirty;
};
/**
* The list of methods implementing the basic VFS operations on the
* given struct sos_fs_node
*
* @see sos_fs_node::ops_file
*/
struct sos_fs_node_ops_file
{
/**
* Change size of file
*
* @note Optional, may block. Appropriate locking MUST be implemented
*/
sos_ret_t (*truncate)(struct sos_fs_node *this,
sos_lsoffset_t length);
/**
* Retrieve the status (eg size) of the file
*
* @note Mandatory, may block. Appropriate locking MUST be implemented
*/
sos_ret_t (*stat)(struct sos_fs_node * this,
struct sos_fs_stat * result);
/**
* Change the sos_fs_node::access_rights attribute
*
* @note Mandatory, may block. Appropriate locking MUST be implemented
*/
sos_ret_t (*chmod)(struct sos_fs_node * this,
sos_ui32_t new_access_rights);
/**
* Flush any change to the node back to the file system backing store
*
* @note Mandatory, may block. Appropriate locking MUST be implemented
*/
sos_ret_t (*sync)(struct sos_fs_node *this);
};
/**
* The list of methods implementing the basic VFS symlink operations
*
* @see sos_fs_node::ops_symlink
*/
struct sos_fs_node_ops_symlink
{
/**
* Used by the _kernel_ to resolve the symlinks. To change/create a
* symlink target, it is needed only from userland: the read/write
* methods are made for this
*
* @param target Pointer to the string representing the target's
* path, allocated for the fs_node's lifetime !
*
* @note Mandatory, may block. Appropriate locking MUST be implemented
*/
sos_ret_t (*expand)(struct sos_fs_node *this,
char const ** target,
sos_size_t * target_len);
};
/**
* The list of methods implementing the basic VFS directory operations
*
* @see sos_fs_node::ops_dir
*/
struct sos_fs_node_ops_dir
{
/**
* Look for the on-disk location of the sos_fs_node having the given
* name
*
* @note Mandatory, may block. Appropriate locking MUST be implemented
*/
sos_ret_t (*lookup)(struct sos_fs_node *this,
const char * name, sos_ui16_t namelen,
sos_ui64_t * result_storage_location);
/**
* Add a new reference in the current sos_fs_node to the on-disk
* location of the given sos_fs_node
*
* @note Responsible for updating this->ondisk_lnk_cnt
* @note Mandatory for writable directories, may block. Appropriate
* locking MUST be implemented
*/
sos_ret_t (*link)(struct sos_fs_node *this,
const struct sos_process *actor,
const char * entry_name, sos_ui16_t entry_namelen,
struct sos_fs_node * node);
/**
* Remove the entry in the current sos_fs_node for the on-disk
* location with the given name
*
* @note Responsible for updating this->ondisk_lnk_cnt
* @note Mandatory for writable directories, may block. Appropriate
* locking MUST be implemented
*/
sos_ret_t (*unlink)(struct sos_fs_node *this,
const struct sos_process *actor,
const char * entry_name, sos_ui16_t entry_namelen);
};
/**
* The data structure holding information and method related to a
* particular usage of a file. A so-called "struct file"
*
* This represents the kernel structure behind a "file descriptor" or
* behind a chdir/chroot. Among other things, it holds the methods
* responsible for reading/writing into the file, and for moving the
* file pointer (see @sos_fs_opened_file::position) inside it.
*/
struct sos_fs_opened_file
{
/** The process that opened the file/dir */
const struct sos_process * owner;
/**
* The reference to the sos_fs_nscache_node and, hence, to the underlying sos_fs_node.
*
* Used to cache the in-memory fs nodes
*/
struct sos_fs_nscache_node * direntry;
/** Use for memory-management */
sos_count_t ref_cnt;
/**
* Always > 0 (ie max size = 2^63-1 = 9.2 10^18). We make it
* "signed" here to limit its range. Because we must be able to
* seek to the begining of the file with SEEK_END and a negative
* offset, so the max size of the file must be reachable by a lseek
* offset
*
* @note reserved to filesystem instance code. Not modified nor used
* by fs.c
*/
sos_lsoffset_t position;
/**
* Incremented each time this opened file is modified
*
* Used to implement a readdir method resilient to
* creat/mkdir/rmdir/unlink
*/
sos_lcount_t generation;
/**
* @see SOS_FS_OPEN_* flags
*/
sos_ui32_t open_flags;
/** Operations common to all node types */
struct sos_fs_ops_opened_file * ops_file;
/** Operations specific to some node types */
union
{
/** when direntry->fs_node->type == SOS_FS_NODE_DIRECTORY */
struct sos_fs_ops_opened_dir * ops_dir;
/** when direntry->fs_node->type == SOS_FS_NODE_DEVICE_CHAR */
struct sos_fs_ops_opened_chardev * ops_chardev;
/** when direntry->fs_node->type == SOS_FS_NODE_DEVICE_BLOCK */
struct sos_fs_ops_opened_blockdev * ops_blockdev;
}; /* Anonymous union (gcc extension) */
/**
* Called upon fork() to duplicate all the opened files
*
* @note FS-specific EXCEPT for device special files (char &
* block) because they are handled in an uniform way by the
* chardev/blockdev subsystems
* @note As a consequence, FS code can safely assume that "this" is
* never a character or block device
*/
sos_ret_t (*duplicate)(struct sos_fs_opened_file *this,
const struct sos_process * for_owner,
struct sos_fs_opened_file **result);
void * custom_data;
};
/**
* Reference position for sos_fs_seek
*/
typedef enum { SOS_SEEK_SET=42,
SOS_SEEK_CUR=24,
SOS_SEEK_END=84 } sos_seek_whence_t;
/**
* The list of methods implementing the basic VFS opened file
* operations
*
* See the Unix manual pages, they basically form the interfaces to to
* these functions
*
* @see sos_fs_opened_file::ops_file
*/
struct sos_fs_ops_opened_file
{
/**
* @note Mandatory, may block. Appropriate locking MUST be implemented
* @note Please call sos_fs_mark_dirty() if disk contents is changed
*/
sos_ret_t (*seek)(struct sos_fs_opened_file *this,
sos_lsoffset_t offset,
sos_seek_whence_t whence,
/* out */ sos_lsoffset_t * result_position);
/**
* @note Mandatory, may block. Appropriate locking MUST be implemented
* @note Please call sos_fs_mark_dirty() if disk contents is changed
*/
sos_ret_t (*read)(struct sos_fs_opened_file *this,
sos_uaddr_t dest_buf,
sos_size_t * /* in/out */len);
/**
* @note Optional (might be NULL), may block. Appropriate locking
* MUST be implemented
* @note Please call sos_fs_mark_dirty() if disk contents is changed
*/
sos_ret_t (*write)(struct sos_fs_opened_file *this,
sos_uaddr_t src_buf,
sos_size_t * /* in/out */len);
/**
* @note Optional (might be NULL), may block. Appropriate locking
* MUST be implemented
* @note Please call sos_fs_mark_dirty() if disk contents is changed
*/
sos_ret_t (*mmap)(struct sos_fs_opened_file *this,
sos_uaddr_t *uaddr, sos_size_t size,
sos_ui32_t access_rights,
sos_ui32_t flags,
sos_luoffset_t offset);
/**
* @note Optional (might be NULL), may block. Appropriate locking
* MUST be implemented
* @note Please call sos_fs_mark_dirty() if disk contents is changed
*/
sos_ret_t (*fcntl)(struct sos_fs_opened_file *this,
int req_id,
sos_ui32_t req_arg /* Usually: sos_uaddr_t */);
};
/**
* The list of methods implementing the basic VFS opened character device
* operations
*
* @see sos_fs_opened_file::ops_file
*/
struct sos_fs_ops_opened_chardev
{
/**
* @note Optional (might be NULL), may block. Appropriate locking
* MUST be implemented
* @note Please call sos_fs_mark_dirty() if disk contents is changed
*/
sos_ret_t (*ioctl)(struct sos_fs_opened_file *this,
int req_id,
sos_ui32_t req_arg /* Usually: sos_uaddr_t */);
};
/**
* The list of methods implementing the basic VFS opened block device
* operations
*
* @see sos_fs_opened_file::ops_file
*/
struct sos_fs_ops_opened_blockdev
{
/**
* @note Optional (might be NULL), may block. Appropriate locking
* MUST be implemented
* @note Please call sos_fs_mark_dirty() if disk contents is changed
*/
sos_ret_t (*ioctl)(struct sos_fs_opened_file *this,
int req_id,
sos_ui32_t req_arg /* Usually: sos_uaddr_t */);
};
/** Data structure that is to be filled by readdir */
struct sos_fs_dirent
{
sos_ui64_t storage_location;
sos_si64_t offset_in_dirfile;
sos_ui32_t type;
sos_ui16_t namelen;
#define SOS_FS_DIRENT_NAME_MAXLEN 128
char name[SOS_FS_DIRENT_NAME_MAXLEN];
};
/**
* The list of methods implementing the basic VFS opened directory
* operations
*
* @see sos_fs_opened_file::ops_file
*/
struct sos_fs_ops_opened_dir
{
/**
* Each time it is called, responsible for filling the sos_fs_dirent
* structure, return -SOS_ENOENT when done.
*
* @note Mandatory, may block. Appropriate locking MUST be implemented
* @note Please call sos_fs_mark_dirty() if disk contents is changed
*/
sos_ret_t (*readdir)(struct sos_fs_opened_file *this,
struct sos_fs_dirent * result);
};
/**
* Used by the stat calls
*
* @see sos_fs_node_ops_file::stat
*/
struct sos_fs_stat
{
struct sos_fs_dev_id_t st_rdev;
sos_fs_node_type_t st_type;
sos_ui64_t st_storage_location;
sos_ui32_t st_access_rights;
sos_count_t st_nlink;
sos_si64_t st_size;
};
/**
* Used by the statvfs calls
*
* @see sos_fs_manager_instance::statfs
*/
struct sos_fs_statfs
{
struct sos_fs_dev_id_t f_rdev;
sos_size_t f_sz_total; /**< Total size */
sos_size_t f_sz_free; /**< Size left on device */
sos_count_t f_node_total;/**< Total allocatable FS nodes */
sos_count_t f_node_avail;/**< Number of available free FS nodes */
sos_ui32_t f_flags;
};
/**
* Must be called AFTER the FS manager types needed to mount the root
* filesystem have been registered
*/
sos_ret_t sos_fs_subsystem_setup(const char * root_device,
const char * fs_type,
const char * mount_args,
struct sos_fs_manager_instance ** result_rootfs);
/* ***************************************************************
* The Following functions are relatively standard
*
* @see Unix manual pages for details
*/
/**
* mount a file system
*
* @param actor process calling mount
* @param _src_path(len) may be NULL (as for virtfs or /proc)
* @fsname the name of the filesystem type to mount
* @args any args passed to the sos_fs_manager_type::mount method
* @result_fs the resulting filesystem instance
*/
sos_ret_t sos_fs_mount(struct sos_process * actor,
const char * _src_path,
sos_size_t _src_pathlen,
const char * _dst_path,
sos_size_t _dst_pathlen,
const char * fsname,
sos_ui32_t mountflags,
const char * args,
struct sos_fs_manager_instance ** /*out*/result_fs);
/**
* unmount the filesystem at the given location
*/
sos_ret_t sos_fs_umount(struct sos_process * actor,
const char * _mountpoint_path,
sos_size_t _mountpoint_pathlen);
/**
* Flush all the dirty nodes of all the FS to disk
*/
sos_ret_t sos_fs_sync_all_fs(void);
/**
* Retrieve filesystem status, or return -SOS_ENOSYS if filesystem
* cannot report this
*/
sos_ret_t sos_fs_vfstat(const struct sos_process * actor,
const char * _path,
sos_size_t _pathlen,
struct sos_fs_statfs * result);
/**
* Open flags
*/
#define SOS_FS_OPEN_EXCL (1 << 0)
#define SOS_FS_OPEN_CREAT (1 << 1)
#define SOS_FS_OPEN_TRUNC (1 << 2)
#define SOS_FS_OPEN_NOFOLLOW (1 << 3)
#define SOS_FS_OPEN_DIRECTORY (1 << 4) /* Incompatible with CREAT/TRUNC */
#define SOS_FS_OPEN_SYNC (1 << 5)
#define SOS_FS_OPEN_CLOSEONEXEC (1 << 6) /* By default, files are kept
open upon an exec() */
#define SOS_FS_OPEN_READ (1 << 16)
#define SOS_FS_OPEN_WRITE (1 << 17)
/**
* FS access rights
*/
#define SOS_FS_S_IRUSR 00400
#define SOS_FS_S_IWUSR 00200
#define SOS_FS_S_IXUSR 00100
#define SOS_FS_S_IRWXALL 07777 /* For symlinks */
sos_ret_t sos_fs_open(const struct sos_process *owner,
const char *_path,
sos_size_t _pathlen,
sos_ui32_t open_flags,
sos_ui32_t creat_access_rights,
struct sos_fs_opened_file ** of);
sos_ret_t sos_fs_close(struct sos_fs_opened_file * of);
sos_ret_t sos_fs_read(struct sos_fs_opened_file * of,
sos_uaddr_t dest_buf,
sos_size_t * /* in/ou */len);
sos_ret_t sos_fs_readdir(struct sos_fs_opened_file * of,
struct sos_fs_dirent * result);
sos_ret_t sos_fs_write(struct sos_fs_opened_file * of,
sos_uaddr_t src_buf,
sos_size_t * /* in/out */len);
sos_ret_t sos_fs_seek(struct sos_fs_opened_file *of,
sos_lsoffset_t offset,
sos_seek_whence_t whence,
sos_lsoffset_t * result_position);
sos_ret_t sos_fs_ftruncate(struct sos_fs_opened_file *of,
sos_lsoffset_t length);
sos_ret_t sos_fs_mmap(struct sos_fs_opened_file *of,
sos_uaddr_t *uaddr, sos_size_t size,
sos_ui32_t access_rights,
sos_ui32_t flags,
sos_luoffset_t offset);
sos_ret_t sos_fs_fsync(struct sos_fs_opened_file * of);
sos_ret_t sos_fs_fcntl(struct sos_fs_opened_file *of,
int req_id,
sos_ui32_t req_arg /* Usually: sos_uaddr_t */);
sos_ret_t sos_fs_ioctl(struct sos_fs_opened_file *of,
int req_id,
sos_ui32_t req_arg /* Usually: sos_uaddr_t */);
sos_ret_t sos_fs_creat(const struct sos_process * creator,
const char * _path,
sos_size_t _pathlen,
sos_ui32_t access_rights);
sos_ret_t sos_fs_link(const struct sos_process * creator,
const char * _old_path,
sos_size_t _old_pathlen,
const char * _dest_path,
sos_size_t _dest_pathlen);
sos_ret_t sos_fs_rename(const struct sos_process * creator,
const char * _old_path,
sos_size_t _old_pathlen,
const char * _dest_path,
sos_size_t _dest_pathlen);
sos_ret_t sos_fs_unlink(const struct sos_process * actor,
const char * _path,
sos_size_t _pathlen);
sos_ret_t sos_fs_symlink(const struct sos_process * creator,
const char * _path,
sos_size_t _pathlen,
sos_uaddr_t symlink_target,
sos_size_t symlink_target_len);
sos_ret_t sos_fs_mknod(const struct sos_process * creator,
const char * _path,
sos_size_t _pathlen,
sos_fs_node_type_t type /* only block/char allowed */,
sos_ui32_t access_rights,
const struct sos_fs_dev_id_t * devid);
sos_ret_t sos_fs_mkdir(const struct sos_process * creator,
const char * _path,
sos_size_t _pathlen,
sos_ui32_t access_rights);
sos_ret_t sos_fs_rmdir(const struct sos_process * actor,
const char * _path,
sos_size_t _pathlen);
sos_ret_t sos_fs_chmod(const struct sos_process * actor,
const char * _path,
sos_size_t _pathlen,
sos_ui32_t access_rights);
sos_ret_t sos_fs_stat(const struct sos_process * actor,
const char * _path,
sos_size_t _pathlen,
int nofollow,
struct sos_fs_stat * result);
/* ***************************************************************
* Restricted functions reserved to FS code and block/char devices
*/
/**
* Function to be called when proposing a new File system type
*/
sos_ret_t sos_fs_register_fs_type(struct sos_fs_manager_type * fstype);
sos_ret_t sos_fs_unregister_fs_type(struct sos_fs_manager_type * fstype);
/**
* Marthe given file as dirty, for FS supporting deferred write access
* mode
*/
sos_ret_t sos_fs_mark_dirty(struct sos_fs_opened_file * of);
/**
* Helper function to be called from the mount() method of the FS
* instance code. Responsible for creating and updating the "root"
* field of the FS instance structure and for connecting this FS in
* the nscache
* @param root_fsnode The root of the FS being mounted
*/
sos_ret_t sos_fs_register_fs_instance(struct sos_fs_manager_instance * fs,
struct sos_fs_node * root_fsnode);
/**
* Helper function to be called from the umount() method of the FS
* instance code. Responsible for unregistering the instance from the
* FS type's instances list and for disconnecting this mountpoint in
* the nscache.
*/
sos_ret_t sos_fs_unregister_fs_instance(struct sos_fs_manager_instance * fs);
/* ***************************************************************
* Restricted functions reserved to syscall.c
*/
sos_ret_t sos_fs_ref_opened_file(struct sos_fs_opened_file * of);
sos_ret_t _sos_fs_unref_opened_file(struct sos_fs_opened_file ** of);
#define sos_fs_unref_opened_file(f) _sos_fs_unref_opened_file(&(f))
/* ***************************************************************
* Restricted functions to be used only by fs_nscache.c
*/
sos_ret_t sos_fs_ref_fsnode(struct sos_fs_node * fsnode);
sos_ret_t _sos_fs_unref_fsnode(struct sos_fs_node * fsnode);
#define sos_fs_unref_fsnode(n) \
({ sos_ret_t __retval = _sos_fs_unref_fsnode(n); (n)=NULL; __retval; })
/* ***************************************************************
* Restricted functions reserved to process.c and main.c:start_init()
*/
sos_ret_t sos_fs_new_opened_file(const struct sos_process * proc,
struct sos_fs_nscache_node * nsnode,
sos_ui32_t open_flags,
struct sos_fs_opened_file ** result_of);
sos_ret_t sos_fs_duplicate_opened_file(struct sos_fs_opened_file * src_of,
const struct sos_process * dst_proc,
struct sos_fs_opened_file ** result_of);
/**
* Generic fcntl function that can be called from inside the FS's
* fcntl method. It will handle the following fcntl commands:
* - F_DUPFD
* - F_GETFD
* - F_SETFD
* - F_GETFL
* - F_SETFL
* Any other command will lead to a -SOS_ENOSUP return value.
* It will take care not to change anything besides the fs.h structures.
*/
sos_ret_t sos_fs_basic_fcntl_helper(struct sos_fs_opened_file * src_of,
int req_id, sos_ui32_t req_arg);
#endif /* _SOS_FS_H_ */