nfs-ganesha 1.4
|
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 }