⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fs_nscache.c

📁 Simple Operating Systems (简称SOS)是一个可以运行在X86平台上(包括QEMU
💻 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. */#include <sos/assert.h>#include <sos/list.h>#include <sos/kmem_slab.h>#include <sos/kmalloc.h>#include "fs_nscache.h"/** * A so-called "dentry" / "nsnode" structure. Used to make the * "in-memory" representation of the file system files/dir/devices * that have been used up to now */struct sos_fs_nscache_node{  /** The reference to the associated sos_fs_node */  struct sos_fs_node     *fs_node;  struct sos_fs_pathname name;  /** Number of references to that node, reference from parent (if      any) is EXCLUDED */  sos_count_t ref_cnt;  /*   * Ued to chain the mounted filesystem   */  /** If this node is a mountpoint (a file system is mounted on it):      reference to the filesystem mounted on it */  struct sos_fs_nscache_node *mounted_root;  /** If this node is the root of a mounted filesystem: reference to      the mountpoint where it is mounted on */  struct sos_fs_nscache_node *mountpoint;  /** ".." */  struct sos_fs_nscache_node *parent;  /** List of the already known children */  struct sos_fs_nscache_node *children;    /** Other children for the same parent */  struct sos_fs_nscache_node *siblings_prev, *siblings_next;};/** The cache of nscache_node objects */static struct sos_kslab_cache * cache_of_nscache_nodes;sos_ret_t sos_fs_nscache_subsystem_setup(){  cache_of_nscache_nodes    = sos_kmem_cache_create("fs_nscache",			    sizeof(struct sos_fs_nscache_node),			    3, 0,			    SOS_KSLAB_CREATE_MAP | SOS_KSLAB_CREATE_ZERO);  if (! cache_of_nscache_nodes)    return -SOS_ENOMEM;  return SOS_OK;};sos_bool_tsos_fs_pathname_eat_slashes(const struct sos_fs_pathname * path,			    struct sos_fs_pathname * result){  sos_bool_t retval = FALSE;  result->contents = path->contents;  result->length   = path->length;  while (result->length > 0)    {      if (*result->contents != '/')	break;      result->contents ++;      result->length --;      retval = TRUE;    }  if(result->length <= 0)    result->contents = NULL;  return retval;}static sos_bool_tsos_fs_pathname_eat_non_slashes(const struct sos_fs_pathname * path,				struct sos_fs_pathname * result){  sos_bool_t retval = FALSE;  result->contents = path->contents;  result->length   = path->length;  while (result->length > 0)    {      if (*result->contents == '/')	break;      result->contents ++;      result->length --;      retval = TRUE;    }  if(result->length <= 0)    result->contents = NULL;  return retval;}sos_bool_tsos_fs_pathname_split_path(const struct sos_fs_pathname * path,			   struct sos_fs_pathname * result_first_component,			   struct sos_fs_pathname * result_remaining_path){  result_first_component->contents = path->contents;  result_first_component->length   = path->length;  /* Skip any leading slash */  sos_fs_pathname_eat_slashes(result_first_component,			      result_first_component);  /* Extract the first component */  sos_fs_pathname_eat_non_slashes(result_first_component,				  result_remaining_path);  SOS_ASSERT_FATAL(result_remaining_path->length >= 0);  result_first_component->length -= result_remaining_path->length;  /* Return true if there is something left (at least one slash) */  return (result_remaining_path->length > 0);}sos_bool_t fs_pathname_iseq(const struct sos_fs_pathname * p1,			    const struct sos_fs_pathname * p2){  if (!p1->contents)    SOS_ASSERT_FATAL(p1->length == 0);  if (!p2->contents)    SOS_ASSERT_FATAL(p2->length == 0);  if (p1->length != p2->length)    return FALSE;  if (p1->length == 0)    return TRUE;  return (0 == memcmp(p1->contents, p2->contents, p1->length));}#define fs_pathname_isstr(str,path) \  ({ struct sos_fs_pathname _s; _s.contents = str; _s.length = sizeof(str)-1; \     fs_pathname_iseq(&_s, (path)); })struct sos_fs_node *sos_fs_nscache_get_fs_node(const struct sos_fs_nscache_node * nsnode){  return nsnode->fs_node;}sos_ret_tsos_fs_nscache_get_parent(const struct sos_fs_nscache_node * nsnode,			  struct sos_fs_nscache_node ** result_parent){  *result_parent = nsnode->parent;  if (*result_parent)    return SOS_OK;  return -SOS_ENOENT;}sos_ret_tsos_fs_nscache_get_name(const struct sos_fs_nscache_node * nsnode,			struct sos_fs_pathname * result_pathname){  result_pathname->contents = nsnode->name.contents;  result_pathname->length   = nsnode->name.length;  return SOS_OK;}sos_ret_tsos_fs_nscache_get_ref_cnt(const struct sos_fs_nscache_node * nsnode){  return nsnode->ref_cnt;}sos_ret_tsos_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){  if (fs_pathname_isstr(".", node_name))    {      *result_nsnode = cur_nsnode;    }  else if (fs_pathname_isstr("..", node_name))    {      /* Effectively go up only if we did not reach a root node */      if (cur_nsnode == root_nsnode) /* did reach chroot */	{	  /* Simply stay here */	  *result_nsnode = cur_nsnode;	}      else	{	  /* If current node is a mounted FS, rewind the mountpoint	     chain */	  for ( ; cur_nsnode->mountpoint ; cur_nsnode = cur_nsnode->mountpoint)	    /* nop */ ;	  /* Now go up to parent */	  SOS_ASSERT_FATAL(NULL != cur_nsnode->parent);	  *result_nsnode = cur_nsnode->parent;	}      /* Update the nscache_node result */      sos_fs_nscache_ref_node(*result_nsnode);      return SOS_OK;    }  else    {      /* Normal lookup: we iterate over the list of children nscache	 nodes */      int nb_children;      struct sos_fs_nscache_node * child;      /* Lookup the child node with the correct name, if any */      list_foreach_named(cur_nsnode->children,			 child, nb_children,			 siblings_prev, siblings_next)	{	  struct sos_fs_node * fs_node = cur_nsnode->fs_node;	  	  if (fs_node->fs->nsnode_same_name)	    {	      if (fs_node->fs->		    nsnode_same_name(child->name.contents,				     child->name.length,				     node_name->contents,				     node_name->length))		break;	    }	  else	    if (fs_pathname_iseq(& child->name,				 node_name))	      break;	}      /* Did not find it ! */      if (! list_foreach_early_break(cur_nsnode->children,				     child, nb_children))	return -SOS_ENOENT;      /* Yes, found it ! */      *result_nsnode = child;    }  /* Found it. Now, Follow the mountpoint chain, if any */  for ( ; (*result_nsnode)->mounted_root ;	*result_nsnode = (*result_nsnode)->mounted_root)    /* nop */ ;  /* Update the nscache_node result */  sos_fs_nscache_ref_node(*result_nsnode);  return SOS_OK;}sos_ret_t sos_fs_nscache_ref_node(struct sos_fs_nscache_node * nsnode){  SOS_ASSERT_FATAL(nsnode->ref_cnt > 0);  nsnode->ref_cnt ++;  return SOS_OK;}/* Eventually collapses a whole list of nsnodes (non recursive) */sos_ret_t _sos_fs_nscache_unref_node(struct sos_fs_nscache_node ** nsnode){  struct sos_fs_nscache_node * to_delete = NULL, *node;  node = *nsnode;  *nsnode = NULL;  while (node)    {      /* Unreference this node */      SOS_ASSERT_FATAL(node->ref_cnt > 0);      node->ref_cnt --;      /* Is it a good candidate for deletion ? */      if (node->ref_cnt > 0)	break; /* No */      if (node->parent)	{	  struct sos_fs_nscache_node * parent = node->parent;	  SOS_ASSERT_FATAL(node->parent->ref_cnt >= 1);	  list_delete_named(parent->children, node,			    siblings_prev, siblings_next);	  /* The parent lost one child: next iteration will decrement	     ths parent's ref cnt */	}      /* Add to the list of elements to suppress */      list_add_tail_named(to_delete, node, siblings_prev, siblings_next);      /* Now look if parent (if any) can be destroyed */      node = node->parent;    }  /* Now destroy all the elements gathered */  while (! list_is_empty_named(to_delete, siblings_prev, siblings_next))    {      node = list_pop_head_named(to_delete, siblings_prev, siblings_next);      sos_fs_unref_fsnode(node->fs_node);      sos_kfree((sos_vaddr_t)node);    }  return SOS_OK;}sos_ret_tsos_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){  struct sos_fs_nscache_node * nsnode;  /* Allocate a new nscache node from slab */  nsnode = (struct sos_fs_nscache_node*)    sos_kmem_cache_alloc(cache_of_nscache_nodes,			 SOS_KSLAB_ALLOC_ATOMIC);  if (! nsnode)    return -SOS_ENOMEM;  /* Allocate a new memory chunk to hold the node's name */  if (node_name && (node_name->length > 0))    {      char * contents = (char*) sos_kmalloc(node_name->length,					    SOS_KMALLOC_ATOMIC);      if (! contents)	{	  sos_kfree((sos_vaddr_t)nsnode);	  return -SOS_ENOMEM;	}      memcpy(contents, node_name->contents, node_name->length);      nsnode->name.contents = contents;      nsnode->name.length   = node_name->length;    }  /* Now initialize the new node's fields */  nsnode->ref_cnt = 1;  sos_fs_ref_fsnode(fsnode);  nsnode->fs_node = fsnode;  /* Register this node as a child of its parent, if any */  nsnode->parent  = parent;  if (parent)    {      sos_fs_nscache_ref_node(parent);      list_add_head_named(parent->children, nsnode,			  siblings_prev, siblings_next);    }  *result_nsnode = nsnode;  return SOS_OK;}sos_ret_tsos_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){  SOS_ASSERT_FATAL(nsnode->parent == NULL);  /* If the node already had a name, suppress it */  if (NULL != nsnode->name.contents)    {      sos_kfree((sos_vaddr_t)nsnode->name.contents);    }  memset(& nsnode->name, 0x0, sizeof(struct sos_fs_pathname));  /* Allocate a new memory chunk to hold the node's name */  if (node_name && (node_name->length > 0))    {      char * contents = (char*) sos_kmalloc(node_name->length,					    SOS_KMALLOC_ATOMIC);      if (! contents)	{	  sos_kfree((sos_vaddr_t)nsnode);	  return -SOS_ENOMEM;	}      memcpy(contents, node_name->contents, node_name->length);      nsnode->name.contents = contents;      nsnode->name.length   = node_name->length;    }  /* Register this node as a child of its parent, if any */  nsnode->parent  = parent;  if (parent)    {      sos_fs_nscache_ref_node(parent);      list_add_head_named(parent->children, nsnode,			  siblings_prev, siblings_next);    }  return SOS_OK;}sos_ret_tsos_fs_nscache_disconnect_node(struct sos_fs_nscache_node * nsnode){  if (! nsnode->parent)    return SOS_OK;  list_delete_named(nsnode->parent->children, nsnode,		    siblings_prev, siblings_next);  sos_fs_nscache_unref_node(nsnode->parent);  nsnode->parent = NULL;  return SOS_OK;}sos_ret_tsos_fs_nscache_register_opened_file(struct sos_fs_nscache_node * nsnode,				    struct sos_fs_opened_file * of){  of->direntry = nsnode;  sos_fs_nscache_ref_node(nsnode);  return SOS_OK;}sos_ret_tsos_fs_nscache_mount(struct sos_fs_nscache_node * mountpoint,		     struct sos_fs_nscache_node * mounted_root){  SOS_ASSERT_FATAL(NULL == mountpoint->mounted_root);  SOS_ASSERT_FATAL(NULL == mounted_root->mountpoint);  mountpoint->mounted_root = mounted_root;  mounted_root->mountpoint = mountpoint;  sos_fs_nscache_ref_node(mountpoint);  sos_fs_nscache_ref_node(mounted_root);    return SOS_OK;}sos_ret_tsos_fs_nscache_umount(struct sos_fs_nscache_node * mounted_root){  struct sos_fs_manager_instance *fs;  SOS_ASSERT_FATAL(NULL != mounted_root->mountpoint);  SOS_ASSERT_FATAL(mounted_root->mountpoint->mounted_root == mounted_root);  /* No FS should be mounted on the mounted root to umount */  SOS_ASSERT_FATAL(NULL == mounted_root->mounted_root);  /* The mounted root should have its own reference, plus a reference     from the mountpoint and from the fs instance */  SOS_ASSERT_FATAL(mounted_root->ref_cnt >= 3);  if (mounted_root->ref_cnt != 3)    return -SOS_EBUSY;  fs = mounted_root->fs_node->fs;  SOS_ASSERT_FATAL(NULL != fs);  SOS_ASSERT_FATAL(fs->root == mounted_root);  /* Undo the mountpoint <-> mounted_root mutual reference */  mounted_root->mountpoint->mounted_root = NULL;  sos_fs_nscache_unref_node(mounted_root->mountpoint);  mounted_root->mountpoint = NULL;  sos_fs_nscache_unref_node(mounted_root);  /* Undo the fs->root -> mounted_root reference */  sos_fs_nscache_unref_node(fs->root);  return SOS_OK;}sos_bool_tsos_fs_nscache_is_mountnode(const struct sos_fs_nscache_node * nsnode){  return ( (NULL != nsnode->mounted_root) || (NULL != nsnode->mountpoint) );}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -