Exemplo n.º 1
0
static void
rules_restore(void)
{
	struct conf c;
	struct dbinfo dbi;
	unsigned int f;

	for (f = 1; state_iterate(state, &c, &dbi, f) == 1; f = 0) {
		if (dbi.id[0] == '\0')
			continue;
		(void)run_change("rem", &c, dbi.id, 0);
		(void)run_change("add", &c, dbi.id, sizeof(dbi.id));
	}
}
Exemplo n.º 2
0
static void
update(void)
{
	struct timespec ts;
	struct conf c;
	struct dbinfo dbi;
	unsigned int f, n;
	char buf[128];
	void *ss = &c.c_ss;

	if (clock_gettime(CLOCK_REALTIME, &ts) == -1) {
		(*lfun)(LOG_ERR, "clock_gettime failed (%m)"); 
		return;
	}

again:
	for (n = 0, f = 1; state_iterate(state, &c, &dbi, f) == 1;
	    f = 0, n++)
	{
		time_t when = c.c_duration + dbi.last;
		if (debug > 1) {
			char b1[64], b2[64];
			sockaddr_snprintf(buf, sizeof(buf), "%a:%p", ss);
			(*lfun)(LOG_DEBUG, "%s:[%u] %s count=%d duration=%d "
			    "last=%s " "now=%s", __func__, n, buf, dbi.count,
			    c.c_duration, fmttime(b1, sizeof(b1), dbi.last),
			    fmttime(b2, sizeof(b2), ts.tv_sec));
		}
		if (c.c_duration == -1 || when >= ts.tv_sec)
			continue;
		if (dbi.id[0]) {
			run_change("rem", &c, dbi.id, 0);
			sockaddr_snprintf(buf, sizeof(buf), "%a", ss);
			syslog(LOG_INFO, "released %s/%d:%d after %d seconds",
			    buf, c.c_lmask, c.c_port, c.c_duration);
		}
		state_del(state, &c);
		goto again;
	}
}
Exemplo n.º 3
0
int nfs4_op_lock(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp)
{
  char __attribute__ ((__unused__)) funcname[] = "nfs4_op_lock";

#ifndef _WITH_NFSV4_LOCKS
  /* Lock are not supported */
  resp->resop = NFS4_OP_LOCK;
  res_LOCK4.status = NFS4ERR_LOCK_NOTSUPP;

  return res_LOCK4.status;
#else

  state_status_t            state_status;
  state_data_t              candidate_data;
  state_type_t              candidate_type;
  int                       rc = 0;
  seqid4                    seqid;
  state_t                 * plock_state;    /* state for the lock */
  state_t                 * pstate_open;    /* state for the open owner */
  state_t                 * pstate_previous_iterate;
  state_t                 * pstate_iterate;
  state_owner_t           * plock_owner;
  state_owner_t           * popen_owner;
  state_owner_t           * presp_owner;    /* Owner to store response in */
  state_owner_t           * conflict_owner = NULL;
  state_nfs4_owner_name_t   owner_name;
  nfs_client_id_t           nfs_client_id;
  state_lock_desc_t         lock_desc, conflict_desc;
  state_blocking_t          blocking = STATE_NON_BLOCKING;
  const char              * tag = "LOCK";

  LogDebug(COMPONENT_NFS_V4_LOCK,
           "Entering NFS v4 LOCK handler -----------------------------------------------------");

  /* Initialize to sane starting values */
  resp->resop = NFS4_OP_LOCK;

  /* If there is no FH */
  if(nfs4_Is_Fh_Empty(&(data->currentFH)))
    {
      res_LOCK4.status = NFS4ERR_NOFILEHANDLE;
      LogDebug(COMPONENT_NFS_V4_LOCK,
               "LOCK failed nfs4_Is_Fh_Empty");
      return res_LOCK4.status;
    }

  /* If the filehandle is invalid */
  if(nfs4_Is_Fh_Invalid(&(data->currentFH)))
    {
      res_LOCK4.status = NFS4ERR_BADHANDLE;
      LogDebug(COMPONENT_NFS_V4_LOCK,
               "LOCK failed nfs4_Is_Fh_Invalid");
      return res_LOCK4.status;
    }

  /* Tests if the Filehandle is expired (for volatile filehandle) */
  if(nfs4_Is_Fh_Expired(&(data->currentFH)))
    {
      res_LOCK4.status = NFS4ERR_FHEXPIRED;
      LogDebug(COMPONENT_NFS_V4_LOCK,
               "LOCK failed nfs4_Is_Fh_Expired");
      return res_LOCK4.status;
    }

  /* Lock is done only on a file */
  if(data->current_filetype != REGULAR_FILE)
    {
      /* Type of the entry is not correct */
      switch (data->current_filetype)
        {
        case DIR_BEGINNING:
        case DIR_CONTINUE:
          res_LOCK4.status = NFS4ERR_ISDIR;
          break;
        default:
          res_LOCK4.status = NFS4ERR_INVAL;
          break;
        }
      LogDebug(COMPONENT_NFS_V4_LOCK,
               "LOCK failed wrong file type");
      return res_LOCK4.status;
    }

  /* Convert lock parameters to internal types */
  switch(arg_LOCK4.locktype)
    {
      case READ_LT:
        lock_desc.sld_type = STATE_LOCK_R;
        blocking           = STATE_NON_BLOCKING;
        break;

      case WRITE_LT:
        lock_desc.sld_type = STATE_LOCK_W;
        blocking           = STATE_NON_BLOCKING;
        break;

      case READW_LT:
        lock_desc.sld_type = STATE_LOCK_R;
        blocking           = STATE_NFSV4_BLOCKING;
        break;

      case WRITEW_LT:
        lock_desc.sld_type = STATE_LOCK_W;
        blocking           = STATE_NFSV4_BLOCKING;
        break;
    }

  lock_desc.sld_offset = arg_LOCK4.offset;

  if(arg_LOCK4.length != STATE_LOCK_OFFSET_EOF)
    lock_desc.sld_length = arg_LOCK4.length;
  else
    lock_desc.sld_length = 0;

  if(arg_LOCK4.locker.new_lock_owner)
    {
      /* New lock owner, Find the open owner */
      tag = "LOCK (new owner)";

      /* Check stateid correctness and get pointer to state */
      if((rc = nfs4_Check_Stateid(&arg_LOCK4.locker.locker4_u.open_owner.open_stateid,
                                  data->current_entry,
                                  0LL,
                                  &pstate_open,
                                  data,
                                  STATEID_SPECIAL_FOR_LOCK,
                                  tag)) != NFS4_OK)
        {
          res_LOCK4.status = rc;
          return res_LOCK4.status;
        }

      popen_owner = pstate_open->state_powner;
      plock_state = NULL;
      plock_owner = NULL;
      presp_owner = popen_owner;
      seqid       = arg_LOCK4.locker.locker4_u.open_owner.open_seqid;

      LogLock(COMPONENT_NFS_V4_LOCK, NIV_FULL_DEBUG,
              "LOCK New lock owner from open owner",
              data->current_entry,
              data->pcontext,
              popen_owner,
              &lock_desc);

      /* Check is the clientid is known or not */
      if(nfs_client_id_get(arg_LOCK4.locker.locker4_u.open_owner.lock_owner.clientid,
                           &nfs_client_id) == CLIENT_ID_NOT_FOUND)
        {
          res_LOCK4.status = NFS4ERR_STALE_CLIENTID;
          LogDebug(COMPONENT_NFS_V4_LOCK,
                   "LOCK failed nfs_client_id_get");
          return res_LOCK4.status;
        }

      /* The related stateid is already stored in pstate_open */

      /* An open state has been found. Check its type */
      if(pstate_open->state_type != STATE_TYPE_SHARE)
        {
          res_LOCK4.status = NFS4ERR_BAD_STATEID;
          LogDebug(COMPONENT_NFS_V4_LOCK,
                   "LOCK failed open stateid is not a SHARE");
          return res_LOCK4.status;
        }

      /* Lock seqid (seqid wanted for new lock) should be 0 (see newpynfs test LOCK8c)  */
      if(arg_LOCK4.locker.locker4_u.open_owner.lock_seqid != 0)
        {
          res_LOCK4.status = NFS4ERR_BAD_SEQID;
          LogDebug(COMPONENT_NFS_V4_LOCK,
                   "LOCK failed new lock stateid is not 0");
          return res_LOCK4.status;
        }

      /* Is this lock_owner known ? */
      convert_nfs4_owner((open_owner4 *)&arg_LOCK4.locker.locker4_u.open_owner.lock_owner,
                         &owner_name);
    }
  else
    {
      /* Existing lock owner
       * Find the lock stateid
       * From that, get the open_owner
       */
      tag = "LOCK (existing owner)";

      /* There was code here before to handle all-0 stateid, but that
       * really doesn't apply - when we handle temporary locks for
       * I/O operations (which is where we will see all-0 or all-1
       * stateid, those will not come in through nfs4_op_lock.
       */

      /* Check stateid correctness and get pointer to state */
      if((rc = nfs4_Check_Stateid(&arg_LOCK4.locker.locker4_u.lock_owner.lock_stateid,
                                  data->current_entry,
                                  0LL,
                                  &plock_state,
                                  data,
                                  STATEID_SPECIAL_FOR_LOCK,
                                  tag)) != NFS4_OK)
        {
          res_LOCK4.status = rc;
          LogDebug(COMPONENT_NFS_V4_LOCK,
                   "LOCK failed nfs4_Check_Stateid for existing lock owner");
          return res_LOCK4.status;
        }

      /* An lock state has been found. Check its type */
      if(plock_state->state_type != STATE_TYPE_LOCK)
        {
          res_LOCK4.status = NFS4ERR_BAD_STATEID;
          LogDebug(COMPONENT_NFS_V4_LOCK,
                   "LOCK failed existing lock owner, state type is not LOCK");
          return res_LOCK4.status;
        }

      /* Get the old lockowner. We can do the following 'cast', in NFSv4 lock_owner4 and open_owner4
       * are different types but with the same definition*/
      plock_owner = plock_state->state_powner;
      popen_owner = plock_owner->so_owner.so_nfs4_owner.so_related_owner;
      pstate_open = plock_state->state_data.lock.popenstate;
      presp_owner = plock_owner;
      seqid       = arg_LOCK4.locker.locker4_u.lock_owner.lock_seqid;

      LogLock(COMPONENT_NFS_V4_LOCK, NIV_FULL_DEBUG,
              "LOCK Existing lock owner",
              data->current_entry,
              data->pcontext,
              plock_owner,
              &lock_desc);

#ifdef _CONFORM_TO_TEST_LOCK8c
      /* Check validity of the seqid */
      if(arg_LOCK4.locker.locker4_u.lock_owner.lock_seqid != 0)
        {
          res_LOCK4.status = NFS4ERR_BAD_SEQID;
          LogDebug(COMPONENT_NFS_V4_LOCK,
                   "LOCK failed existing lock owner, lock seqid != 0");
          return res_LOCK4.status;
        }
#endif
    }                           /* if( arg_LOCK4.locker.new_lock_owner ) */

  /* Check seqid (lock_seqid or open_seqid) */
  if(!Check_nfs4_seqid(presp_owner, seqid, op, data, resp, tag))
    {
      /* Response is all setup for us and LogDebug told what was wrong */
      return res_LOCK4.status;
    }

  /* Lock length should not be 0 */
  if(arg_LOCK4.length == 0LL)
    {
      res_LOCK4.status = NFS4ERR_INVAL;
      LogDebug(COMPONENT_NFS_V4_LOCK,
               "LOCK failed length == 0");

      /* Save the response in the lock or open owner */
      Copy_nfs4_state_req(presp_owner, seqid, op, data, resp, tag);

      return res_LOCK4.status;
    }

  /* Check for range overflow.
   * Comparing beyond 2^64 is not possible int 64 bits precision,
   * but off+len > 2^64-1 is equivalent to len > 2^64-1 - off
   */
  if(lock_desc.sld_length > (STATE_LOCK_OFFSET_EOF - lock_desc.sld_offset))
    {
      res_LOCK4.status = NFS4ERR_INVAL;
      LogDebug(COMPONENT_NFS_V4_LOCK,
               "LOCK failed length overflow");

      /* Save the response in the lock or open owner */
      Copy_nfs4_state_req(presp_owner, seqid, op, data, resp, tag);

      return res_LOCK4.status;
    }

  /* Check for conflicts with previously obtained states */

  /* TODO FSF:
   * This will eventually all go into the function of state_lock()
   * For now, we will keep checking against SHARE
   * Check against LOCK will be removed
   * We eventually need to handle special stateids, but not here.
   */

  /* loop into the states related to this pentry to find the related lock */
  pstate_iterate = NULL;
  pstate_previous_iterate = NULL;
  do
    {
      state_iterate(data->current_entry,
                    &pstate_iterate,
                    pstate_previous_iterate,
                    data->pclient, data->pcontext, &state_status);
      if((state_status == STATE_STATE_ERROR)
         || (state_status == STATE_INVALID_ARGUMENT))
        {
          res_LOCK4.status = NFS4ERR_INVAL;
          LogDebug(COMPONENT_NFS_V4_LOCK,
                   "LOCK failed state_iterate");

          /* Save the response in the lock or open owner */
          Copy_nfs4_state_req(presp_owner, seqid, op, data, resp, tag);

          return res_LOCK4.status;
        }

      if(pstate_iterate != NULL)
        {
          /* For now still check conflicts with SHARE here */
          if(pstate_iterate->state_type == STATE_TYPE_SHARE)
            {
              /* In a correct POSIX behavior, a write lock should not be allowed on a read-mode file */
              if((pstate_iterate->state_data.share.share_deny &
                   OPEN4_SHARE_DENY_WRITE) &&
                 !(pstate_iterate->state_data.share.share_access &
                   OPEN4_SHARE_ACCESS_WRITE) &&
                 (arg_LOCK4.locktype == WRITE_LT))
                {
                  /* A conflicting open state, return NFS4ERR_OPENMODE
                   * This behavior is implemented to comply with newpynfs's test LOCK4 */
                  LogLock(COMPONENT_NFS_V4_LOCK, NIV_DEBUG,
                          "LOCK failed conflicts with SHARE",
                          data->current_entry,
                          data->pcontext,
                          plock_owner,
                          &lock_desc);

                  res_LOCK4.status = NFS4ERR_OPENMODE;

                  /* Save the response in the lock or open owner */
                  Copy_nfs4_state_req(presp_owner, seqid, op, data, resp, tag);

                  return res_LOCK4.status;
                }
            }
        }                       /* if( pstate_iterate != NULL ) */
      pstate_previous_iterate = pstate_iterate;
    }
  while(pstate_iterate != NULL);

  /* TODO FSF:
   * Ok from here on out, stuff is broken...
   * For new lock owner, need to create a new stateid
   * And then call state_lock()
   * If that fails, need to back out any stateid changes
   * If that succeeds, need to increment seqids
   */
  if(arg_LOCK4.locker.new_lock_owner)
    {
      /* A lock owner is always associated with a previously made open
       * which has itself a previously made stateid */
      if(nfs4_owner_Get_Pointer(&owner_name, &plock_owner))
        {
          /* Lock owner already existsc, check lock_seqid */
          if(!Check_nfs4_seqid(plock_owner,
                               arg_LOCK4.locker.locker4_u.open_owner.lock_seqid,
                               op,
                               data,
                               resp,
                               "LOCK (new owner but owner exists)"))
            {
              /* Response is all setup for us and LogDebug told what was wrong */
              return res_LOCK4.status;
            }
        }
      else
        {
          /* This lock owner is not known yet, allocated and set up a new one */
          plock_owner = create_nfs4_owner(data->pclient,
                                          &owner_name,
                                          (open_owner4 *) &arg_LOCK4.locker.locker4_u.open_owner.lock_owner,
                                          popen_owner,
                                          0);

          if(plock_owner == NULL)
            {
              res_LOCK4.status = NFS4ERR_RESOURCE;

              LogLock(COMPONENT_NFS_V4_LOCK, NIV_DEBUG,
                      "LOCK failed to create new lock owner",
                      data->current_entry,
                      data->pcontext,
                      popen_owner,
                      &lock_desc);
              return res_LOCK4.status;
            }
        }

      /* Prepare state management structure */
      candidate_type = STATE_TYPE_LOCK;
      candidate_data.lock.popenstate = pstate_open;

      /* Add the lock state to the lock table */
      if(state_add(data->current_entry,
                   candidate_type,
                   &candidate_data,
                   plock_owner,
                   data->pclient,
                   data->pcontext,
                   &plock_state, &state_status) != STATE_SUCCESS)
        {
          res_LOCK4.status = NFS4ERR_RESOURCE;

          LogLock(COMPONENT_NFS_V4_LOCK, NIV_DEBUG,
                  "LOCK failed to add new stateid",
                  data->current_entry,
                  data->pcontext,
                  plock_owner,
                  &lock_desc);

          if(destroy_nfs4_owner(data->pclient, &owner_name) != STATE_SUCCESS)
            LogDebug(COMPONENT_NFS_V4_LOCK,
                     "destroy_nfs4_owner failed");

          return res_LOCK4.status;
        }
    }                           /* if( arg_LOCK4.locker.new_lock_owner ) */

  /* Now we have a lock owner and a stateid.
   * Go ahead and push lock into SAL (and FSAL).
   */
  if(state_lock(data->current_entry,
                data->pcontext,
                plock_owner,
                plock_state,
                blocking,
                NULL,     /* No block data for now */
                &lock_desc,
                &conflict_owner,
                &conflict_desc,
                data->pclient,
                &state_status) != STATE_SUCCESS)
    {
      if(state_status == STATE_LOCK_CONFLICT)
        {
          /* A  conflicting lock from a different lock_owner, returns NFS4ERR_DENIED */
          Process_nfs4_conflict(&res_LOCK4.LOCK4res_u.denied,
                                conflict_owner,
                                &conflict_desc);
        }

      LogDebug(COMPONENT_NFS_V4_LOCK,
               "LOCK failed with status %s",
               state_err_str(state_status));

      res_LOCK4.status = nfs4_Errno_state(state_status);

      if(arg_LOCK4.locker.new_lock_owner)
        {
          /* Need to destroy lock owner and state */
          if(state_del(plock_state,
                       data->pclient,
                       &state_status) != STATE_SUCCESS)
            LogDebug(COMPONENT_NFS_V4_LOCK,
                     "state_del failed with status %s",
                     state_err_str(state_status));

          if(destroy_nfs4_owner(data->pclient, &owner_name) != STATE_SUCCESS)
            LogDebug(COMPONENT_NFS_V4_LOCK,
                     "destroy_nfs4_owner failed");

        }

      /* Save the response in the lock or open owner */
      if(res_LOCK4.status != NFS4ERR_RESOURCE &&
         res_LOCK4.status != NFS4ERR_BAD_STATEID)
        Copy_nfs4_state_req(presp_owner, seqid, op, data, resp, tag);

      return res_LOCK4.status;
    }

  res_LOCK4.status = NFS4_OK;

  /* Handle stateid/seqid for success */
  update_stateid(plock_state,
                 &res_LOCK4.LOCK4res_u.resok4.lock_stateid,
                 data,
                 tag);

  LogFullDebug(COMPONENT_NFS_V4_LOCK,
               "LOCK state_seqid = %u, plock_state = %p",
               plock_state->state_seqid,
               plock_state);

  /* update the lock counter in the related open-stateid */
  pstate_open->state_data.share.lockheld += 1;

  /* Save the response in the lock or open owner */
  Copy_nfs4_state_req(presp_owner, seqid, op, data, resp, tag);

  LogLock(COMPONENT_NFS_V4_LOCK, NIV_FULL_DEBUG,
          "LOCK applied",
          data->current_entry,
          data->pcontext,
          plock_owner,
          &lock_desc);

  return res_LOCK4.status;
#endif
}                               /* nfs4_op_lock */
Exemplo n.º 4
0
int nfs41_op_open(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp)
{
  char __attribute__ ((__unused__)) funcname[] = "nfs4_op_open";

  cache_entry_t           * pentry_parent = NULL;
  cache_entry_t           * pentry_lookup = NULL;
  cache_entry_t           * pentry_newfile = NULL;
  fsal_handle_t           * pnewfsal_handle = NULL;
  fsal_attrib_list_t        attr_parent;
  fsal_attrib_list_t        attr;
  fsal_attrib_list_t        attr_newfile;
  fsal_attrib_list_t        sattr;
  fsal_openflags_t          openflags = 0;
  cache_inode_status_t      cache_status;
  state_status_t            state_status;
  nfsstat4                  rc;
  int                       retval;
  fsal_name_t               filename;
  bool_t                    AttrProvided = FALSE;
  fsal_accessmode_t         mode = 0600;
  nfs_fh4                   newfh4;
  nfs_worker_data_t       * pworker = NULL;
  int                       convrc = 0;
  state_data_t              candidate_data;
  state_type_t              candidate_type;
  state_t                 * pfile_state = NULL;
  state_t                 * pstate_found_iterate = NULL;
  state_t                 * pstate_previous_iterate = NULL;
  state_t                 * pstate_found_same_owner = NULL;
  state_nfs4_owner_name_t   owner_name;
  state_owner_t           * powner = NULL;

  fsal_accessflags_t write_access = FSAL_MODE_MASK_SET(FSAL_W_OK) |
                                    FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_DATA |
                                                       FSAL_ACE_PERM_APPEND_DATA);
  fsal_accessflags_t read_access = FSAL_MODE_MASK_SET(FSAL_R_OK) |
                                   FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_READ_DATA);

  resp->resop = NFS4_OP_OPEN;
  res_OPEN4.status = NFS4_OK;

  uint32_t tmp_attr[2];
  uint_t tmp_int = 2;

