nfs-ganesha 1.4

cache_inode_rdwr.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                          /* _SOLARIS */
00044 
00045 #include "fsal.h"
00046 
00047 #include "LRU_List.h"
00048 #include "log.h"
00049 #include "HashData.h"
00050 #include "HashTable.h"
00051 #include "cache_inode.h"
00052 #include "cache_inode_lru.h"
00053 #include "nfs_core.h"
00054 
00055 #include <unistd.h>
00056 #include <sys/types.h>
00057 #include <sys/stat.h>
00058 #include <sys/param.h>
00059 #include <time.h>
00060 #include <pthread.h>
00061 #include <assert.h>
00062 
00085 cache_inode_status_t
00086 cache_inode_rdwr(cache_entry_t *entry,
00087                  cache_inode_io_direction_t io_direction,
00088                  uint64_t offset,
00089                  size_t io_size,
00090                  size_t *bytes_moved,
00091                  void *buffer,
00092                  bool_t *eof,
00093                  fsal_op_context_t *context,
00094                  cache_inode_stability_t stable,
00095                  cache_inode_status_t *status)
00096 {
00097      /* Error return from FSAL calls */
00098      fsal_status_t fsal_status = {0, 0};
00099      /* Required open mode to successfully read or write */
00100      fsal_openflags_t openflags = FSAL_O_CLOSED;
00101      fsal_openflags_t loflags;
00102      /* TRUE if we have taken the content lock on 'entry' */
00103      bool_t content_locked = FALSE;
00104      /* TRUE if we have taken the attribute lock on 'entry' */
00105      bool_t attributes_locked = FALSE;
00106      /* TRUE if we opened a previously closed FD */
00107      bool_t opened = FALSE;
00108      /* We need this until Jim Lieb redoes the FSAL interface.  But
00109         there's no reason to make users of cache_inode deal with it. */
00110      fsal_seek_t seek_descriptor = {
00111           .whence = FSAL_SEEK_SET,
00112           .offset = offset
00113      };
00114 
00115      /* Set flags for a read or write, as appropriate */
00116      if (io_direction == CACHE_INODE_READ) {
00117           openflags = FSAL_O_RDONLY;
00118      } else {
00119           openflags = FSAL_O_WRONLY;
00120           if (stable == CACHE_INODE_SAFE_WRITE_TO_FS)
00121              openflags |= FSAL_O_SYNC;
00122      }
00123 
00124      /* IO is done only on REGULAR_FILEs */
00125      if (entry->type != REGULAR_FILE) {
00126           *status = CACHE_INODE_BAD_TYPE;
00127           goto out;
00128      }
00129 
00130      if (stable == CACHE_INODE_UNSAFE_WRITE_TO_GANESHA_BUFFER) {
00131           /* Write to memory */
00132           pthread_rwlock_wrlock(&entry->content_lock);
00133           content_locked = TRUE;
00134 
00135           /* Is the unstable_data buffer allocated? */
00136           if ((entry->object.file.unstable_data.buffer == NULL) &&
00137               (io_size <= CACHE_INODE_UNSTABLE_BUFFERSIZE)) {
00138                if ((entry->object.file.unstable_data.buffer =
00139                     gsh_malloc(CACHE_INODE_UNSTABLE_BUFFERSIZE)) == NULL) {
00140                     *status = CACHE_INODE_MALLOC_ERROR;
00141                     goto out;
00142                }
00143 
00144                entry->object.file.unstable_data.offset = offset;
00145                entry->object.file.unstable_data.length = io_size;
00146 
00147                memcpy(entry->object.file.unstable_data.buffer,
00148                       buffer, io_size);
00149 
00150                pthread_rwlock_wrlock(&entry->attr_lock);
00151                attributes_locked = TRUE;
00152                cache_inode_set_time_current(&entry->attributes.mtime);
00153                *bytes_moved = io_size;
00154           } else {
00155                if ((entry->object.file.unstable_data.offset < offset) &&
00156                    (io_size + offset < CACHE_INODE_UNSTABLE_BUFFERSIZE)) {
00157                     entry->object.file.unstable_data.length =
00158                          io_size + offset;
00159                     memcpy(entry->object.file.unstable_data.buffer +
00160                            offset, buffer, io_size);
00161 
00162                     pthread_rwlock_wrlock(&entry->attr_lock);
00163                     attributes_locked = TRUE;
00164                     cache_inode_set_time_current(&entry->attributes.mtime);
00165                     *bytes_moved = io_size;
00166                } else {
00167                     /* Go back to stable writes */
00168                     stable = CACHE_INODE_SAFE_WRITE_TO_FS;
00169                }
00170           }
00171           if (content_locked) {
00172                pthread_rwlock_unlock(&entry->content_lock);
00173                content_locked = FALSE;
00174           }
00175           if (attributes_locked) {
00176                pthread_rwlock_unlock(&entry->attr_lock);
00177                attributes_locked = FALSE;
00178           }
00179      }
00180 
00181      if (stable == CACHE_INODE_SAFE_WRITE_TO_FS ||
00182          stable == CACHE_INODE_UNSAFE_WRITE_TO_FS_BUFFER) {
00183           /* Write through the FSAL.  We need a write lock only
00184              if we need to open or close a file descriptor. */
00185           pthread_rwlock_rdlock(&entry->content_lock);
00186           content_locked = TRUE;
00187           loflags = entry->object.file.open_fd.openflags;
00188           if ((!cache_inode_fd(entry)) ||
00189               (loflags && loflags != FSAL_O_RDWR && loflags != openflags)) {
00190                pthread_rwlock_unlock(&entry->content_lock);
00191                pthread_rwlock_wrlock(&entry->content_lock);
00192                loflags = entry->object.file.open_fd.openflags;
00193                if ((!cache_inode_fd(entry)) ||
00194                    (loflags && loflags != FSAL_O_RDWR &&
00195                     loflags != openflags)) {
00196                     if (cache_inode_open(entry,
00197                                          openflags,
00198                                          context,
00199                                          CACHE_INODE_FLAG_CONTENT_HAVE |
00200                                          CACHE_INODE_FLAG_CONTENT_HOLD,
00201                                          status) != CACHE_INODE_SUCCESS) {
00202                          goto out;
00203                     }
00204                     opened = TRUE;
00205                }
00206           }
00207 
00208           /* Call FSAL_read or FSAL_write */
00209           if (io_direction == CACHE_INODE_READ) {
00210                fsal_status
00211                     = FSAL_read(&(entry->object.file.open_fd.fd),
00212                                 &seek_descriptor,
00213                                 io_size,
00214                                 buffer,
00215                                 bytes_moved,
00216                                 eof);
00217           } else {
00218                fsal_status
00219                     = FSAL_write(&(entry->object.file.open_fd.fd),
00220                                  context,
00221                                  &seek_descriptor,
00222                                  io_size,
00223                                  buffer,
00224                                  bytes_moved);
00225 
00226                /* Alright, the unstable write is complete. Now if it was
00227                   supposed to be a stable write we can sync to the hard
00228                   drive. */
00229 
00230                if (stable == CACHE_INODE_SAFE_WRITE_TO_FS &&
00231                    !(entry->object.file.open_fd.openflags & FSAL_O_SYNC)) {
00232                     fsal_status
00233                          = FSAL_commit(&(entry->object.file.open_fd.fd),
00234                                   offset, io_size);
00235                }
00236           }
00237 
00238           LogFullDebug(COMPONENT_FSAL,
00239                        "cache_inode_rdwr: FSAL IO operation returned "
00240                        "%d, asked_size=%zu, effective_size=%zu",
00241                        fsal_status.major, io_size, *bytes_moved);
00242 
00243           if (FSAL_IS_ERROR(fsal_status)) {
00244                if (fsal_status.major == ERR_FSAL_DELAY) {
00245                     LogEvent(COMPONENT_CACHE_INODE,
00246                              "cache_inode_rdwr: FSAL_write "
00247                              " returned EBUSY");
00248                } else {
00249                     LogDebug(COMPONENT_CACHE_INODE,
00250                              "cache_inode_rdwr: fsal_status.major = %d",
00251                              fsal_status.major);
00252                }
00253 
00254                *bytes_moved = 0;
00255                *status = cache_inode_error_convert(fsal_status);
00256 
00257                if (fsal_status.major == ERR_FSAL_STALE) {
00258                     cache_inode_kill_entry(entry);
00259                     goto out;
00260                }
00261 
00262                if ((fsal_status.major != ERR_FSAL_NOT_OPENED)
00263                    && (entry->object.file.open_fd.openflags
00264                        != FSAL_O_CLOSED)) {
00265                     cache_inode_status_t cstatus;
00266                     LogFullDebug(COMPONENT_CACHE_INODE,
00267                                  "cache_inode_rdwr: CLOSING entry %p",
00268                                  entry);
00269                     pthread_rwlock_unlock(&entry->content_lock);
00270                     pthread_rwlock_wrlock(&entry->content_lock);
00271                     cache_inode_close(entry,
00272                                       (CACHE_INODE_FLAG_REALLYCLOSE |
00273                                        CACHE_INODE_FLAG_CONTENT_HAVE |
00274                                        CACHE_INODE_FLAG_CONTENT_HOLD),
00275                                        &cstatus);
00276 
00277                     if (cstatus != CACHE_INODE_SUCCESS) {
00278                         LogCrit(COMPONENT_CACHE_INODE_LRU,
00279                                 "Error closing file in cache_inode_rdwr: %d.",
00280                                 cstatus); 
00281                     }
00282                }
00283 
00284                goto out;
00285           }
00286 
00287           LogFullDebug(COMPONENT_CACHE_INODE,
00288                        "cache_inode_rdwr: inode/direct: io_size=%zu, "
00289                        "bytes_moved=%zu, offset=%"PRIu64,
00290                        io_size, *bytes_moved, offset);
00291 
00292           if (opened) {
00293                if (cache_inode_close(entry,
00294                                      CACHE_INODE_FLAG_CONTENT_HAVE |
00295                                      CACHE_INODE_FLAG_CONTENT_HOLD,
00296                                      status) != CACHE_INODE_SUCCESS) {
00297                     LogEvent(COMPONENT_CACHE_INODE,
00298                              "cache_inode_rdwr: cache_inode_close = %d",
00299                              *status);
00300                     goto out;
00301                }
00302           }
00303 
00304           if (content_locked) {
00305                pthread_rwlock_unlock(&entry->content_lock);
00306                content_locked = FALSE;
00307           }
00308      }
00309 
00310      pthread_rwlock_wrlock(&entry->attr_lock);
00311      attributes_locked = TRUE;
00312      if (io_direction == CACHE_INODE_WRITE) {
00313           if ((*status = cache_inode_refresh_attrs(entry,
00314                                                    context))
00315               != CACHE_INODE_SUCCESS) {
00316                goto out;
00317           }
00318      } else {
00319           cache_inode_set_time_current(&entry->attributes.atime);
00320      }
00321      pthread_rwlock_unlock(&entry->attr_lock);
00322      attributes_locked = FALSE;
00323 
00324      *status = CACHE_INODE_SUCCESS;
00325 
00326 out:
00327 
00328      if (content_locked) {
00329           pthread_rwlock_unlock(&entry->content_lock);
00330           content_locked = FALSE;
00331      }
00332 
00333      if (attributes_locked) {
00334           pthread_rwlock_unlock(&entry->attr_lock);
00335           attributes_locked = FALSE;
00336      }
00337 
00338      return *status;
00339 } /* cache_inode_rdwr */