nfs-ganesha 1.4

posixdb_add.c

Go to the documentation of this file.
00001 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil; -*-
00002  * vim:expandtab:shiftwidth=4:tabstop=4:
00003  */
00004 #ifdef HAVE_CONFIG_H
00005 #include "config.h"
00006 #endif
00007 
00008 #ifdef _SOLARIS
00009 #include "solaris_port.h"
00010 #endif
00011 
00012 #include "posixdb_internal.h"
00013 #include "posixdb_consistency.h"
00014 #include <string.h>
00015 
00016 fsal_posixdb_status_t fsal_posixdb_add(fsal_posixdb_conn * p_conn,      /* IN */
00017                                        fsal_posixdb_fileinfo_t * p_object_info, /* IN */
00018                                        posixfsal_handle_t * p_parent_directory_handle,  /* IN */
00019                                        fsal_name_t * p_filename,        /* IN */
00020                                        posixfsal_handle_t * p_object_handle /* OUT */ )
00021 {
00022   unsigned long long id;
00023   unsigned int ts;
00024   int found;
00025   fsal_posixdb_status_t st;
00026   result_handle_t res;
00027   char query[4096];
00028   MYSQL_ROW row;
00029   int add_parent_entry = FALSE;
00030 
00031   /*******************
00032    * 1/ sanity check *
00033    *******************/
00034 
00035   /* parent_directory and filename are NULL only if it is the root directory */
00036   if(!p_conn || !p_object_info || !p_object_handle
00037      || (p_filename && !p_parent_directory_handle)
00038      || (!p_filename && p_parent_directory_handle))
00039     ReturnCodeDB(ERR_FSAL_POSIXDB_FAULT, 0);
00040 
00041   LogFullDebug(COMPONENT_FSAL, "adding entry with parentid=%llu, id=%"PRIu64", name=%s\n",
00042          p_parent_directory_handle ? p_parent_directory_handle->data.id : 0,
00043          p_object_info ? p_object_info->inode : 0,
00044          p_filename ? p_filename->name : "NULL");
00045 
00046   /***************************************
00047    * 2/ check that parent handle exists
00048    ***************************************/
00049 
00050   if(p_parent_directory_handle) /* the root has no parent */
00051     {
00052       snprintf(query, 4096,
00053                "SELECT Handle.deviceid, Handle.inode, Handle.nlink, Handle.ctime, Handle.ftype "
00054                "FROM Handle WHERE handleid=%llu AND handlets=%u",
00055                p_parent_directory_handle->data.id, p_parent_directory_handle->data.ts);
00056 
00057       st = db_exec_sql(p_conn, query, &res);
00058       if(FSAL_POSIXDB_IS_ERROR(st))
00059         goto rollback;
00060 
00061       if(mysql_num_rows(res) < 1)
00062         {
00063           /* parent entry not found */
00064           mysql_free_result(res);
00065           RollbackTransaction(p_conn);
00066           ReturnCodeDB(ERR_FSAL_POSIXDB_NOENT, 0);
00067         }
00068 
00069       mysql_free_result(res);
00070 
00071     }
00072   /**********************************************************
00073    * 3/ Check if there is an existing Handle for the object *
00074    **********************************************************/
00075   snprintf(query, 4096, "SELECT handleid, handlets, nlink, ctime, ftype "
00076            "FROM Handle "
00077            "WHERE deviceid=%llu AND inode=%llu "
00078            "FOR UPDATE", (unsigned long long)p_object_info->devid, (unsigned long long)p_object_info->inode);
00079 
00080   st = db_exec_sql(p_conn, query, &res);
00081   if(FSAL_POSIXDB_IS_ERROR(st))
00082     goto rollback;
00083 
00084   found = (mysql_num_rows(res) == 1);
00085 
00086   if(found)
00087     {
00088       row = mysql_fetch_row(res);
00089       if(!row)
00090         {
00091           /* Error */
00092           mysql_free_result(res);
00093           RollbackTransaction(p_conn);
00094           ReturnCodeDB(ERR_FSAL_POSIXDB_NOENT, 0);
00095         }
00096 
00097       /* a Handle (that matches devid & inode) already exists */
00098       /* fill 'info' with information about the handle in the database */
00099       posixdb_internal_fillFileinfoFromStrValues(&(p_object_handle->data.info), NULL, NULL, row[2],  /* nlink */
00100                                                  row[3],        /* ctime */
00101                                                  row[4]);       /* ftype */
00102 
00103       p_object_handle->data.info.inode = p_object_info->inode;
00104       p_object_handle->data.info.devid = p_object_info->devid;
00105 
00106       p_object_handle->data.id = atoll(row[0]);
00107       p_object_handle->data.ts = atoi(row[1]);
00108       mysql_free_result(res);
00109 
00110       /* check the consistency of the handle */
00111       if(fsal_posixdb_consistency_check(&(p_object_handle->data.info), p_object_info))
00112         {
00113           /* consistency check failed */
00114           /* p_object_handle has been filled in order to be able to fix the consistency later */
00115           RollbackTransaction(p_conn);
00116           ReturnCodeDB(ERR_FSAL_POSIXDB_CONSISTENCY, 0);
00117         }
00118 
00119       /* update nlink & ctime if needed */
00120       if(p_object_info->nlink != p_object_handle->data.info.nlink
00121          || p_object_info->ctime != p_object_handle->data.info.ctime)
00122         {
00123 
00124           snprintf(query, 4096, "UPDATE Handle "
00125                    "SET ctime=%u, nlink=%u "
00126                    "WHERE handleid=%llu AND handlets=%u",
00127                    (unsigned int)p_object_info->ctime,
00128                    p_object_info->nlink, p_object_handle->data.id, p_object_handle->data.ts);
00129 
00130           p_object_handle->data.info = *p_object_info;
00131 
00132           st = db_exec_sql(p_conn, query, NULL);
00133           if(FSAL_POSIXDB_IS_ERROR(st))
00134             goto rollback;
00135         }
00136 
00137       fsal_posixdb_UpdateInodeCache(p_object_handle);
00138 
00139     }
00140   else                          /* no handle found */
00141     {
00142       mysql_free_result(res);
00143 
00144       /* Handle does not exist, add a new Handle entry */
00145 
00146       p_object_handle->data.ts = (int)time(NULL);
00147       p_object_handle->data.info = *p_object_info;
00148 
00149       snprintf(query, 4096,
00150                "INSERT INTO Handle(deviceid, inode, handlets, nlink, ctime, ftype) "
00151                "VALUES ( %u, %llu, %u, %u, %u, %u)", (unsigned int)p_object_info->devid,
00152                (unsigned long long)p_object_info->inode,
00153                (unsigned int)p_object_handle->data.ts, (unsigned int)p_object_info->nlink,
00154                (unsigned int)p_object_info->ctime, (unsigned int)p_object_info->ftype);
00155 
00156       st = db_exec_sql(p_conn, query, NULL);
00157       if(FSAL_POSIXDB_IS_ERROR(st))
00158         goto rollback;
00159 
00160       p_object_handle->data.id = mysql_insert_id(&p_conn->db_conn);
00161 
00162       /* now, we have the handle id */
00163       fsal_posixdb_UpdateInodeCache(p_object_handle);
00164 
00165     }
00166 
00167   /************************************************
00168    * add (or update) an entry in the Parent table *
00169    ************************************************/
00170   snprintf(query, 4096, "SELECT handleid, handlets "
00171            "FROM Parent WHERE handleidparent=%llu AND handletsparent=%u AND name='%s'",
00172            p_parent_directory_handle ? p_parent_directory_handle->data.id : p_object_handle->
00173            data.id,
00174            p_parent_directory_handle ? p_parent_directory_handle->data.ts : p_object_handle->
00175            data.ts, p_filename ? p_filename->name : "");
00176 
00177   st = db_exec_sql(p_conn, query, &res);
00178   if(FSAL_POSIXDB_IS_ERROR(st))
00179     goto rollback;
00180 
00181   /* res contains handleid & handlets */
00182   found = (mysql_num_rows(res) == 1);
00183 
00184   if(found)
00185     {
00186       row = mysql_fetch_row(res);
00187       if(!row)
00188         {
00189           /* Error */
00190           mysql_free_result(res);
00191           RollbackTransaction(p_conn);
00192           ReturnCodeDB(ERR_FSAL_POSIXDB_NOENT, 0);
00193         }
00194 
00195       id = atoll(row[0]);
00196       ts = atoi(row[1]);
00197       mysql_free_result(res);
00198 
00199       /* update the Parent entry if necessary (there entry exists with another handle) */
00200       if((id != p_object_handle->data.id) || (ts != p_object_handle->data.ts))
00201         {
00202           /* steps :
00203              - check the nlink value of the Parent entry to be overwritten
00204              - if nlink = 1, then we can delete the handle.
00205              else we have to update it (nlink--) : that is done by fsal_posixdb_deleteParent
00206              - update the handle of the entry
00207            */
00208           int nlink;
00209 
00210           snprintf(query, 4096,
00211                    "SELECT Handle.deviceid, Handle.inode, Handle.nlink, Handle.ctime, Handle.ftype "
00212                    "FROM Handle WHERE handleid=%llu AND handlets=%u FOR UPDATE",
00213                    p_parent_directory_handle ? p_parent_directory_handle->data.id :
00214                    p_object_handle->data.id,
00215                    p_parent_directory_handle ? p_parent_directory_handle->data.ts :
00216                    p_object_handle->data.ts);
00217 
00218           /* check the nlink value of the entry to be updated */
00219           st = db_exec_sql(p_conn, query, &res);
00220           if(FSAL_POSIXDB_IS_ERROR(st))
00221             goto rollback;
00222 
00223           found = (mysql_num_rows(res) == 1);
00224 
00225           if(found)
00226             {
00227 
00228               row = mysql_fetch_row(res);
00229               if(!row)
00230                 {
00231                   /* Error */
00232                   mysql_free_result(res);
00233                   RollbackTransaction(p_conn);
00234                   ReturnCodeDB(ERR_FSAL_POSIXDB_FAULT, 0);
00235                 }
00236 
00237               /* we have retrieved the handle information of the bad entry */
00238               nlink = atoi(row[2]);
00239               mysql_free_result(res);   /* clear old res before a new query */
00240 
00241               /* a Parent entry already exists, we delete it */
00242 
00243               st = fsal_posixdb_deleteParent(p_conn, id, ts,
00244                                              p_parent_directory_handle ?
00245                                              p_parent_directory_handle->data.id
00246                                              : p_object_handle->data.id,
00247                                              p_parent_directory_handle ?
00248                                              p_parent_directory_handle->data.ts
00249                                              : p_object_handle->data.ts,
00250                                              p_filename ? p_filename->name : "", nlink);
00251               if(FSAL_POSIXDB_IS_ERROR(st))
00252                 goto rollback;
00253             }
00254           else
00255             {
00256               /* the Handle line has been deleted */
00257               mysql_free_result(res);   /* clear old res before a new query */
00258             }
00259 
00260           /* the bad entry has been deleted. Now we had a new Parent entry */
00261           add_parent_entry = TRUE;
00262 
00263         }
00264       else
00265         {
00266           /* a Parent entry exists with our handle, nothing to do */
00267           mysql_free_result(res);
00268         }
00269     }
00270   else                          /* no parent entry found */
00271     {
00272       mysql_free_result(res);
00273       add_parent_entry = TRUE;
00274     }
00275 
00276   if(add_parent_entry)
00277     {
00278       /* add a Parent entry */
00279 
00280       snprintf(query, 4096,
00281                "INSERT INTO Parent(handleidparent, handletsparent, name, handleid, handlets) "
00282                "VALUES(%llu, %u, '%s', %llu, %u)",
00283                p_parent_directory_handle ? p_parent_directory_handle->data.id :
00284                p_object_handle->data.id,
00285                p_parent_directory_handle ? p_parent_directory_handle->data.ts :
00286                p_object_handle->data.ts, p_filename ? p_filename->name : "",
00287                p_object_handle->data.id, p_object_handle->data.ts);
00288 
00289       st = db_exec_sql(p_conn, query, NULL);
00290       if(FSAL_POSIXDB_IS_ERROR(st))
00291         goto rollback;
00292 
00293       /* XXX : is it possible to have unique key violation ? */
00294     }
00295 
00296   return EndTransaction(p_conn);
00297 
00298  rollback:
00299   RollbackTransaction(p_conn);
00300   return st;
00301 }