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 License 00011 * as published by the Free Software Foundation; either version 3 of 00012 * the License, or (at your option) any later version. 00013 * 00014 * This program is distributed in the hope that it will be useful, but 00015 * 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 00022 * 02110-1301 USA 00023 * 00024 * --------------------------------------- 00025 */ 00026 00027 #ifdef HAVE_CONFIG_H 00028 #include "config.h" 00029 #endif 00030 00031 #ifdef _SOLARIS 00032 #include "solaris_port.h" 00033 #endif 00034 00035 #include <stdio.h> 00036 #include <string.h> 00037 #include <pthread.h> 00038 #include <fcntl.h> 00039 #include <sys/file.h> /* for having FNDELAY */ 00040 #include <stdint.h> 00041 #include "HashData.h" 00042 #include "HashTable.h" 00043 #include "log.h" 00044 #include "ganesha_rpc.h" 00045 #include "nfs23.h" 00046 #include "nfs4.h" 00047 #include "mount.h" 00048 #include "nfs_core.h" 00049 #include "cache_inode.h" 00050 #include "nfs_exports.h" 00051 #include "nfs_creds.h" 00052 #include "nfs_proto_functions.h" 00053 #include "nfs_proto_tools.h" 00054 #include "nfs_file_handle.h" 00055 #include "nfs_tools.h" 00056 #ifdef _PNFS_MDS 00057 #include "fsal.h" 00058 #include "fsal_pnfs.h" 00059 #include "sal_data.h" 00060 #include "sal_functions.h" 00061 #endif /* _PNFS_MDS */ 00062 00063 #ifdef _PNFS_MDS 00064 static nfsstat4 acquire_layout_state(compound_data_t *data, 00065 stateid4 *supplied_stateid, 00066 layouttype4 layout_type, 00067 state_t **layout_state, 00068 const char *tag); 00069 00070 static nfsstat4 one_segment(fsal_handle_t *handle, 00071 fsal_op_context_t *context, 00072 state_t *layout_state, 00073 const struct fsal_layoutget_arg *arg, 00074 struct fsal_layoutget_res *res, 00075 layout4 *current); 00076 #endif /* _PNFS_MDS */ 00077 00095 #define arg_LAYOUTGET4 op->nfs_argop4_u.oplayoutget 00096 #define res_LAYOUTGET4 resp->nfs_resop4_u.oplayoutget 00097 00098 int nfs41_op_layoutget(struct nfs_argop4 *op, 00099 compound_data_t * data, 00100 struct nfs_resop4 *resp) 00101 { 00102 char __attribute__ ((__unused__)) funcname[] = "nfs41_op_layoutget"; 00103 #ifdef _PNFS_MDS 00104 /* Return code from state functions */ 00105 state_status_t state_status = 0; 00106 /* NFSv4.1 status code */ 00107 nfsstat4 nfs_status = 0; 00108 /* Status from Cache_inode */ 00109 cache_inode_status_t cache_status = 0; 00110 /* Pointer to state governing layouts */ 00111 state_t *layout_state = NULL; 00112 /* Pointer to the array of layouts */ 00113 layout4 *layouts = NULL; 00114 /* Total number of layout segments returned by the FSAL */ 00115 uint32_t numlayouts = 0; 00116 /* Pointer to the file handle */ 00117 fsal_handle_t *handle = NULL; 00118 /* Tag supplied to SAL functions for debugging messages */ 00119 const char *tag = "LAYOUTGET"; 00120 /* Input arguments of layoutget */ 00121 struct fsal_layoutget_arg arg; 00122 /* Input/output and output arguments of layoutget */ 00123 struct fsal_layoutget_res res; 00124 /* Maximum number of segments this FSAL will ever return for a 00125 single LAYOUTGET */ 00126 int max_segment_count = 0; 00127 #endif /* _PNFS_MDS */ 00128 00129 resp->resop = NFS4_OP_LAYOUTGET; 00130 00131 #ifdef _PNFS_MDS 00132 00133 if ((nfs_status = nfs4_sanity_check_FH(data, 00134 REGULAR_FILE)) 00135 != NFS4_OK) { 00136 goto out; 00137 } 00138 00139 if (!nfs4_pnfs_supported(data->pexport)) { 00140 nfs_status = NFS4ERR_LAYOUTUNAVAILABLE; 00141 goto out; 00142 } 00143 00144 if ((nfs_status = acquire_layout_state(data, 00145 &arg_LAYOUTGET4.loga_stateid, 00146 arg_LAYOUTGET4.loga_layout_type, 00147 &layout_state, 00148 tag)) 00149 != NFS4_OK) { 00150 goto out; 00151 } 00152 00153 /* 00154 * Blank out argument structures and get the filehandle. 00155 */ 00156 00157 memset(&arg, 0, sizeof(struct fsal_layoutget_arg)); 00158 memset(&res, 0, sizeof(struct fsal_layoutget_res)); 00159 00160 handle = cache_inode_get_fsal_handle(data->current_entry, 00161 &cache_status); 00162 00163 if (cache_status != CACHE_INODE_SUCCESS) { 00164 nfs_status = nfs4_Errno(cache_status); 00165 goto out; 00166 } 00167 00168 /* 00169 * Initialize segment array and fill out input-only arguments 00170 */ 00171 00172 max_segment_count = (data->pcontext->export_context-> 00173 fe_static_fs_info->max_segment_count); 00174 00175 if (max_segment_count == 0) { 00176 LogCrit(COMPONENT_PNFS, 00177 "The FSAL must specify a non-zero max_segment_count " 00178 "in its fsal_staticfsinfo_t"); 00179 nfs_status = NFS4ERR_SERVERFAULT; 00180 goto out; 00181 } 00182 00183 if ((layouts = gsh_calloc(max_segment_count, sizeof(layout4))) 00184 == NULL) { 00185 nfs_status = NFS4ERR_SERVERFAULT; 00186 goto out; 00187 } 00188 00189 memset(layouts, 0, sizeof(layout4) * max_segment_count); 00190 00191 arg.type = arg_LAYOUTGET4.loga_layout_type; 00192 arg.minlength = arg_LAYOUTGET4.loga_minlength; 00193 arg.export_id = data->pexport->id; 00194 arg.maxcount = arg_LAYOUTGET4.loga_maxcount; 00195 00196 /* Guaranteed on the first call */ 00197 res.context = NULL; 00198 00199 /* XXX Currently we have no callbacks, so it makes no sense to 00200 pass the client-supplied value to the FSAL. When we get 00201 callbacks, it will. */ 00202 res.signal_available = FALSE; 00203 00204 do { 00205 /* Since the FSAL writes to tis structure with every call, we 00206 re-initialize it with the operation's arguments */ 00207 res.segment.io_mode = arg_LAYOUTGET4.loga_iomode; 00208 res.segment.offset = arg_LAYOUTGET4.loga_offset; 00209 res.segment.length = arg_LAYOUTGET4.loga_length; 00210 00211 /* Clear anything from a previous segment */ 00212 res.fsal_seg_data = NULL; 00213 00214 if ((nfs_status = one_segment(handle, 00215 data->pcontext, 00216 layout_state, 00217 &arg, 00218 &res, 00219 layouts + numlayouts)) 00220 != NFS4_OK) { 00221 goto out; 00222 } 00223 00224 numlayouts++; 00225 00226 if ((numlayouts == max_segment_count) && !res.last_segment) { 00227 nfs_status = NFS4ERR_SERVERFAULT; 00228 goto out; 00229 } 00230 } while (!res.last_segment); 00231 00232 /* Update stateid.seqid and copy to current */ 00233 update_stateid(layout_state, 00234 &res_LAYOUTGET4.LAYOUTGET4res_u.logr_resok4.logr_stateid, 00235 data, 00236 tag); 00237 00238 res_LAYOUTGET4.LAYOUTGET4res_u.logr_resok4.logr_return_on_close = 00239 layout_state->state_data.layout.state_return_on_close; 00240 00241 /* Now the layout specific information */ 00242 res_LAYOUTGET4.LAYOUTGET4res_u.logr_resok4.logr_layout.logr_layout_len 00243 = numlayouts; 00244 res_LAYOUTGET4.LAYOUTGET4res_u.logr_resok4.logr_layout.logr_layout_val 00245 = layouts; 00246 00247 nfs_status = NFS4_OK; 00248 00249 out: 00250 00251 if (res_LAYOUTGET4.logr_status != NFS4_OK) { 00252 if (layouts) { 00253 size_t i; 00254 for (i = 0; i < numlayouts; i++) { 00255 if (layouts[i].lo_content.loc_body.loc_body_val) { 00256 gsh_free(layouts[i].lo_content.loc_body.loc_body_val); 00257 } 00258 } 00259 gsh_free(layouts); 00260 } 00261 00262 if ((layout_state) && (layout_state->state_seqid == 0)) { 00263 state_del(layout_state, 00264 &state_status); 00265 layout_state = NULL; 00266 } 00267 } 00268 00269 res_LAYOUTGET4.logr_status = nfs_status; 00270 00271 #else /* !_PNFS_MDS */ 00272 res_LAYOUTGET4.logr_status = NFS4ERR_NOTSUPP; 00273 #endif /* !_PNFS_MDS */ 00274 return res_LAYOUTGET4.logr_status; 00275 } /* pnfs_layoutget */ 00276 00277 00288 void nfs41_op_layoutget_Free(LAYOUTGET4res * resp) 00289 { 00290 #ifdef _PNFS_MDS 00291 size_t i = 0; 00292 if (resp->logr_status == NFS4_OK) { 00293 for (i = 0; 00294 i < (resp->LAYOUTGET4res_u.logr_resok4 00295 .logr_layout.logr_layout_len); 00296 i++) { 00297 gsh_free(resp->LAYOUTGET4res_u.logr_resok4.logr_layout. 00298 logr_layout_val[i].lo_content.loc_body.loc_body_val); 00299 } 00300 } 00301 #endif /* !_PNFS_MDS */ 00302 return; 00303 } /* nfs41_op_layoutget_Free */ 00304 00305 #ifdef _PNFS_MDS 00306 00325 static nfsstat4 00326 acquire_layout_state(compound_data_t *data, 00327 stateid4 *supplied_stateid, 00328 layouttype4 layout_type, 00329 state_t **layout_state, 00330 const char *tag) 00331 { 00332 /* State associated with the client-supplied stateid */ 00333 state_t *supplied_state = NULL; 00334 /* State owner for per-clientid states */ 00335 state_owner_t *clientid_owner = NULL; 00336 /* Return from this function */ 00337 nfsstat4 nfs_status = 0; 00338 /* Return from state functions */ 00339 state_status_t state_status = 0; 00340 /* Layout state, forgotten about by caller */ 00341 state_t *condemned_state = NULL; 00342 00343 if ((state_status = get_clientid_owner(data->psession->clientid, 00344 &clientid_owner)) 00345 != STATE_SUCCESS) { 00346 nfs_status = nfs4_Errno_state(state_status); 00347 } 00348 00349 /* Retrieve state corresponding to supplied ID, inspect it and, if 00350 necessary, create a new layout state */ 00351 00352 if ((nfs_status = nfs4_Check_Stateid(supplied_stateid, 00353 data->current_entry, 00354 &supplied_state, 00355 data, 00356 STATEID_SPECIAL_CURRENT, 00357 tag)) != NFS4_OK) { 00358 goto out; 00359 } 00360 00361 if (supplied_state->state_type == STATE_TYPE_LAYOUT) { 00362 /* If the state supplied is a layout state, we can simply 00363 * use it */ 00364 *layout_state = supplied_state; 00365 } else if ((supplied_state->state_type == STATE_TYPE_SHARE) || 00366 (supplied_state->state_type == STATE_TYPE_DELEG) || 00367 (supplied_state->state_type == STATE_TYPE_LOCK)) { 00368 /* For share, delegation, and lock states, create a new 00369 layout state. */ 00370 state_data_t layout_data; 00371 memset(&layout_data, 0, sizeof(state_data_t)); 00372 /* See if a layout state already exists */ 00373 state_status = state_lookup_layout_state(data->current_entry, 00374 clientid_owner, 00375 layout_type, 00376 &condemned_state); 00377 /* If it does, we assume that the client is using the 00378 forgetful model and has forgotten it had any layouts. 00379 Free all layouts associated with the state and delete 00380 it. */ 00381 if (state_status == STATE_SUCCESS) { 00382 /* Flag indicating whether all layouts were returned 00383 and the state was deleted */ 00384 bool_t deleted = FALSE; 00385 struct pnfs_segment entire = { 00386 .io_mode = LAYOUTIOMODE4_ANY, 00387 .offset = 0, 00388 .length = NFS4_UINT64_MAX 00389 }; 00390 if ((nfs_status 00391 = nfs4_return_one_state(data->current_entry, 00392 data->pcontext, 00393 TRUE, 00394 FALSE, 00395 0, 00396 condemned_state, 00397 entire, 00398 0, 00399 NULL, 00400 &deleted)) != NFS4_OK) { 00401 goto out; 00402 } 00403 if (!deleted) { 00404 nfs_status = NFS4ERR_SERVERFAULT; 00405 goto out; 00406 } 00407 condemned_state = NULL; 00408 } else if (state_status != STATE_NOT_FOUND) { 00409 nfs_status = nfs4_Errno_state(state_status); 00410 goto out; 00411 } 00412 00413 layout_data.layout.state_layout_type = layout_type; 00414 layout_data.layout.state_return_on_close = FALSE; 00415 00416 if (state_add(data->current_entry, 00417 STATE_TYPE_LAYOUT, 00418 &layout_data, 00419 clientid_owner, 00420 data->pcontext, 00421 layout_state, 00422 &state_status) != STATE_SUCCESS) { 00423 nfs_status = nfs4_Errno_state(state_status); 00424 goto out; 00425 } 00426 00427 init_glist(&(*layout_state)->state_data.layout.state_segments); 00428 } else { 00429 /* A state eixsts but is of an invalid type. */ 00430 nfs_status = NFS4ERR_BAD_STATEID; 00431 goto out; 00432 } 00433 00434 out: 00435 00436 return nfs_status; 00437 } 00438 00456 static nfsstat4 00457 one_segment(fsal_handle_t *handle, 00458 fsal_op_context_t *context, 00459 state_t *layout_state, 00460 const struct fsal_layoutget_arg *arg, 00461 struct fsal_layoutget_res *res, 00462 layout4 *current) 00463 { 00464 /* The initial position of the XDR stream after creation, so we 00465 can find the total length of encoded data. */ 00466 size_t start_position = 0; 00467 /* XDR stream to encode loc_body of the current segment */ 00468 XDR loc_body; 00469 /* Return code from this function */ 00470 nfsstat4 nfs_status = 0; 00471 /* Return from state calls */ 00472 state_status_t state_status = 0; 00473 /* Size of a loc_body buffer */ 00474 size_t loc_body_size = 00475 context->export_context->fe_static_fs_info->loc_buffer_size; 00476 00477 if (loc_body_size == 0) { 00478 LogCrit(COMPONENT_PNFS, 00479 "The FSAL must specify a non-zero loc_buffer_size " 00480 "in its fsal_staticfsinfo_t"); 00481 nfs_status = NFS4ERR_SERVERFAULT; 00482 goto out; 00483 } 00484 00485 /* Initialize the layout_content4 structure, allocate a buffer, 00486 and create an XDR stream for the FSAL to encode to. */ 00487 00488 current->lo_content.loc_type 00489 = arg->type; 00490 current->lo_content.loc_body.loc_body_val 00491 = gsh_malloc(loc_body_size); 00492 00493 xdrmem_create(&loc_body, 00494 current->lo_content.loc_body.loc_body_val, 00495 loc_body_size, 00496 XDR_ENCODE); 00497 00498 start_position = xdr_getpos(&loc_body); 00499 00500 /* 00501 * XXX This assumes a single FSAL and must be changed after the 00502 * XXX Lieb Rearchitecture. The MDS function structure 00503 * XXX associated with the current filehandle should be used. 00504 */ 00505 00506 nfs_status 00507 = fsal_mdsfunctions.layoutget(handle, 00508 context, 00509 &loc_body, 00510 arg, 00511 res); 00512 00513 current->lo_content.loc_body.loc_body_len 00514 = xdr_getpos(&loc_body) - start_position; 00515 xdr_destroy(&loc_body); 00516 00517 if (nfs_status != NFS4_OK) { 00518 goto out; 00519 } 00520 00521 current->lo_offset = res->segment.offset; 00522 current->lo_length = res->segment.length; 00523 current->lo_iomode = res->segment.io_mode; 00524 00525 if ((state_status = state_add_segment(layout_state, 00526 &res->segment, 00527 res->fsal_seg_data, 00528 res->return_on_close)) 00529 != STATE_SUCCESS) { 00530 nfs_status = nfs4_Errno_state(state_status); 00531 goto out; 00532 } 00533 00534 out: 00535 00536 if (nfs_status != NFS4_OK) { 00537 if (current->lo_content.loc_body.loc_body_val) 00538 gsh_free(current->lo_content.loc_body.loc_body_val); 00539 } 00540 00541 return nfs_status; 00542 } 00543 #endif /* _PNFS_MDS */