nfs-ganesha 1.4
|
00001 /* 00002 * vim:expandtab:shiftwidth=8:tabstop=8: 00003 * 00004 * Copyright CEA/DAM/DIF (2008) 00005 * contributeur : Philippe DENIEL philippe.deniel@cea.fr 00006 * Thomas LEIBOVICI thomas.leibovici@cea.fr 00007 * 00008 * 00009 * This program is free software; you can redistribute it and/or 00010 * modify it under the terms of the GNU Lesser General Public 00011 * License as published by the Free Software Foundation; either 00012 * version 3 of the License, or (at your option) any later version. 00013 * 00014 * This program is distributed in the hope that it will be useful, 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 * Lesser General Public License for more details. 00018 * 00019 * You should have received a copy of the GNU Lesser General Public 00020 * License along with this library; if not, write to the Free Software 00021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00022 * 00023 * --------------------------------------- 00024 */ 00025 00036 #ifdef HAVE_CONFIG_H 00037 #include "config.h" 00038 #endif 00039 00040 #ifdef _SOLARIS 00041 #include "solaris_port.h" 00042 #endif 00043 00044 #include <pthread.h> 00045 #include "log.h" 00046 #include "nfs4.h" 00047 #include "nfs_core.h" 00048 #include "nfs_exports.h" 00049 #include "nfs_proto_functions.h" 00050 #include "sal_functions.h" 00051 00068 int nfs41_op_create_session(struct nfs_argop4 *op, 00069 compound_data_t * data, struct nfs_resop4 *resp) 00070 { 00071 nfs_client_id_t * pconf = NULL; 00072 nfs_client_id_t * punconf = NULL; 00073 nfs_client_id_t * pfound = NULL; 00074 nfs_client_record_t * pclient_record; 00075 nfs41_session_t * nfs41_session = NULL; 00076 clientid4 clientid = 0; 00077 sockaddr_t client_addr; 00078 char str_client_addr[SOCK_NAME_MAX]; 00079 char str_client[NFS4_OPAQUE_LIMIT * 2 + 1]; 00080 int rc; 00081 log_components_t component = COMPONENT_CLIENTID; 00082 00083 if(isDebug(COMPONENT_SESSIONS)) 00084 component = COMPONENT_SESSIONS; 00085 00086 #define arg_CREATE_SESSION4 op->nfs_argop4_u.opcreate_session 00087 #define res_CREATE_SESSION4 resp->nfs_resop4_u.opcreate_session 00088 #define res_CREATE_SESSION4ok res_CREATE_SESSION4.CREATE_SESSION4res_u.csr_resok4 00089 00090 resp->resop = NFS4_OP_CREATE_SESSION; 00091 res_CREATE_SESSION4.csr_status = NFS4_OK; 00092 clientid = arg_CREATE_SESSION4.csa_clientid; 00093 00094 copy_xprt_addr(&client_addr, data->reqp->rq_xprt); 00095 00096 if(isDebug(component)) 00097 sprint_sockip(&client_addr, str_client_addr, sizeof(str_client_addr)); 00098 00099 LogDebug(component, 00100 "CREATE_SESSION client addr=%s clientid=%"PRIx64" -------------------", 00101 str_client_addr, 00102 clientid); 00103 00104 /* First try to look up unconfirmed record */ 00105 rc = nfs_client_id_get_unconfirmed(clientid, &punconf); 00106 00107 if(rc == CLIENT_ID_SUCCESS) 00108 { 00109 pclient_record = punconf->cid_client_record; 00110 pfound = punconf; 00111 } 00112 else 00113 { 00114 rc = nfs_client_id_get_confirmed(clientid, &pconf); 00115 if(rc != CLIENT_ID_SUCCESS) 00116 { 00117 /* No record whatsoever of this clientid */ 00118 LogDebug(component, 00119 "Stale clientid = %"PRIx64, 00120 clientid); 00121 res_CREATE_SESSION4.csr_status = NFS4ERR_STALE_CLIENTID; 00122 00123 return res_CREATE_SESSION4.csr_status; 00124 } 00125 pclient_record = pconf->cid_client_record; 00126 pfound = pconf; 00127 } 00128 00129 P(pclient_record->cr_mutex); 00130 00131 inc_client_record_ref(pclient_record); 00132 00133 if(isFullDebug(component)) 00134 { 00135 char str[HASHTABLE_DISPLAY_STRLEN]; 00136 00137 display_client_record(pclient_record, str); 00138 00139 LogFullDebug(component, 00140 "Client Record %s cr_pconfirmed_id=%p cr_punconfirmed_id=%p", 00141 str, 00142 pclient_record->cr_pconfirmed_id, 00143 pclient_record->cr_punconfirmed_id); 00144 } 00145 00146 /* At this point one and only one of pconf and punconf is non-NULL, and pfound 00147 * also references the single clientid record that was found. 00148 */ 00149 00150 LogDebug(component, 00151 "CREATE_SESSION clientid=%"PRIx64" csa_sequence=%"PRIu32 00152 " clientid_cs_seq=%" PRIu32" data_oppos=%d data_use_drc=%d", 00153 clientid, 00154 arg_CREATE_SESSION4.csa_sequence, 00155 pfound->cid_create_session_sequence, 00156 data->oppos, 00157 data->use_drc); 00158 00159 if(isFullDebug(component)) 00160 { 00161 char str[HASHTABLE_DISPLAY_STRLEN]; 00162 00163 display_client_id_rec(pfound, str); 00164 LogFullDebug(component, 00165 "Found %s", 00166 str); 00167 } 00168 00169 data->use_drc = FALSE; 00170 00171 if(data->oppos == 0) 00172 { 00173 /* Special case : the request is used without use of OP_SEQUENCE */ 00174 if((arg_CREATE_SESSION4.csa_sequence + 1 == pfound->cid_create_session_sequence) 00175 && (pfound->cid_create_session_slot.cache_used == TRUE)) 00176 { 00177 data->use_drc = TRUE; 00178 data->pcached_res = &pfound->cid_create_session_slot.cached_result; 00179 00180 res_CREATE_SESSION4.csr_status = NFS4_OK; 00181 00182 dec_client_id_ref(pfound); 00183 00184 LogDebug(component, "CREATE_SESSION replay=%p special case", data->pcached_res); 00185 00186 goto out; 00187 } 00188 else if(arg_CREATE_SESSION4.csa_sequence != pfound->cid_create_session_sequence) 00189 { 00190 res_CREATE_SESSION4.csr_status = NFS4ERR_SEQ_MISORDERED; 00191 00192 dec_client_id_ref(pfound); 00193 00194 LogDebug(component, "CREATE_SESSION returning NFS4ERR_SEQ_MISORDERED"); 00195 00196 goto out; 00197 } 00198 00199 } 00200 00201 if(punconf != NULL) 00202 { 00203 /* First must match principal */ 00204 if(!nfs_compare_clientcred(&punconf->cid_credential, &data->credential) || 00205 !cmp_sockaddr(&punconf->cid_client_addr, &client_addr, IGNORE_PORT)) 00206 { 00207 if(isDebug(component)) 00208 { 00209 char unconfirmed_addr[SOCK_NAME_MAX]; 00210 00211 sprint_sockip(&punconf->cid_client_addr, unconfirmed_addr, sizeof(unconfirmed_addr)); 00212 00213 LogDebug(component, 00214 "Unconfirmed ClientId %"PRIx64"->'%s': Principals do not match... unconfirmed addr=%s Return NFS4ERR_CLID_INUSE", 00215 clientid, str_client_addr, unconfirmed_addr); 00216 } 00217 00218 dec_client_id_ref(punconf); 00219 00220 res_CREATE_SESSION4.csr_status = NFS4ERR_CLID_INUSE; 00221 00222 goto out; 00223 } 00224 } 00225 00226 if(pconf != NULL) 00227 { 00228 if(isDebug(component) && pconf != NULL) 00229 display_clientid_name(pconf, str_client); 00230 00231 /* First must match principal */ 00232 if(!nfs_compare_clientcred(&pconf->cid_credential, &data->credential) || 00233 !cmp_sockaddr(&pconf->cid_client_addr, &client_addr, IGNORE_PORT)) 00234 { 00235 if(isDebug(component)) 00236 { 00237 char confirmed_addr[SOCK_NAME_MAX]; 00238 00239 sprint_sockip(&pconf->cid_client_addr, confirmed_addr, sizeof(confirmed_addr)); 00240 00241 LogDebug(component, 00242 "Confirmed ClientId %"PRIx64"->%s addr=%s: Principals do not match... confirmed addr=%s Return NFS4ERR_CLID_INUSE", 00243 clientid, str_client, str_client_addr, confirmed_addr); 00244 } 00245 00246 /* Release our reference to the confirmed clientid. */ 00247 dec_client_id_ref(pconf); 00248 00249 res_CREATE_SESSION4.csr_status = NFS4ERR_CLID_INUSE; 00250 00251 goto out; 00252 } 00253 00254 /* In this case, the record was confirmed proceed with CREATE_SESSION */ 00255 } 00256 00257 /* We don't need to do any further principal checks, we can't have a confirmed 00258 * clientid record with a different principal than the unconfirmed record. 00259 */ 00260 00261 /* At this point, we need to try and create the session before we modify the 00262 * confirmed and/or unconfirmed clientid records. 00263 */ 00264 00267 /* Check flags value (test CSESS15) */ 00268 if(arg_CREATE_SESSION4.csa_flags > CREATE_SESSION4_FLAG_CONN_RDMA) 00269 { 00270 LogDebug(component, 00271 "Invalid create session flags %"PRIu32, 00272 arg_CREATE_SESSION4.csa_flags); 00273 00274 dec_client_id_ref(pfound); 00275 00276 res_CREATE_SESSION4.csr_status = NFS4ERR_INVAL; 00277 00278 goto out; 00279 } 00280 00281 /* Record session related information at the right place */ 00282 nfs41_session = pool_alloc(nfs41_session_pool, NULL); 00283 00284 if(nfs41_session == NULL) 00285 { 00286 LogDebug(component, 00287 "Could not allocate memory for a session"); 00288 00289 dec_client_id_ref(pfound); 00290 00291 res_CREATE_SESSION4.csr_status = NFS4ERR_SERVERFAULT; 00292 00293 goto out; 00294 } 00295 00296 nfs41_session->clientid = clientid; 00297 nfs41_session->pclientid_record = pfound; 00298 nfs41_session->sequence = arg_CREATE_SESSION4.csa_sequence; 00299 nfs41_session->session_flags = CREATE_SESSION4_FLAG_CONN_BACK_CHAN; 00300 nfs41_session->fore_channel_attrs = arg_CREATE_SESSION4.csa_fore_chan_attrs; 00301 nfs41_session->back_channel_attrs = arg_CREATE_SESSION4.csa_back_chan_attrs; 00302 00303 /* Take reference to clientid record */ 00304 inc_client_id_ref(pfound); 00305 00306 /* Set ca_maxrequests */ 00307 nfs41_session->fore_channel_attrs.ca_maxrequests = NFS41_NB_SLOTS; 00308 nfs41_session->fore_channel_attrs.ca_maxrequests = NFS41_NB_SLOTS; 00309 00310 nfs41_Build_sessionid(&clientid, nfs41_session->session_id); 00311 00312 res_CREATE_SESSION4ok.csr_sequence = nfs41_session->sequence; 00313 res_CREATE_SESSION4ok.csr_flags = CREATE_SESSION4_FLAG_CONN_BACK_CHAN; 00314 00315 /* return the input for wanting of something better (will change in 00316 later versions) */ 00317 res_CREATE_SESSION4ok.csr_fore_chan_attrs 00318 = nfs41_session->fore_channel_attrs; 00319 res_CREATE_SESSION4ok.csr_back_chan_attrs 00320 = nfs41_session->back_channel_attrs; 00321 00322 memcpy(res_CREATE_SESSION4ok.csr_sessionid, 00323 nfs41_session->session_id, 00324 NFS4_SESSIONID_SIZE); 00325 00326 /* Create Session replay cache */ 00327 data->pcached_res = &pfound->cid_create_session_slot.cached_result; 00328 pfound->cid_create_session_slot.cache_used = TRUE; 00329 00330 LogDebug(component, "CREATE_SESSION replay=%p", data->pcached_res); 00331 00332 if(!nfs41_Session_Set(nfs41_session->session_id, nfs41_session)) 00333 { 00334 LogDebug(component, 00335 "Could not insert session into table"); 00336 00337 /* Decrement our reference to the clientid record and the one for the session */ 00338 dec_client_id_ref(pfound); 00339 dec_client_id_ref(pfound); 00340 00341 /* Free the memory for the session */ 00342 pool_free(nfs41_session_pool, nfs41_session); 00343 00344 res_CREATE_SESSION4.csr_status = NFS4ERR_SERVERFAULT; /* Maybe a more precise status would be better */ 00345 00346 goto out; 00347 } 00348 00349 /* Make sure we have a reference to the confirmed clientid record if any */ 00350 if(pconf == NULL) 00351 { 00352 pconf = pclient_record->cr_pconfirmed_id; 00353 00354 if(isDebug(component) && pconf != NULL) 00355 display_clientid_name(pconf, str_client); 00356 00357 /* Need a reference to the confirmed record for below */ 00358 if(pconf != NULL) 00359 inc_client_id_ref(pconf); 00360 } 00361 00362 if(pconf != NULL && pconf->cid_clientid != clientid) 00363 { 00364 /* Old confirmed record - need to expire it */ 00365 if(isDebug(component)) 00366 { 00367 char str[HASHTABLE_DISPLAY_STRLEN]; 00368 00369 display_client_id_rec(pconf, str); 00370 LogDebug(component, 00371 "Expiring %s", 00372 str); 00373 } 00374 00375 /* Expire clientid and release our reference. */ 00376 nfs_client_id_expire(pconf); 00377 00378 dec_client_id_ref(pconf); 00379 00380 pconf = NULL; 00381 } 00382 00383 if(pconf != NULL) 00384 { 00385 /* At this point we are updating the confirmed clientid. 00386 * Update the confirmed record from the unconfirmed record. 00387 */ 00388 LogDebug(component, 00389 "Updating clientid %"PRIx64"->%s cb_program=%u", 00390 pconf->cid_clientid, 00391 str_client, 00392 arg_CREATE_SESSION4.csa_cb_program); 00393 00394 pconf->cid_cb.cid_program = arg_CREATE_SESSION4.csa_cb_program; 00395 00396 if(punconf != NULL) 00397 { 00398 00399 /* unhash the unconfirmed clientid record */ 00400 remove_unconfirmed_client_id(punconf); 00401 00402 /* Release our reference to the unconfirmed entry */ 00403 dec_client_id_ref(punconf); 00404 } 00405 00406 if(isDebug(component)) 00407 { 00408 char str[HASHTABLE_DISPLAY_STRLEN]; 00409 00410 display_client_id_rec(pconf, str); 00411 LogDebug(component, 00412 "Updated %s", 00413 str); 00414 } 00415 00416 /* Release our reference to the confirmed clientid. */ 00417 dec_client_id_ref(pconf); 00418 } 00419 else 00420 { 00421 /* This is a new clientid */ 00422 if(isFullDebug(component)) 00423 { 00424 char str[HASHTABLE_DISPLAY_STRLEN]; 00425 00426 display_client_id_rec(punconf, str); 00427 00428 LogFullDebug(component, 00429 "Confirming new %s", 00430 str); 00431 } 00432 00433 punconf->cid_cb.cid_program = arg_CREATE_SESSION4.csa_cb_program; 00434 00435 rc = nfs_client_id_confirm(punconf, component); 00436 00437 if(rc != CLIENT_ID_SUCCESS) 00438 { 00439 if(rc == CLIENT_ID_INVALID_ARGUMENT) 00440 res_CREATE_SESSION4.csr_status = NFS4ERR_SERVERFAULT; 00441 else 00442 res_CREATE_SESSION4.csr_status = NFS4ERR_RESOURCE; 00443 00444 /* Need to destroy the session */ 00445 if(!nfs41_Session_Del(nfs41_session->session_id)) 00446 LogDebug(component, 00447 "Oops nfs41_Session_Del failed"); 00448 00449 /* Release our reference to the unconfirmed record */ 00450 dec_client_id_ref(punconf); 00451 00452 goto out; 00453 } 00454 00455 pconf = punconf; 00456 punconf = NULL; 00457 00458 if(isDebug(component)) 00459 { 00460 char str[HASHTABLE_DISPLAY_STRLEN]; 00461 00462 display_client_id_rec(pconf, str); 00463 00464 LogDebug(component, 00465 "Confirmed %s", 00466 str); 00467 } 00468 } 00469 00470 pconf->cid_create_session_sequence++; 00471 00472 /* Release our reference to the confirmed record */ 00473 dec_client_id_ref(pconf); 00474 00475 if(isFullDebug(component)) 00476 { 00477 char str[HASHTABLE_DISPLAY_STRLEN]; 00478 00479 display_client_record(pclient_record, str); 00480 00481 LogFullDebug(component, 00482 "Client Record %s cr_pconfirmed_id=%p cr_punconfirmed_id=%p", 00483 str, 00484 pclient_record->cr_pconfirmed_id, 00485 pclient_record->cr_punconfirmed_id); 00486 } 00487 00488 LogDebug(component, 00489 "CREATE_SESSION success"); 00490 00491 /* Successful exit */ 00492 res_CREATE_SESSION4.csr_status = NFS4_OK; 00493 00494 out: 00495 00496 V(pclient_record->cr_mutex); 00497 00498 /* Release our reference to the client record and return */ 00499 dec_client_record_ref(pclient_record); 00500 00501 return res_CREATE_SESSION4.csr_status; 00502 } /* nfs41_op_create_session */ 00503 00514 void nfs41_op_create_session_Free(CREATE_SESSION4res * resp) 00515 { 00516 /* To be completed */ 00517 return; 00518 } /* nfs41_op_create_session_Free */