nfs-ganesha 1.4

fsal_ds.c

Go to the documentation of this file.
00001 /*
00002  * vim:expandtab:shiftwidth=8:tabstop=8:
00003  *
00004  * Copyright (C) 2010 The Linux Box Corporation
00005  * All Rights Reserved
00006  *
00007  * Contributor: Adam C. Emerson
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 
00034 #ifdef HAVE_CONFIG_H
00035 #include "config.h"
00036 #endif
00037 
00038 #include "fsal.h"
00039 #include "fsal_internal.h"
00040 #include "fsal_convert.h"
00041 #include "nfsv41.h"
00042 #include <cephfs/libcephfs.h>
00043 #include <fcntl.h>
00044 #include "HashTable.h"
00045 #include <pthread.h>
00046 #include "fsal_types.h"
00047 #include "fsal_pnfs.h"
00048 #include "pnfs_common.h"
00049 #include "fsal_pnfs_files.h"
00050 
00051 #define min(a,b)          \
00052      ({ typeof (a) _a = (a);                    \
00053           typeof (b) _b = (b);                  \
00054           _a < _b ? _a : _b; })
00055 
00056 nfsstat4
00057 CEPHFSAL_DS_read(fsal_handle_t *exthandle,
00058                  fsal_op_context_t *extcontext,
00059                  const stateid4 *stateid,
00060                  offset4 offset,
00061                  count4 requested_length,
00062                  caddr_t buffer,
00063                  count4 *supplied_length,
00064                  fsal_boolean_t *end_of_file)
00065 {
00066      /* Our format for the file handle */
00067      cephfsal_handle_t* handle = (cephfsal_handle_t*) exthandle;
00068      /* Our format for the operational context */
00069      cephfsal_op_context_t* context = (cephfsal_op_context_t*) extcontext;
00070      /* Mount parameter specified for all calls to Ceph */
00071      struct ceph_mount_info *cmount = context->export_context->cmount;
00072      /* The OSD number for this machine */
00073      int local_OSD = 0;
00074      /* Width of a stripe in the file */
00075      uint32_t stripe_width = 0;
00076      /* Beginning of a block */
00077      uint64_t block_start = 0;
00078      /* Number of the stripe being read */
00079      uint32_t stripe = 0;
00080      /* Internal offset within the stripe*/
00081      uint32_t internal_offset = 0;
00082      /* The amount actually read */
00083      int amount_read = 0;
00084 
00085      /* Find out what my OSD ID is, so we can avoid talking to other
00086         OSDs. */
00087 
00088      local_OSD = ceph_get_local_osd(cmount);
00089      if (local_OSD < 0) {
00090           return posix2nfs4_error(-local_OSD);
00091      }
00092 
00093      /* Find out what stripe we're writing to and where within the
00094         stripe. */
00095 
00096      stripe_width = handle->data.layout.fl_stripe_unit;
00097      if (stripe_width == 0) {
00098           /* READ isn't actually allowed to return BADHANDLE */
00099           return NFS4ERR_INVAL;
00100      }
00101      stripe = offset / stripe_width;
00102      block_start = stripe * stripe_width;
00103      internal_offset = offset - block_start;
00104 
00105      if (local_OSD
00106          != ceph_ll_get_stripe_osd(cmount,
00107                                    VINODE(handle),
00108                                    stripe,
00109                                    &(handle->data.layout))) {
00110           return NFS4ERR_PNFS_IO_HOLE;
00111      }
00112 
00113      amount_read
00114           = ceph_ll_read_block(cmount,
00115                                VINODE(handle),
00116                                stripe,
00117                                buffer,
00118                                internal_offset,
00119                                min((stripe_width -
00120                                     internal_offset),
00121                                    requested_length),
00122                                &(handle->data.layout));
00123      if (amount_read < 0) {
00124           return posix2nfs4_error(-amount_read);
00125      }
00126 
00127      *supplied_length = amount_read;
00128 
00129      *end_of_file = FALSE;
00130 
00131      return NFS4_OK;
00132 }
00133 
00134 nfsstat4
00135 CEPHFSAL_DS_write(fsal_handle_t *exthandle,
00136                   fsal_op_context_t *extcontext,
00137                   const stateid4 *stateid,
00138                   offset4 offset,
00139                   count4 write_length,
00140                   caddr_t buffer,
00141                   stable_how4 stability_wanted,
00142                   count4 *written_length,
00143                   verifier4 *writeverf,
00144                   stable_how4 *stability_got)
00145 {
00146      /* Our format for the file handle */
00147      cephfsal_handle_t* handle = (cephfsal_handle_t*) exthandle;
00148      /* Our format for the operational context */
00149      cephfsal_op_context_t* context = (cephfsal_op_context_t*) extcontext;
00150      /* Mount parameter specified for all calls to Ceph */
00151      struct ceph_mount_info *cmount = context->export_context->cmount;
00152      /* User ID and group ID for permissions */
00153      int uid = FSAL_OP_CONTEXT_TO_UID(context);
00154      int gid = FSAL_OP_CONTEXT_TO_GID(context);
00155      /* The OSD number for this host */
00156      int local_OSD = 0;
00157      /* Width of a stripe in the file */
00158      uint32_t stripe_width = 0;
00159      /* Beginning of a block */
00160      uint64_t block_start = 0;
00161      /* Number of the stripe being written */
00162      uint32_t stripe = 0;
00163      /* Internal offset within the stripe*/
00164      uint32_t internal_offset = 0;
00165      /* The amount actually written */
00166      int32_t amount_written = 0;
00167      /* The adjusted write length, confined to one object */
00168      uint32_t adjusted_write = 0;
00169      /* Return code from ceph calls */
00170      int ceph_status = 0;
00171 
00172      /* Zero the verifier.  All our DS writes are stable, so we don't
00173         use it, but we do want to rpevent spurious junk from making it
00174         look like there was a failure. */
00175 
00176      memset(*writeverf, 0, NFS4_VERIFIER_SIZE);
00177 
00178      /* Find out what my OSD ID is, so we can avoid talking to other
00179         OSDs. */
00180 
00181      local_OSD = ceph_get_local_osd(cmount);
00182 
00183      /* Find out what stripe we're writing to and where within the
00184         stripe. */
00185 
00186      stripe_width = handle->data.layout.fl_stripe_unit;
00187      if (stripe_width == 0) {
00188           /* WRITE isn't actually allowed to return BADHANDLE */
00189           return NFS4ERR_INVAL;
00190      }
00191      stripe = offset / stripe_width;
00192      block_start = stripe * stripe_width;
00193      internal_offset = offset - block_start;
00194 
00195      if (local_OSD
00196          != ceph_ll_get_stripe_osd(cmount,
00197                                    VINODE(handle),
00198                                    stripe,
00199                                    &(handle->data.layout))) {
00200           return NFS4ERR_PNFS_IO_HOLE;
00201      }
00202 
00203      adjusted_write = min((stripe_width - internal_offset),
00204                           write_length);
00205 
00206      /* If the client specifies FILE_SYNC4, then we have to connect
00207         the filehandle and use the MDS to update size and access
00208         time. */
00209      if (stability_wanted == FILE_SYNC4) {
00210           Fh* descriptor = NULL;
00211 
00212           if ((ceph_status = ceph_ll_connectable_m(cmount, &VINODE(handle),
00213                                                    handle->data.parent_ino,
00214                                                    handle->data.parent_hash))
00215               != 0) {
00216                printf("Filehandle connection failed with: %d\n", ceph_status);
00217                return posix2nfs4_error(-ceph_status);
00218           }
00219           if ((ceph_status = ceph_ll_open(cmount,
00220                                           VINODE(handle),
00221                                           O_WRONLY,
00222                                           &descriptor,
00223                                           uid,
00224                                           gid)) != 0) {
00225                printf("Open failed with: %d\n", ceph_status);
00226                return posix2nfs4_error(-ceph_status);
00227           }
00228 
00229           amount_written
00230                = ceph_ll_write(cmount,
00231                                descriptor,
00232                                offset,
00233                                adjusted_write,
00234                                buffer);
00235 
00236           if (amount_written < 0) {
00237                printf("Write failed with: %d\n", amount_written);
00238                ceph_ll_close(cmount, descriptor);
00239                return posix2nfs4_error(-amount_written);
00240           }
00241 
00242           if ((ceph_status = ceph_ll_fsync(cmount, descriptor, 0)) < 0) {
00243                printf("fsync failed with: %d\n", ceph_status);
00244                ceph_ll_close(cmount, descriptor);
00245                return posix2nfs4_error(-ceph_status);
00246           }
00247 
00248       if ((ceph_status = ceph_ll_close(cmount, descriptor)) < 0) {
00249            printf("close failed with: %d\n", ceph_status);
00250            return posix2nfs4_error(-ceph_status);
00251       }
00252       *written_length = amount_written;
00253       *stability_got = FILE_SYNC4;
00254      } else {
00255           /* FILE_SYNC4 wasn't specified, so we don't have to bother with
00256              the MDS. */
00257 
00258           if ((amount_written
00259                = ceph_ll_write_block(cmount,
00260                                      VINODE(handle),
00261                                      stripe,
00262                                      buffer,
00263                                      internal_offset,
00264                                      adjusted_write,
00265                                      &(handle->data.layout),
00266                                      handle->data.snapseq,
00267                                      (stability_wanted
00268                                       == DATA_SYNC4)))
00269               < 0) {
00270                return posix2nfs4_error(-amount_written);
00271           }
00272 
00273           *written_length = amount_written;
00274           *stability_got = stability_wanted;
00275      }
00276 
00277      return NFS4_OK;
00278 }
00279 
00280 nfsstat4
00281 CEPHFSAL_DS_commit(fsal_handle_t *exthandle,
00282                    fsal_op_context_t *extcontext,
00283                    offset4 offset,
00284                    count4 count,
00285                    verifier4 *writeverf)
00286 {
00287      /* Our format for the file handle */
00288      cephfsal_handle_t* handle = (cephfsal_handle_t*) exthandle;
00289      /* Our format for the operational context */
00290      cephfsal_op_context_t* context = (cephfsal_op_context_t*) extcontext;
00291      /* Mount parameter specified for all calls to Ceph */
00292      struct ceph_mount_info *cmount = context->export_context->cmount;
00293      /* Width of a stripe in the file */
00294      const uint32_t stripe_width = handle->data.layout.fl_stripe_unit;
00295      /* Error return from Ceph */
00296      int rc = 0;
00297 
00298      /* Find out what stripe we're writing to and where within the
00299         stripe. */
00300 
00301      if (stripe_width == 0) {
00302           /* COMMIT isn't actually allowed to return BADHANDLE */
00303           return NFS4ERR_INVAL;
00304      }
00305 
00306      memset(*writeverf, 0, NFS4_VERIFIER_SIZE);
00307 
00308      rc = ceph_ll_commit_blocks(cmount,
00309                                 VINODE(handle),
00310                                 offset,
00311                                 count);
00312      if (rc < 0) {
00313           return posix2nfs4_error(rc);
00314      }
00315 
00316      return NFS4_OK;
00317 }