예제 #1
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_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 DIRECTORY:
          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;
          LogDebug(COMPONENT_NFS_V4_LOCK,
                   "LOCK failed nfs4_Check_Stateid for open owner");
          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_lock_owner(&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 if open state has correct access for type of lock.
   * Don't need to check for conflicting states since this open
   * state assures there are no conflicting states.
   */
  if(((arg_LOCK4.locktype == WRITE_LT || arg_LOCK4.locktype == WRITEW_LT) &&
      ((pstate_open->state_data.share.share_access & OPEN4_SHARE_ACCESS_WRITE) == 0)) ||
     ((arg_LOCK4.locktype == READ_LT || arg_LOCK4.locktype == READW_LT) &&
      ((pstate_open->state_data.share.share_access & OPEN4_SHARE_ACCESS_READ) == 0)))
    {
      /* The open state doesn't allow access based on the type of lock */
      LogLock(COMPONENT_NFS_V4_LOCK, NIV_DEBUG,
              "LOCK failed, SHARE doesn't allow access",
              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(arg_LOCK4.locker.new_lock_owner)
    {
      /* A lock owner is always associated with a previously made open
       * which has itself a previously made stateid
       */

      /* Get reference to open owner */
      inc_state_owner_ref(popen_owner);

      if(nfs4_owner_Get_Pointer(&owner_name, &plock_owner))
        {
          /* Lock owner already existsc, check lock_seqid if it's not 0 */
          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,
                                          STATE_LOCK_OWNER_NFSV4,
                                          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 */
      memset(&candidate_type, 0, sizeof(candidate_type));
      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);

          dec_state_owner_ref(plock_owner, data->pclient);

          return res_LOCK4.status;
        }

      init_glist(&plock_state->state_data.lock.state_locklist);

      /* Add lock state to the list of lock states belonging to the open state */
      glist_add_tail(&pstate_open->state_data.share.share_lockstates,
                     &plock_state->state_data.lock.state_sharelist);
    }                           /* 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,
                                data->pclient);
        }

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

      res_LOCK4.status = nfs4_Errno_state(state_status);

      /* 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);

      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));
        }

      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);

  /* 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 */
예제 #2
0
int nfs41_op_exchange_id(struct nfs_argop4 *op,
                         compound_data_t * data, struct nfs_resop4 *resp)
{
  char __attribute__ ((__unused__)) funcname[] = "nfs4_op_setclientid";
  char str_verifier[MAXNAMLEN];
  char str_client[MAXNAMLEN];

#define arg_EXCHANGE_ID4  op->nfs_argop4_u.opexchange_id
#define res_EXCHANGE_ID4  resp->nfs_resop4_u.opexchange_id

  clientid4 clientid;
  nfs_client_id_t nfs_clientid;
  nfs_worker_data_t *pworker = NULL;

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

  strncpy(str_verifier, arg_EXCHANGE_ID4.eia_clientowner.co_verifier, MAXNAMLEN);
  strncpy(str_client, arg_EXCHANGE_ID4.eia_clientowner.co_ownerid.co_ownerid_val,
          arg_EXCHANGE_ID4.eia_clientowner.co_ownerid.co_ownerid_len);
  str_client[arg_EXCHANGE_ID4.eia_clientowner.co_ownerid.co_ownerid_len] = '\0';

  LogDebug(COMPONENT_NFS_V4, "EXCHANGE_ID Client id len = %u",
           arg_EXCHANGE_ID4.eia_clientowner.co_ownerid.co_ownerid_len);
  LogDebug(COMPONENT_NFS_V4, "EXCHANGE_ID Client name = #%s#", str_client);
  //LogDebug(COMPONENT_NFS_V4, "EXCHANGE_ID Verifier = #%s#", str_verifier ) ; 

  /* There was no pb, returns the clientid */
  resp->resop = NFS4_OP_EXCHANGE_ID;
  res_EXCHANGE_ID4.eir_status = NFS4_OK;

  /* Compute the client id */
  if(nfs_client_id_basic_compute(str_client, &clientid) != CLIENT_ID_SUCCESS)
    {
      res_EXCHANGE_ID4.eir_status = NFS4ERR_SERVERFAULT;
      return res_EXCHANGE_ID4.eir_status;
    }

  LogDebug(COMPONENT_NFS_V4,
           "EXCHANGE_ID computed clientid4=%llux for name='%s'",
           (long long unsigned int)clientid, str_client);

#if 0 //plante le client sous windows. Ai-je réellement besoin de cela ???? //
  /* Check flags value (test EID4) */
  if(arg_EXCHANGE_ID4.eia_flags & all_eia_flags != arg_EXCHANGE_ID4.eia_flags)
    {
      res_EXCHANGE_ID4.eir_status = NFS4ERR_INVAL;
      return res_EXCHANGE_ID4.eir_status;
    }
#endif

  /* Does this id already exists ? */
  if(nfs_client_id_get(clientid, &nfs_clientid) == CLIENT_ID_SUCCESS)
    {
      /* Client id already in use */
      LogDebug(COMPONENT_NFS_V4,
               "EXCHANGE_ID ClientId %llx already in use for client '%s', check if same",
               (long long unsigned int)clientid, nfs_clientid.client_name);

      /* Principals are the same, check content of the setclientid request */
      if(nfs_clientid.confirmed == CONFIRMED_CLIENT_ID)
        {
#ifdef _NFSV4_COMPARE_CRED_IN_EXCHANGE_ID
          /* Check if client id has same credentials */
          if(nfs_compare_clientcred(&(nfs_clientid.credential), &(data->credential)) ==
             FALSE)
            {
              LogDebug(COMPONENT_NFS_V4,
                       "EXCHANGE_ID Confirmed ClientId %llx -> '%s': Credential do not match... Return NFS4ERR_CLID_INUSE",
                       clientid, nfs_clientid.client_name);

              res_EXCHANGE_ID4.eir_status = NFS4ERR_CLID_INUSE;
#ifdef _USE_NFS4_1
              res_EXCHANGE_ID4.EXCHANGE_ID4res_u.client_using.na_r_netid =
                  nfs_clientid.client_r_netid;
              res_EXCHANGE_ID4.EXCHANGE_ID4res_u.client_using.na_r_addr =
                  nfs_clientid.client_r_addr;
#else
              res_EXCHANGE_ID4.EXCHANGE_ID4res_u.client_using.r_netid =
                  nfs_clientid.client_r_netid;
              res_EXCHANGE_ID4.EXCHANGE_ID4res_u.client_using.r_addr =
                  nfs_clientid.client_r_addr;
#endif /* _USE_NFS4_1 */
              return res_EXCHANGE_ID4.eir_status;
            }
          else
            LogDebug(COMPONENT_NFS_V4,
                     "EXCHANGE_ID ClientId %llx is set again by same principal",
                     clientid);
#endif

          /* Ask for a different client with the same client id... returns an error if different client */
          LogDebug(COMPONENT_NFS_V4,
                   "EXCHANGE_ID Confirmed ClientId %llx already in use for client '%s'",
                   (long long unsigned int)clientid, nfs_clientid.client_name);

          if(strncmp
             (nfs_clientid.incoming_verifier,
              arg_EXCHANGE_ID4.eia_clientowner.co_verifier, NFS4_VERIFIER_SIZE))
            {
              LogDebug(COMPONENT_NFS_V4,
                       "EXCHANGE_ID Confirmed ClientId %llx already in use for client '%s', verifier do not match...",
                       (long long unsigned int)clientid, nfs_clientid.client_name);

              /* A client has rebooted and rebuilds its state */
              LogDebug(COMPONENT_NFS_V4,
                       "Probably something to be done here: a client has rebooted and try recovering its state. Update the record for this client");

              /* Update the record, but set it as REBOOTED */
              strncpy(nfs_clientid.client_name,
                      arg_EXCHANGE_ID4.eia_clientowner.co_ownerid.co_ownerid_val,
                      arg_EXCHANGE_ID4.eia_clientowner.co_ownerid.co_ownerid_len);
              nfs_clientid.client_name[arg_EXCHANGE_ID4.eia_clientowner.co_ownerid.
                                       co_ownerid_len] = '\0';

              strncpy(nfs_clientid.incoming_verifier,
                      arg_EXCHANGE_ID4.eia_clientowner.co_verifier, NFS4_VERIFIER_SIZE);
              snprintf(nfs_clientid.verifier, NFS4_VERIFIER_SIZE, "%u",
                       (unsigned int)ServerBootTime);
              nfs_clientid.confirmed = REBOOTED_CLIENT_ID;
              nfs_clientid.clientid = clientid;
              nfs_clientid.last_renew = 0;

              if(nfs_client_id_set(clientid, nfs_clientid,
                                   &pworker->clientid_pool) !=
                 CLIENT_ID_SUCCESS)
                {
                  res_EXCHANGE_ID4.eir_status = NFS4ERR_SERVERFAULT;
                  return res_EXCHANGE_ID4.eir_status;
                }

            }
          else
            {
              LogDebug(COMPONENT_NFS_V4,
                       "EXCHANGE_ID Confirmed ClientId %llx already in use for client '%s', verifier matches. Now check callback",
                       (long long unsigned int)clientid, nfs_clientid.client_name);
            }
        }
      else
        {
          LogDebug(COMPONENT_NFS_V4,
                   "EXCHANGE_ID ClientId %llx already in use for client '%s', but unconfirmed",
                   (long long unsigned int)clientid, nfs_clientid.client_name);
          LogCrit(COMPONENT_NFS_V4,
	          "Reuse of a formerly obtained clientid that is not yet confirmed."); // Code needs to be improved here.
        }
    }
  else
    {
      /* Build the client record */
      strncpy(nfs_clientid.client_name,
              arg_EXCHANGE_ID4.eia_clientowner.co_ownerid.co_ownerid_val,
              arg_EXCHANGE_ID4.eia_clientowner.co_ownerid.co_ownerid_len);
      nfs_clientid.client_name[arg_EXCHANGE_ID4.eia_clientowner.co_ownerid.
                               co_ownerid_len] = '\0';

      strncpy(nfs_clientid.incoming_verifier,
              arg_EXCHANGE_ID4.eia_clientowner.co_verifier, NFS4_VERIFIER_SIZE);
      snprintf(nfs_clientid.verifier, NFS4_VERIFIER_SIZE, "%u",
               (unsigned int)ServerBootTime);
      nfs_clientid.confirmed = UNCONFIRMED_CLIENT_ID;
      nfs_clientid.cb_program = 0;      /* to be set at create_session time */
      nfs_clientid.clientid = clientid;
      nfs_clientid.last_renew = 0;
      nfs_clientid.nb_session = 0;
      nfs_clientid.create_session_sequence = 1;
      nfs_clientid.credential = data->credential;

      if(gethostname(nfs_clientid.server_owner, MAXNAMLEN) == -1)
        {
          res_EXCHANGE_ID4.eir_status = NFS4ERR_SERVERFAULT;
          return res_EXCHANGE_ID4.eir_status;
        }
//      strncpy(nfs_clientid.server_scope, nfs_clientid.server_owner, MAXNAMLEN);

      snprintf( nfs_clientid.server_scope, MAXNAMLEN, "%s_NFS-Ganesha", nfs_clientid.server_owner ) ;

      if(nfs_client_id_add(clientid, nfs_clientid, data->pclient) !=
         CLIENT_ID_SUCCESS)
        {
          res_EXCHANGE_ID4.eir_status = NFS4ERR_SERVERFAULT;
          return res_EXCHANGE_ID4.eir_status;
        }
    }

  res_EXCHANGE_ID4.EXCHANGE_ID4res_u.eir_resok4.eir_clientid = clientid;
  res_EXCHANGE_ID4.EXCHANGE_ID4res_u.eir_resok4.eir_sequenceid =
      nfs_clientid.create_session_sequence;
#if defined(_USE_FSALMDS) && defined(_USE_FSALDS)
  res_EXCHANGE_ID4.EXCHANGE_ID4res_u.eir_resok4.eir_flags =
      EXCHGID4_FLAG_USE_PNFS_MDS | EXCHGID4_FLAG_USE_PNFS_DS |
      EXCHGID4_FLAG_SUPP_MOVED_REFER;
#elif defined(_USE_FSALMDS)
  res_EXCHANGE_ID4.EXCHANGE_ID4res_u.eir_resok4.eir_flags =
      EXCHGID4_FLAG_USE_PNFS_MDS | EXCHGID4_FLAG_SUPP_MOVED_REFER;
#elif defined(_USE_FSALDS)
  res_EXCHANGE_ID4.EXCHANGE_ID4res_u.eir_resok4.eir_flags =
      EXCHGID4_FLAG_USE_PNFS_DS | EXCHGID4_FLAG_SUPP_MOVED_REFER;
#elif defined(_USE_DS)
  res_EXCHANGE_ID4.EXCHANGE_ID4res_u.eir_resok4.eir_flags =
      EXCHGID4_FLAG_USE_PNFS_MDS | EXCHGID4_FLAG_USE_PNFS_DS |
      EXCHGID4_FLAG_SUPP_MOVED_REFER;
#else
  res_EXCHANGE_ID4.EXCHANGE_ID4res_u.eir_resok4.eir_flags =
      EXCHGID4_FLAG_USE_NON_PNFS | EXCHGID4_FLAG_SUPP_MOVED_REFER;
#endif

  res_EXCHANGE_ID4.EXCHANGE_ID4res_u.eir_resok4.eir_state_protect.spr_how = SP4_NONE;

  res_EXCHANGE_ID4.EXCHANGE_ID4res_u.eir_resok4.eir_server_owner.so_major_id.
      so_major_id_len = strlen(nfs_clientid.server_owner);
  res_EXCHANGE_ID4.EXCHANGE_ID4res_u.eir_resok4.eir_server_owner.so_major_id.
      so_major_id_val = Mem_Alloc(strlen(nfs_clientid.server_owner));
  memcpy(res_EXCHANGE_ID4.EXCHANGE_ID4res_u.eir_resok4.eir_server_owner.so_major_id.
         so_major_id_val, nfs_clientid.server_owner, strlen(nfs_clientid.server_owner));
  res_EXCHANGE_ID4.EXCHANGE_ID4res_u.eir_resok4.eir_server_owner.so_minor_id = 0;

  res_EXCHANGE_ID4.EXCHANGE_ID4res_u.eir_resok4.eir_server_scope.eir_server_scope_len =
      strlen(nfs_clientid.server_scope);
  res_EXCHANGE_ID4.EXCHANGE_ID4res_u.eir_resok4.eir_server_scope.eir_server_scope_val =
      Mem_Alloc(strlen(nfs_clientid.server_scope));
  memcpy(res_EXCHANGE_ID4.EXCHANGE_ID4res_u.eir_resok4.eir_server_scope.
         eir_server_scope_val, nfs_clientid.server_scope,
         strlen(nfs_clientid.server_scope));

  res_EXCHANGE_ID4.EXCHANGE_ID4res_u.eir_resok4.eir_server_impl_id.
      eir_server_impl_id_len = 0;
  res_EXCHANGE_ID4.EXCHANGE_ID4res_u.eir_resok4.eir_server_impl_id.
      eir_server_impl_id_val = NULL;

  LogDebug(COMPONENT_NFS_V4, "EXCHANGE_ID reply :ClientId=%llx",
           (long long unsigned int)res_EXCHANGE_ID4.EXCHANGE_ID4res_u.eir_resok4.eir_clientid);

  res_EXCHANGE_ID4.eir_status = NFS4_OK;
  return res_EXCHANGE_ID4.eir_status;
}                               /* nfs41_op_exchange_id */