nfs-ganesha 1.4
|
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 }