nfs-ganesha 1.4

namespace.c

Go to the documentation of this file.
00001 /*
00002  * \brief Manage a namespace for path<->inode association
00003  */
00004 #ifdef HAVE_CONFIG_H
00005 #include "config.h"
00006 #endif
00007 
00008 #include "namespace.h"
00009 #include "RW_Lock.h"
00010 #include "HashTable.h"
00011 
00012 #include <string.h>
00013 #include <pthread.h>
00014 #include <errno.h>
00015 #include <assert.h>
00016 
00017 /*-----------------------------------------------------
00018  *              Type definitions
00019  *-----------------------------------------------------*/
00020 
00021 /* We provide 2 associations:
00022  * Lookup: (parent,name) -> fsnode
00023  * Path:   inode->fsnode with list of (parent,name)
00024  */
00025 
00026 typedef struct __inode__
00027 {
00028   ino_t inum;
00029   dev_t dev;
00030   unsigned int generation;
00031 } inode_t;
00032 
00033 /* - key for lookup hash table
00034  * - it is also used to keep a list of parent/name of an entry
00035  */
00036 typedef struct __lookup_peer__
00037 {
00038   inode_t parent;
00039   char name[FSAL_MAX_NAME_LEN];
00040 
00041   /* used for pool chaining into parent list and pool allocation */
00042   struct __lookup_peer__ *p_next;
00043 
00044 } lookup_peer_t;
00045 
00046 /* - data for lookup hash table is a fsnode ;
00047  * - key for path hash table is an inode_t ;
00048  * - data for path hash table is a fsnode.
00049  */
00050 
00051 typedef struct __fsnode__
00052 {
00053   inode_t inode;
00054   unsigned int n_lookup;       
00057   unsigned int n_children;       
00060   lookup_peer_t *parent_list;
00061 
00062   /* used for pool allocation */
00063   struct __fsnode__ *p_next;
00064 
00065 } fsnode_t;
00066 
00067 /*-----------------------------------------------------
00068  *                 Memory management
00069  *-----------------------------------------------------*/
00070 
00071 pool_t node_pool;
00072 static pthread_mutex_t node_pool_mutex = PTHREAD_MUTEX_INITIALIZER;
00073 
00074 static fsnode_t *node_alloc()
00075 {
00076   fsnode_t *p_new;
00077 
00078   P(node_pool_mutex);
00079   p_new = pool_add(node_pool);
00080   V(node_pool_mutex);
00081 
00082   memset(p_new, 0, sizeof(fsnode_t));
00083 
00084   return p_new;
00085 }
00086 
00087 static void node_free(fsnode_t * p_node)
00088 {
00089   memset(p_node, 0, sizeof(fsnode_t));
00090 
00091   P(node_pool_mutex);
00092   pool_free(node_pool, p_node);
00093   V(node_pool_mutex);
00094 }
00095 
00096 /* pool of lookup peers */
00097 
00098 pool_t peer_pool;
00099 static pthread_mutex_t peer_pool_mutex = PTHREAD_MUTEX_INITIALIZER;
00100 
00101 static lookup_peer_t *peer_alloc()
00102 {
00103   lookup_peer_t *p_new;
00104 
00105   P(peer_pool_mutex);
00106   p_new = pool_alloc(peer_pool, NULL);
00107   V(peer_pool_mutex);
00108 
00109   memset(p_new, 0, sizeof(lookup_peer_t));
00110 
00111   return p_new;
00112 }
00113 
00114 static void peer_free(lookup_peer_t * p_peer)
00115 {
00116   memset(p_peer, 0, sizeof(lookup_peer_t));
00117 
00118   P(peer_pool_mutex);
00119   pool_free(peer_pool, p_peer);
00120   V(peer_pool_mutex);
00121 }
00122 
00123 /*----------------------------------------------------
00124  *                  hash tables
00125  *----------------------------------------------------*/
00126 
00127 /* functions for hashing/comparing lookup peers */
00128 
00129 static unsigned long hash_peer_idx(hash_parameter_t * p_conf, hash_buffer_t * p_key);
00130 static unsigned long hash_peer_rbt(hash_parameter_t * p_conf, hash_buffer_t * p_key);
00131 static int cmp_peers(hash_buffer_t * p_key1, hash_buffer_t * p_key2);
00132 
00133 /* functions for hashing/comparing inode numbers */
00134 
00135 static unsigned long hash_ino_idx(hash_parameter_t * p_conf, hash_buffer_t * p_key);
00136 static unsigned long hash_ino_rbt(hash_parameter_t * p_conf, hash_buffer_t * p_key);
00137 static int cmp_inodes(hash_buffer_t * p_key1, hash_buffer_t * p_key2);
00138 
00139 /* display functions */
00140 
00141 static int print_lookup_peer(hash_buffer_t * p_val, char *outbuff);
00142 static int print_inode(hash_buffer_t * p_val, char *outbuff);
00143 static int print_fsnode(hash_buffer_t * p_val, char *outbuff);
00144 
00145 /* configuration for lookup hashtable
00146  * TODO: externize those parameters
00147  */
00148 
00149 static hash_parameter_t lookup_hash_config = {
00150   .index_size = 877,
00151   .alphabet_length = 26,
00152   .hash_func_key = hash_peer_idx,
00153   .hash_func_rbt = hash_peer_rbt,
00154   .compare_key = cmp_peers,
00155   .key_to_str = print_lookup_peer,
00156   .val_to_str = print_fsnode,
00157   .ht_name = "FUSE Lookup Cache",
00158   .flags = HT_FLAG_CACHE,
00159   .ht_log_component = COMPONENT_FSAL
00160 };
00161 
00162 /* configuration for inode->fsnode hashtable
00163  * TODO: externize those parameters
00164  */
00165 static hash_parameter_t nodes_hash_config = {
00166   .index_size = 877,
00167   .alphabet_length = 10,
00168   .hash_func_key = hash_ino_idx,
00169   .hash_func_rbt = hash_ino_rbt,
00170   .compare_key = cmp_inodes,
00171   .key_to_str = print_inode,
00172   .val_to_str = print_fsnode,
00173   .ht_name = "FUSE fsnode Cache",
00174   .flags = HT_FLAG_CACHE,
00175   .ht_log_component = COMPONENT_FSAL
00176 };
00177 
00178 /* namespace structures */
00179 
00180 static rw_lock_t ns_lock = { 0 };
00181 
00182 static hash_table_t *lookup_hash = NULL;
00183 static hash_table_t *nodes_hash = NULL;
00184 
00185 /*----------------------------------------------------
00186  *         hash tables functions implementation
00187  *----------------------------------------------------*/
00188 
00189 /* functions for hashing/comparing lookup peers */
00190 
00191 static unsigned long hash_peer_idx(hash_parameter_t * p_conf, hash_buffer_t * p_key)
00192 {
00193   unsigned long hash;
00194   lookup_peer_t *p_peer = (lookup_peer_t *) p_key->pdata;
00195   char *name;
00196 
00197   hash = 1;
00198 
00199   for(name = p_peer->name; *name != '\0'; name++)
00200     hash =
00201         ((hash * p_conf->alphabet_length) + (unsigned long)(*name)) % p_conf->index_size;
00202 
00203   hash = (hash + (unsigned long)p_peer->parent.inum) % p_conf->index_size;
00204   hash = (hash ^ (unsigned long)p_peer->parent.dev) % p_conf->index_size;
00205 
00206   return hash;
00207 }
00208 
00209 static unsigned long hash_peer_rbt(hash_parameter_t * p_conf, hash_buffer_t * p_key)
00210 {
00211   unsigned long hash;
00212   lookup_peer_t *p_peer = (lookup_peer_t *) p_key->pdata;
00213   char *name;
00214 
00215   hash = 1;
00216 
00217   for(name = p_peer->name; *name != '\0'; name++)
00218     hash = ((hash << 5) - hash + (unsigned long)(*name));
00219 
00220   return (hash ^ (unsigned long)p_peer->parent.inum ^ (unsigned long)p_peer->parent.dev);
00221 }
00222 
00223 static int cmp_peers(hash_buffer_t * p_key1, hash_buffer_t * p_key2)
00224 {
00225   lookup_peer_t *p_peer1 = (lookup_peer_t *) p_key1->pdata;
00226   lookup_peer_t *p_peer2 = (lookup_peer_t *) p_key2->pdata;
00227 
00228   /* compare parent inode, then name */
00229 
00230   if((p_peer1->parent.inum > p_peer2->parent.inum)
00231      || (p_peer1->parent.dev > p_peer2->parent.dev))
00232     return 1;
00233   else if((p_peer1->parent.inum < p_peer2->parent.inum)
00234           || (p_peer1->parent.dev < p_peer2->parent.dev))
00235     return -1;
00236   else                          /* same parent */
00237     return strncmp(p_peer1->name, p_peer2->name, FSAL_MAX_NAME_LEN);
00238 
00239 }
00240 
00241 /* functions for hashing/comparing inode numbers */
00242 
00243 static unsigned long hash_ino_idx(hash_parameter_t * p_conf, hash_buffer_t * p_key)
00244 {
00245   unsigned long hash;
00246   inode_t *p_ino = (inode_t *) p_key->pdata;
00247 
00248   hash =
00249       (p_conf->alphabet_length + ((unsigned long)p_ino->inum ^ (unsigned int)p_ino->dev));
00250   return (3 * hash + 1999) % p_conf->index_size;
00251 
00252 }
00253 
00254 static unsigned long hash_ino_rbt(hash_parameter_t * p_conf, hash_buffer_t * p_key)
00255 {
00256   inode_t *p_ino = (inode_t *) p_key->pdata;
00257 
00258   return (unsigned long)(p_ino->inum ^ (3 * (p_ino->dev + 1)));
00259 }
00260 
00261 static int cmp_inodes(hash_buffer_t * p_key1, hash_buffer_t * p_key2)
00262 {
00263   inode_t *p_ino1 = (inode_t *) p_key1->pdata;
00264   inode_t *p_ino2 = (inode_t *) p_key2->pdata;
00265 
00266   if((p_ino1->inum > p_ino2->inum) || (p_ino1->dev > p_ino2->dev))
00267     return 1;
00268   else if((p_ino1->inum < p_ino2->inum) || (p_ino1->dev < p_ino2->dev))
00269     return -1;
00270   else
00271     return 0;
00272 }
00273 
00274 /* display functions */
00275 
00276 static int print_lookup_peer(hash_buffer_t * p_val, char *outbuff)
00277 {
00278   lookup_peer_t *p_peer = (lookup_peer_t *) p_val->pdata;
00279   return sprintf(outbuff, "parent:%lX.%lu, name:%s",
00280                  (unsigned long int)p_peer->parent.dev,
00281                  (unsigned long int)p_peer->parent.inum, p_peer->name);
00282 }
00283 
00284 static int print_inode(hash_buffer_t * p_val, char *outbuff)
00285 {
00286   inode_t *p_ino = (inode_t *) p_val->pdata;
00287   return sprintf(outbuff, "device:%lX inode:%lu (gen:%u)",
00288                  (unsigned long int)p_ino->dev, (unsigned long int)p_ino->inum,
00289                  p_ino->generation);
00290 }
00291 
00292 static int print_fsnode(hash_buffer_t * p_val, char *outbuff)
00293 {
00294   fsnode_t *p_node = (fsnode_t *) p_val->pdata;
00295 
00296   if(p_node->parent_list)
00297     return sprintf(outbuff,
00298                    "device:%lX inode:%lu (gen:%u), linkcount:%u, children:%u, first_parent:%lX.%lu, name=%s",
00299                    (unsigned long int)p_node->inode.dev,
00300                    (unsigned long int)p_node->inode.inum, p_node->inode.generation,
00301                    p_node->n_lookup, p_node->n_children,
00302                    (unsigned long int)p_node->parent_list->parent.dev,
00303                    (unsigned long int)p_node->parent_list->parent.inum,
00304                    p_node->parent_list->name);
00305   else
00306     return sprintf(outbuff,
00307                    "device:%lX inode:%lu (gen:%u), linkcount:%u, children:%u (no parent)",
00308                    (unsigned long int)p_node->inode.dev,
00309                    (unsigned long int)p_node->inode.inum, p_node->inode.generation,
00310                    p_node->n_lookup, p_node->n_children);
00311 
00312 }
00313 
00314 /*----------------------------------------------------
00315  *              hash tables helpers
00316  *----------------------------------------------------*/
00317 lookup_peer_t *h_insert_new_lookup(ino_t parent_inode,
00318                                    dev_t parent_dev,
00319                                    unsigned int parent_gen,
00320                                    char *name, fsnode_t * p_entry, int overwrite)
00321 {
00322   hash_buffer_t buffkey;
00323   hash_buffer_t buffval;
00324 
00325   lookup_peer_t *p_lpeer;
00326   int flag;
00327 
00328   /* alloc new peer */
00329   p_lpeer = peer_alloc();
00330   if(!p_lpeer)
00331     return NULL;
00332 
00333   p_lpeer->parent.inum = parent_inode;
00334   p_lpeer->parent.dev = parent_dev;
00335   p_lpeer->parent.generation = parent_gen;
00336   strncpy(p_lpeer->name, name, FSAL_MAX_NAME_LEN);
00337 
00338   buffkey.pdata = (caddr_t) p_lpeer;
00339   buffkey.len = sizeof(*p_lpeer);
00340 
00341   buffval.pdata = (caddr_t) p_entry;
00342   buffval.len = sizeof(*p_entry);
00343 
00344   if(overwrite)
00345     flag = HASHTABLE_SET_HOW_SET_OVERWRITE;
00346   else
00347     flag = HASHTABLE_SET_HOW_SET_NO_OVERWRITE;
00348 
00349   if(HashTable_Test_And_Set(lookup_hash, &buffkey, &buffval, flag) != HASHTABLE_SUCCESS)
00350     {
00351       peer_free(p_lpeer);
00352       return NULL;
00353     }
00354 
00355   /* Add lookup to node and increase n_lookup count */
00356   p_entry->n_lookup++;
00357   p_lpeer->p_next = p_entry->parent_list;
00358   p_entry->parent_list = p_lpeer;
00359 
00360   return p_lpeer;
00361 
00362 }                               /* h_insert_new_lookup */
00363 
00364 /* get the node pointed by a lookup peer (if it exists) */
00365 fsnode_t *h_get_lookup(ino_t parent_inode, dev_t parent_dev, char *name, int *p_rc)
00366 {
00367   lookup_peer_t lpeer;
00368   hash_buffer_t buffkey;
00369   hash_buffer_t buffval;
00370   int rc;
00371 
00372   /* test if lookup peer is referenced in lookup hashtable */
00373   lpeer.parent.inum = parent_inode;
00374   lpeer.parent.dev = parent_dev;
00375 
00376   strncpy(lpeer.name, name, FSAL_MAX_NAME_LEN);
00377 
00378   buffkey.pdata = (caddr_t) & lpeer;
00379   buffkey.len = sizeof(lpeer);
00380 
00381   rc = HashTable_Get(lookup_hash, &buffkey, &buffval);
00382 
00383   if(p_rc)
00384     *p_rc = rc;
00385 
00386   if(rc == HASHTABLE_SUCCESS)
00387     return (fsnode_t *) (buffval.pdata);
00388   else
00389     return NULL;
00390 }                               /* h_get_lookup */
00391 
00392 /* remove a lookup entry and return the pointed node */
00393 fsnode_t *h_del_lookup(ino_t parent_inode, dev_t parent_dev, unsigned int parent_gen,
00394                        char *name, int *p_rc)
00395 {
00396   lookup_peer_t lpeer;
00397   lookup_peer_t *p_lpeer;
00398   lookup_peer_t *p_lpeer_last;
00399   hash_buffer_t buffkey_in, buffkey_out;
00400   hash_buffer_t buffdata;
00401   fsnode_t *p_node;
00402   int rc;
00403 
00404   /* test if lookup peer is referenced in lookup hashtable */
00405   lpeer.parent.inum = parent_inode;
00406   lpeer.parent.dev = parent_dev;
00407   /* note: generation not needed for Hashtable_Get/Del */
00408 
00409   strncpy(lpeer.name, name, FSAL_MAX_NAME_LEN);
00410 
00411   buffkey_in.pdata = (caddr_t) & lpeer;
00412   buffkey_in.len = sizeof(lpeer);
00413 
00414   rc = HashTable_Del(lookup_hash, &buffkey_in, &buffkey_out, &buffdata);
00415 
00416   if(p_rc)
00417     *p_rc = rc;
00418 
00419   if(rc == HASHTABLE_SUCCESS)
00420     {
00421       /* Remove lookup from node and decrease n_lookup count */
00422       p_node = (fsnode_t *) buffdata.pdata;
00423 
00424       assert(p_node->n_lookup > 0);
00425       p_node->n_lookup--;
00426 
00427       /* find lpeer in node */
00428       p_lpeer_last = NULL;
00429 
00430       for(p_lpeer = p_node->parent_list; p_lpeer != NULL; p_lpeer = p_lpeer->p_next)
00431         {
00432           if(p_lpeer == (lookup_peer_t *) buffkey_out.pdata)
00433             {
00434               /* check parent inode and entry name */
00435               if((p_lpeer->parent.inum != parent_inode)
00436                  || (p_lpeer->parent.dev != parent_dev)
00437                  || (p_lpeer->parent.generation != parent_gen)
00438                  || strncmp(p_lpeer->name, name, FSAL_MAX_NAME_LEN))
00439                 {
00440                   LogCrit(COMPONENT_FSAL,
00441                           "NAMESPACE MANAGER: An incompatible direntry was found. In node: %lu.%lu (gen:%u) ,%s  Deleted:%lu.%lu (gen:%u),%s",
00442                           p_lpeer->parent.inum, p_lpeer->parent.dev,
00443                           p_lpeer->parent.generation, p_lpeer->name, parent_dev,
00444                           parent_inode, parent_gen, name);
00445                   /* remove it anyway... */
00446                 }
00447 
00448               /* remove it from list */
00449 
00450               if(p_lpeer_last)
00451                 p_lpeer_last->p_next = p_lpeer->p_next;
00452               else
00453                 p_node->parent_list = p_lpeer->p_next;
00454 
00455               /* free it */
00456 
00457               peer_free(p_lpeer);
00458 
00459               /* finished */
00460               break;
00461 
00462             }
00463           /* if lpeer found */
00464           p_lpeer_last = p_lpeer;
00465         }
00466 
00467       /* return the pointer node */
00468       return p_node;
00469     }
00470   else
00471     return NULL;
00472 
00473 }                               /* h_del_lookup */
00474 
00475 fsnode_t *h_insert_new_node(ino_t inode, dev_t device, unsigned int gen, int overwrite)
00476 {
00477   hash_buffer_t buffkey;
00478   hash_buffer_t buffval;
00479 
00480   fsnode_t *p_node;
00481   int flag;
00482 
00483   p_node = node_alloc();
00484   if(!p_node)
00485     return NULL;
00486 
00487   p_node->inode.inum = inode;
00488   p_node->inode.dev = device;
00489 
00490   p_node->inode.generation = gen;
00491 
00492   /* no children, no hardlink for the moment */
00493   p_node->n_lookup = 0;
00494   p_node->n_children = 0;
00495   p_node->parent_list = NULL;
00496 
00497   /* insert it to hash table */
00498 
00499   buffkey.pdata = (caddr_t) & p_node->inode;
00500   buffkey.len = sizeof(p_node->inode);
00501 
00502   buffval.pdata = (caddr_t) p_node;
00503   buffval.len = sizeof(*p_node);
00504 
00505   if(overwrite)
00506     flag = HASHTABLE_SET_HOW_SET_OVERWRITE;
00507   else
00508     flag = HASHTABLE_SET_HOW_SET_NO_OVERWRITE;
00509 
00510   if(HashTable_Test_And_Set(nodes_hash, &buffkey, &buffval, flag) != HASHTABLE_SUCCESS)
00511     {
00512       node_free(p_node);
00513       return NULL;
00514     }
00515 
00516   return p_node;
00517 
00518 }                               /* h_insert_new_node */
00519 
00520 /* get the node corresponding to an inode number */
00521 fsnode_t *h_get_node(ino_t inode, dev_t device, int *p_rc)
00522 {
00523   hash_buffer_t buffkey;
00524   hash_buffer_t buffval;
00525   inode_t key;
00526   int rc;
00527 
00528   /* test if inode is referenced in nodes hashtable */
00529 
00530   key.inum = inode;
00531   key.dev = device;
00532   /* note: generation not needed for Hashtable_Get */
00533 
00534   buffkey.pdata = (caddr_t) & key;
00535   buffkey.len = sizeof(key);
00536 
00537   rc = HashTable_Get(nodes_hash, &buffkey, &buffval);
00538 
00539   if(p_rc)
00540     *p_rc = rc;
00541 
00542   if(rc == HASHTABLE_SUCCESS)
00543     return (fsnode_t *) (buffval.pdata);
00544   else
00545     return NULL;
00546 }                               /* h_get_node */
00547 
00548 /* remove the node corresponding to an inode number */
00549 int h_del_node(ino_t inode, dev_t device)
00550 {
00551   hash_buffer_t buffkey;
00552   inode_t key;
00553 
00554   /* test if inode is referenced in nodes hashtable */
00555   key.inum = inode;
00556   key.dev = device;
00557 
00558   /* note: generation not needed for Hashtable_Get/Del */
00559 
00560   buffkey.pdata = (caddr_t) & key;
00561   buffkey.len = sizeof(key);
00562 
00563   return HashTable_Del(nodes_hash, &buffkey, NULL, NULL);
00564 
00565 }                               /* h_del_node */
00566 
00567 /*----------------------------------------------------
00568  *              Exported functions
00569  *----------------------------------------------------*/
00570 
00571 /* Initialize namespace and create root with the given inode number */
00572 int NamespaceInit(ino_t root_inode, dev_t root_dev, unsigned int *p_root_gen)
00573 {
00574   fsnode_t *root;
00575 
00576   /* Initialize pools.
00577    */
00578 
00579   peer_pool = pool_init(NULL, sizeof(lookup_peer_t),
00580                         pool_basic_substrate,
00581                         NULL, NULL, NULL);
00582   node_pool = pool_init(NULL, sizeof(fsnode_t),
00583                         pool_basic_substrate,
00584                         NULL, NULL, NULL);
00585 
00586   /* initialize namespace lock */
00587   if(rw_lock_init(&ns_lock))
00588     return ENOMEM;
00589 
00590   /* init the lookup hash table */
00591   lookup_hash = HashTable_Init(&lookup_hash_config);
00592   nodes_hash = HashTable_Init(&nodes_hash_config);
00593 
00594   if(!lookup_hash || !nodes_hash)
00595     return ENOMEM;
00596 
00597   /* allocate the root entry */
00598   root = h_insert_new_node(root_inode, root_dev, *p_root_gen, TRUE);
00599 
00600   if(!root)
00601     return ENOMEM;
00602 
00603   LogFullDebug(COMPONENT_FSAL, "namespace: Root=%lX.%ld (gen:%u)", root_dev, root_inode,
00604          root->inode.generation);
00605 
00606   *p_root_gen = root->inode.generation;
00607 
00608   /* never remove it */
00609   root->n_lookup = 1;
00610 
00611   return 0;
00612 }
00613 
00614 /* Add a child entry (no lock) */
00615 static int NamespaceAdd_nl(ino_t parent_ino, dev_t parent_dev, unsigned int parent_gen,
00616                            char *name,
00617                            ino_t entry_ino, dev_t entry_dev, unsigned int *p_new_gen)
00618 {
00619   fsnode_t *p_parent = NULL;
00620   fsnode_t *p_node = NULL;
00621   fsnode_t *p_node_exist = NULL;
00622   lookup_peer_t *p_lpeer;
00623   int rc;
00624 
00625   LogFullDebug(COMPONENT_FSAL, "namespace: Adding (%lX.%ld,%s)=%lX.%ld",
00626          parent_dev, parent_ino, name, entry_dev, entry_ino);
00627 
00628   /* does parent inode exist in namespace ? */
00629 
00630   p_parent = h_get_node(parent_ino, parent_dev, &rc);
00631 
00632   if(!p_parent)
00633     return ENOENT;
00634   else if(p_parent->inode.generation != parent_gen)
00635     return ESTALE;
00636 
00637   /* does another entry exist with this inode ? (hardlink) */
00638 
00639   p_node = h_get_node(entry_ino, entry_dev, &rc);
00640 
00641   switch (rc)
00642     {
00643     case HASHTABLE_SUCCESS:
00644       {
00645         /* this node exists */
00646 
00647         /* test if it is already referenced in lookup hashtable */
00648 
00649         p_node_exist = h_get_lookup(parent_ino, parent_dev, name, &rc);
00650 
00651         if(rc == HASHTABLE_ERROR_NO_SUCH_KEY)
00652           {
00653 
00654             /* create and add new peer to hash table */
00655             p_lpeer =
00656                 h_insert_new_lookup(parent_ino, parent_dev, parent_gen, name, p_node,
00657                                     FALSE);
00658             if(!p_lpeer)
00659               return EFAULT;
00660 
00661             /* increment parent's refcount */
00662             p_parent->n_children++;
00663 
00664           }
00665         else if(rc == HASHTABLE_SUCCESS)
00666           {
00667 
00668             if((p_node_exist->inode.inum == entry_ino)
00669                && (p_node_exist->inode.dev == entry_dev))
00670               {
00671                 /* entry already exist: nothing to do, return last generation */
00672                 *p_new_gen = p_node_exist->inode.generation;
00673                 return 0;
00674               }
00675             else
00676               {
00677                 /* an incompatible entry was found ! */
00678 
00679                 /* TODO: REMOVE IT silently because the filesystem changed behind us */
00680 
00681                 LogCrit(COMPONENT_FSAL,
00682                         "NAMESPACE MANAGER: An incompatible direntry was found. Existing: %lX.%lu,%s->%lX.%lu  New:%lX.%lu,%s->%lX.%lu",
00683                         parent_dev, parent_ino, name, p_node_exist->inode.dev,
00684                         p_node_exist->inode.inum, parent_dev, parent_ino, name, entry_dev, entry_ino);
00685                 return EEXIST;
00686               }
00687           }
00688         else                    /* other error */
00689           {
00690             return EFAULT;
00691           }
00692 
00693         break;
00694       }
00695 
00696     case HASHTABLE_ERROR_NO_SUCH_KEY:
00697       {
00698 
00699         /* allocate new node entry */
00700         p_node = h_insert_new_node(entry_ino, entry_dev, *p_new_gen, FALSE);
00701 
00702         if(!p_node)
00703           return ENOMEM;
00704 
00705         /* now, create the associated lookup peer */
00706 
00707         p_lpeer =
00708             h_insert_new_lookup(parent_ino, parent_dev, parent_gen, name, p_node, FALSE);
00709 
00710         if(!p_lpeer)
00711           return ENOMEM;
00712 
00713         /* increase parent's refcount */
00714         p_parent->n_children++;
00715 
00716         break;
00717       }
00718 
00719     default:
00720       return EFAULT;            /* should not occur ! */
00721     }
00722 
00723   LogFullDebug(COMPONENT_FSAL, "namespace: Entry %lX.%ld (gen:%u)  has now link count = %u",
00724          p_node->inode.dev, p_node->inode.inum, p_node->inode.generation,
00725          p_node->n_lookup);
00726 
00727   *p_new_gen = p_node->inode.generation;
00728 
00729   /* added successfuly */
00730   return 0;
00731 }                               /* NamespaceAdd_nl */
00732 
00733 /* Remove a child entry (no lock) */
00734 static int NamespaceRemove_nl(ino_t parent_ino, dev_t parent_dev, unsigned int parent_gen,
00735                               char *name)
00736 {
00737   fsnode_t *p_parent = NULL;
00738   fsnode_t *p_node = NULL;
00739   int rc;
00740 
00741   LogFullDebug(COMPONENT_FSAL, "namespace: removing %lX.%ld/%s", parent_dev, parent_ino, name);
00742 
00743   /* get parent node */
00744   p_parent = h_get_node(parent_ino, parent_dev, &rc);
00745 
00746   if(rc == HASHTABLE_ERROR_NO_SUCH_KEY)
00747     return ENOENT;
00748   else if(!p_parent)
00749     return EFAULT;
00750   else if(p_parent->inode.generation != parent_gen)
00751     return ESTALE;
00752 
00753   /* remove the lookup entry in the hash and get pointed node (if exists) */
00754   p_node = h_del_lookup(parent_ino, parent_dev, parent_gen, name, &rc);
00755 
00756   if(rc == HASHTABLE_ERROR_NO_SUCH_KEY)
00757     {
00758       /* consider its OK */
00759       return 0;
00760     }
00761   else if(!p_node)
00762     {
00763       return EFAULT;
00764     }
00765 
00766   assert(p_parent->n_children > 0);
00767 
00768   /* decrement parents' lookup count */
00769   p_parent->n_children--;
00770 
00771   LogFullDebug(COMPONENT_FSAL, "namespace: Entry %lX.%ld has now link count = %u",
00772          p_node->inode.dev, p_node->inode.inum, p_node->n_lookup);
00773 
00774   /* node not in namespace tree anymore */
00775   if(p_node->n_lookup == 0)
00776     {
00777       assert(p_node->n_children == 0);
00778 
00779       /* remove from hash table */
00780       rc = h_del_node(p_node->inode.inum, p_node->inode.dev);
00781 
00782       if(rc != HASHTABLE_SUCCESS)
00783         {
00784           return EFAULT;
00785         }
00786 
00787       /* free the node */
00788       node_free(p_node);
00789     }
00790 
00791   /* remove succeeded ! */
00792   return 0;
00793 }                               /* NamespaceRemove_nl */
00794 
00795 /* Add a child entry */
00796 int NamespaceAdd(ino_t parent_ino, dev_t parent_dev, unsigned int gen,
00797                  char *name, ino_t entry_ino, dev_t entry_dev, unsigned int *p_new_gen)
00798 {
00799   int rc;
00800 
00801   /* lock the namespace for modification */
00802   P_w(&ns_lock);
00803   rc = NamespaceAdd_nl(parent_ino, parent_dev, gen, name,
00804                        entry_ino, entry_dev, p_new_gen);
00805   V_w(&ns_lock);
00806 
00807   return rc;
00808 }
00809 
00810 /* Remove a child entry */
00811 int NamespaceRemove(ino_t parent_ino, dev_t parent_dev, unsigned int gen, char *name)
00812 {
00813   int rc;
00814 
00815   /* lock the namespace for modification */
00816   P_w(&ns_lock);
00817   rc = NamespaceRemove_nl(parent_ino, parent_dev, gen, name);
00818   V_w(&ns_lock);
00819 
00820   return rc;
00821 }
00822 
00823 /* Move an entry in the namespace */
00824 int NamespaceRename(ino_t parent_entry_src, dev_t src_dev, unsigned int srcgen,
00825                     char *name_src, ino_t parent_entry_tgt, dev_t tgt_dev,
00826                     unsigned int tgtgen, char *name_tgt)
00827 {
00828 
00829   int rc = 0;
00830   fsnode_t *p_node;
00831   unsigned int new_gen;
00832 
00833   /* lock the namespace for modification */
00834   P_w(&ns_lock);
00835 
00836   /* get source node info */
00837   p_node = h_get_lookup(parent_entry_src, src_dev, name_src, &rc);
00838 
00839   if(!p_node || rc != 0)
00840     {
00841       V_w(&ns_lock);
00842       return rc;
00843     }
00844 
00845   /* check that source != target (if so, do nothing) */
00846   if((parent_entry_src == parent_entry_tgt)
00847      && (src_dev == tgt_dev) && !strcmp(name_src, name_tgt))
00848     {
00849       V_w(&ns_lock);
00850       return 0;
00851     }
00852 
00853   /* try to add new path (with the same gen number) */
00854   new_gen = p_node->inode.generation;
00855 
00856   rc = NamespaceAdd_nl(parent_entry_tgt, tgt_dev, tgtgen, name_tgt, p_node->inode.inum,
00857                        p_node->inode.dev, &new_gen);
00858 
00859   if(rc == EEXIST)
00860     {
00861       /* remove previous entry */
00862       rc = NamespaceRemove_nl(parent_entry_tgt, tgt_dev, tgtgen, name_tgt);
00863       if(rc)
00864         {
00865           V_w(&ns_lock);
00866           return rc;
00867         }
00868 
00869       /* add the new one */
00870       new_gen = p_node->inode.generation;
00871 
00872       rc = NamespaceAdd_nl(parent_entry_tgt, tgt_dev, tgtgen, name_tgt,
00873                            p_node->inode.inum, p_node->inode.dev, &new_gen);
00874     }
00875 
00876   if(rc)
00877     {
00878       V_w(&ns_lock);
00879       return rc;
00880     }
00881 
00882   /* remove old path */
00883   rc = NamespaceRemove_nl(parent_entry_src, src_dev, srcgen, name_src);
00884 
00885   V_w(&ns_lock);
00886 
00887   return rc;
00888 
00889 }
00890 
00891 int NamespaceGetGen(ino_t inode, dev_t dev, unsigned int *p_gen)
00892 {
00893   fsnode_t *p_node;
00894   int rc;
00895 
00896   /* get entry from hash */
00897   p_node = h_get_node(inode, dev, &rc);
00898 
00899   LogFullDebug(COMPONENT_FSAL, "NamespaceGetGen(%lX,%ld): p_node = %p, rc = %d", dev, inode, p_node, rc);
00900 
00901   if(!p_node)
00902     return ENOENT;
00903   else if(rc != 0)
00904     return rc;
00905 
00906   *p_gen = p_node->inode.generation;
00907 
00908   return 0;
00909 }
00910 
00911 /* Get a possible full path for an entry */
00912 int NamespacePath(ino_t entry, dev_t dev, unsigned int gen, char *path)
00913 {
00914   fsnode_t *p_node;
00915   int rc;
00916   char tmp_path[FSAL_MAX_PATH_LEN];
00917 
00918   inode_t curr_inode;
00919 
00920   /* initialize paths */
00921   path[0] = '\0';
00922   tmp_path[0] = '\0';
00923 
00924   /* lock the namespace read-only */
00925   P_r(&ns_lock);
00926 
00927   curr_inode.inum = entry;
00928   curr_inode.dev = dev;
00929   curr_inode.generation = gen;
00930 
00931   do
00932     {
00933       /* get entry from hash */
00934       p_node = h_get_node(curr_inode.inum, curr_inode.dev, &rc);
00935 
00936       if(!p_node)
00937         {
00938           V_r(&ns_lock);
00939           if(rc == HASHTABLE_ERROR_NO_SUCH_KEY)
00940             {
00941               LogFullDebug(COMPONENT_FSAL, "namespace: %lX.%ld not found", (unsigned long)dev,
00942                      (unsigned long)entry);
00943               return ENOENT;
00944             }
00945           else
00946             return EFAULT;
00947         }
00948       else if(p_node->inode.generation != curr_inode.generation)
00949         {
00950           V_r(&ns_lock);
00951           return ESTALE;
00952         }
00953 
00954       if(!p_node->parent_list)
00955         {
00956           /* this is the root entry, just add '/' at the begining and return */
00957 
00958           LogFullDebug(COMPONENT_FSAL, "namespace: root entry reached");
00959 
00960           snprintf(path, FSAL_MAX_PATH_LEN, "/%s", tmp_path);
00961           break;
00962         }
00963       else if(path[0] == '\0')
00964         {
00965           /* nothing in path for the moment, just copy entry name in it */
00966           strncpy(path, p_node->parent_list->name, FSAL_MAX_NAME_LEN);
00967           curr_inode = p_node->parent_list->parent;
00968         }
00969       else
00970         {
00971           /* this is a parent dir, path is now <dirname>/<subpath> */
00972           snprintf(path, FSAL_MAX_PATH_LEN, "%s/%s", p_node->parent_list->name, tmp_path);
00973 
00974           LogFullDebug(COMPONENT_FSAL, "lookup peer found: (%lX.%ld,%s)",
00975                  p_node->parent_list->parent.dev,
00976                  p_node->parent_list->parent.inum, p_node->parent_list->name);
00977 
00978           /* loop detection */
00979           if((curr_inode.inum == p_node->parent_list->parent.inum)
00980              && (curr_inode.dev == p_node->parent_list->parent.dev))
00981             {
00982               LogCrit(COMPONENT_FSAL,
00983                       "NAMESPACE MANAGER: loop detected in namespace: %lX.%ld/%s = %lX.%ld",
00984                       p_node->parent_list->parent.dev, p_node->parent_list->parent.inum,
00985                       p_node->parent_list->name, curr_inode.dev, curr_inode.inum);
00986               V_r(&ns_lock);
00987               return ELOOP;
00988             }
00989 
00990           curr_inode = p_node->parent_list->parent;
00991         }
00992 
00993       /* backup path to tmp_path for next loop */
00994       strcpy(tmp_path, path);
00995 
00996     }
00997   while(1);
00998 
00999   LogFullDebug(COMPONENT_FSAL, "inode=%lX.%ld (gen %u), path='%s'", dev, entry, gen, path);
01000 
01001   /* reverse lookup succeeded */
01002   V_r(&ns_lock);
01003   return 0;
01004 
01005 }