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 00037 #ifdef HAVE_CONFIG_H 00038 #include "config.h" 00039 #endif 00040 00041 #ifdef _SOLARIS 00042 #include "solaris_port.h" 00043 #endif 00044 00045 #include <stdio.h> 00046 #include <string.h> 00047 #include <pthread.h> 00048 #include <fcntl.h> 00049 #include <sys/file.h> /* for having FNDELAY */ 00050 #include "HashData.h" 00051 #include "HashTable.h" 00052 #include "log.h" 00053 #include "ganesha_rpc.h" 00054 #include "nfs4.h" 00055 #include "nfs_core.h" 00056 #include "nfs_proto_functions.h" 00057 #include "nfs_proto_tools.h" 00058 #include "nfs_file_handle.h" 00059 #include "nfs_tools.h" 00060 #ifdef _PNFS_MDS 00061 #include "fsal.h" 00062 #include "fsal_pnfs.h" 00063 #include "sal_data.h" 00064 #include "sal_functions.h" 00065 #endif /* _PNFS_MDS */ 00066 00085 #define arg_LAYOUTRETURN4 op->nfs_argop4_u.oplayoutreturn 00086 #define res_LAYOUTRETURN4 resp->nfs_resop4_u.oplayoutreturn 00087 00088 int nfs41_op_layoutreturn(struct nfs_argop4 *op, 00089 compound_data_t *data, 00090 struct nfs_resop4 *resp) 00091 { 00092 char __attribute__ ((__unused__)) funcname[] = "nfs41_op_layoutreturn"; 00093 #ifdef _PNFS_MDS 00094 /* Return code from cache_inode operations */ 00095 cache_inode_status_t cache_status = CACHE_INODE_SUCCESS; 00096 /* Return code from state operations */ 00097 state_status_t state_status = STATE_SUCCESS; 00098 /* NFS4 status code */ 00099 nfsstat4 nfs_status = 0; 00100 /* File attributes, used to compare FSID supplied to FSID of file. */ 00101 fsal_attrib_list_t attrs; 00102 /* FSID of candidate file to return */ 00103 fsal_fsid_t fsid = {0, 0}; 00104 /* True if the supplied layout state was deleted */ 00105 bool_t deleted = FALSE; 00106 /* State specified in the case of LAYOUTRETURN4_FILE */ 00107 state_t *layout_state = NULL; 00108 /* State owner associated with this clientid, for bulk returns */ 00109 state_owner_t *clientid_owner = NULL; 00110 /* Linked list node for iteration */ 00111 struct glist_head *glist = NULL; 00112 /* Saved next node for safe iteration */ 00113 struct glist_head *glistn = NULL; 00114 /* Tag to identify caller in tate log messages */ 00115 const char* tag = "LAYOUTRETURN"; 00116 /* Segment selecting which segments to return. */ 00117 struct pnfs_segment spec = {0, 0, 0}; 00118 #endif /* _PNFS_MDS */ 00119 00120 resp->resop = NFS4_OP_LAYOUTRETURN; 00121 00122 #ifdef _PNFS_MDS 00123 switch (arg_LAYOUTRETURN4.lora_layoutreturn.lr_returntype) { 00124 case LAYOUTRETURN4_FILE: 00125 if ((nfs_status = nfs4_sanity_check_FH(data, 00126 REGULAR_FILE)) 00127 != NFS4_OK) { 00128 res_LAYOUTRETURN4.lorr_status = nfs_status; 00129 return res_LAYOUTRETURN4.lorr_status; 00130 } 00131 /* Retrieve state corresponding to supplied ID */ 00132 if (arg_LAYOUTRETURN4.lora_reclaim) { 00133 layout_state = NULL; 00134 } else { 00135 if ((nfs_status 00136 = nfs4_Check_Stateid(&arg_LAYOUTRETURN4.lora_layoutreturn 00137 .layoutreturn4_u.lr_layout 00138 .lrf_stateid, 00139 data->current_entry, 00140 &layout_state, 00141 data, 00142 STATEID_SPECIAL_CURRENT, 00143 tag)) != NFS4_OK) { 00144 res_LAYOUTRETURN4.lorr_status = nfs_status; 00145 return res_LAYOUTRETURN4.lorr_status; 00146 } 00147 } 00148 00149 spec.io_mode = arg_LAYOUTRETURN4.lora_iomode; 00150 spec.offset = (arg_LAYOUTRETURN4.lora_layoutreturn 00151 .layoutreturn4_u.lr_layout.lrf_offset); 00152 spec.length = (arg_LAYOUTRETURN4.lora_layoutreturn 00153 .layoutreturn4_u.lr_layout.lrf_length); 00154 00155 res_LAYOUTRETURN4.lorr_status = 00156 nfs4_return_one_state( 00157 data->current_entry, 00158 data->pcontext, 00159 FALSE, 00160 arg_LAYOUTRETURN4.lora_reclaim, 00161 arg_LAYOUTRETURN4.lora_layoutreturn.lr_returntype, 00162 layout_state, 00163 spec, 00164 arg_LAYOUTRETURN4.lora_layoutreturn 00165 .layoutreturn4_u.lr_layout.lrf_body.lrf_body_len, 00166 arg_LAYOUTRETURN4.lora_layoutreturn 00167 .layoutreturn4_u.lr_layout.lrf_body.lrf_body_val, 00168 &deleted); 00169 if (res_LAYOUTRETURN4.lorr_status == NFS4_OK) { 00170 if (deleted) { 00171 memset(data->current_stateid.other, 0, 00172 sizeof(data->current_stateid.other)); 00173 data->current_stateid.seqid = NFS4_UINT32_MAX; 00174 res_LAYOUTRETURN4.LAYOUTRETURN4res_u.lorr_stateid 00175 .lrs_present = 0; 00176 } else { 00177 (res_LAYOUTRETURN4.LAYOUTRETURN4res_u 00178 .lorr_stateid.lrs_present) = 1; 00179 /* Update stateid.seqid and copy to current */ 00180 update_stateid( 00181 layout_state, 00182 &res_LAYOUTRETURN4.LAYOUTRETURN4res_u.lorr_stateid 00183 .layoutreturn_stateid_u.lrs_stateid, 00184 data, 00185 tag); 00186 } 00187 } 00188 break; 00189 00190 case LAYOUTRETURN4_FSID: 00191 if ((nfs_status 00192 = nfs4_sanity_check_FH(data, 00193 0)) 00194 != NFS4_OK) { 00195 res_LAYOUTRETURN4.lorr_status = nfs_status; 00196 return res_LAYOUTRETURN4.lorr_status; 00197 } 00198 if (!nfs4_pnfs_supported(data->pexport)) { 00199 res_LAYOUTRETURN4.lorr_status = NFS4_OK; 00200 return res_LAYOUTRETURN4.lorr_status; 00201 } 00202 memset(&attrs, 0, sizeof(fsal_attrib_list_t)); 00203 attrs.asked_attributes |= FSAL_ATTR_FSID; 00204 cache_status 00205 = cache_inode_getattr(data->current_entry, 00206 &attrs, 00207 data->pcontext, 00208 &cache_status); 00209 if (cache_status != CACHE_INODE_SUCCESS) { 00210 res_LAYOUTRETURN4.lorr_status = nfs4_Errno(cache_status); 00211 return res_LAYOUTRETURN4.lorr_status; 00212 } 00213 fsid = attrs.fsid; 00214 case LAYOUTRETURN4_ALL: 00215 spec.io_mode = arg_LAYOUTRETURN4.lora_iomode; 00216 spec.offset = 0; 00217 spec.length = NFS4_UINT64_MAX; 00218 00219 if ((state_status 00220 = get_clientid_owner(data->psession->clientid, 00221 &clientid_owner)) 00222 != STATE_SUCCESS) { 00223 res_LAYOUTRETURN4.lorr_status = 00224 nfs4_Errno_state(state_status); 00225 return res_LAYOUTRETURN4.lorr_status; 00226 } 00227 00228 /* We need the safe version because return_one_state can 00229 delete the current state. */ 00230 00231 glist_for_each_safe(glist, 00232 glistn, 00233 (&clientid_owner->so_owner.so_nfs4_owner 00234 .so_state_list)) { 00235 state_t *candidate_state 00236 = glist_entry(glist, 00237 state_t, 00238 state_owner_list); 00239 if (candidate_state->state_type != STATE_TYPE_LAYOUT) { 00240 continue; 00241 } else { 00242 layout_state = candidate_state; 00243 } 00244 00245 if (arg_LAYOUTRETURN4.lora_layoutreturn.lr_returntype 00246 == LAYOUTRETURN4_FSID) { 00247 memset(&attrs, 0, sizeof(fsal_attrib_list_t)); 00248 attrs.asked_attributes |= FSAL_ATTR_FSID; 00249 cache_inode_getattr(layout_state->state_pentry, 00250 &attrs, 00251 data->pcontext, 00252 &cache_status); 00253 if (cache_status != CACHE_INODE_SUCCESS) { 00254 res_LAYOUTRETURN4.lorr_status 00255 = nfs4_Errno(cache_status); 00256 return res_LAYOUTRETURN4.lorr_status; 00257 } 00258 00259 memset(&attrs, 0, sizeof(fsal_attrib_list_t)); 00260 attrs.asked_attributes |= FSAL_ATTR_FSID; 00261 00262 if (memcmp(&fsid, &(attrs.fsid), sizeof(fsal_fsid_t))) 00263 continue; 00264 } 00265 00266 res_LAYOUTRETURN4.lorr_status = 00267 nfs4_return_one_state(layout_state->state_pentry, 00268 data->pcontext, 00269 TRUE, 00270 arg_LAYOUTRETURN4.lora_reclaim, 00271 (arg_LAYOUTRETURN4.lora_layoutreturn.lr_returntype), 00272 layout_state, 00273 spec, 00274 0, 00275 NULL, 00276 &deleted); 00277 if (res_LAYOUTRETURN4.lorr_status != NFS4_OK) { 00278 break; 00279 } 00280 } 00281 00282 memset(data->current_stateid.other, 0, 00283 sizeof(data->current_stateid.other)); 00284 data->current_stateid.seqid = NFS4_UINT32_MAX; 00285 res_LAYOUTRETURN4.LAYOUTRETURN4res_u.lorr_stateid.lrs_present = 0; 00286 break; 00287 00288 default: 00289 res_LAYOUTRETURN4.lorr_status = NFS4ERR_INVAL; 00290 return res_LAYOUTRETURN4.lorr_status; 00291 } 00292 #else /* !_PNFS_MDS */ 00293 res_LAYOUTRETURN4.lorr_status = NFS4ERR_NOTSUPP; 00294 #endif /* !_PNFS_MDS */ 00295 return res_LAYOUTRETURN4.lorr_status; 00296 } /* nfs41_op_layoutreturn */ 00297 00308 void nfs41_op_layoutreturn_Free(LOCK4res * resp) 00309 { 00310 return; 00311 } /* nfs41_op_layoutreturn_Free */ 00312 00313 #ifdef _PNFS_MDS 00314 00340 nfsstat4 nfs4_return_one_state(cache_entry_t *entry, 00341 fsal_op_context_t* context, 00342 fsal_boolean_t synthetic, 00343 fsal_boolean_t reclaim, 00344 layoutreturn_type4 return_type, 00345 state_t *layout_state, 00346 struct pnfs_segment spec_segment, 00347 u_int body_len, 00348 const char* body_val, 00349 bool_t* deleted) 00350 { 00351 /* Return from cache_inode calls */ 00352 cache_inode_status_t cache_status = 0; 00353 /* Return from SAL calls */ 00354 state_status_t state_status = 0; 00355 /* Return from this function */ 00356 nfsstat4 nfs_status = 0; 00357 /* Iterator along linked list */ 00358 struct glist_head *glist = NULL; 00359 /* Saved 'next' pointer for glist_for_each_safe */ 00360 struct glist_head *glistn = NULL; 00361 /* Input arguments to FSAL_layoutreturn */ 00362 struct fsal_layoutreturn_arg arg; 00363 /* The FSAL file handle */ 00364 fsal_handle_t *handle = NULL; 00365 /* XDR stream holding the lrf_body opaque */ 00366 XDR lrf_body; 00367 /* The beginning of the stream */ 00368 unsigned int beginning = 0; 00369 /* The current segment in iteration */ 00370 state_layout_segment_t *segment = NULL; 00371 /* If we have a lock on the segment */ 00372 bool_t seg_locked = FALSE; 00373 00374 if (body_val) { 00375 xdrmem_create(&lrf_body, 00376 (char*) body_val, /* Decoding won't modify this */ 00377 body_len, 00378 XDR_DECODE); 00379 beginning = xdr_getpos(&lrf_body); 00380 } 00381 00382 handle = cache_inode_get_fsal_handle(entry, 00383 &cache_status); 00384 00385 if (cache_status != CACHE_INODE_SUCCESS) { 00386 return nfs4_Errno(cache_status); 00387 } 00388 00389 memset(&arg, 0, sizeof(struct fsal_layoutreturn_arg)); 00390 00391 arg.reclaim = reclaim; 00392 arg.lo_type = layout_state->state_data.layout.state_layout_type; 00393 arg.return_type = return_type; 00394 arg.spec_segment = spec_segment; 00395 arg.synthetic = synthetic; 00396 00397 if (!reclaim) { 00398 /* The _safe version of glist_for_each allows us to delete 00399 segments while we iterate. */ 00400 glist_for_each_safe(glist, 00401 glistn, 00402 &layout_state->state_data.layout.state_segments) { 00403 segment = glist_entry(glist, 00404 state_layout_segment_t, 00405 sls_state_segments); 00406 00407 pthread_mutex_lock(&segment->sls_mutex); 00408 seg_locked = TRUE; 00409 00410 arg.cur_segment = segment->sls_segment; 00411 arg.fsal_seg_data = segment->sls_fsal_data; 00412 arg.last_segment = (glistn->next == glistn); 00413 00414 if (pnfs_segment_contains(spec_segment, 00415 segment->sls_segment)) { 00416 arg.dispose = TRUE; 00417 } else if (pnfs_segments_overlap(spec_segment, 00418 segment->sls_segment)) { 00419 arg.dispose = FALSE; 00420 } else { 00421 pthread_mutex_unlock(&segment->sls_mutex); 00422 continue; 00423 } 00424 00425 nfs_status = 00426 fsal_mdsfunctions 00427 .layoutreturn(handle, 00428 context, 00429 (body_val ? &lrf_body : NULL), 00430 &arg); 00431 00432 if (nfs_status != NFS4_OK) { 00433 goto out; 00434 } 00435 00436 if (arg.dispose) { 00437 if (state_delete_segment(segment) 00438 != STATE_SUCCESS) { 00439 nfs_status = nfs4_Errno_state(state_status); 00440 goto out; 00441 } 00442 } else { 00443 segment->sls_segment 00444 = pnfs_segment_difference(spec_segment, 00445 segment->sls_segment); 00446 pthread_mutex_unlock(&segment->sls_mutex); 00447 } 00448 } 00449 seg_locked = FALSE; 00450 00451 if (body_val) { 00452 /* This really should work in all cases for an 00453 in-memory decode stream. */ 00454 xdr_setpos(&lrf_body, beginning); 00455 } 00456 if (glist_empty(&layout_state->state_data.layout.state_segments)) { 00457 state_del(layout_state, &state_status); 00458 *deleted = TRUE; 00459 } else { 00460 *deleted = FALSE; 00461 } 00462 } else { 00463 /* For a reclaim return, there are no recorded segments in 00464 state. */ 00465 arg.cur_segment.io_mode = 0; 00466 arg.cur_segment.offset = 0; 00467 arg.cur_segment.length = 0; 00468 arg.fsal_seg_data = NULL; 00469 arg.last_segment = FALSE; 00470 arg.dispose = FALSE; 00471 00472 nfs_status = 00473 fsal_mdsfunctions 00474 .layoutreturn(handle, 00475 context, 00476 (body_val ? &lrf_body : NULL), 00477 &arg); 00478 00479 if (nfs_status != NFS4_OK) { 00480 goto out; 00481 } 00482 *deleted = TRUE; 00483 } 00484 00485 nfs_status = NFS4_OK; 00486 00487 out: 00488 if (body_val) { 00489 xdr_destroy(&lrf_body); 00490 } 00491 if (seg_locked) { 00492 pthread_mutex_unlock(&segment->sls_mutex); 00493 } 00494 00495 return nfs_status; 00496 } 00497 00509 fsal_boolean_t nfs4_pnfs_supported(const exportlist_t *export) 00510 { 00511 if (!export) 00512 { 00513 return FALSE; 00514 } 00515 else 00516 { 00517 return export->FS_export_context.fe_static_fs_info->pnfs_supported; 00518 } 00519 } 00520 #endif /* _PNFS_MDS */