1141 lines
36 KiB
C
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_ */
|