sos-code-article10/sos/fs_nscache.h

285 lines
9.2 KiB
C

/* Copyright (C) 2005 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_NSCACHE_H_
#define _SOS_FS_NSCACHE_H_
/**
* @file fs_nscache.h
*
* FS Namespace cache (aka file hierarchy) management. Internal API
* reserved to fs.c and to the FS managers ! See fs.c for details and
* role of this subsystem in the whole VFS.
*
* We keep the usual filesystem semantics of a "file hierarchy":
*
* parent0
* / \
* child1 child2
* / \ \
* child1a child1b child2a
*
* The system allows that different children actually reference the
* same "on-disk" node (sos_fs_node). For example: child1a and child2a
* might reference the same sos_fs_node: this represents a so-called
* "hard link".
*
* The functions of this module are in charge of updating the nscache
* nodes and their reference count. They don't influence the other
* subsystems (apart from the sos_fs_nscache_unref_node() function
* which can unreference the underlying sos_fs_node).
*
* Note: only the nscache nodes that are actually used or those that
* are their parents (ie in the path from these nodes to the global
* root) will remain in memory. The others will be destroyed as soon
* as they are not needed anymore. For example, il I do a
* stat("/mnt/toto/titi.txt", & st), all the nscache nodes from "/" to
* "titi.txt" will be allocated, the stat performed, and all of them
* will be destroyed. We could imagine a real "cache" here to avoid
* these bursts of allocations/deallocations, by keeping the last
* accessed nodes aside when they are not referenced anymore (in a
* hash table for example, the key being {parent nscache node address,
* child name}).
*
* Note about mountpoints: When a FS is mounted in, say "/mnt", the
* nscache node of the new FS is registered neither as its child nor
* as its parent, but as a kind of "brother" of /mnt. As seen from the
* global root ("/"), "mnt" in a direct child and the mounted root is
* its brother. But, once mounted, as seen from a child node
* "/mnt/toto", the mounted root is seen as the direct parent of
* /mnt/toto and "mnt" is seen as its brother. That is, each time we
* try to resolve (lookup) the children on a mountpoint, we must
* "follow" the mountchain. In the previous example, multiple
* successive FS could be mounted on the same "/mnt".
*/
#include <sos/types.h>
#include <sos/errno.h>
/**
* Opaque structure defined in fs_nscache.c
*
* Essentially contains:
* - a name (allocated in-place)
* - a reference to the associated FS node (struct sos_fs_node)
* - a reference to the parent nscache node (if any)
* - a list of pointers to the children nscache nodes (for directories)
*/
struct sos_fs_nscache_node;
#include "fs.h"
/**
* Support for non-0 terminated strings (Pascal-style). Useful to
* prevent from altering the contents of the string in order to split
* pathnames into components (@see sos_fs_pathname_split_path)
*/
struct sos_fs_pathname
{
const char * contents;
sos_size_t length;
};
sos_ret_t sos_fs_nscache_subsystem_setup(void);
/**
* Lookup the given entry in the given nsnode. The lookup is limited
* to the children entries that are already in memory. When this
* lookup fails, this simply means that the entry is not already in
* memory, and has to be resolved using disk accesses (@see
* fs_lookup_node in fs.c)
*
* @param cur_nsnode The node in which we are looking for the entry
* @param root_node The base node beyond which lookup must not go (to
* support chroot): a kind of "barrier"
*
* @param result_nsnode The nsnode for the given entry (set only when
* the return value is SOS_OK)
*
* @return error if the entry could not be found in the nsnode
* directory. OK otherwise, and *result_nsnode is set.
*
* @note The symlinks are NOT expanded. The mountpoints ARE followed.
* @note result_nsnode is a NEW reference to the node. It should be
* unreferenced when unused
*/
sos_ret_t
sos_fs_nscache_lookup(struct sos_fs_nscache_node * cur_nsnode,
const struct sos_fs_pathname * node_name,
const struct sos_fs_nscache_node * root_nsnode,
struct sos_fs_nscache_node ** result_nsnode);
/**
* Add a new child node for the given parent, for the given fs_node
*
* @param parent might be NULL, meaning that the node is the root of a
* mounted filesystem
*
* @note The new node has the value 0 for the opened_file and
* mount_chain counters
* @note result_nsnode is a NEW reference to the node. It should be
* unreferenced when unused
*/
sos_ret_t
sos_fs_nscache_add_new_child_node(struct sos_fs_nscache_node * parent,
const struct sos_fs_pathname * node_name,
struct sos_fs_node * fsnode,
struct sos_fs_nscache_node ** result_nsnode);
/**
* Add a new child node for the given parent, for the given already
* existing nsnode (with no parent !)
*
* @param parent can not be NULL
*
* @note nsnode should NOT have any parent
*/
sos_ret_t
sos_fs_nscache_add_existing_child_node(struct sos_fs_nscache_node * parent,
const struct sos_fs_pathname * node_name,
struct sos_fs_nscache_node * nsnode);
/**
* Disconnect the given node from its parent, if any
* @note reference count of nsnode is NOT modified
*/
sos_ret_t
sos_fs_nscache_disconnect_node(struct sos_fs_nscache_node * nsnode);
/**
* Register the given root of a new file system (mounted_root) in the
* mountpoint chain located at mountpoint, ie build the mountchain.
*/
sos_ret_t
sos_fs_nscache_mount(struct sos_fs_nscache_node * mountpoint,
struct sos_fs_nscache_node * mounted_root);
/**
* Break the mountchain at the given mounted root, making sure that
* this nscache node is not reference by any opened file or child node
* anymore.
*/
sos_ret_t
sos_fs_nscache_umount(struct sos_fs_nscache_node * mounted_root);
/** Return true if the node is involved in any mountchain */
sos_bool_t
sos_fs_nscache_is_mountnode(const struct sos_fs_nscache_node * nsnode);
/*
* Accessor functions
*/
/**
* Return the FS node of the given nscache node.
*
* @note The FS node returned is NOT newly referenced
*/
struct sos_fs_node *
sos_fs_nscache_get_fs_node(const struct sos_fs_nscache_node * nsnode);
/**
* Return the parent nscache node of the given nscache node.
*
* @note The nscache node returned is NOT newly referenced
*/
sos_ret_t
sos_fs_nscache_get_parent(const struct sos_fs_nscache_node * nsnode,
struct sos_fs_nscache_node ** result_parent);
sos_ret_t
sos_fs_nscache_get_name(const struct sos_fs_nscache_node * nsnode,
struct sos_fs_pathname * result_pathname);
/**
* Return the value of the reference count for the given nscache node
*/
sos_ret_t
sos_fs_nscache_get_ref_cnt(const struct sos_fs_nscache_node * nsnode);
sos_ret_t
sos_fs_nscache_register_opened_file(struct sos_fs_nscache_node * nsnode,
struct sos_fs_opened_file * of);
sos_ret_t sos_fs_nscache_ref_node(struct sos_fs_nscache_node * nsnode);
sos_ret_t _sos_fs_nscache_unref_node(struct sos_fs_nscache_node ** nsnode);
#define sos_fs_nscache_unref_node(n) _sos_fs_nscache_unref_node(& (n))
/*
* Functions reserved to sos_fs_manager_type::mount() and
* sos_fs_manager_type::umount()
*/
#define sos_fs_nscache_create_mounted_root(fsnode,result_nsnode) \
sos_fs_nscache_add_new_child_node(NULL, NULL, (fsnode), (result_nsnode))
/*
* Pathname manipulation functions
*/
sos_bool_t fs_pathname_iseq(const struct sos_fs_pathname * p1,
const struct sos_fs_pathname * p2);
/**
* Remove any leading slash from the path
*
* @Return TRUE when slashes were found at the begining
*/
sos_bool_t sos_fs_pathname_eat_slashes(const struct sos_fs_pathname * path,
struct sos_fs_pathname * result);
/**
* Transform "a/b/c" into { first_component="a" remaining_path="/b/c" }
* Transform "/a/b/c" into { first_component="a" remaining_path="/b/c" }
* Transform "////a////b/c" into { first_component="a" remaining_path="////b/c" }
* Transform "a" into { first_component="a" remaining_path="" }
* Transform "/a" into { first_component="a" remaining_path="" }
* Transform "a/" into { first_component="a" remaining_path="" }
* Transform "/a/" into { first_component="a" remaining_path="" }
*
* @Return TRUE when slashes after first component were found. In the
* previous example: true everywhere except for the path "a" and "/a"
*/
sos_bool_t
sos_fs_pathname_split_path(const struct sos_fs_pathname * path,
struct sos_fs_pathname * result_first_component,
struct sos_fs_pathname * result_remaining_path);
#endif /* _SOS_FS_NSCACHE_H_ */