#ifdef _USE_PNFS
  nfs_client_id_t nfs_clientid;
  bool_t open_owner_known = FALSE;
  int pnfs_status;
#endif
  cache_inode_create_arg_t create_arg;

  pworker = (nfs_worker_data_t *) data->pclient->pworker;

  /* If there is no FH */
  if(nfs4_Is_Fh_Empty(&(data->currentFH)))
    {
      res_OPEN4.status = NFS4ERR_NOFILEHANDLE;
      return res_OPEN4.status;
    }

  /* If the filehandle is invalid */
  if(nfs4_Is_Fh_Invalid(&(data->currentFH)))
    {
      res_OPEN4.status = NFS4ERR_BADHANDLE;
      return res_OPEN4.status;
    }

  /* Tests if the Filehandle is expired (for volatile filehandle) */
  if(nfs4_Is_Fh_Expired(&(data->currentFH)))
    {
      res_OPEN4.status = NFS4ERR_FHEXPIRED;
      return res_OPEN4.status;
    }

  /* This can't be done on the pseudofs */
  if(nfs4_Is_Fh_Pseudo(&(data->currentFH)))
    {
      res_OPEN4.status = NFS4ERR_ROFS;
      return res_OPEN4.status;
    }

  /* If Filehandle points to a xattr object, manage it via the xattrs specific functions */
  if(nfs4_Is_Fh_Xattr(&(data->currentFH)))
    return nfs4_op_open_xattr(op, data, resp);

  /* If data->current_entry is empty, repopulate it */
  if(data->current_entry == NULL)
    {
      if((data->current_entry = nfs_FhandleToCache(NFS_V4,
                                                   NULL,
                                                   NULL,
                                                   &(data->currentFH),
                                                   NULL,
                                                   NULL,
                                                   &(res_OPEN4.status),
                                                   &attr,
                                                   data->pcontext,
                                                   data->pclient,
                                                   data->ht, &retval)) == NULL)
        {
          res_OPEN4.status = NFS4ERR_SERVERFAULT;
          return res_OPEN4.status;
        }
    }

  /* Set parent */
  pentry_parent = data->current_entry;

  /* First switch is based upon claim type */
  switch (arg_OPEN4.claim.claim)
    {
    case CLAIM_DELEGATE_CUR:
    case CLAIM_DELEGATE_PREV:
      /* Check for name length */
      if(arg_OPEN4.claim.open_claim4_u.file.utf8string_len > FSAL_MAX_NAME_LEN)
        {
          res_OPEN4.status = NFS4ERR_NAMETOOLONG;
          return res_OPEN4.status;
        }

      /* get the filename from the argument, it should not be empty */
      if(arg_OPEN4.claim.open_claim4_u.file.utf8string_len == 0)
        {
          res_OPEN4.status = NFS4ERR_INVAL;
          return res_OPEN4.status;
        }

      res_OPEN4.status = NFS4ERR_NOTSUPP;
      return res_OPEN4.status;
      break;

    case CLAIM_NULL:
      /* Check for name length */
      if(arg_OPEN4.claim.open_claim4_u.file.utf8string_len > FSAL_MAX_NAME_LEN)
        {
          res_OPEN4.status = NFS4ERR_NAMETOOLONG;
          return res_OPEN4.status;
        }

      /* get the filename from the argument, it should not be empty */
      if(arg_OPEN4.claim.open_claim4_u.file.utf8string_len == 0)
        {
          res_OPEN4.status = NFS4ERR_INVAL;
          return res_OPEN4.status;
        }

      /* Check if asked attributes are correct */
      if(arg_OPEN4.openhow.openflag4_u.how.mode == GUARDED4 ||
         arg_OPEN4.openhow.openflag4_u.how.mode == UNCHECKED4)
        {
          if(!nfs4_Fattr_Supported
             (&arg_OPEN4.openhow.openflag4_u.how.createhow4_u.createattrs))
            {
              res_OPEN4.status = NFS4ERR_ATTRNOTSUPP;
              return res_OPEN4.status;
            }

          /* Do not use READ attr, use WRITE attr */
          if(!nfs4_Fattr_Check_Access
             (&arg_OPEN4.openhow.openflag4_u.how.createhow4_u.createattrs,
              FATTR4_ATTR_WRITE))
            {
              res_OPEN4.status = NFS4ERR_INVAL;
              return res_OPEN4.status;
            }
        }

      /* Check if filename is correct */
      if((cache_status =
          cache_inode_error_convert(FSAL_buffdesc2name
                                    ((fsal_buffdesc_t *) & arg_OPEN4.claim.open_claim4_u.
                                     file, &filename))) != CACHE_INODE_SUCCESS)
        {
          res_OPEN4.status = nfs4_Errno(cache_status);
          return res_OPEN4.status;
        }

      /* Check parent */
      pentry_parent = data->current_entry;

      /* Parent must be a directory */
      if((pentry_parent->internal_md.type != DIR_BEGINNING) &&
         (pentry_parent->internal_md.type != DIR_CONTINUE))
        {
          /* Parent object is not a directory... */
          if(pentry_parent->internal_md.type == SYMBOLIC_LINK)
            res_OPEN4.status = NFS4ERR_SYMLINK;
          else
            res_OPEN4.status = NFS4ERR_NOTDIR;

          return res_OPEN4.status;
        }

      /* What kind of open is it ? */
      LogFullDebug(COMPONENT_NFS_V4,
                   "     OPEN: Claim type = %d   Open Type = %d  Share Deny = %d   Share Access = %d ",
                   arg_OPEN4.claim.claim,
                   arg_OPEN4.openhow.opentype,
                   arg_OPEN4.share_deny,
                   arg_OPEN4.share_access);


      /* It this a known client id ? */
      LogDebug(COMPONENT_NFS_V4,
               "OPEN Client id = %llx",
               (long long unsigned int)arg_OPEN4.owner.clientid);

      /* Is this open_owner known ? */
      convert_nfs4_owner(&arg_OPEN4.owner, &owner_name);

      if(!nfs4_owner_Get_Pointer(&owner_name, &powner))
        {
          /* This open owner is not known yet, allocated and set up a new one */
          powner = create_nfs4_owner(data->pclient,
                                     &owner_name,
                                     &arg_OPEN4.owner,
                                     NULL,
                                     1); /* NFSv4.1 specific, initial seqid is 1 */

          if(powner == NULL)
            {
              res_OPEN4.status = NFS4ERR_SERVERFAULT;
              return res_OPEN4.status;
            }
        }

      /* Status of parent directory before the operation */
      if(cache_inode_getattr(pentry_parent,
                             &attr_parent,
                             data->ht,
                             data->pclient,
                             data->pcontext,
                             &cache_status) != CACHE_INODE_SUCCESS)
        {
          res_OPEN4.status = nfs4_Errno(cache_status);
          return res_OPEN4.status;
        }

      memset(&(res_OPEN4.OPEN4res_u.resok4.cinfo.before), 0, sizeof(changeid4));
      res_OPEN4.OPEN4res_u.resok4.cinfo.before =
          (changeid4) pentry_parent->internal_md.mod_time;

      /* CLient may have provided fattr4 to set attributes at creation time */
      if(arg_OPEN4.openhow.openflag4_u.how.mode == GUARDED4 ||
         arg_OPEN4.openhow.openflag4_u.how.mode == UNCHECKED4)
        {
          if(arg_OPEN4.openhow.openflag4_u.how.createhow4_u.createattrs.attrmask.
             bitmap4_len != 0)
            {
              /* Convert fattr4 so nfs4_sattr */
              convrc =
                  nfs4_Fattr_To_FSAL_attr(&sattr,
                                          &(arg_OPEN4.openhow.openflag4_u.how.
                                            createhow4_u.createattrs));

              if(convrc != NFS4_OK)
                {
                  res_OPEN4.status = convrc;
                  return res_OPEN4.status;
                }

              AttrProvided = TRUE;
            }

        }

      /* Second switch is based upon "openhow" */
      switch (arg_OPEN4.openhow.opentype)
        {
        case OPEN4_CREATE:
          /* a new file is to be created */

          /* Does a file with this name already exist ? */
          pentry_lookup = cache_inode_lookup(pentry_parent,
                                             &filename,
                                             &attr_newfile,
                                             data->ht,
                                             data->pclient,
                                             data->pcontext, &cache_status);

          if(cache_status != CACHE_INODE_NOT_FOUND)
            {
              /* if open is UNCHECKED, return NFS4_OK (RFC3530 page 172) */
              if(arg_OPEN4.openhow.openflag4_u.how.mode == UNCHECKED4
                 && (cache_status == CACHE_INODE_SUCCESS))
                {
                  /* If the file is opened for write, OPEN4 while deny share write access,
                   * in this case, check caller has write access to the file */
                  if(arg_OPEN4.share_deny & OPEN4_SHARE_DENY_WRITE)
                    {
                      if(cache_inode_access(pentry_lookup,
                                            write_access,
                                            data->ht,
                                            data->pclient,
                                            data->pcontext,
                                            &cache_status) != CACHE_INODE_SUCCESS)
                        {
                          res_OPEN4.status = NFS4ERR_ACCESS;
                          return res_OPEN4.status;
                        }
                      openflags = FSAL_O_WRONLY;
                    }

                  /* Same check on read: check for readability of a file before opening it for read */
                  if(arg_OPEN4.share_access & OPEN4_SHARE_ACCESS_READ)
                    {
                      if(cache_inode_access(pentry_lookup,
                                            read_access,
                                            data->ht,
                                            data->pclient,
                                            data->pcontext,
                                            &cache_status) != CACHE_INODE_SUCCESS)
                        {
                          res_OPEN4.status = NFS4ERR_ACCESS;
                          return res_OPEN4.status;
                        }
                      openflags = FSAL_O_RDONLY;
                    }

                  if(AttrProvided == TRUE)      /* Set the attribute if provided */
                    {
                      if(cache_inode_setattr(pentry_lookup,
                                             &sattr,
                                             data->ht,
                                             data->pclient,
                                             data->pcontext,
                                             &cache_status) != CACHE_INODE_SUCCESS)
                        {
                          res_OPEN4.status = nfs4_Errno(cache_status);
                          return res_OPEN4.status;
                        }

                      res_OPEN4.OPEN4res_u.resok4.attrset =
                          arg_OPEN4.openhow.openflag4_u.how.createhow4_u.createattrs.
                          attrmask;
                    }
                  else
                    res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_len = 0;

                  /* Same check on write */
                  if(arg_OPEN4.share_access & OPEN4_SHARE_ACCESS_WRITE)
                    {
                      if(cache_inode_access(pentry_lookup,
                                            write_access,
                                            data->ht,
                                            data->pclient,
                                            data->pcontext,
                                            &cache_status) != CACHE_INODE_SUCCESS)
                        {
                          res_OPEN4.status = NFS4ERR_ACCESS;
                          return res_OPEN4.status;
                        }
                      openflags = FSAL_O_RDWR;
                    }

                  /* Set the state for the related file */

                  /* Prepare state management structure */
                  candidate_type = STATE_TYPE_SHARE;
                  candidate_data.share.share_deny = arg_OPEN4.share_deny;
                  candidate_data.share.share_access = arg_OPEN4.share_access;

                  if(state_add(pentry_lookup,
                               candidate_type,
                               &candidate_data,
                               powner,
                               data->pclient,
                               data->pcontext,
                               &pfile_state,
                               &state_status) != STATE_SUCCESS)
                    {
                      /* Seqid has to be incremented even in this case */
                      P(powner->so_mutex);
                      powner->so_owner.so_nfs4_owner.so_seqid += 1;
                      V(powner->so_mutex);

                      res_OPEN4.status = NFS4ERR_SHARE_DENIED;
                      return res_OPEN4.status;
                    }

                  /* Open the file */
                  if(cache_inode_open_by_name(pentry_parent,
                                              &filename,
                                              pentry_lookup,
                                              data->pclient,
                                              openflags,
                                              data->pcontext,
                                              &cache_status) != CACHE_INODE_SUCCESS)
                    {
                      /* Seqid has to be incremented even in this case */
                      P(powner->so_mutex);
                      powner->so_owner.so_nfs4_owner.so_seqid += 1;
                      V(powner->so_mutex);

                      res_OPEN4.status = NFS4ERR_SHARE_DENIED;
                      res_OPEN4.status = NFS4ERR_ACCESS;
                      return res_OPEN4.status;
                    }

                  res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_len = 2;
                  if((res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_val =
                      (uint32_t *) Mem_Alloc(res_OPEN4.OPEN4res_u.resok4.attrset.
                                             bitmap4_len * sizeof(uint32_t))) == NULL)
                    {
                      res_OPEN4.status = NFS4ERR_SERVERFAULT;
                      return res_OPEN4.status;
                    }

                  memset(&(res_OPEN4.OPEN4res_u.resok4.cinfo.after), 0,
                         sizeof(changeid4));
                  res_OPEN4.OPEN4res_u.resok4.cinfo.after =
                      (changeid4) pentry_parent->internal_md.mod_time;
                  res_OPEN4.OPEN4res_u.resok4.cinfo.atomic = TRUE;

                  res_OPEN4.OPEN4res_u.resok4.stateid.seqid = pfile_state->state_seqid;
                  memcpy(res_OPEN4.OPEN4res_u.resok4.stateid.other,
                         pfile_state->stateid_other, OTHERSIZE);

                  /* No delegation */
                  res_OPEN4.OPEN4res_u.resok4.delegation.delegation_type =
                      OPEN_DELEGATE_NONE;
                  res_OPEN4.OPEN4res_u.resok4.rflags = OPEN4_RESULT_LOCKTYPE_POSIX;

                  /* Now produce the filehandle to this file */
                  if((pnewfsal_handle =
                      cache_inode_get_fsal_handle(pentry_lookup, &cache_status)) == NULL)
                    {
                      res_OPEN4.status = nfs4_Errno(cache_status);
                      return res_OPEN4.status;
                    }

                  /* Allocation of a new file handle */
                  if((rc = nfs4_AllocateFH(&newfh4)) != NFS4_OK)
                    {
                      res_OPEN4.status = rc;
                      return res_OPEN4.status;
                    }

                  /* Building a new fh */
                  if(!nfs4_FSALToFhandle(&newfh4, pnewfsal_handle, data))
                    {
                      res_OPEN4.status = NFS4ERR_SERVERFAULT;
                      return res_OPEN4.status;
                    }

                  /* This new fh replaces the current FH */
                  data->currentFH.nfs_fh4_len = newfh4.nfs_fh4_len;
                  memcpy(data->currentFH.nfs_fh4_val, newfh4.nfs_fh4_val,
                         newfh4.nfs_fh4_len);

                  data->current_entry = pentry_lookup;
                  data->current_filetype = REGULAR_FILE;

                  res_OPEN4.status = NFS4_OK;
                  return res_OPEN4.status;
                }

              /* if open is EXCLUSIVE, but verifier is the same, return NFS4_OK (RFC3530 page 173) */
              if(arg_OPEN4.openhow.openflag4_u.how.mode == EXCLUSIVE4)
                {
                  if((pentry_lookup != NULL)
                     && (pentry_lookup->internal_md.type == REGULAR_FILE))
                    {
                      pstate_found_iterate = NULL;
                      pstate_previous_iterate = NULL;

                      do
                        {
                          state_iterate(pentry_lookup,
                                        &pstate_found_iterate,
                                        pstate_previous_iterate,
                                        data->pclient,
                                        data->pcontext, &state_status);

                          if(state_status == STATE_STATE_ERROR)
                            break;

                          if(state_status == STATE_INVALID_ARGUMENT)
                            {
                              /* Seqid has to be incremented even in this case */
                              P(powner->so_mutex);
                              powner->so_owner.so_nfs4_owner.so_seqid += 1;
                              V(powner->so_mutex);

                              res_OPEN4.status = NFS4ERR_INVAL;
                              return res_OPEN4.status;
                            }

                          cache_status = CACHE_INODE_SUCCESS;

                          /* Check is open_owner is the same */
                          if(pstate_found_iterate != NULL)
                            {
                              if((pstate_found_iterate->state_type ==
                                  STATE_TYPE_SHARE)
                                 && !memcmp(arg_OPEN4.owner.owner.owner_val,
                                            pstate_found_iterate->state_powner->so_owner_val,
                                            pstate_found_iterate->state_powner->so_owner_len)
                                 && !memcmp(pstate_found_iterate->state_data.share.
                                            oexcl_verifier,
                                            arg_OPEN4.openhow.openflag4_u.how.
                                            createhow4_u.createverf, NFS4_VERIFIER_SIZE))
                                {

                                  /* A former open EXCLUSIVE with same owner and verifier was found, resend it */
                                  res_OPEN4.OPEN4res_u.resok4.stateid.seqid =
                                      pstate_found_iterate->state_seqid;
                                  memcpy(res_OPEN4.OPEN4res_u.resok4.stateid.other,
                                         pstate_found_iterate->stateid_other, OTHERSIZE);

                                  memset(&(res_OPEN4.OPEN4res_u.resok4.cinfo.after), 0,
                                         sizeof(changeid4));
                                  res_OPEN4.OPEN4res_u.resok4.cinfo.after =
                                      (changeid4) pentry_parent->internal_md.mod_time;
                                  res_OPEN4.OPEN4res_u.resok4.cinfo.atomic = TRUE;

                                  /* No delegation */
                                  res_OPEN4.OPEN4res_u.resok4.delegation.delegation_type =
                                      OPEN_DELEGATE_NONE;
                                  res_OPEN4.OPEN4res_u.resok4.rflags =
                                      OPEN4_RESULT_LOCKTYPE_POSIX;

                                  /* Now produce the filehandle to this file */
                                  if((pnewfsal_handle =
                                      cache_inode_get_fsal_handle(pentry_lookup,
                                                                  &cache_status)) == NULL)
                                    {
                                      res_OPEN4.status = nfs4_Errno(cache_status);
                                      return res_OPEN4.status;
                                    }

                                  /* Allocation of a new file handle */
                                  if((rc = nfs4_AllocateFH(&newfh4)) != NFS4_OK)
                                    {
                                      res_OPEN4.status = rc;
                                      return res_OPEN4.status;
                                    }

                                  /* Building a new fh */
                                  if(!nfs4_FSALToFhandle(&newfh4, pnewfsal_handle, data))
                                    {
                                      res_OPEN4.status = NFS4ERR_SERVERFAULT;
                                      return res_OPEN4.status;
                                    }

                                  /* This new fh replaces the current FH */
                                  data->currentFH.nfs_fh4_len = newfh4.nfs_fh4_len;
                                  memcpy(data->currentFH.nfs_fh4_val, newfh4.nfs_fh4_val,
                                         newfh4.nfs_fh4_len);

                                  data->current_entry = pentry_lookup;
                                  data->current_filetype = REGULAR_FILE;

                                  /* regular exit */
                                  res_OPEN4.status = NFS4_OK;
                                  return res_OPEN4.status;
                                }

                            }
                          /* if( pstate_found_iterate != NULL ) */
                          pstate_previous_iterate = pstate_found_iterate;
                        }
                      while(pstate_found_iterate != NULL);
                    }
                }

              /* Managing GUARDED4 mode */
              if(cache_status != CACHE_INODE_SUCCESS)
                res_OPEN4.status = nfs4_Errno(cache_status);
              else
                res_OPEN4.status = NFS4ERR_EXIST;       /* File already exists */
              return res_OPEN4.status;
            }

          /*  if( cache_status != CACHE_INODE_NOT_FOUND ), if file already exists basically */
          LogFullDebug(COMPONENT_NFS_V4,
                       "    OPEN open.how = %d",
                       arg_OPEN4.openhow.openflag4_u.how.mode);

          create_arg.use_pnfs = FALSE;
#ifdef _USE_PNFS
          /*  set the file has "managed via pNFS" */
          if(data->pexport->options & EXPORT_OPTION_USE_PNFS)
            create_arg.use_pnfs = TRUE;
#endif                          /* _USE_PNFS */

          /* Create the file, if we reach this point, it does not exist, we can create it */
          if((pentry_newfile = cache_inode_create(pentry_parent,
                                                  &filename,
                                                  REGULAR_FILE,
                                                  mode,
                                                  &create_arg,
                                                  &attr_newfile,
                                                  data->ht,
                                                  data->pclient,
                                                  data->pcontext, &cache_status)) == NULL)
            {
              /* If the file already exists, this is not an error if open mode is UNCHECKED */
              if(cache_status != CACHE_INODE_ENTRY_EXISTS)
                {
                  res_OPEN4.status = nfs4_Errno(cache_status);
                  return res_OPEN4.status;
                }
              else
                {
                  /* If this point is reached, then the file already exists, cache_status == CACHE_INODE_ENTRY_EXISTS and pentry_newfile == NULL 
                     This probably means EXCLUSIVE4 mode is used and verifier matches. pentry_newfile is then set to pentry_lookup */
                  pentry_newfile = pentry_lookup;
                }
            }

          /* Prepare state management structure */
          candidate_type = STATE_TYPE_SHARE;
          candidate_data.share.share_deny = arg_OPEN4.share_deny;
          candidate_data.share.share_access = arg_OPEN4.share_access;
          candidate_data.share.lockheld = 0;

          /* If file is opened under mode EXCLUSIVE4, open verifier should be kept to detect non vicious double open */
          if(arg_OPEN4.openhow.openflag4_u.how.mode == EXCLUSIVE4)
            {
              strncpy(candidate_data.share.oexcl_verifier,
                      arg_OPEN4.openhow.openflag4_u.how.createhow4_u.createverf,
                      NFS4_VERIFIER_SIZE);
            }

          if(state_add(pentry_newfile,
                       candidate_type,
                       &candidate_data,
                       powner,
                       data->pclient,
                       data->pcontext,
                       &pfile_state, &state_status) != STATE_SUCCESS)
            {
              /* Seqid has to be incremented even in this case */
              P(powner->so_mutex);
              powner->so_owner.so_nfs4_owner.so_seqid += 1;
              V(powner->so_mutex);

              res_OPEN4.status = NFS4ERR_SHARE_DENIED;
              return res_OPEN4.status;
            }

          cache_status = CACHE_INODE_SUCCESS;

          if(AttrProvided == TRUE)      /* Set the attribute if provided */
            {
              if((cache_status = cache_inode_setattr(pentry_newfile,
                                                     &sattr,
                                                     data->ht,
                                                     data->pclient,
                                                     data->pcontext,
                                                     &cache_status)) !=
                 CACHE_INODE_SUCCESS)
                {
                  res_OPEN4.status = nfs4_Errno(cache_status);
                  return res_OPEN4.status;
                }

            }

          /* Set the openflags variable */
          if(arg_OPEN4.share_deny & OPEN4_SHARE_DENY_WRITE)
            openflags |= FSAL_O_RDONLY;
          if(arg_OPEN4.share_deny & OPEN4_SHARE_DENY_READ)
            openflags |= FSAL_O_WRONLY;
          if(arg_OPEN4.share_access & OPEN4_SHARE_ACCESS_WRITE)
            openflags = FSAL_O_RDWR;
          if(arg_OPEN4.share_access != 0)
            openflags = FSAL_O_RDWR;    /* @todo : BUGAZOMEU : Something better later */

          /* Open the file */
          if(cache_inode_open_by_name(pentry_parent,
                                      &filename,
                                      pentry_newfile,
                                      data->pclient,
                                      openflags,
                                      data->pcontext,
                                      &cache_status) != CACHE_INODE_SUCCESS)
            {
              /* Seqid has to be incremented even in this case */
              P(powner->so_mutex);
              powner->so_owner.so_nfs4_owner.so_seqid += 1;
              V(powner->so_mutex);

              res_OPEN4.status = NFS4ERR_ACCESS;
              return res_OPEN4.status;
            }

          break;

        case OPEN4_NOCREATE:
          /* It was not a creation, but a regular open */
          /* The filehandle to the new file replaces the current filehandle */
          if(pentry_newfile == NULL)
            {
              if((pentry_newfile = cache_inode_lookup(pentry_parent,
                                                      &filename,
                                                      &attr_newfile,
                                                      data->ht,
                                                      data->pclient,
                                                      data->pcontext,
                                                      &cache_status)) == NULL)
                {
                  res_OPEN4.status = nfs4_Errno(cache_status);
                  return res_OPEN4.status;
                }
            }

          /* OPEN4 is to be done on a file */
          if(pentry_newfile->internal_md.type != REGULAR_FILE)
            {
              if(pentry_newfile->internal_md.type == DIR_BEGINNING
                 || pentry_newfile->internal_md.type == DIR_CONTINUE)
                {
                  res_OPEN4.status = NFS4ERR_ISDIR;
                  return res_OPEN4.status;
                }
              else if(pentry_newfile->internal_md.type == SYMBOLIC_LINK)
                {
                  res_OPEN4.status = NFS4ERR_SYMLINK;
                  return res_OPEN4.status;
                }
              else
                {
                  res_OPEN4.status = NFS4ERR_INVAL;
                  return res_OPEN4.status;
                }
            }

          /* If the file is opened for write, OPEN4 while deny share write access,
           * in this case, check caller has write access to the file */
          if(arg_OPEN4.share_deny & OPEN4_SHARE_DENY_WRITE)
            {
              if(cache_inode_access(pentry_newfile,
                                    write_access,
                                    data->ht,
                                    data->pclient,
                                    data->pcontext, &cache_status) != CACHE_INODE_SUCCESS)
                {
                  res_OPEN4.status = NFS4ERR_ACCESS;
                  return res_OPEN4.status;
                }
              openflags = FSAL_O_WRONLY;
            }

          /* Same check on read: check for readability of a file before opening it for read */
          if(arg_OPEN4.share_access & OPEN4_SHARE_ACCESS_READ)
            {
              if(cache_inode_access(pentry_newfile,
                                    read_access,
                                    data->ht,
                                    data->pclient,
                                    data->pcontext, &cache_status) != CACHE_INODE_SUCCESS)
                {
                  res_OPEN4.status = NFS4ERR_ACCESS;
                  return res_OPEN4.status;
                }
              openflags = FSAL_O_RDONLY;
            }

          /* Same check on write */
          if(arg_OPEN4.share_access & OPEN4_SHARE_ACCESS_WRITE)
            {
              if(cache_inode_access(pentry_newfile,
                                    write_access,
                                    data->ht,
                                    data->pclient,
                                    data->pcontext, &cache_status) != CACHE_INODE_SUCCESS)
                {
                  res_OPEN4.status = NFS4ERR_ACCESS;
                  return res_OPEN4.status;
                }
              openflags = FSAL_O_RDWR;
            }

          /* Try to find if the same open_owner already has acquired a stateid for this file */
          pstate_found_iterate = NULL;
          pstate_previous_iterate = NULL;
          do
            {
              state_iterate(pentry_newfile,
                            &pstate_found_iterate,
                            pstate_previous_iterate,
                            data->pclient, data->pcontext, &state_status);

              if(state_status == STATE_STATE_ERROR)
                break;          /* Get out of the loop */

              if(state_status == STATE_INVALID_ARGUMENT)
                {
                  res_OPEN4.status = NFS4ERR_INVAL;
                  return res_OPEN4.status;
                }

              cache_status = CACHE_INODE_SUCCESS;

              /* Check is open_owner is the same */
              if(pstate_found_iterate != NULL)
                {
                  if((pstate_found_iterate->state_type == STATE_TYPE_SHARE) &&
                     (pstate_found_iterate->state_powner->so_owner.so_nfs4_owner.so_clientid == arg_OPEN4.owner.clientid)
                     &&
                     ((pstate_found_iterate->state_powner->so_owner_len ==
                       arg_OPEN4.owner.owner.owner_len)
                      &&
                      (!memcmp
                       (arg_OPEN4.owner.owner.owner_val,
                        pstate_found_iterate->state_powner->so_owner_val,
                        pstate_found_iterate->state_powner->so_owner_len))))
                    {
                      /* We'll be re-using the found state */
                      pstate_found_same_owner = pstate_found_iterate;
                    }
                  else
                    {

                      /* This is a different owner, check for possible conflicts */

                      if(memcmp(arg_OPEN4.owner.owner.owner_val,
                                pstate_found_iterate->state_powner->so_owner_val,
                                pstate_found_iterate->state_powner->so_owner_len))
                        {
                          if(pstate_found_iterate->state_type == STATE_TYPE_SHARE)
                            {
                              if((pstate_found_iterate->state_data.share.
                                  share_access & OPEN4_SHARE_ACCESS_WRITE)
                                 && (arg_OPEN4.share_deny & OPEN4_SHARE_DENY_WRITE))
                                {
                                  res_OPEN4.status = NFS4ERR_SHARE_DENIED;
                                  return res_OPEN4.status;
                                }
                            }
                        }

                    }

                  /* In all cases opening in read access a read denied file or write access to a write denied file 
                   * should fail, even if the owner is the same, see discussion in 14.2.16 and 8.9 */
                  if(pstate_found_iterate->state_type == STATE_TYPE_SHARE)
                    {
                      /* deny read access on read denied file */
                      if((pstate_found_iterate->state_data.share.
                          share_deny & OPEN4_SHARE_DENY_READ)
                         && (arg_OPEN4.share_access & OPEN4_SHARE_ACCESS_READ))
                        {
                          /* Seqid has to be incremented even in this case */
                          P(powner->so_mutex);
                          powner->so_owner.so_nfs4_owner.so_seqid += 1;
                          V(powner->so_mutex);

                          powner->so_owner.so_nfs4_owner.so_seqid += 1;
                          res_OPEN4.status = NFS4ERR_SHARE_DENIED;
                          return res_OPEN4.status;
                        }

                      /* deny write access on write denied file */
                      if((pstate_found_iterate->state_data.share.
                          share_deny & OPEN4_SHARE_DENY_WRITE)
                         && (arg_OPEN4.share_access & OPEN4_SHARE_ACCESS_WRITE))
                        {
                          /* Seqid has to be incremented even in this case */
                          P(powner->so_mutex);
                          powner->so_owner.so_nfs4_owner.so_seqid += 1;
                          V(powner->so_mutex);

                          res_OPEN4.status = NFS4ERR_SHARE_DENIED;
                          return res_OPEN4.status;
                        }

                    }

                }
              /*  if( pstate_found_iterate != NULL ) */
              pstate_previous_iterate = pstate_found_iterate;
            }
          while(pstate_found_iterate != NULL);

          if(pstate_found_same_owner != NULL)
            {
              pfile_state = pstate_found_same_owner;
              pfile_state->state_seqid += 1;

              P(powner->so_mutex);
              powner->so_owner.so_nfs4_owner.so_seqid += 1;
              V(powner->so_mutex);

            }
          else
            {
              /* Set the state for the related file */
              /* Prepare state management structure */
              candidate_type = STATE_TYPE_SHARE;
              candidate_data.share.share_deny = arg_OPEN4.share_deny;
              candidate_data.share.share_access = arg_OPEN4.share_access;

              if(state_add(pentry_newfile,
                           candidate_type,
                           &candidate_data,
                           powner,
                           data->pclient,
                           data->pcontext,
                           &pfile_state,
                           &state_status) != STATE_SUCCESS)
                {
                  /* Seqid has to be incremented even in this case */
                  P(powner->so_mutex);
                  powner->so_owner.so_nfs4_owner.so_seqid += 1;
                  V(powner->so_mutex);

                  res_OPEN4.status = NFS4ERR_SHARE_DENIED;
                  return res_OPEN4.status;
                }
            }

          /* Open the file */
          if(cache_inode_open_by_name(pentry_parent,
                                      &filename,
                                      pentry_newfile,
                                      data->pclient,
                                      openflags,
                                      data->pcontext,
                                      &cache_status) != CACHE_INODE_SUCCESS)
            {
              /* Seqid has to be incremented even in this case */
              P(powner->so_mutex);
              powner->so_owner.so_nfs4_owner.so_seqid += 1;
              V(powner->so_mutex);

              res_OPEN4.status = NFS4ERR_ACCESS;
              return res_OPEN4.status;
            }
          break;

        default:
          /* Seqid has to be incremented even in this case */
          if(powner != NULL)
            {
              P(powner->so_mutex);
              powner->so_owner.so_nfs4_owner.so_seqid += 1;
              V(powner->so_mutex);
            }

          res_OPEN4.status = NFS4ERR_INVAL;
          return res_OPEN4.status;
          break;
        }                       /* switch( arg_OPEN4.openhow.opentype ) */

      break;

    case CLAIM_PREVIOUS:
      break;

    default:
      /* Seqid has to be incremented even in this case */
      if(powner != NULL)
        {
          P(powner->so_mutex);
          powner->so_owner.so_nfs4_owner.so_seqid += 1;
          V(powner->so_mutex);
        }

      res_OPEN4.status = NFS4ERR_INVAL;
      return res_OPEN4.status;
      break;
    }                           /*  switch(  arg_OPEN4.claim.claim ) */

  /* Now produce the filehandle to this file */
  if((pnewfsal_handle =
      cache_inode_get_fsal_handle(pentry_newfile, &cache_status)) == NULL)
    {
      res_OPEN4.status = nfs4_Errno(cache_status);
      return res_OPEN4.status;
    }

  /* Allocation of a new file handle */
  if((rc = nfs4_AllocateFH(&newfh4)) != NFS4_OK)
    {
      res_OPEN4.status = rc;
      return res_OPEN4.status;
    }

  /* Building a new fh */
  if(!nfs4_FSALToFhandle(&newfh4, pnewfsal_handle, data))
    {
      res_OPEN4.status = NFS4ERR_SERVERFAULT;
      return res_OPEN4.status;
    }

  /* This new fh replaces the current FH */
  data->currentFH.nfs_fh4_len = newfh4.nfs_fh4_len;
  memcpy(data->currentFH.nfs_fh4_val, newfh4.nfs_fh4_val, newfh4.nfs_fh4_len);

  data->current_entry = pentry_newfile;
  data->current_filetype = REGULAR_FILE;

  /* No do not need newfh any more */
  Mem_Free((char *)newfh4.nfs_fh4_val);

  /* Status of parent directory after the operation */
  if((cache_status = cache_inode_getattr(pentry_parent,
                                         &attr_parent,
                                         data->ht,
                                         data->pclient,
                                         data->pcontext,
                                         &cache_status)) != CACHE_INODE_SUCCESS)
    {
      res_OPEN4.status = nfs4_Errno(cache_status);
      return res_OPEN4.status;
    }

  res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_len = 2;
  if((res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_val =
      (uint32_t *) Mem_Alloc(res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_len *
                             sizeof(uint32_t))) == NULL)
    {
      res_OPEN4.status = NFS4ERR_SERVERFAULT;
      return res_OPEN4.status;
    }
  res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_val[0] = 0;       /* No Attributes set */
  res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_val[1] = 0;       /* No Attributes set */

  if(arg_OPEN4.openhow.opentype == OPEN4_CREATE)
    {
      tmp_int = 2;
      tmp_attr[0] = FATTR4_SIZE;
      tmp_attr[1] = FATTR4_MODE;
      nfs4_list_to_bitmap4(&(res_OPEN4.OPEN4res_u.resok4.attrset), &tmp_int, tmp_attr);
      res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_len = 2;
    }

  res_OPEN4.OPEN4res_u.resok4.cinfo.after =
      (changeid4) pentry_parent->internal_md.mod_time;
  res_OPEN4.OPEN4res_u.resok4.cinfo.atomic = TRUE;

  res_OPEN4.OPEN4res_u.resok4.stateid.seqid = powner->so_owner.so_nfs4_owner.so_seqid;
  memcpy(res_OPEN4.OPEN4res_u.resok4.stateid.other, pfile_state->stateid_other, OTHERSIZE);

  /* No delegation */
  res_OPEN4.OPEN4res_u.resok4.delegation.delegation_type = OPEN_DELEGATE_NONE;

  res_OPEN4.OPEN4res_u.resok4.rflags = OPEN4_RESULT_LOCKTYPE_POSIX;

  /* regular exit */
  res_OPEN4.status = NFS4_OK;
  return res_OPEN4.status;
}                               /* nfs41_op_open */
Exemplo n.º 5
0
int nfs4_op_read(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp)
{
  char __attribute__ ((__unused__)) funcname[] = "nfs4_op_read";

  fsal_seek_t              seek_descriptor;
  fsal_size_t              size;
  fsal_size_t              read_size;
  fsal_off_t               offset;
  fsal_boolean_t           eof_met;
  caddr_t                  bufferdata;
  cache_inode_status_t     cache_status;
  state_status_t           state_status;
  state_t                * pstate_found = NULL;
  state_t                * pstate_open = NULL;
  cache_content_status_t   content_status;
  fsal_attrib_list_t       attr;
  cache_entry_t          * entry = NULL;
  state_t                * pstate_iterate = NULL;
  state_t                * pstate_previous_iterate = NULL;
  int                      rc = 0;

  cache_content_policy_data_t datapol;

  datapol.UseMaxCacheSize = FALSE;

  /* Say we are managing NFS4_OP_READ */
  resp->resop = NFS4_OP_READ;
  res_READ4.status = NFS4_OK;

  /* If there is no FH */
  if(nfs4_Is_Fh_Empty(&(data->currentFH)))
    {
      res_READ4.status = NFS4ERR_NOFILEHANDLE;
      return res_READ4.status;
    }

  /* If the filehandle is invalid */
  if(nfs4_Is_Fh_Invalid(&(data->currentFH)))
    {
      res_READ4.status = NFS4ERR_BADHANDLE;
      return res_READ4.status;
    }

  /* Tests if the Filehandle is expired (for volatile filehandle) */
  if(nfs4_Is_Fh_Expired(&(data->currentFH)))
    {
      res_READ4.status = NFS4ERR_FHEXPIRED;
      return res_READ4.status;
    }

  /* If Filehandle points to a xattr object, manage it via the xattrs specific functions */
  if(nfs4_Is_Fh_Xattr(&(data->currentFH)))
    return nfs4_op_read_xattr(op, data, resp);

  /* Manage access type MDONLY */
  if(data->pexport->access_type == ACCESSTYPE_MDONLY)
    {
      res_READ4.status = NFS4ERR_DQUOT;
      return res_READ4.status;
    }

  /* Only files can be read */
  if(data->current_filetype != REGULAR_FILE)
    {
      /* If the source is no file, return EISDIR if it is a directory and EINAVL otherwise */
      if(data->current_filetype == DIR_BEGINNING
         || data->current_filetype == DIR_CONTINUE)
        res_READ4.status = NFS4ERR_ISDIR;
      else
        res_READ4.status = NFS4ERR_INVAL;

      return res_READ4.status;
    }

  /* vnode to manage is the current one */
  entry = data->current_entry;

  /* Check stateid correctness and get pointer to state
   * (also checks for special stateids)
   */
  if((rc = nfs4_Check_Stateid(&arg_READ4.stateid,
                              data->current_entry,
                              0LL,
                              &pstate_found,
                              data,
                              STATEID_SPECIAL_ANY,
                              "READ")) != NFS4_OK)
    {
      res_READ4.status = rc;
      return res_READ4.status;
    }

  /* NB: After this points, if pstate_found == NULL, then the stateid is all-0 or all-1 */

  if(pstate_found != NULL)
    {
      switch(pstate_found->state_type)
        {
          case STATE_TYPE_SHARE:
            pstate_open = pstate_found;
            break;

          case STATE_TYPE_LOCK:
            pstate_open = pstate_found->state_data.lock.popenstate;
            break;

          case STATE_TYPE_DELEG:
            pstate_open = NULL;
            break;

          default:
            res_READ4.status = NFS4ERR_BAD_STATEID;
            LogDebug(COMPONENT_NFS_V4_LOCK,
                     "READ with invalid statid of type %d",
                     (int) pstate_found->state_type);
            return res_READ4.status;
        }

      /* This is a read operation, this means that the file MUST have been opened for reading */
      if(pstate_open != NULL &&
         (pstate_open->state_data.share.share_access & OPEN4_SHARE_ACCESS_READ) == 0)
        {
          /* Bad open mode, return NFS4ERR_OPENMODE */
          res_READ4.status = NFS4ERR_OPENMODE;
          LogDebug(COMPONENT_NFS_V4_LOCK,
                   "READ state %p doesn't have OPEN4_SHARE_ACCESS_READ",
                   pstate_found);
          return res_READ4.status;
        }

      /* If NFSv4::Use_OPEN_CONFIRM is set to TRUE in the configuration file, check is state is confirmed */
      if(nfs_param.nfsv4_param.use_open_confirm == TRUE)
        {
          if(pstate_found->state_powner->so_owner.so_nfs4_owner.so_confirmed == FALSE)
            {
              res_READ4.status = NFS4ERR_BAD_STATEID;
              return res_READ4.status;
            }
        }
    }

  /* Iterate through file's state to look for conflicts */
  pstate_iterate = NULL;
  pstate_previous_iterate = NULL;
  do
    {
      state_iterate(data->current_entry,
                    &pstate_iterate,
                    pstate_previous_iterate,
                    data->pclient,
                    data->pcontext,
                    &state_status);

      if(state_status == STATE_STATE_ERROR)
        break;                  /* Get out of the loop */

      if(state_status == STATE_INVALID_ARGUMENT)
        {
          res_READ4.status = NFS4ERR_INVAL;
          return res_READ4.status;
        }

      cache_status = CACHE_INODE_SUCCESS;

      if(pstate_iterate != NULL)
        {
          if(pstate_iterate->state_type == STATE_TYPE_SHARE)
            {
              if(pstate_found != pstate_iterate &&
                 pstate_open != pstate_iterate)
                {
                  if(pstate_iterate->state_data.share.share_deny & OPEN4_SHARE_DENY_READ)
                    {
                      /* Writing to this file if prohibited, file is write-denied */
                      LogDebug(COMPONENT_NFS_V4_LOCK,
                               "READ is denied by state %p",
                               pstate_iterate);
                      res_READ4.status = NFS4ERR_LOCKED;
                      return res_READ4.status;
                    }
                }
            }
        }
      pstate_previous_iterate = pstate_iterate;
    }
  while(pstate_iterate != NULL);

  /* Get the size and offset of the read operation */
  offset = arg_READ4.offset;
  size = arg_READ4.count;

  LogFullDebug(COMPONENT_NFS_V4,
               "   NFS4_OP_READ: offset = %"PRIu64" length = %llu",
               offset, size);

  if((data->pexport->options & EXPORT_OPTION_MAXOFFSETREAD) ==
     EXPORT_OPTION_MAXOFFSETREAD)
    if((fsal_off_t) (offset + size) > data->pexport->MaxOffsetRead)
      {
        res_READ4.status = NFS4ERR_DQUOT;
        return res_READ4.status;
      }

  /* Do not read more than FATTR4_MAXREAD */
  if((data->pexport->options & EXPORT_OPTION_MAXREAD) == EXPORT_OPTION_MAXREAD &&
     size > data->pexport->MaxRead)
    {
      /* the client asked for too much data,
       * this should normally not happen because
       * client will get FATTR4_MAXREAD value at mount time */
      size = data->pexport->MaxRead;
    }

  /* If size == 0 , no I/O is to be made and everything is alright */
  if(size == 0)
    {
      res_READ4.READ4res_u.resok4.eof = FALSE;  /* end of file was not reached because READ occured, and a size = 0 can not lead to eof */
      res_READ4.READ4res_u.resok4.data.data_len = 0;
      res_READ4.READ4res_u.resok4.data.data_val = NULL;

      res_READ4.status = NFS4_OK;
      return res_READ4.status;
    }

  if((data->pexport->options & EXPORT_OPTION_USE_DATACACHE) &&
     (entry->object.file.pentry_content == NULL))
    {
      /* Entry is not in datacache, but should be in, cache it .
       * Several threads may call this function at the first time and a race condition can occur here
       * in order to avoid this, cache_inode_add_data_cache is "mutex protected"
       * The first call will create the file content cache entry, the further will return
       * with error CACHE_INODE_CACHE_CONTENT_EXISTS which is not a pathological thing here */

      datapol.UseMaxCacheSize = data->pexport->options & EXPORT_OPTION_MAXCACHESIZE;
      datapol.MaxCacheSize = data->pexport->MaxCacheSize;

      /* Status is set in last argument */
      cache_inode_add_data_cache(entry, data->ht, data->pclient, data->pcontext,
                                 &cache_status);

      if((cache_status != CACHE_INODE_SUCCESS) &&
         (cache_content_cache_behaviour(entry,
                                        &datapol,
                                        (cache_content_client_t *) (data->pclient->
                                                                    pcontent_client),
                                        &content_status) == CACHE_CONTENT_FULLY_CACHED)
         && (cache_status != CACHE_INODE_CACHE_CONTENT_EXISTS))
        {
          res_READ4.status = NFS4ERR_SERVERFAULT;
          return res_READ4.status;
        }

    }

  /* Some work is to be done */
  if((bufferdata = (char *)Mem_Alloc(size)) == NULL)
    {
      res_READ4.status = NFS4ERR_SERVERFAULT;
      return res_READ4.status;
    }
  memset((char *)bufferdata, 0, size);

  seek_descriptor.whence = FSAL_SEEK_SET;
  seek_descriptor.offset = offset;

  if(cache_inode_rdwr(entry,
                      CACHE_CONTENT_READ,
                      &seek_descriptor,
                      size,
                      &read_size,
                      &attr,
                      bufferdata,
                      &eof_met,
                      data->ht,
                      data->pclient,
                      data->pcontext, TRUE, &cache_status) != CACHE_INODE_SUCCESS)
    {
      res_READ4.status = nfs4_Errno(cache_status);
      return res_READ4.status;
    }

  /* What is the filesize ? */
  if((offset + read_size) > attr.filesize)
    res_READ4.READ4res_u.resok4.eof = TRUE;

  res_READ4.READ4res_u.resok4.data.data_len = read_size;
  res_READ4.READ4res_u.resok4.data.data_val = bufferdata;

  LogFullDebug(COMPONENT_NFS_V4,
               "   NFS4_OP_READ: offset = %"PRIu64"  read length = %llu eof=%u",
               offset, read_size, eof_met);

  /* Is EOF met or not ? */
  if(eof_met == TRUE)
    res_READ4.READ4res_u.resok4.eof = TRUE;
  else
    res_READ4.READ4res_u.resok4.eof = FALSE;

  /* Say it is ok */
  res_READ4.status = NFS4_OK;

  return res_READ4.status;
}                               /* nfs4_op_read */
Exemplo n.º 6
0
int nfs41_op_write(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp)
{
  char __attribute__ ((__unused__)) funcname[] = "nfs41_op_write";

  fsal_seek_t              seek_descriptor;
  fsal_size_t              size;
  fsal_size_t              written_size;
  fsal_off_t               offset;
  fsal_boolean_t           eof_met;
  bool_t                   stable_flag = TRUE;
  caddr_t                  bufferdata;
  stable_how4              stable_how;
  cache_content_status_t   content_status;
  state_t                * pstate_found = NULL;
  cache_inode_status_t     cache_status;
  state_status_t           state_status;
  fsal_attrib_list_t       attr;
  cache_entry_t          * entry = NULL;
  state_t                * pstate_iterate = NULL;
  state_t                * pstate_previous_iterate = NULL;

  cache_content_policy_data_t datapol;

  datapol.UseMaxCacheSize = FALSE;

  /* Lock are not supported */
  resp->resop = NFS4_OP_WRITE;
  res_WRITE4.status = NFS4_OK;

  /* If there is no FH */
  if(nfs4_Is_Fh_Empty(&(data->currentFH)))
    {
      res_WRITE4.status = NFS4ERR_NOFILEHANDLE;
      return res_WRITE4.status;
    }

  /* If the filehandle is invalid */
  if(nfs4_Is_Fh_Invalid(&(data->currentFH)))
    {
      res_WRITE4.status = NFS4ERR_BADHANDLE;
      return res_WRITE4.status;
    }

  /* Tests if the Filehandle is expired (for volatile filehandle) */
  if(nfs4_Is_Fh_Expired(&(data->currentFH)))
    {
      res_WRITE4.status = NFS4ERR_FHEXPIRED;
      return res_WRITE4.status;
    }

  /* If Filehandle points to a xattr object, manage it via the xattrs specific functions */
  if(nfs4_Is_Fh_Xattr(&(data->currentFH)))
    return nfs4_op_write_xattr(op, data, resp);

  /* Manage access type MDONLY */
  if(data->pexport->access_type == ACCESSTYPE_MDONLY)
    {
      res_WRITE4.status = NFS4ERR_DQUOT;
      return res_WRITE4.status;
    }

  /* vnode to manage is the current one */
  entry = data->current_entry;

  /* Check for special stateid */
  if(!memcmp((char *)all_zero, arg_WRITE4.stateid.other, OTHERSIZE) &&
     arg_WRITE4.stateid.seqid == 0)
    {
      /* "All 0 stateid special case", see RFC3530 page 220-221 for details
       * This will be treated as a client that held no lock at all,
       * I set pstate_found to NULL to remember this situation later */
      pstate_found = NULL;
    }
  else if(!memcmp((char *)all_one, arg_WRITE4.stateid.other, OTHERSIZE) &&
          arg_WRITE4.stateid.seqid == 0xFFFFFFFF)
    {
      /* "All 1 stateid special case", see RFC3530 page 220-221 for details
       * This will be treated as a client that held no lock at all,
       * I set pstate_found to NULL to remember this situation later */
      pstate_found = NULL;
    }

  /* NB: After this points, if pstate_found == NULL, then the stateid is all-0 or all-1 */

  /* Iterate through file's state to look for conflicts */
  pstate_iterate = NULL;
  pstate_previous_iterate = NULL;
  do
    {
      state_iterate(data->current_entry,
                    &pstate_iterate,
                    pstate_previous_iterate,
                    data->pclient, data->pcontext, &state_status);

      if(state_status == STATE_STATE_ERROR)
        break;                  /* Get out of the loop */

      if(state_status == STATE_INVALID_ARGUMENT)
        {
          res_WRITE4.status = NFS4ERR_INVAL;
          return res_WRITE4.status;
        }

      cache_status = CACHE_INODE_SUCCESS;

      if(pstate_iterate != NULL)
        {
          if(pstate_iterate->state_type == STATE_TYPE_SHARE)
            {
              if(pstate_found != pstate_iterate)
                {
                  if(pstate_iterate->state_data.share.share_deny & OPEN4_SHARE_DENY_WRITE)
                    {
                      /* Writing to this file if prohibited, file is write-denied */
                      res_WRITE4.status = NFS4ERR_LOCKED;
                      return res_WRITE4.status;
                    }
                }
            }
        }
      pstate_previous_iterate = pstate_iterate;
    }
  while(pstate_iterate != NULL);

  /* Only files can be written */
  if(data->current_filetype != REGULAR_FILE)
    {
      /* If the destination is no file, return EISDIR if it is a directory and EINAVL otherwise */
      if(data->current_filetype == DIR_BEGINNING
         || data->current_filetype == DIR_CONTINUE)
        res_WRITE4.status = NFS4ERR_ISDIR;
      else
        res_WRITE4.status = NFS4ERR_INVAL;

      return res_WRITE4.status;
    }

  /* Get the characteristics of the I/O to be made */
  offset = arg_WRITE4.offset;
  size = arg_WRITE4.data.data_len;
  stable_how = arg_WRITE4.stable;
  LogFullDebug(COMPONENT_NFS_V4,
               "NFS4_OP_WRITE: offset = %llu  length = %llu  stable = %d",
               (unsigned long long)offset, size, stable_how);

  if((data->pexport->options & EXPORT_OPTION_MAXOFFSETWRITE) ==
     EXPORT_OPTION_MAXOFFSETWRITE)
    if((fsal_off_t) (offset + size) > data->pexport->MaxOffsetWrite)
      {
        res_WRITE4.status = NFS4ERR_DQUOT;
        return res_WRITE4.status;
      }

  /* The size to be written should not be greater than FATTR4_MAXWRITESIZE because this value is asked
   * by the client at mount time, but we check this by security */
  if(((data->pexport->options & EXPORT_OPTION_MAXWRITE) == EXPORT_OPTION_MAXWRITE) &&
     size > data->pexport->MaxWrite)
    {
      /*
       * The client asked for too much data, we
       * must restrict him
       */
      size = data->pexport->MaxWrite;
    }

  /* Where are the data ? */
  bufferdata = arg_WRITE4.data.data_val;

  LogFullDebug(COMPONENT_NFS_V4,
               "NFS4_OP_WRITE: offset = %llu  length = %llu",
               (unsigned long long)offset, size);

  /* if size == 0 , no I/O) are actually made and everything is alright */
  if(size == 0)
    {
      res_WRITE4.WRITE4res_u.resok4.count = 0;
      res_WRITE4.WRITE4res_u.resok4.committed = FILE_SYNC4;

      memcpy(res_WRITE4.WRITE4res_u.resok4.writeverf, NFS4_write_verifier,
             sizeof(verifier4));

      res_WRITE4.status = NFS4_OK;
      return res_WRITE4.status;
    }

  if((data->pexport->options & EXPORT_OPTION_USE_DATACACHE) &&
     (cache_content_cache_behaviour(entry,
                                    &datapol,
                                    (cache_content_client_t *) (data->pclient->
                                                                pcontent_client),
                                    &content_status) == CACHE_CONTENT_FULLY_CACHED)
     && (entry->object.file.pentry_content == NULL))
    {
      /* Entry is not in datacache, but should be in, cache it .
       * Several threads may call this function at the first time and a race condition can occur here
       * in order to avoid this, cache_inode_add_data_cache is "mutex protected"
       * The first call will create the file content cache entry, the further will return
       * with error CACHE_INODE_CACHE_CONTENT_EXISTS which is not a pathological thing here */

      datapol.UseMaxCacheSize = data->pexport->options & EXPORT_OPTION_MAXCACHESIZE;
      datapol.MaxCacheSize = data->pexport->MaxCacheSize;

      /* Status is set in last argument */
      cache_inode_add_data_cache(entry, data->ht, data->pclient, data->pcontext,
                                 &cache_status);

      if((cache_status != CACHE_INODE_SUCCESS) &&
         (cache_status != CACHE_INODE_CACHE_CONTENT_EXISTS))
        {
          res_WRITE4.status = NFS4ERR_SERVERFAULT;
          return res_WRITE4.status;
        }

    }

  if((nfs_param.core_param.use_nfs_commit == TRUE) && (arg_WRITE4.stable == UNSTABLE4))
    {
      stable_flag = FALSE;
    }
  else
    {
      stable_flag = TRUE;
    }

  /* An actual write is to be made, prepare it */
  /* only FILE_SYNC mode is supported */
  /* Set up uio to define the transfer */
  seek_descriptor.whence = FSAL_SEEK_SET;
  seek_descriptor.offset = offset;

  if(cache_inode_rdwr(entry,
                      CACHE_CONTENT_WRITE,
                      &seek_descriptor,
                      size,
                      &written_size,
                      &attr,
                      bufferdata,
                      &eof_met,
                      data->ht,
                      data->pclient,
                      data->pcontext, stable_flag, &cache_status) != CACHE_INODE_SUCCESS)
    {
      res_WRITE4.status = nfs4_Errno(cache_status);
      return res_WRITE4.status;
    }

  /* Set the returned value */
  if(stable_flag == TRUE)
    res_WRITE4.WRITE4res_u.resok4.committed = FILE_SYNC4;
  else
    res_WRITE4.WRITE4res_u.resok4.committed = UNSTABLE4;

  res_WRITE4.WRITE4res_u.resok4.count = written_size;
  memcpy(res_WRITE4.WRITE4res_u.resok4.writeverf, NFS4_write_verifier, sizeof(verifier4));

  res_WRITE4.status = NFS4_OK;

  return res_WRITE4.status;
}                               /* nfs41_op_write */