nfs-ganesha 1.4

nfs41_op_layoutreturn.c

Go to the documentation of this file.
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 */