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