SimpleOS

LXR

Navigation



Site hébergé par : enix

The LXR Cross Referencer for SOS

source navigation ]
diff markup ]
identifier search ]
general search ]
 
 
Article:1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 6.5 ] [ 7 ] [ 7.5 ] [ 8 ] [ 9 ] [ 9.5 ]

001 /* Copyright (C) 2005      David Decotigny
002    Copyright (C) 2000-2005 The KOS Team (Thomas Petazzoni, David
003                            Decotigny, Julien Munier)
004 
005    This program is free software; you can redistribute it and/or
006    modify it under the terms of the GNU General Public License
007    as published by the Free Software Foundation; either version 2
008    of the License, or (at your option) any later version.
009    
010    This program is distributed in the hope that it will be useful,
011    but WITHOUT ANY WARRANTY; without even the implied warranty of
012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013    GNU General Public License for more details.
014    
015    You should have received a copy of the GNU General Public License
016    along with this program; if not, write to the Free Software
017    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
018    USA. 
019 */
020 
021 #include <sos/assert.h>
022 #include <sos/list.h>
023 #include <sos/kmem_slab.h>
024 #include <sos/kmalloc.h>
025 
026 #include "fs_nscache.h"
027 
028 
029 /**
030  * A so-called "dentry" / "nsnode" structure. Used to make the
031  * "in-memory" representation of the file system files/dir/devices
032  * that have been used up to now
033  */
034 struct sos_fs_nscache_node
035 {
036   /** The reference to the associated sos_fs_node */
037   struct sos_fs_node     *fs_node;
038 
039   struct sos_fs_pathname name;
040 
041   /** Number of references to that node, reference from parent (if
042       any) is EXCLUDED */
043   sos_count_t ref_cnt;
044 
045   /*
046    * Ued to chain the mounted filesystem
047    */
048 
049   /** If this node is a mountpoint (a file system is mounted on it):
050       reference to the filesystem mounted on it */
051   struct sos_fs_nscache_node *mounted_root;
052   /** If this node is the root of a mounted filesystem: reference to
053       the mountpoint where it is mounted on */
054   struct sos_fs_nscache_node *mountpoint;
055 
056   /** ".." */
057   struct sos_fs_nscache_node *parent;
058 
059   /** List of the already known children */
060   struct sos_fs_nscache_node *children;
061   
062   /** Other children for the same parent */
063   struct sos_fs_nscache_node *siblings_prev, *siblings_next;
064 };
065 
066 
067 /** The cache of nscache_node objects */
068 static struct sos_kslab_cache * cache_of_nscache_nodes;
069 
070 
071 sos_ret_t sos_fs_nscache_subsystem_setup()
072 {
073   cache_of_nscache_nodes
074     = sos_kmem_cache_create("fs_nscache",
075                             sizeof(struct sos_fs_nscache_node),
076                             3, 0,
077                             SOS_KSLAB_CREATE_MAP | SOS_KSLAB_CREATE_ZERO);
078   if (! cache_of_nscache_nodes)
079     return -SOS_ENOMEM;
080 
081   return SOS_OK;
082 };
083 
084 
085 sos_bool_t
086 sos_fs_pathname_eat_slashes(const struct sos_fs_pathname * path,
087                             struct sos_fs_pathname * result)
088 {
089   sos_bool_t retval = FALSE;
090 
091   result->contents = path->contents;
092   result->length   = path->length;
093   while (result->length > 0)
094     {
095       if (*result->contents != '/')
096         break;
097 
098       result->contents ++;
099       result->length --;
100       retval = TRUE;
101     }
102 
103   if(result->length <= 0)
104     result->contents = NULL;
105 
106   return retval;
107 }
108 
109 
110 static sos_bool_t
111 sos_fs_pathname_eat_non_slashes(const struct sos_fs_pathname * path,
112                                 struct sos_fs_pathname * result)
113 {
114   sos_bool_t retval = FALSE;
115 
116   result->contents = path->contents;
117   result->length   = path->length;
118   while (result->length > 0)
119     {
120       if (*result->contents == '/')
121         break;
122 
123       result->contents ++;
124       result->length --;
125       retval = TRUE;
126     }
127 
128   if(result->length <= 0)
129     result->contents = NULL;
130 
131   return retval;
132 }
133 
134 
135 sos_bool_t
136 sos_fs_pathname_split_path(const struct sos_fs_pathname * path,
137                            struct sos_fs_pathname * result_first_component,
138                            struct sos_fs_pathname * result_remaining_path)
139 {
140   result_first_component->contents = path->contents;
141   result_first_component->length   = path->length;
142 
143   /* Skip any leading slash */
144   sos_fs_pathname_eat_slashes(result_first_component,
145                               result_first_component);
146 
147   /* Extract the first component */
148   sos_fs_pathname_eat_non_slashes(result_first_component,
149                                   result_remaining_path);
150   SOS_ASSERT_FATAL(result_remaining_path->length >= 0);
151   result_first_component->length -= result_remaining_path->length;
152 
153   /* Return true if there is something left (at least one slash) */
154   return (result_remaining_path->length > 0);
155 }
156 
157 
158 sos_bool_t fs_pathname_iseq(const struct sos_fs_pathname * p1,
159                             const struct sos_fs_pathname * p2)
160 {
161   if (!p1->contents)
162     SOS_ASSERT_FATAL(p1->length == 0);
163   if (!p2->contents)
164     SOS_ASSERT_FATAL(p2->length == 0);
165 
166   if (p1->length != p2->length)
167     return FALSE;
168 
169   if (p1->length == 0)
170     return TRUE;
171 
172   return (0 == memcmp(p1->contents, p2->contents, p1->length));
173 }
174 
175 
176 #define fs_pathname_isstr(str,path) \
177   ({ struct sos_fs_pathname _s; _s.contents = str; _s.length = sizeof(str)-1; \
178      fs_pathname_iseq(&_s, (path)); })
179 
180 
181 struct sos_fs_node *
182 sos_fs_nscache_get_fs_node(const struct sos_fs_nscache_node * nsnode)
183 {
184   return nsnode->fs_node;
185 }
186 
187 
188 sos_ret_t
189 sos_fs_nscache_get_parent(const struct sos_fs_nscache_node * nsnode,
190                           struct sos_fs_nscache_node ** result_parent)
191 {
192   *result_parent = nsnode->parent;
193   if (*result_parent)
194     return SOS_OK;
195   return -SOS_ENOENT;
196 }
197 
198 
199 sos_ret_t
200 sos_fs_nscache_get_name(const struct sos_fs_nscache_node * nsnode,
201                         struct sos_fs_pathname * result_pathname)
202 {
203   result_pathname->contents = nsnode->name.contents;
204   result_pathname->length   = nsnode->name.length;
205   return SOS_OK;
206 }
207 
208 
209 sos_ret_t
210 sos_fs_nscache_get_ref_cnt(const struct sos_fs_nscache_node * nsnode)
211 {
212   return nsnode->ref_cnt;
213 }
214 
215 
216 sos_ret_t
217 sos_fs_nscache_lookup(struct sos_fs_nscache_node * cur_nsnode,
218                       const struct sos_fs_pathname * node_name,
219                       const struct sos_fs_nscache_node * root_nsnode,
220                       struct sos_fs_nscache_node ** result_nsnode)
221 {
222   if (fs_pathname_isstr(".", node_name))
223     {
224       *result_nsnode = cur_nsnode;
225     }
226   else if (fs_pathname_isstr("..", node_name))
227     {
228       /* Effectively go up only if we did not reach a root node */
229       if (cur_nsnode == root_nsnode) /* did reach chroot */
230         {
231           /* Simply stay here */
232           *result_nsnode = cur_nsnode;
233         }
234       else
235         {
236           /* If current node is a mounted FS, rewind the mountpoint
237              chain */
238           for ( ; cur_nsnode->mountpoint ; cur_nsnode = cur_nsnode->mountpoint)
239             /* nop */ ;
240 
241           /* Now go up to parent */
242           SOS_ASSERT_FATAL(NULL != cur_nsnode->parent);
243           *result_nsnode = cur_nsnode->parent;
244         }
245 
246       /* Update the nscache_node result */
247       sos_fs_nscache_ref_node(*result_nsnode);
248       return SOS_OK;
249     }
250   else
251     {
252       /* Normal lookup: we iterate over the list of children nscache
253          nodes */
254       int nb_children;
255       struct sos_fs_nscache_node * child;
256 
257       /* Lookup the child node with the correct name, if any */
258       list_foreach_named(cur_nsnode->children,
259                          child, nb_children,
260                          siblings_prev, siblings_next)
261         {
262           struct sos_fs_node * fs_node = cur_nsnode->fs_node;
263           
264           if (fs_node->fs->nsnode_same_name)
265             {
266               if (fs_node->fs->
267                     nsnode_same_name(child->name.contents,
268                                      child->name.length,
269                                      node_name->contents,
270                                      node_name->length))
271                 break;
272             }
273           else
274             if (fs_pathname_iseq(& child->name,
275                                  node_name))
276               break;
277         }
278 
279       /* Did not find it ! */
280       if (! list_foreach_early_break(cur_nsnode->children,
281                                      child, nb_children))
282         return -SOS_ENOENT;
283 
284       /* Yes, found it ! */
285       *result_nsnode = child;
286     }
287 
288   /* Found it. Now, Follow the mountpoint chain, if any */
289   for ( ; (*result_nsnode)->mounted_root ;
290         *result_nsnode = (*result_nsnode)->mounted_root)
291     /* nop */ ;
292 
293   /* Update the nscache_node result */
294   sos_fs_nscache_ref_node(*result_nsnode);
295 
296   return SOS_OK;
297 }
298 
299 
300 sos_ret_t sos_fs_nscache_ref_node(struct sos_fs_nscache_node * nsnode)
301 {
302   SOS_ASSERT_FATAL(nsnode->ref_cnt > 0);
303   nsnode->ref_cnt ++;
304   return SOS_OK;
305 }
306 
307 
308 /* Eventually collapses a whole list of nsnodes (non recursive) */
309 sos_ret_t _sos_fs_nscache_unref_node(struct sos_fs_nscache_node ** nsnode)
310 {
311   struct sos_fs_nscache_node * to_delete = NULL, *node;
312 
313   node = *nsnode;
314   *nsnode = NULL;
315 
316   while (node)
317     {
318       /* Unreference this node */
319       SOS_ASSERT_FATAL(node->ref_cnt > 0);
320       node->ref_cnt --;
321 
322       /* Is it a good candidate for deletion ? */
323       if (node->ref_cnt > 0)
324         break; /* No */
325 
326       if (node->parent)
327         {
328           struct sos_fs_nscache_node * parent = node->parent;
329 
330           SOS_ASSERT_FATAL(node->parent->ref_cnt >= 1);
331 
332           list_delete_named(parent->children, node,
333                             siblings_prev, siblings_next);
334           /* The parent lost one child: next iteration will decrement
335              ths parent's ref cnt */
336         }
337 
338       /* Add to the list of elements to suppress */
339       list_add_tail_named(to_delete, node, siblings_prev, siblings_next);
340 
341       /* Now look if parent (if any) can be destroyed */
342       node = node->parent;
343     }
344 
345   /* Now destroy all the elements gathered */
346   while (! list_is_empty_named(to_delete, siblings_prev, siblings_next))
347     {
348       node = list_pop_head_named(to_delete, siblings_prev, siblings_next);
349       sos_fs_unref_fsnode(node->fs_node);
350       sos_kfree((sos_vaddr_t)node);
351     }
352 
353   return SOS_OK;
354 }
355 
356 
357 sos_ret_t
358 sos_fs_nscache_add_new_child_node(struct sos_fs_nscache_node * parent,
359                                   const struct sos_fs_pathname * node_name,
360                                   struct sos_fs_node * fsnode,
361                                   struct sos_fs_nscache_node ** result_nsnode)
362 {
363   struct sos_fs_nscache_node * nsnode;
364 
365   /* Allocate a new nscache node from slab */
366   nsnode = (struct sos_fs_nscache_node*)
367     sos_kmem_cache_alloc(cache_of_nscache_nodes,
368                          SOS_KSLAB_ALLOC_ATOMIC);
369   if (! nsnode)
370     return -SOS_ENOMEM;
371 
372   /* Allocate a new memory chunk to hold the node's name */
373   if (node_name && (node_name->length > 0))
374     {
375       char * contents = (char*) sos_kmalloc(node_name->length,
376                                             SOS_KMALLOC_ATOMIC);
377       if (! contents)
378         {
379           sos_kfree((sos_vaddr_t)nsnode);
380           return -SOS_ENOMEM;
381         }
382 
383       memcpy(contents, node_name->contents, node_name->length);
384       nsnode->name.contents = contents;
385       nsnode->name.length   = node_name->length;
386     }
387 
388   /* Now initialize the new node's fields */
389   nsnode->ref_cnt = 1;
390   sos_fs_ref_fsnode(fsnode);
391   nsnode->fs_node = fsnode;
392 
393   /* Register this node as a child of its parent, if any */
394   nsnode->parent  = parent;
395   if (parent)
396     {
397       sos_fs_nscache_ref_node(parent);
398       list_add_head_named(parent->children, nsnode,
399                           siblings_prev, siblings_next);
400     }
401 
402   *result_nsnode = nsnode;
403   return SOS_OK;
404 }
405 
406 
407 sos_ret_t
408 sos_fs_nscache_add_existing_child_node(struct sos_fs_nscache_node * parent,
409                                        const struct sos_fs_pathname * node_name,
410                                        struct sos_fs_nscache_node * nsnode)
411 {
412   SOS_ASSERT_FATAL(nsnode->parent == NULL);
413 
414   /* If the node already had a name, suppress it */
415   if (NULL != nsnode->name.contents)
416     {
417       sos_kfree((sos_vaddr_t)nsnode->name.contents);
418     }
419   memset(& nsnode->name, 0x0, sizeof(struct sos_fs_pathname));
420 
421   /* Allocate a new memory chunk to hold the node's name */
422   if (node_name && (node_name->length > 0))
423     {
424       char * contents = (char*) sos_kmalloc(node_name->length,
425                                             SOS_KMALLOC_ATOMIC);
426       if (! contents)
427         {
428           sos_kfree((sos_vaddr_t)nsnode);
429           return -SOS_ENOMEM;
430         }
431 
432       memcpy(contents, node_name->contents, node_name->length);
433       nsnode->name.contents = contents;
434       nsnode->name.length   = node_name->length;
435     }
436 
437 
438   /* Register this node as a child of its parent, if any */
439   nsnode->parent  = parent;
440   if (parent)
441     {
442       sos_fs_nscache_ref_node(parent);
443       list_add_head_named(parent->children, nsnode,
444                           siblings_prev, siblings_next);
445     }
446   return SOS_OK;
447 }
448 
449 
450 sos_ret_t
451 sos_fs_nscache_disconnect_node(struct sos_fs_nscache_node * nsnode)
452 {
453   if (! nsnode->parent)
454     return SOS_OK;
455 
456   list_delete_named(nsnode->parent->children, nsnode,
457                     siblings_prev, siblings_next);
458   sos_fs_nscache_unref_node(nsnode->parent);
459   nsnode->parent = NULL;
460 
461   return SOS_OK;
462 }
463 
464 
465 sos_ret_t
466 sos_fs_nscache_register_opened_file(struct sos_fs_nscache_node * nsnode,
467                                     struct sos_fs_opened_file * of)
468 {
469   of->direntry = nsnode;
470   sos_fs_nscache_ref_node(nsnode);
471   return SOS_OK;
472 }
473 
474 
475 sos_ret_t
476 sos_fs_nscache_mount(struct sos_fs_nscache_node * mountpoint,
477                      struct sos_fs_nscache_node * mounted_root)
478 {
479   SOS_ASSERT_FATAL(NULL == mountpoint->mounted_root);
480   SOS_ASSERT_FATAL(NULL == mounted_root->mountpoint);
481   mountpoint->mounted_root = mounted_root;
482   mounted_root->mountpoint = mountpoint;
483   sos_fs_nscache_ref_node(mountpoint);
484   sos_fs_nscache_ref_node(mounted_root);
485   
486   return SOS_OK;
487 }
488 
489 
490 sos_ret_t
491 sos_fs_nscache_umount(struct sos_fs_nscache_node * mounted_root)
492 {
493   struct sos_fs_manager_instance *fs;
494 
495   SOS_ASSERT_FATAL(NULL != mounted_root->mountpoint);
496   SOS_ASSERT_FATAL(mounted_root->mountpoint->mounted_root == mounted_root);
497 
498   /* No FS should be mounted on the mounted root to umount */
499   SOS_ASSERT_FATAL(NULL == mounted_root->mounted_root);
500 
501   /* The mounted root should have its own reference, plus a reference
502      from the mountpoint and from the fs instance */
503   SOS_ASSERT_FATAL(mounted_root->ref_cnt >= 3);
504   if (mounted_root->ref_cnt != 3)
505     return -SOS_EBUSY;
506 
507   fs = mounted_root->fs_node->fs;
508   SOS_ASSERT_FATAL(NULL != fs);
509   SOS_ASSERT_FATAL(fs->root == mounted_root);
510 
511   /* Undo the mountpoint <-> mounted_root mutual reference */
512   mounted_root->mountpoint->mounted_root = NULL;
513   sos_fs_nscache_unref_node(mounted_root->mountpoint);
514   mounted_root->mountpoint = NULL;
515   sos_fs_nscache_unref_node(mounted_root);
516 
517   /* Undo the fs->root -> mounted_root reference */
518   sos_fs_nscache_unref_node(fs->root);
519 
520   return SOS_OK;
521 }
522 
523 sos_bool_t
524 sos_fs_nscache_is_mountnode(const struct sos_fs_nscache_node * nsnode)
525 {
526   return ( (NULL != nsnode->mounted_root) || (NULL != nsnode->mountpoint) );
527 }

source navigation ] diff markup ] identifier search ] general search ]