nfs-ganesha 1.4

posixdb_internal.c

Go to the documentation of this file.
00001 #ifdef HAVE_CONFIG_H
00002 #include "config.h"
00003 #endif
00004 
00005 #include "posixdb_internal.h"
00006 #include "posixdb_consistency.h"
00007 #include <string.h>
00008 #include "RW_Lock.h"
00009 
00010 /* cyclic cache of paths */
00011 
00012 typedef struct cache_path_entry__
00013 {
00014   int is_set;
00015   int path_is_set;
00016   int info_is_set;
00017   posixfsal_handle_t handle;
00018   fsal_path_t path;
00019   rw_lock_t entry_lock;
00020 
00021 } cache_path_entry_t;
00022 
00023 #define CACHE_PATH_SIZE 509     /* prime near 512 */
00024 
00025 int fsal_posixdb_cache_init()
00026 {
00027 #ifdef _ENABLE_CACHE_PATH
00028   unsigned int i;
00029 
00030   memset((char *)cache_array, 0, CACHE_PATH_SIZE * sizeof(cache_path_entry_t));
00031 
00032   for(i = 0; i < CACHE_PATH_SIZE; i++)
00033     {
00034       if(rw_lock_init(&cache_array[i].entry_lock))
00035         return -1;
00036 
00037       cache_array[i].is_set = 0;
00038       cache_array[i].path_is_set = 0;
00039       cache_array[i].info_is_set = 0;
00040     }
00041 
00042 #endif
00043   return 0;
00044 }
00045 
00046 /* @todo pour augmenter les performances d'acces au cache,
00047  * on hash le handle, et on considere qu'un seul element
00048  * ayant un hash donne peut occuper une case du tableau.
00049  */
00050 
00051 void fsal_posixdb_CachePath(posixfsal_handle_t * p_handle,      /* IN */
00052                             fsal_path_t * p_path /* IN */ )
00053 {
00054 
00055 #ifdef _ENABLE_CACHE_PATH
00056 
00057   unsigned int i;
00058 
00059   LogDebug(COMPONENT_FSAL, "fsal_posixdb_CachePath: %u, %u = %s", (unsigned int)(p_handle->id),
00060            (unsigned int)(p_handle->ts), p_path->path);
00061 
00062   i = hash_cache_path(p_handle->id, p_handle->ts);
00063 
00064   /* in the handle already in cache ? */
00065   P_w(&cache_array[i].entry_lock);
00066 
00067   if(cache_array[i].is_set
00068      && cache_array[i].handle.id == p_handle->id
00069      && cache_array[i].handle.ts == p_handle->ts)
00070     {
00071       cache_array[i].path_is_set = TRUE;
00072 
00073       /* override it */
00074       cache_array[i].path = *p_path;
00075 
00076       V_w(&cache_array[i].entry_lock);
00077       return;
00078     }
00079 
00080   /* add it (replace previous handle) */
00081   cache_array[i].is_set = TRUE;
00082   cache_array[i].path_is_set = TRUE;
00083   cache_array[i].info_is_set = FALSE;
00084   cache_array[i].handle = *p_handle;
00085   cache_array[i].path = *p_path;
00086   V_w(&cache_array[i].entry_lock);
00087 
00088 #endif
00089   return;
00090 }
00091 
00092 /* set/update informations about a handle */
00093 int fsal_posixdb_UpdateInodeCache(posixfsal_handle_t * p_handle)        /* IN */
00094 {
00095 #ifdef _ENABLE_CACHE_PATH
00096 
00097   unsigned int i;
00098 
00099   LogDebug(COMPONENT_FSAL, "UpdateInodeCache: inode_id=%llu", p_handle->info.inode);
00100 
00101   i = hash_cache_path(p_handle->id, p_handle->ts);
00102 
00103   /* in the handle in cache ? */
00104   P_w(&cache_array[i].entry_lock);
00105 
00106   if(cache_array[i].is_set
00107      && cache_array[i].handle.id == p_handle->id
00108      && cache_array[i].handle.ts == p_handle->ts)
00109     {
00110       /* update its inode info */
00111       cache_array[i].handle.info = p_handle->info;
00112       cache_array[i].info_is_set = TRUE;
00113 
00114       LogDebug(COMPONENT_FSAL, "fsal_posixdb_UpdateInodeCache: %u, %u (existing entry)",
00115                (unsigned int)(p_handle->id), (unsigned int)(p_handle->ts));
00116 
00117       V_w(&cache_array[i].entry_lock);
00118 
00119       return TRUE;
00120     }
00121   LogDebug(COMPONENT_FSAL, "fsal_posixdb_UpdateInodeCache: %u, %u (new entry)",
00122            (unsigned int)(p_handle->id), (unsigned int)(p_handle->ts));
00123 
00124   /* add it (replace previous handle) */
00125   cache_array[i].is_set = TRUE;
00126   cache_array[i].path_is_set = FALSE;
00127   cache_array[i].info_is_set = TRUE;
00128   cache_array[i].handle = *p_handle;
00129   memset(&cache_array[i].path, 0, sizeof(fsal_path_t));
00130 
00131   V_w(&cache_array[i].entry_lock);
00132 #endif
00133   return FALSE;
00134 
00135 }
00136 
00137 /* retrieve last informations about a handle */
00138 int fsal_posixdb_GetInodeCache(posixfsal_handle_t * p_handle)   /* IN/OUT */
00139 {
00140 #ifdef _ENABLE_CACHE_PATH
00141   unsigned int i;
00142 
00143   i = hash_cache_path(p_handle->id, p_handle->ts);
00144 
00145   /* in the handle in cache ? */
00146   P_r(&cache_array[i].entry_lock);
00147   if(cache_array[i].is_set
00148      && cache_array[i].handle.id == p_handle->id
00149      && cache_array[i].handle.ts == p_handle->ts)
00150     {
00151       if(cache_array[i].info_is_set)
00152         {
00153           p_handle->info = cache_array[i].handle.info;
00154 
00155           LogDebug(COMPONENT_FSAL, "fsal_posixdb_GetInodeCache(%u, %u)", (unsigned int)(p_handle->id),
00156                    (unsigned int)(p_handle->ts));
00157           V_r(&cache_array[i].entry_lock);
00158 
00159           return TRUE;
00160         }
00161     }
00162   V_r(&cache_array[i].entry_lock);
00163 #endif
00164   return FALSE;
00165 
00166 }
00167 
00168 void fsal_posixdb_InvalidateCache()
00169 {
00170 #ifdef _ENABLE_CACHE_PATH
00171   unsigned int i;
00172 
00173   LogDebug(COMPONENT_FSAL, "fsal_posixdb_InvalidateCache");
00174 
00175   for(i = 0; i < CACHE_PATH_SIZE; i++)
00176     {
00177       P_w(&cache_array[i].entry_lock);
00178       cache_array[i].is_set = FALSE;
00179       cache_array[i].path_is_set = FALSE;
00180       cache_array[i].info_is_set = FALSE;
00181       cache_array[i].handle.id = 0;
00182       cache_array[i].handle.ts = 0;
00183       V_w(&cache_array[i].entry_lock);
00184     }
00185 
00186 #endif
00187 }
00188 
00189 int fsal_posixdb_GetPathCache(posixfsal_handle_t * p_handle,    /* IN */
00190                               fsal_path_t * p_path /* OUT */ )
00191 {
00192 #ifdef _ENABLE_CACHE_PATH
00193 
00194   unsigned int i;
00195 
00196   i = hash_cache_path(p_handle->id, p_handle->ts);
00197 
00198   /* in the handle in cache ? */
00199   P_r(&cache_array[i].entry_lock);
00200   if(cache_array[i].is_set
00201      && cache_array[i].handle.id == p_handle->id
00202      && cache_array[i].handle.ts == p_handle->ts)
00203     {
00204       if(cache_array[i].path_is_set)
00205         {
00206           /* return path it */
00207           memcpy(p_path, &cache_array[i].path, sizeof(fsal_path_t));
00208           V_r(&cache_array[i].entry_lock);
00209 
00210           LogDebug(COMPONENT_FSAL, "fsal_posixdb_GetPathCache(%u, %u)=%s",
00211                    (unsigned int)p_handle->id, (unsigned int)p_handle->ts,
00212                    p_path->path);
00213           return TRUE;
00214         }
00215     }
00216   V_r(&cache_array[i].entry_lock);
00217 #endif
00218   return FALSE;
00219 }
00220 
00221 fsal_posixdb_status_t fsal_posixdb_buildOnePath(fsal_posixdb_conn * p_conn,
00222                                                 posixfsal_handle_t * p_handle,
00223                                                 fsal_path_t * p_path)
00224 {
00225   PGresult *p_res;
00226   char handleid_str[MAX_HANDLEIDSTR_SIZE];
00227   char handlets_str[MAX_HANDLETSSTR_SIZE];
00228   unsigned int shift;
00229   char *new_pos;
00230   int toomanypaths = 0;
00231   const char *paramValues[2] = { handleid_str, handlets_str };
00232 
00233   if(!p_conn || !p_handle || !p_path)
00234     {
00235       ReturnCodeDB(ERR_FSAL_POSIXDB_FAULT, 0);
00236     }
00237 
00238   /* init values */
00239   memset(p_path, 0, sizeof(fsal_path_t));
00240 
00241   /* Nothing to do, it's the root path */
00242   if(p_handle->data.id == 0 && p_handle->data.ts == 0)
00243     ReturnCodeDB(ERR_FSAL_POSIXDB_NOERR, 0);
00244 
00245   /* check if the entry is in the cache */
00246   if(fsal_posixdb_GetPathCache(p_handle, p_path))
00247     ReturnCodeDB(ERR_FSAL_POSIXDB_NOERR, 0);
00248 
00249   snprintf(handleid_str, MAX_HANDLEIDSTR_SIZE, "%lli", p_handle->data.id);
00250   snprintf(handlets_str, MAX_HANDLETSSTR_SIZE, "%i", p_handle->data.ts);
00251 
00252   /* with PL/PGSQL */
00253 #ifdef _WITH_PLPGSQL
00254   p_res = PQexecPrepared(p_conn, "buildOnePathPL", 2, paramValues, NULL, NULL, 0);
00255   CheckResult(p_res);
00256 
00257   p_path->len = strlen(PQgetvalue(p_res, 0, 0));
00258 
00259   if(p_path->len >= FSAL_MAX_PATH_LEN)
00260     {
00261       PQclear(p_res);
00262       ReturnCodeDB(ERR_FSAL_POSIXDB_PATHTOOLONG, 0);
00263     }
00264 
00265   strcpy(p_path->path, PQgetvalue(p_res, 0, 0));
00266   PQclear(p_res);
00267 
00268   /* set result in cache */
00269   fsal_posixdb_CachePath(p_handle, p_path);
00270 
00271   ReturnCodeDB(ERR_FSAL_POSIXDB_NOERR, 0);
00272 
00273 #else
00274   /* without PL/PGSQL */
00275   while(handleid_str[0] != '\0')
00276     {
00277       p_res = PQexecPrepared(p_conn, "buildOnePath", 2, paramValues, NULL, NULL, 0);
00278       CheckResult(p_res);
00279 
00280       if(PQntuples(p_res) == 0)
00281         {
00282           PQclear(p_res);
00283           ReturnCodeDB(ERR_FSAL_POSIXDB_NOENT, 0);        /* not found */
00284         }
00285 
00286       if(PQntuples(p_res) > 1)
00287         {
00288           LogCrit(COMPONENT_FSAL, "Too many paths found for object %s.%s: found=%d, expected=1",
00289                   handleid_str, handlets_str, PQntuples(p_res));
00290 
00291           toomanypaths++;       /* too many entries */
00292         }
00293 
00294       if(!strncmp(handleid_str, PQgetvalue(p_res, 0, 1), MAX_HANDLEIDSTR_SIZE)
00295          && !strncmp(handlets_str, PQgetvalue(p_res, 0, 2), MAX_HANDLETSSTR_SIZE))
00296         {
00297           PQclear(p_res);
00298           break;                  /* handle is equal to its parent handle (root reached) */
00299         }
00300       strncpy(handleid_str, PQgetvalue(p_res, 0, 1), MAX_HANDLEIDSTR_SIZE);
00301       strncpy(handlets_str, PQgetvalue(p_res, 0, 2), MAX_HANDLETSSTR_SIZE);
00302 
00303       /* insertion of the name at the beginning of the path */
00304       shift = strlen(PQgetvalue(p_res, 0, 0));
00305       if(p_path->len + shift >= FSAL_MAX_PATH_LEN)
00306         {
00307           PQclear(p_res);
00308           ReturnCodeDB(ERR_FSAL_POSIXDB_PATHTOOLONG, 0);
00309         }
00310       new_pos = p_path->path + shift;
00311       memmove(new_pos, p_path->path, p_path->len);
00312       memcpy(p_path->path, PQgetvalue(p_res, 0, 0), shift);
00313       p_path->len += shift;
00314 
00315       PQclear(p_res);
00316     }
00317 
00318   if(toomanypaths)
00319     {
00320       LogCrit(COMPONENT_FSAL, "Returned path: %s", p_path->path);
00321       ReturnCodeDB(ERR_FSAL_POSIXDB_TOOMANYPATHS, toomanypaths);        /* too many entries */
00322     }
00323   else
00324     {
00325       /* set result in cache */
00326       fsal_posixdb_CachePath(p_handle, p_path);
00327 
00328       ReturnCodeDB(ERR_FSAL_POSIXDB_NOERR, 0);
00329     }
00330 #endif
00331 }
00332 
00333 fsal_posixdb_status_t fsal_posixdb_recursiveDelete(fsal_posixdb_conn * p_conn,
00334                                                    char *handleid_str, char *handlets_str,
00335                                                    fsal_nodetype_t ftype)
00336 {
00337   PGresult *p_res;
00338   fsal_posixdb_status_t st;
00339   fsal_nodetype_t ftype_tmp;
00340   unsigned int i;
00341   unsigned int i_max;
00342   const char *paramValues[2];
00343 
00344   /* Sanity check */
00345   if(!p_conn || !handleid_str || !handlets_str)
00346     {
00347       ReturnCodeDB(ERR_FSAL_POSIXDB_FAULT, 0);
00348     }
00349 
00350   if(ftype == FSAL_TYPE_DIR)
00351     {
00352       /* We find all the children of the directory in order to delete them, and then we delete the current handle */
00353       paramValues[0] = handleid_str;
00354       paramValues[1] = handlets_str;
00355       p_res = PQexecPrepared(p_conn, "lookupChildrenFU", 2, paramValues, NULL, NULL, 0);
00356       CheckResult(p_res);
00357       i_max = (unsigned int)PQntuples(p_res);
00358       for(i = 0; i < i_max; i++)
00359         {
00360           ftype_tmp = (fsal_nodetype_t) atoi(PQgetvalue(p_res, i, 2));
00361           if(ftype_tmp == FSAL_TYPE_DIR)
00362             {
00363               st = fsal_posixdb_recursiveDelete(p_conn, PQgetvalue(p_res, i, 0),
00364                                                 PQgetvalue(p_res, i, 1), ftype_tmp);
00365             }
00366           else
00367             {
00368               st = fsal_posixdb_deleteParent(p_conn, PQgetvalue(p_res, i, 0),   /* handleidparent */
00369                                              PQgetvalue(p_res, i, 1),   /* handletsparent */
00370                                              handleid_str, handlets_str, PQgetvalue(p_res, i, 3),       /* filename */
00371                                              atoi(PQgetvalue(p_res, i, 4))      /* nlink */
00372                   );
00373             }
00374           if(FSAL_POSIXDB_IS_ERROR(st))
00375             {
00376               PQclear(p_res);
00377               return st;
00378             }
00379         }
00380       PQclear(p_res);
00381     }
00382 
00383   /* Delete the Handle */
00384   /* All Parent entries having this handle will be deleted thanks to foreign keys */
00385   paramValues[0] = handleid_str;
00386   paramValues[1] = handlets_str;
00387 
00388   /* invalidate name cache */
00389   fsal_posixdb_InvalidateCache();
00390 
00391   p_res = PQexecPrepared(p_conn, "deleteHandle", 2, paramValues, NULL, NULL, 0);
00392   CheckCommand(p_res);
00393 
00394   ReturnCodeDB(ERR_FSAL_POSIXDB_NOERR, 0);
00395 }
00396 
00397 fsal_posixdb_status_t fsal_posixdb_deleteParent(fsal_posixdb_conn * p_conn,     /* IN */
00398                                                 char *handleid_str,     /* IN */
00399                                                 char *handlets_str,     /* IN */
00400                                                 char *handleidparent_str,       /* IN */
00401                                                 char *handletsparent_str,       /* IN */
00402                                                 char *filename, /* IN */
00403                                                 int nlink)      /* IN */
00404 {
00405   PGresult *p_res;
00406   char nlink_str[MAX_NLINKSTR_SIZE];
00407   const char *paramValues[3];
00408 
00409   /* Sanity check */
00410   if(!p_conn || !filename || nlink < 1)
00411     {
00412       ReturnCodeDB(ERR_FSAL_POSIXDB_FAULT, 0);
00413     }
00414 
00415   /* delete the Parent entry */
00416   paramValues[0] = handleidparent_str;
00417   paramValues[1] = handletsparent_str;
00418   paramValues[2] = filename;
00419 
00420   /* invalidate name cache */
00421   fsal_posixdb_InvalidateCache();
00422 
00423   p_res = PQexecPrepared(p_conn, "deleteParent", 3, paramValues, NULL, NULL, 0);
00424   CheckCommand(p_res);
00425 
00426   /* delete the handle or update it */
00427   if(nlink == 1)
00428     {
00429       /* delete the handle */
00430       /* If there are other entries in the Parent table with this Handle, they will be deleted (thanks to foreign keys) */
00431       paramValues[0] = handleid_str;
00432       paramValues[1] = handlets_str;
00433 
00434       /* invalidate cache */
00435       fsal_posixdb_InvalidateCache();
00436 
00437       p_res = PQexecPrepared(p_conn, "deleteHandle", 2, paramValues, NULL, NULL, 0);
00438       CheckCommand(p_res);
00439     }
00440   else
00441     {
00442       /* update the Handle entry ( Handle.nlink <- (nlink - 1) ) */
00443       paramValues[0] = handleid_str;
00444       paramValues[1] = handlets_str;
00445       snprintf(nlink_str, MAX_NLINKSTR_SIZE, "%i", nlink - 1);
00446       paramValues[2] = nlink_str;
00447 
00448       /* invalidate cache */
00449       fsal_posixdb_InvalidateCache();
00450 
00451       p_res = PQexecPrepared(p_conn, "updateHandleNlink", 3, paramValues, NULL, NULL, 0);
00452       CheckCommand(p_res);
00453     }
00454 
00455   ReturnCodeDB(ERR_FSAL_POSIXDB_NOERR, 0);
00456 }
00457 
00458 fsal_posixdb_status_t fsal_posixdb_internal_delete(fsal_posixdb_conn * p_conn,  /* IN */
00459                                                    char *handleidparent_str,    /* IN */
00460                                                    char *handletsparent_str,    /* IN */
00461                                                    char *filename,      /* IN */
00462                                                    fsal_posixdb_fileinfo_t *
00463                                                    p_object_info /* IN */ )
00464 {
00465 
00466   PGresult *p_res;
00467   char handleid_str[MAX_HANDLEIDSTR_SIZE];
00468   char handlets_str[MAX_HANDLETSSTR_SIZE];
00469   fsal_posixdb_status_t st;
00470   fsal_posixdb_fileinfo_t infodb;
00471   const char *paramValues[3];
00472 
00473   if(!p_conn || !handleidparent_str || !handletsparent_str || !filename)
00474     ReturnCodeDB(ERR_FSAL_POSIXDB_FAULT, 0);
00475 
00476   paramValues[0] = handleidparent_str;
00477   paramValues[1] = handletsparent_str;
00478   paramValues[2] = filename;
00479   p_res = PQexecPrepared(p_conn, "lookupHandleByNameFU", 3, paramValues, NULL, NULL, 0);
00480   CheckResult(p_res);
00481   /* p_res contains : handleid, handlets, deviceId, inode, nlink, ctime, ftype  */
00482 
00483   /* no entry found */
00484   if(PQntuples(p_res) != 1)
00485     {
00486       ReturnCodeDB(ERR_FSAL_POSIXDB_NOENT, 0);
00487     }
00488 
00489   strncpy(handleid_str, PQgetvalue(p_res, 0, 0), MAX_HANDLEIDSTR_SIZE);
00490   strncpy(handlets_str, PQgetvalue(p_res, 0, 1), MAX_HANDLETSSTR_SIZE);
00491 
00492   /* consistency check */
00493   /* fill 'infodb' with information about the handle in the database */
00494   posixdb_internal_fillFileinfoFromStrValues(&infodb, PQgetvalue(p_res, 0, 2),  /* no need to compare inode & devid, they are the same */
00495                                              PQgetvalue(p_res, 0, 3), PQgetvalue(p_res, 0, 4),  /* nlink */
00496                                              PQgetvalue(p_res, 0, 5),   /* ctime */
00497                                              PQgetvalue(p_res, 0, 6)    /* ftype */
00498       );
00499   PQclear(p_res);
00500 
00501   if(p_object_info && fsal_posixdb_consistency_check(&infodb, p_object_info))
00502     {
00503       /* not consistent, the bad handle have to be deleted */
00504       LogCrit(COMPONENT_FSAL, "Consistency check failed while deleting a Path : Handle deleted");
00505       infodb.ftype = FSAL_TYPE_DIR;     /* considers that the entry is a directory in order to delete all its Parent entries and its Handle */
00506     }
00507 
00508   switch (infodb.ftype)
00509     {
00510     case FSAL_TYPE_DIR:
00511       /* directory */
00512       st = fsal_posixdb_recursiveDelete(p_conn, handleid_str, handlets_str, infodb.ftype);
00513       break;
00514     default:
00515       st = fsal_posixdb_deleteParent(p_conn,
00516                                      handleid_str,
00517                                      handlets_str,
00518                                      handleidparent_str,
00519                                      handletsparent_str, filename, infodb.nlink);
00520     }
00521   return st;
00522 }
00523 
00524 fsal_posixdb_status_t posixdb_internal_fillFileinfoFromStrValues(fsal_posixdb_fileinfo_t *
00525                                                                  p_info, char *devid_str,
00526                                                                  char *inode_str,
00527                                                                  char *nlink_str,
00528                                                                  char *ctime_str,
00529                                                                  char *ftype_str)
00530 {
00531 
00532   if(!p_info)
00533     ReturnCodeDB(ERR_FSAL_POSIXDB_FAULT, 0);
00534 
00535   p_info->devid = devid_str ? (dev_t) atoll(devid_str) : 0;
00536   p_info->inode = inode_str ? (ino_t) atoll(inode_str) : 0;
00537   p_info->nlink = nlink_str ? atoi(nlink_str) : 0;
00538   p_info->ctime = ctime_str ? (time_t) atoi(ctime_str) : 0;
00539   p_info->ftype = ftype_str ? (fsal_nodetype_t) atoi(ftype_str) : 0;
00540 
00541   ReturnCodeDB(ERR_FSAL_POSIXDB_NOERR, 0);
00542 }