Exemplo n.º 1
0
/**
 * @brief Initialize an NFS4 open owner object
 *
 * @param[in] owner The owner record
 *
 */
static void init_nfs4_owner(state_owner_t *owner)
{
	glist_init(&owner->so_owner.so_nfs4_owner.so_state_list);

	/* Increment refcount on related owner */
	if (owner->so_owner.so_nfs4_owner.so_related_owner != NULL)
		inc_state_owner_ref(owner->so_owner.so_nfs4_owner.
				    so_related_owner);

	/* Increment reference count for clientid record */
	inc_client_id_ref(owner->so_owner.so_nfs4_owner.so_clientrec);

	PTHREAD_MUTEX_lock(&owner->so_owner.so_nfs4_owner.so_clientrec
			   ->cid_mutex);

	if (owner->so_type == STATE_OPEN_OWNER_NFSV4) {
		/* If open owner, add to clientid lock owner list */
		glist_add_tail(&owner->so_owner.so_nfs4_owner.so_clientrec->
			       cid_openowners,
			       &owner->so_owner.so_nfs4_owner.so_perclient);
	} else if (owner->so_type == STATE_LOCK_OWNER_NFSV4) {
		/* If lock owner, add to clientid open owner list */
		glist_add_tail(&owner->so_owner.so_nfs4_owner.so_clientrec->
			       cid_lockowners,
			       &owner->so_owner.so_nfs4_owner.so_perclient);
	}

	PTHREAD_MUTEX_unlock(&owner->so_owner.so_nfs4_owner.so_clientrec
			     ->cid_mutex);
}
Exemplo n.º 2
0
void
all_list_init(void)
{
    LIST_INIT(&all_list_head);

    glist_init();
    return;
}
/* Equivalent du _9p_socket_thread( */
void * _9p_rdma_thread( void * Arg )
{
  msk_trans_t   * trans   = Arg  ;

  _9p_rdma_priv * priv    = NULL ;
  _9p_conn_t    * p_9p_conn = NULL ;
  uint8_t       * rdmabuf = NULL ;
  struct ibv_mr * mr      = NULL ;
  msk_data_t    * rdata   = NULL ;
  _9p_datalock_t  * datalock  = NULL ;
  unsigned int i = 0 ;
  int rc = 0 ;

  if( ( priv = gsh_malloc( sizeof(*priv) ) ) == NULL )
   {
      LogFatal( COMPONENT_9P, "9P/RDMA: trans handler could not malloc private structure" ) ;
      goto error ;
   }
  memset(priv, 0, sizeof(*priv));
  trans->private_data = priv;

  if( ( p_9p_conn = gsh_malloc( sizeof(*p_9p_conn) ) ) == NULL )
   {
      LogFatal( COMPONENT_9P, "9P/RDMA: trans handler could not malloc _9p_conn" ) ;
      goto error ;
   }
  memset(p_9p_conn, 0, sizeof(*p_9p_conn));
  priv->pconn = p_9p_conn;

  for (i = 0; i < FLUSH_BUCKETS; i++)
   {
     pthread_mutex_init(&p_9p_conn->flush_buckets[i].lock, NULL);
     glist_init(&p_9p_conn->flush_buckets[i].list);
   }
  p_9p_conn->sequence = 0 ;
  atomic_store_uint32_t(&p_9p_conn->refcount, 0) ;
  p_9p_conn->trans_type = _9P_RDMA ;
  p_9p_conn->trans_data.rdma_trans = trans ;
  memcpy(&p_9p_conn->addrpeer, msk_get_dst_addr(trans), sizeof(p_9p_conn->addrpeer));

  /* Init the fids pointers array */
  memset( &p_9p_conn->fids, 0, _9P_FID_PER_CONN* sizeof( _9p_fid_t * ) ) ;

  /* Set initial msize. Client may request a lower value during TVERSION */
  p_9p_conn->msize = nfs_param._9p_param._9p_rdma_msize ;

  if( gettimeofday( &p_9p_conn->birth, NULL ) == -1 )
   LogMajor( COMPONENT_9P, "Cannot get connection's time of birth" ) ;

  /* Alloc rdmabuf */
  if( ( rdmabuf = gsh_malloc( (_9P_RDMA_BUFF_NUM)*_9P_RDMA_CHUNK_SIZE)) == NULL )
   {
      LogFatal( COMPONENT_9P, "9P/RDMA: trans handler could not malloc rdmabuf" ) ;
      goto error ;
   }
  memset( rdmabuf, 0, (_9P_RDMA_BUFF_NUM)*_9P_RDMA_CHUNK_SIZE);
  priv->rdmabuf = rdmabuf;

  /* Register rdmabuf */
  if( ( mr = msk_reg_mr( trans,
                         rdmabuf,
                         (_9P_RDMA_BUFF_NUM)*_9P_RDMA_CHUNK_SIZE,
                         IBV_ACCESS_LOCAL_WRITE)) == NULL  )
   {
      LogFatal( COMPONENT_9P, "9P/RDMA: trans handler could not register rdmabuf" ) ;
      goto error ;
   }

  /* Get prepared to recv data */

  if( ( rdata = gsh_malloc( _9P_RDMA_BUFF_NUM * sizeof(*rdata) ) ) == NULL )
   {
      LogFatal( COMPONENT_9P, "9P/RDMA: trans handler could not malloc rdata" ) ;
      goto error ;
   }
  memset( rdata, 0, (_9P_RDMA_BUFF_NUM * sizeof(*rdata)) ) ;
  priv->rdata = rdata;

  if( (datalock = gsh_malloc(_9P_RDMA_BUFF_NUM*sizeof(*datalock))) == NULL )
   {
      LogFatal( COMPONENT_9P, "9P/RDMA: trans handler could not malloc datalock" ) ;
      goto error ;
   }
  memset( datalock, 0, (_9P_RDMA_BUFF_NUM * sizeof(*datalock)) ) ;
  priv->datalock = datalock;

  for( i=0; i < _9P_RDMA_BUFF_NUM; i++)
   {
      rdata[i].data=rdmabuf+i*_9P_RDMA_CHUNK_SIZE ;
      rdata[i].max_size=_9P_RDMA_CHUNK_SIZE ;
      rdata[i].mr = mr;
      datalock[i].data = &rdata[i];
      pthread_mutex_init(&datalock[i].lock, NULL);

      if( i < _9P_RDMA_OUT )
        datalock[i].sender = &datalock[i+_9P_RDMA_OUT] ;
      else
        datalock[i].sender = NULL ;
   } /*  for (unsigned int i=0; i < _9P_RDMA_BUFF_NUM; i++)  */

  for( i=0; i < _9P_RDMA_OUT; i++)
   {
      if( ( rc = msk_post_recv( trans,
                                &rdata[i],
                                _9p_rdma_callback_recv,
				_9p_rdma_callback_recv_err,
                               &(datalock[i]) ) ) != 0 )
       {
          LogEvent( COMPONENT_9P,  "9P/RDMA: trans handler could recv first byte of datalock[%u], rc=%u", i, rc ) ;
          goto error ;
       }
   }

  /* Finalize accept */
  if( ( rc = msk_finalize_accept( trans ) ) != 0 )
   {
      LogMajor( COMPONENT_9P, "9P/RDMA: trans handler could not finalize accept, rc=%u", rc ) ;
      goto error ;
   }

  pthread_exit( NULL ) ;

error:

  _9p_rdma_cleanup_conn_thread( trans ) ;

  pthread_exit( NULL ) ;
} /* _9p_rdma_handle_trans */
Exemplo n.º 4
0
int nfs4_op_lock(struct nfs_argop4 *op, compound_data_t *data,
		 struct nfs_resop4 *resp)
{
	/* Shorter alias for arguments */
	LOCK4args * const arg_LOCK4 = &op->nfs_argop4_u.oplock;
	/* Shorter alias for response */
	LOCK4res * const res_LOCK4 = &resp->nfs_resop4_u.oplock;
	/* Status code from state calls */
	state_status_t state_status = STATE_SUCCESS;
	/* Data for lock state to be created */
	union state_data candidate_data;
	/* Status code for protocol functions */
	nfsstat4 nfs_status = 0;
	/* Created or found lock state */
	state_t *lock_state = NULL;
	/* Associated open state */
	state_t *state_open = NULL;
	/* The lock owner */
	state_owner_t *lock_owner = NULL;
	/* The open owner */
	state_owner_t *open_owner = NULL;
	/* The owner of a conflicting lock */
	state_owner_t *conflict_owner = NULL;
	/* The owner in which to store the response for NFSv4.0 */
	state_owner_t *resp_owner = NULL;
	/* Sequence ID, for NFSv4.0 */
	seqid4 seqid = 0;
	/* The client performing these operations */
	nfs_client_id_t *clientid = NULL;
	/* Name for the lock owner */
	state_nfs4_owner_name_t owner_name;
	/* Description of requrested lock */
	fsal_lock_param_t lock_desc;
	/* Description of conflicting lock */
	fsal_lock_param_t conflict_desc;
	/* Whether to block */
	state_blocking_t blocking = STATE_NON_BLOCKING;
	/* Tracking data for the lock state */
	struct state_refer refer;
	/* Indicate if we let FSAL to handle requests during grace. */
	bool_t fsal_grace = false;
	int rc;

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

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

	/* Record the sequence info */
	if (data->minorversion > 0) {
		memcpy(refer.session,
		       data->session->session_id,
		       sizeof(sessionid4));
		refer.sequence = data->sequence;
		refer.slot = data->slot;
	}

	res_LOCK4->status = nfs4_sanity_check_FH(data, REGULAR_FILE, false);

	if (res_LOCK4->status != NFS4_OK)
		return res_LOCK4->status;

	/* Convert lock parameters to internal types */
	switch (arg_LOCK4->locktype) {
	case READW_LT:
		blocking = STATE_NFSV4_BLOCKING;
		/* Fall through */

	case READ_LT:
		lock_desc.lock_type = FSAL_LOCK_R;
		break;

	case WRITEW_LT:
		blocking = STATE_NFSV4_BLOCKING;
		/* Fall through */

	case WRITE_LT:
		lock_desc.lock_type = FSAL_LOCK_W;
		break;

	default:
		LogDebug(COMPONENT_NFS_V4_LOCK,
			 "Invalid lock type");
		res_LOCK4->status = NFS4ERR_INVAL;
		return res_LOCK4->status;
	}

	lock_desc.lock_start = arg_LOCK4->offset;
	lock_desc.lock_sle_type = FSAL_POSIX_LOCK;
	lock_desc.lock_reclaim = arg_LOCK4->reclaim;

	if (arg_LOCK4->length != STATE_LOCK_OFFSET_EOF)
		lock_desc.lock_length = arg_LOCK4->length;
	else
		lock_desc.lock_length = 0;

	if (arg_LOCK4->locker.new_lock_owner) {
		/* Check stateid correctness and get pointer to state */
		nfs_status = nfs4_Check_Stateid(
			&arg_LOCK4->locker.locker4_u.open_owner.open_stateid,
			data->current_obj,
			&state_open,
			data,
			STATEID_SPECIAL_FOR_LOCK,
			arg_LOCK4->locker.locker4_u.open_owner.open_seqid,
			data->minorversion == 0,
			lock_tag);

		if (nfs_status != NFS4_OK) {
			if (nfs_status == NFS4ERR_REPLAY) {
				open_owner = get_state_owner_ref(state_open);

				LogStateOwner("Open: ", open_owner);

				if (open_owner != NULL) {
					resp_owner = open_owner;
					seqid = arg_LOCK4->locker.locker4_u
						.open_owner.open_seqid;
					goto check_seqid;
				}
			}

			res_LOCK4->status = nfs_status;
			LogDebug(COMPONENT_NFS_V4_LOCK,
				 "LOCK failed nfs4_Check_Stateid for open owner");
			return res_LOCK4->status;
		}

		open_owner = get_state_owner_ref(state_open);

		LogStateOwner("Open: ", open_owner);

		if (open_owner == NULL) {
			/* State is going stale. */
			res_LOCK4->status = NFS4ERR_STALE;
			LogDebug(COMPONENT_NFS_V4_LOCK,
				 "LOCK failed nfs4_Check_Stateid, stale open owner");
			goto out2;
		}

		lock_state = NULL;
		lock_owner = NULL;
		resp_owner = open_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_obj, open_owner, &lock_desc);

		/* Check is the clientid is known or not */
		rc = nfs_client_id_get_confirmed(
			data->minorversion == 0 ? arg_LOCK4->locker.
				  locker4_u.open_owner.lock_owner.clientid
				: data->session->clientid,
			&clientid);

		if (rc != CLIENT_ID_SUCCESS) {
			res_LOCK4->status = clientid_error_to_nfsstat(rc);
			LogDebug(COMPONENT_NFS_V4_LOCK,
				 "LOCK failed nfs_client_id_get");
			goto out2;
		}

		if (isDebug(COMPONENT_CLIENTID) && (clientid !=
		    open_owner->so_owner.so_nfs4_owner.so_clientrec)) {
			char str_open[LOG_BUFF_LEN / 2];
			struct display_buffer dspbuf_open = {
				sizeof(str_open), str_open, str_open};
			char str_lock[LOG_BUFF_LEN / 2];
			struct display_buffer dspbuf_lock = {
				sizeof(str_lock), str_lock, str_lock};

			display_client_id_rec(&dspbuf_open,
					      open_owner->so_owner
					      .so_nfs4_owner.so_clientrec);
			display_client_id_rec(&dspbuf_lock, clientid);

			LogDebug(COMPONENT_CLIENTID,
				 "Unexpected, new lock owner clientid {%s} doesn't match open owner clientid {%s}",
				 str_lock, str_open);
		}

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

		/* An open state has been found. Check its type */
		if (state_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");
			goto out2;
		}

		/* Is this lock_owner known ? */
		convert_nfs4_lock_owner(&arg_LOCK4->locker.locker4_u.open_owner.
					lock_owner, &owner_name);
		LogStateOwner("Lock: ", lock_owner);
	} else {
		/* Existing lock owner Find the lock stateid From
		 * that, get the open_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
		 */
		nfs_status = nfs4_Check_Stateid(
			&arg_LOCK4->locker.locker4_u.lock_owner.lock_stateid,
			data->current_obj,
			&lock_state,
			data,
			STATEID_SPECIAL_FOR_LOCK,
			arg_LOCK4->locker.locker4_u.lock_owner.lock_seqid,
			data->minorversion == 0,
			lock_tag);

		if (nfs_status != NFS4_OK) {
			if (nfs_status == NFS4ERR_REPLAY) {
				lock_owner = get_state_owner_ref(lock_state);

				LogStateOwner("Lock: ", lock_owner);

				if (lock_owner != NULL) {
					open_owner = lock_owner->so_owner
						.so_nfs4_owner.so_related_owner;
					inc_state_owner_ref(open_owner);
					resp_owner = lock_owner;
					seqid = arg_LOCK4->locker.locker4_u
						.lock_owner.lock_seqid;
					goto check_seqid;
				}
			}

			res_LOCK4->status = nfs_status;
			LogDebug(COMPONENT_NFS_V4_LOCK,
				 "LOCK failed nfs4_Check_Stateid for existing lock owner");
			return res_LOCK4->status;
		}

		/* Check if lock state belongs to same export */
		if (!state_same_export(lock_state, op_ctx->ctx_export)) {
			LogEvent(COMPONENT_STATE,
				 "Lock Owner Export Conflict, Lock held for export %"
				 PRIu16" request for export %"PRIu16,
				 state_export_id(lock_state),
				 op_ctx->ctx_export->export_id);
			res_LOCK4->status = NFS4ERR_INVAL;
			goto out2;
		}

		/* A lock state has been found. Check its type */
		if (lock_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");
			goto out2;
		}

		/* 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
		 */
		lock_owner = get_state_owner_ref(lock_state);

		LogStateOwner("Lock: ", lock_owner);

		if (lock_owner == NULL) {
			/* State is going stale. */
			res_LOCK4->status = NFS4ERR_STALE;
			LogDebug(COMPONENT_NFS_V4_LOCK,
				 "LOCK failed nfs4_Check_Stateid, stale open owner");
			goto out2;
		}

		open_owner =
			lock_owner->so_owner.so_nfs4_owner.so_related_owner;
		LogStateOwner("Open: ", open_owner);
		inc_state_owner_ref(open_owner);
		state_open = lock_state->state_data.lock.openstate;
		inc_state_t_ref(state_open);
		resp_owner = lock_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_obj,
			lock_owner, &lock_desc);

		/* Get the client for this open owner */
		clientid = open_owner->so_owner.so_nfs4_owner.so_clientrec;
		inc_client_id_ref(clientid);
	}

 check_seqid:

	/* Check seqid (lock_seqid or open_seqid) */
	if (data->minorversion == 0) {
		if (!Check_nfs4_seqid(resp_owner,
				      seqid,
				      op,
				      data->current_obj,
				      resp,
				      lock_tag)) {
			/* Response is all setup for us and LogDebug
			 * told what was wrong
			 */
			goto out2;
		}
	}

	/* 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");
		goto out;
	}

	/* 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.lock_length >
	    (STATE_LOCK_OFFSET_EOF - lock_desc.lock_start)) {
		res_LOCK4->status = NFS4ERR_INVAL;
		LogDebug(COMPONENT_NFS_V4_LOCK, "LOCK failed length overflow");
		goto out;
	}

	/* 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)
	      &&
	      ((state_open->state_data.share.share_access &
		OPEN4_SHARE_ACCESS_WRITE) == 0))
	    ||
	    ((arg_LOCK4->locktype == READ_LT ||
	      arg_LOCK4->locktype == READW_LT)
	      &&
	      ((state_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_obj, lock_owner, &lock_desc);

		res_LOCK4->status = NFS4ERR_OPENMODE;

		goto out;
	}

	/* Do grace period checking (use resp_owner below since a new
	 * lock request with a new lock owner doesn't have a lock owner
	 * yet, but does have an open owner - resp_owner is always one or
	 * the other and non-NULL at this point - so makes for a better log).
	 */
	if (nfs_in_grace()) {
		if (op_ctx->fsal_export->exp_ops.
			fs_supports(op_ctx->fsal_export, fso_grace_method))
				fsal_grace = true;

		if (!fsal_grace && !arg_LOCK4->reclaim) {
			LogLock(COMPONENT_NFS_V4_LOCK, NIV_DEBUG,
			"LOCK failed, non-reclaim while in grace",
				data->current_obj, resp_owner, &lock_desc);
			res_LOCK4->status = NFS4ERR_GRACE;
			goto out;
		}
		if (!fsal_grace && arg_LOCK4->reclaim
		    && !clientid->cid_allow_reclaim) {
			LogLock(COMPONENT_NFS_V4_LOCK, NIV_DEBUG,
				"LOCK failed, invalid reclaim while in grace",
				data->current_obj, resp_owner, &lock_desc);
			res_LOCK4->status = NFS4ERR_NO_GRACE;
			goto out;
		}
	} else {
		if (arg_LOCK4->reclaim) {
			LogLock(COMPONENT_NFS_V4_LOCK, NIV_DEBUG,
				"LOCK failed, reclaim while not in grace",
				data->current_obj, resp_owner, &lock_desc);
			res_LOCK4->status = NFS4ERR_NO_GRACE;
			goto out;
		}
	}

	/* Test if this request is attempting to create a new lock owner */
	if (arg_LOCK4->locker.new_lock_owner) {
		bool_t isnew;

		/* A lock owner is always associated with a previously
		   made open which has itself a previously made
		   stateid */

		/* This lock owner is not known yet, allocated and set
		   up a new one */
		lock_owner = create_nfs4_owner(&owner_name,
					       clientid,
					       STATE_LOCK_OWNER_NFSV4,
					       open_owner,
					       0,
					       &isnew,
					       CARE_ALWAYS);

		LogStateOwner("Lock: ", lock_owner);

		if (lock_owner == NULL) {
			res_LOCK4->status = NFS4ERR_RESOURCE;
			LogLock(COMPONENT_NFS_V4_LOCK, NIV_EVENT,
				"LOCK failed to create new lock owner",
				data->current_obj, open_owner, &lock_desc);
			goto out2;
		}

		if (!isnew) {
			PTHREAD_MUTEX_lock(&lock_owner->so_mutex);
			/* Check lock_seqid if it has attached locks. */
			if (!glist_empty(&lock_owner->so_lock_list)
			    && (data->minorversion == 0)
			    && !Check_nfs4_seqid(lock_owner,
						 arg_LOCK4->locker.locker4_u.
						     open_owner.lock_seqid,
						 op,
						 data->current_obj,
						 resp,
						 lock_tag)) {
				LogLock(COMPONENT_NFS_V4_LOCK, NIV_DEBUG,
					"LOCK failed to create new lock owner, re-use",
					data->current_obj,
					open_owner, &lock_desc);
				dump_all_locks(
					"All locks (re-use of lock owner)");

				PTHREAD_MUTEX_unlock(&lock_owner->so_mutex);
				/* Response is all setup for us and
				 * LogDebug told what was wrong
				 */
				goto out2;
			}

			PTHREAD_MUTEX_unlock(&lock_owner->so_mutex);

			/* Lock owner is known, see if we also already have
			 * a stateid. Do this here since it's impossible for
			 * there to be such a state if the lock owner was
			 * previously unknown.
			 */
			lock_state = nfs4_State_Get_Obj(data->current_obj,
							  lock_owner);
		}

		if (lock_state == NULL) {
			/* Prepare state management structure */
			memset(&candidate_data, 0, sizeof(candidate_data));
			candidate_data.lock.openstate = state_open;

			/* Add the lock state to the lock table */
			state_status = state_add(data->current_obj,
						 STATE_TYPE_LOCK,
						 &candidate_data,
						 lock_owner,
						 &lock_state,
						 data->minorversion > 0 ?
							&refer : NULL);

			if (state_status != STATE_SUCCESS) {
				res_LOCK4->status = NFS4ERR_RESOURCE;

				LogLock(COMPONENT_NFS_V4_LOCK, NIV_DEBUG,
					"LOCK failed to add new stateid",
					data->current_obj, lock_owner,
					&lock_desc);

				goto out2;
			}

			glist_init(&lock_state->state_data.lock.state_locklist);

			/* Add lock state to the list of lock states belonging
			   to the open state */
			glist_add_tail(
				&state_open->state_data.share.share_lockstates,
				&lock_state->state_data.lock.state_sharelist);

		}
	}

	if (data->minorversion == 0) {
		op_ctx->clientid =
		    &lock_owner->so_owner.so_nfs4_owner.so_clientid;
	}

	/* Now we have a lock owner and a stateid.  Go ahead and push
	 * lock into SAL (and FSAL). */
	state_status = state_lock(data->current_obj,
				  lock_owner,
				  lock_state,
				  blocking,
				  NULL,	/* No block data for now */
				  &lock_desc,
				  &conflict_owner,
				  &conflict_desc);

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

		/* Save the response in the lock or open owner */
		if (res_LOCK4->status != NFS4ERR_RESOURCE
		    && res_LOCK4->status != NFS4ERR_BAD_STATEID
		    && data->minorversion == 0) {
			Copy_nfs4_state_req(resp_owner,
					    seqid,
					    op,
					    data->current_obj,
					    resp,
					    lock_tag);
		}

		if (arg_LOCK4->locker.new_lock_owner) {
			/* Need to destroy new state */
			state_del(lock_state);
		}
		goto out2;
	}

	if (data->minorversion == 0)
		op_ctx->clientid = NULL;

	res_LOCK4->status = NFS4_OK;

	/* Handle stateid/seqid for success */
	update_stateid(lock_state,
		       &res_LOCK4->LOCK4res_u.resok4.lock_stateid,
		       data,
		       lock_tag);

	if (arg_LOCK4->locker.new_lock_owner) {
		/* Also save the response in the lock owner */
		Copy_nfs4_state_req(lock_owner,
				    arg_LOCK4->locker.locker4_u.open_owner.
				    lock_seqid,
				    op,
				    data->current_obj,
				    resp,
				    lock_tag);

	}

	if (isFullDebug(COMPONENT_NFS_V4_LOCK)) {
		char str[LOG_BUFF_LEN];
		struct display_buffer dspbuf = {sizeof(str), str, str};

		display_stateid(&dspbuf, lock_state);

		LogFullDebug(COMPONENT_NFS_V4_LOCK, "LOCK stateid %s", str);
	}

	LogLock(COMPONENT_NFS_V4_LOCK, NIV_FULL_DEBUG, "LOCK applied",
		data->current_obj, lock_owner, &lock_desc);

 out:

	if (data->minorversion == 0) {
		/* Save the response in the lock or open owner */
		Copy_nfs4_state_req(resp_owner,
				    seqid,
				    op,
				    data->current_obj,
				    resp,
				    lock_tag);
	}

 out2:

	if (state_open != NULL)
		dec_state_t_ref(state_open);

	if (lock_state != NULL)
		dec_state_t_ref(lock_state);

	LogStateOwner("Open: ", open_owner);
	LogStateOwner("Lock: ", lock_owner);

	if (open_owner != NULL)
		dec_state_owner_ref(open_owner);

	if (lock_owner != NULL)
		dec_state_owner_ref(lock_owner);

	if (clientid != NULL)
		dec_client_id_ref(clientid);

	return res_LOCK4->status;
}				/* nfs4_op_lock */
Exemplo n.º 5
0
void init(void){
	glist_init(&ModuleList);
	queue_init(&ReadyQueue,1000);
	LoadModules(&ModuleList);
}
Exemplo n.º 6
0
static void open4_ex(OPEN4args *arg,
		     compound_data_t *data,
		     OPEN4res *res_OPEN4,
		     nfs_client_id_t *clientid,
		     state_owner_t *owner,
		     state_t **file_state,
		     bool *new_state)
{
	/* Parent directory in which to open the file. */
	struct fsal_obj_handle *parent = NULL;
	/* The entry we associated with the desired file before open. */
	struct fsal_obj_handle *file_obj = NULL;
	/* Indicator that file_obj came from lookup. */
	bool looked_up_file_obj = false;
	/* The in_obj to pass to fsal_open2. */
	struct fsal_obj_handle *in_obj = NULL;
	/* The entry open associated with the file. */
	struct fsal_obj_handle *out_obj = NULL;
	fsal_openflags_t openflags = 0;
	fsal_openflags_t old_openflags = 0;
	enum fsal_create_mode createmode = FSAL_NO_CREATE;
	/* The filename to create */
	char *filename = NULL;
	/* The supplied calim type */
	open_claim_type4 claim = arg->claim.claim;
	fsal_verifier_t verifier;
	struct attrlist sattr;
	/* Status for fsal calls */
	fsal_status_t status = {0, 0};
	/* The open state for the file */
	bool state_lock_held = false;

	/* Make sure the attributes are initialized */
	memset(&sattr, 0, sizeof(sattr));

	/* Make sure... */
	*file_state = NULL;
	*new_state = false;

	/* Pre-process the claim type */
	switch (claim) {
	case CLAIM_NULL:
		/* Check parent */
		parent = data->current_obj;
		in_obj = parent;

		/* Parent must be a directory */
		if (parent->type != DIRECTORY) {
			if (parent->type == SYMBOLIC_LINK) {
				res_OPEN4->status = NFS4ERR_SYMLINK;
				goto out;
			} else {
				res_OPEN4->status = NFS4ERR_NOTDIR;
				goto out;
			}
		}

		/* Validate and convert the utf8 filename */
		res_OPEN4->status =
		    nfs4_utf8string2dynamic(&arg->claim.open_claim4_u.file,
					    UTF8_SCAN_ALL, &filename);

		if (res_OPEN4->status != NFS4_OK)
			goto out;

		/* Set the createmode if appropriate) */
		if (arg->openhow.opentype == OPEN4_CREATE) {
			open4_ex_create_args(arg, data, res_OPEN4, verifier,
					     &createmode, &sattr);

			if (res_OPEN4->status != NFS4_OK)
				goto out;
		}

		status = fsal_lookup(parent, filename, &file_obj, NULL);

		if (!FSAL_IS_ERROR(status)) {
			/* Check create situations. */
			if (arg->openhow.opentype == OPEN4_CREATE) {
				if (createmode >= FSAL_EXCLUSIVE) {
					/* Could be a replay, need to continue.
					 */
					LogFullDebug(COMPONENT_STATE,
						     "EXCLUSIVE open with existing file %s",
						     filename);
				} else if (createmode == FSAL_GUARDED) {
					/* This will be a failure no matter'
					 * what.
					 */
					looked_up_file_obj = true;
					res_OPEN4->status = NFS4ERR_EXIST;
					goto out;
				} else {
					/* FSAL_UNCHECKED, may be a truncate
					 * and we need to pass in the case
					 * of fsal_reopen2 case.
					 */
					if (FSAL_TEST_MASK(sattr.valid_mask,
							   ATTR_SIZE) &&
					    sattr.filesize == 0) {
						LogFullDebug(COMPONENT_STATE,
							     "Truncate");
						openflags |= FSAL_O_TRUNC;
					}
				}
			}

			/* We found the file by lookup, discard the filename
			 * and remember that we found the entry by lookup.
			 */
			looked_up_file_obj = true;
			gsh_free(filename);
			filename = NULL;
		} else if (status.major != ERR_FSAL_NOENT ||
			   arg->openhow.opentype != OPEN4_CREATE) {
			/* A real error occurred */
			res_OPEN4->status = nfs4_Errno_status(status);
			goto out;
		}

		break;

		/* Both of these just use the current filehandle. */
	case CLAIM_PREVIOUS:
		owner->so_owner.so_nfs4_owner.so_confirmed = true;
		if (!nfs4_check_deleg_reclaim(clientid, &data->currentFH)) {
			/* It must have been revoked. Can't reclaim.*/
			LogInfo(COMPONENT_NFS_V4, "Can't reclaim delegation");
			res_OPEN4->status = NFS4ERR_RECLAIM_BAD;
			goto out;
		}
		openflags |= FSAL_O_RECLAIM;
		file_obj = data->current_obj;
		break;

	case CLAIM_FH:
		file_obj = data->current_obj;
		break;

	case CLAIM_DELEGATE_PREV:
		/* FIXME: Remove this when we have full support
		 * for CLAIM_DELEGATE_PREV and delegpurge operations
		 */
		res_OPEN4->status = NFS4ERR_NOTSUPP;
		goto out;

	case CLAIM_DELEGATE_CUR:
		res_OPEN4->status = open4_claim_deleg(arg, data);
		if (res_OPEN4->status != NFS4_OK)
			goto out;
		openflags |= FSAL_O_RECLAIM;
		file_obj = data->current_obj;
		break;

	default:
		LogFatal(COMPONENT_STATE,
			 "Programming error.  Invalid claim after check.");
	}

	if ((arg->share_access & OPEN4_SHARE_ACCESS_READ) != 0)
		openflags |= FSAL_O_READ;

	if ((arg->share_access & OPEN4_SHARE_ACCESS_WRITE) != 0)
		openflags |= FSAL_O_WRITE;

	if ((arg->share_deny & OPEN4_SHARE_DENY_READ) != 0)
		openflags |= FSAL_O_DENY_READ;

	if ((arg->share_deny & OPEN4_SHARE_DENY_WRITE) != 0)
		openflags |= FSAL_O_DENY_WRITE_MAND;

	/* Check if file_obj a REGULAR_FILE */
	if (file_obj != NULL && file_obj->type != REGULAR_FILE) {
		LogDebug(COMPONENT_NFS_V4,
			 "Wrong file type expected REGULAR_FILE actual %s",
			 object_file_type_to_str(file_obj->type));

		if (file_obj->type == DIRECTORY) {
			res_OPEN4->status = NFS4ERR_ISDIR;
		} else {
			/* All special nodes must return NFS4ERR_SYMLINK for
			 * proper client behavior per this linux-nfs post:
			 * http://marc.info/?l=linux-nfs&m=131342421825436&w=2
			 */
			res_OPEN4->status = NFS4ERR_SYMLINK;
		}

		goto out;
	}

	if (file_obj != NULL) {
		/* Go ahead and take the state lock now. */
		PTHREAD_RWLOCK_wrlock(&file_obj->state_hdl->state_lock);
		state_lock_held = true;
		in_obj = file_obj;

		/* Check if any existing delegations conflict with this open.
		 * Delegation recalls will be scheduled if there is a conflict.
		 */
		if (state_deleg_conflict(file_obj,
					  (arg->share_access &
					   OPEN4_SHARE_ACCESS_WRITE) != 0)) {
			res_OPEN4->status = NFS4ERR_DELAY;
			goto out;
		}

		/* Check if there is already a state for this entry and owner.
		 */
		*file_state = nfs4_State_Get_Obj(file_obj, owner);

		if (isFullDebug(COMPONENT_STATE) && *file_state != NULL) {
			char str[LOG_BUFF_LEN] = "\0";
			struct display_buffer dspbuf = {sizeof(str), str, str};

			display_stateid(&dspbuf, *file_state);

			LogFullDebug(COMPONENT_STATE,
				     "Found existing state %s",
				     str);
		}

		/* Check if open from another export */
		if (*file_state != NULL &&
		    !state_same_export(*file_state, op_ctx->ctx_export)) {
			LogEvent(COMPONENT_STATE,
				 "Lock Owner Export Conflict, Lock held for export %"
				 PRIu16" request for export %"PRIu16,
				 state_export_id(*file_state),
				 op_ctx->ctx_export->export_id);
			res_OPEN4->status = NFS4ERR_INVAL;
			goto out;
		}
	}

	/* If that did not succeed, allocate a state from the FSAL. */
	if (*file_state == NULL) {
		*file_state = op_ctx->fsal_export->exp_ops.alloc_state(
							op_ctx->fsal_export,
							STATE_TYPE_SHARE,
							NULL);

		/* Remember we allocated a new state */
		*new_state = true;

		/* We are ready to perform the open (with possible create).
		 * in_obj has been set to the file itself or the parent.
		 * filename is NULL if in_obj is the file itself.
		 *
		 * Permission check has been done on directory if appropriate,
		 * otherwise fsal_open2 will do a directory permission
		 * check.
		 *
		 * fsal_open2 handles the permission check on the file
		 * itself and also handles all the share reservation stuff.
		 *
		 * fsal_open2 returns with a ref on out_obj, which should be
		 * passed to the state.
		 */
		LogFullDebug(COMPONENT_STATE,
			     "Calling open2 for %s", filename);

		status = fsal_open2(in_obj,
				    *file_state,
				    openflags,
				    createmode,
				    filename,
				    &sattr,
				    verifier,
				    &out_obj,
				    NULL);

		if (FSAL_IS_ERROR(status)) {
			res_OPEN4->status = nfs4_Errno_status(status);
			goto out;
		}
	} else if (createmode >= FSAL_EXCLUSIVE) {
		/* We have an EXCLUSIVE create with an existing
		 * state. We still need to verify it, but no need
		 * to call reopen2.
		 */
		LogFullDebug(COMPONENT_STATE, "Calling verify2 ");

		status = fsal_verify2(file_obj, verifier);

		if (FSAL_IS_ERROR(status)) {
			res_OPEN4->status = nfs4_Errno_status(status);
			goto out;
		}

		/* We need an extra reference below. */
		file_obj->obj_ops->get_ref(file_obj);
	} else {
		old_openflags =
			file_obj->obj_ops->status2(file_obj, *file_state);

		/* Open upgrade */
		LogFullDebug(COMPONENT_STATE, "Calling reopen2");

		status = fsal_reopen2(file_obj, *file_state,
				      openflags | old_openflags,
				      false);

		if (FSAL_IS_ERROR(status)) {
			res_OPEN4->status = nfs4_Errno_status(status);
			goto out;
		}

		/* We need an extra reference below. */
		file_obj->obj_ops->get_ref(file_obj);
	}

	if (file_obj == NULL) {
		/* We have a new cache inode entry, take the state lock. */
		file_obj = out_obj;
		PTHREAD_RWLOCK_wrlock(&file_obj->state_hdl->state_lock);
		state_lock_held = true;
	}

	/* Now the state_lock is held for sure and we have an extra LRU
	 * reference to file_obj, which is the opened file.
	 */

	if (*new_state) {
		/* The state data to be added */
		union state_data candidate_data;
		/* Tracking data for the open state */
		struct state_refer refer, *p_refer = NULL;
		state_status_t state_status;

		candidate_data.share.share_access =
		    arg->share_access & OPEN4_SHARE_ACCESS_BOTH;
		candidate_data.share.share_deny = arg->share_deny;
		candidate_data.share.share_access_prev =
			(1 << candidate_data.share.share_access);
		candidate_data.share.share_deny_prev =
			(1 << candidate_data.share.share_deny);

		LogFullDebug(COMPONENT_STATE,
			     "Creating new state access=%x deny=%x access_prev=%x deny_prev=%x",
			     candidate_data.share.share_access,
			     candidate_data.share.share_deny,
			     candidate_data.share.share_access_prev,
			     candidate_data.share.share_deny_prev);

		/* Record the sequence info */
		if (data->minorversion > 0) {
			memcpy(refer.session,
			       data->session->session_id,
			       sizeof(sessionid4));
			refer.sequence = data->sequence;
			refer.slot = data->slot;
			p_refer = &refer;
		}

		/* We need to register this state now. */
		state_status = state_add_impl(file_obj,
					      STATE_TYPE_SHARE,
					      &candidate_data,
					      owner,
					      file_state,
					      p_refer);

		if (state_status != STATE_SUCCESS) {
			/* state_add_impl failure closed and freed state.
			 * file_state will also be NULL at this point. Also
			 * release the ref on file_obj, since the state add
			 * failed.
			 */
			file_obj->obj_ops->put_ref(file_obj);
			res_OPEN4->status = nfs4_Errno_state(state_status);
			*new_state = false;
			goto out;
		}

		glist_init(&(*file_state)->state_data.share.share_lockstates);
	}

	res_OPEN4->status = open4_create_fh(data, file_obj, true);

	if (res_OPEN4->status != NFS4_OK) {
		if (*new_state) {
			/* state_del_locked will close the file. */
			state_del_locked(*file_state);
			*file_state = NULL;
			*new_state = false;
		} else {
			/*Do an open downgrade to the old open flags */
			status = file_obj->obj_ops->reopen2(file_obj,
							   *file_state,
							   old_openflags);
			if (FSAL_IS_ERROR(status)) {
				LogCrit(COMPONENT_NFS_V4,
					"Failed to allocate handle, reopen2 failed with %s",
					fsal_err_txt(status));
			}

			/* Need to release the state_lock before the put_ref
			 * call.
			 */
			PTHREAD_RWLOCK_unlock(&file_obj->state_hdl->state_lock);
			state_lock_held = false;

			/* Release the extra LRU reference on file_obj. */
			file_obj->obj_ops->put_ref(file_obj);
			goto out;
		}
	}

	/* Since open4_create_fh succeeded the LRU reference to file_obj was
	 * consumed by data->current_obj.
	 */

	if (!(*new_state)) {
		LogFullDebug(COMPONENT_STATE,
			     "Open upgrade old access=%x deny=%x access_prev=%x deny_prev=%x",
			     (*file_state)->state_data.share.share_access,
			     (*file_state)->state_data.share.share_deny,
			     (*file_state)->state_data.share.share_access_prev,
			     (*file_state)->state_data.share.share_deny_prev);

		LogFullDebug(COMPONENT_STATE,
			     "Open upgrade to access=%x deny=%x",
			     arg->share_access,
			     arg->share_deny);

		/* Update share_access and share_deny */
		(*file_state)->state_data.share.share_access |=
			arg->share_access & OPEN4_SHARE_ACCESS_BOTH;

		(*file_state)->state_data.share.share_deny |=
			arg->share_deny;

		/* Update share_access_prev and share_deny_prev */
		(*file_state)->state_data.share.share_access_prev |=
			(1 << (arg->share_access & OPEN4_SHARE_ACCESS_BOTH));

		(*file_state)->state_data.share.share_deny_prev |=
			(1 << arg->share_deny);

		LogFullDebug(COMPONENT_STATE,
			     "Open upgrade new access=%x deny=%x access_prev=%x deny_prev=%x",
			     (*file_state)->state_data.share.share_access,
			     (*file_state)->state_data.share.share_deny,
			     (*file_state)->state_data.share.share_access_prev,
			     (*file_state)->state_data.share.share_deny_prev);
	}

	do_delegation(arg, res_OPEN4, data, owner, *file_state, clientid);
 out:

	/* Release the attributes (may release an inherited ACL) */
	fsal_release_attrs(&sattr);

	if (state_lock_held)
		PTHREAD_RWLOCK_unlock(&file_obj->state_hdl->state_lock);

	if (filename)
		gsh_free(filename);

	if (res_OPEN4->status != NFS4_OK) {
		/* Cleanup state on error */
		if (*new_state)
			(*file_state)
				->state_exp->exp_ops.free_state(
					(*file_state)->state_exp, *file_state);
		else if (*file_state != NULL)
			dec_state_t_ref(*file_state);
		*file_state = NULL;
	}

	if (looked_up_file_obj) {
		/* We got file_obj via lookup, we need to unref it. */
		file_obj->obj_ops->put_ref(file_obj);
	}
}
Exemplo n.º 7
0
static nfsstat4 acquire_layout_state(compound_data_t *data,
				     stateid4 *supplied_stateid,
				     layouttype4 layout_type,
				     state_t **layout_state, const char *tag)
{
	/* State associated with the client-supplied stateid */
	state_t *supplied_state = NULL;
	/* State owner for per-clientid states */
	state_owner_t *clientid_owner = NULL;
	/* Return from this function */
	nfsstat4 nfs_status = 0;
	/* Return from state functions */
	state_status_t state_status = 0;
	/* Layout state, forgotten about by caller */
	state_t *condemned_state = NULL;
	/* Tracking data for the layout state */
	struct state_refer refer;
	bool lock_held = false;

	memcpy(refer.session, data->session->session_id, sizeof(sessionid4));
	refer.sequence = data->sequence;
	refer.slot = data->slot;

	clientid_owner = &data->session->clientid_record->cid_owner;

	/* Retrieve state corresponding to supplied ID, inspect it
	 * and, if necessary, create a new layout state
	 */
	nfs_status = nfs4_Check_Stateid(supplied_stateid,
					data->current_obj,
					&supplied_state,
					data,
					STATEID_SPECIAL_CURRENT,
					0,
					false,
					tag);

	if (nfs_status != NFS4_OK) {
		/* The supplied stateid was invalid */
		return nfs_status;
	}

	if (supplied_state->state_type == STATE_TYPE_LAYOUT) {
		/* If the state supplied is a layout state, we can
		 * simply use it, return with the reference we just
		 * acquired.
		 */
		*layout_state = supplied_state;
		return nfs_status;
	} else if ((supplied_state->state_type == STATE_TYPE_SHARE)
		   || (supplied_state->state_type == STATE_TYPE_DELEG)
		   || (supplied_state->state_type == STATE_TYPE_LOCK)) {
		/* For share, delegation, and lock states, create a
		   new layout state. */
		union state_data layout_data;

		memset(&layout_data, 0, sizeof(layout_data));

		PTHREAD_RWLOCK_wrlock(
			&data->current_obj->state_hdl->state_lock);
		lock_held = true;

		/* See if a layout state already exists */
		state_status =
		    state_lookup_layout_state(data->current_obj,
					      clientid_owner,
					      layout_type,
					      &condemned_state);

		/* If it does, we assume that the client is using the
		 * forgetful model and has forgotten it had any
		 * layouts.  Free all layouts associated with the
		 * state and delete it.
		 */
		if (state_status == STATE_SUCCESS) {
			/* Flag indicating whether all layouts were returned
			 * and the state was deleted
			 */
			bool deleted = false;
			struct pnfs_segment entire = {
				.io_mode = LAYOUTIOMODE4_ANY,
				.offset = 0,
				.length = NFS4_UINT64_MAX
			};

			if (condemned_state->state_data.layout.granting) {
				nfs_status = NFS4ERR_DELAY;
				dec_state_t_ref(condemned_state);
				goto out;
			}

			nfs_status =
			     nfs4_return_one_state(data->current_obj,
						   0,
						   circumstance_forgotten,
						   condemned_state,
						   entire,
						   0,
						   NULL,
						   &deleted);

			dec_state_t_ref(condemned_state);

			if (nfs_status != NFS4_OK)
				goto out;

			if (!deleted) {
				nfs_status = NFS4ERR_SERVERFAULT;
				goto out;
			}

			condemned_state = NULL;
		}

		layout_data.layout.state_layout_type = layout_type;
		layout_data.layout.state_return_on_close = false;

		state_status = state_add_impl(data->current_obj,
					      STATE_TYPE_LAYOUT,
					      &layout_data,
					      clientid_owner,
					      layout_state,
					      &refer);

		if (state_status != STATE_SUCCESS) {
			nfs_status = nfs4_Errno_state(state_status);
			goto out;
		}

		glist_init(&(*layout_state)->state_data.layout.state_segments);
	} else {
Exemplo n.º 8
0
/**
 * @brief Get an NSM client
 *
 * @param[in] care        Care status
 * @param[in] xprt        RPC transport
 * @param[in] caller_name Caller name
 *
 * @return NSM client or NULL.
 */
state_nsm_client_t *get_nsm_client(care_t care, SVCXPRT *xprt,
				   char *caller_name)
{
	state_nsm_client_t key;
	state_nsm_client_t *pclient;
	char str[LOG_BUFF_LEN];
	struct display_buffer dspbuf = {sizeof(str), str, str};
	struct hash_latch latch;
	hash_error_t rc;
	struct gsh_buffdesc buffkey;
	struct gsh_buffdesc buffval;

	if (caller_name == NULL)
		return NULL;

	memset(&key, 0, sizeof(key));

	if (nfs_param.core_param.nsm_use_caller_name) {
		key.ssc_nlm_caller_name_len = strlen(caller_name);

		if (key.ssc_nlm_caller_name_len > LM_MAXSTRLEN)
			return NULL;

		key.ssc_nlm_caller_name = caller_name;
	} else if (op_ctx->client == NULL) {
		LogCrit(COMPONENT_STATE,
			"No gsh_client for caller_name %s", caller_name);

		return NULL;
	} else {
		key.ssc_nlm_caller_name = op_ctx->client->hostaddr_str;
		key.ssc_nlm_caller_name_len = strlen(key.ssc_nlm_caller_name);
		key.ssc_client = op_ctx->client;
	}

	if (isFullDebug(COMPONENT_STATE)) {
		display_nsm_client(&dspbuf, &key);
		LogFullDebug(COMPONENT_STATE, "Find {%s}", str);
	}

	buffkey.addr = &key;
	buffkey.len = sizeof(key);

	rc = hashtable_getlatch(ht_nsm_client, &buffkey, &buffval, true,
				&latch);

	/* If we found it, return it */
	if (rc == HASHTABLE_SUCCESS) {
		pclient = buffval.addr;

		/* Return the found NSM Client */
		if (isFullDebug(COMPONENT_STATE)) {
			display_nsm_client(&dspbuf, pclient);
			LogFullDebug(COMPONENT_STATE, "Found {%s}", str);
		}

		/* Increment refcount under hash latch.
		 * This prevents dec ref from removing this entry from hash
		 * if a race occurs.
		 */
		inc_nsm_client_ref(pclient);

		hashtable_releaselatched(ht_nsm_client, &latch);

		if (care == CARE_MONITOR && !nsm_monitor(pclient)) {
			dec_nsm_client_ref(pclient);
			pclient = NULL;
		}

		return pclient;
	}

	/* An error occurred, return NULL */
	if (rc != HASHTABLE_ERROR_NO_SUCH_KEY) {
		display_nsm_client(&dspbuf, &key);

		LogCrit(COMPONENT_STATE, "Error %s, could not find {%s}",
			hash_table_err_to_str(rc), str);

		return NULL;
	}

	/* Not found, but we don't care, return NULL */
	if (care == CARE_NOT) {
		/* Return the found NSM Client */
		if (isFullDebug(COMPONENT_STATE)) {
			display_nsm_client(&dspbuf, &key);
			LogFullDebug(COMPONENT_STATE, "Ignoring {%s}", str);
		}

		hashtable_releaselatched(ht_nsm_client, &latch);

		return NULL;
	}

	pclient = gsh_malloc(sizeof(*pclient));

	if (pclient == NULL) {
		display_nsm_client(&dspbuf, &key);
		LogCrit(COMPONENT_STATE, "No memory for {%s}", str);

		return NULL;
	}

	/* Copy everything over */
	memcpy(pclient, &key, sizeof(key));

	PTHREAD_MUTEX_init(&pclient->ssc_mutex, NULL);

	pclient->ssc_nlm_caller_name = gsh_strdup(key.ssc_nlm_caller_name);

	if (pclient->ssc_nlm_caller_name == NULL) {
		/* Discard the created client */
		PTHREAD_MUTEX_destroy(&pclient->ssc_mutex);
		free_nsm_client(pclient);
		return NULL;
	}

	glist_init(&pclient->ssc_lock_list);
	glist_init(&pclient->ssc_share_list);
	pclient->ssc_refcount = 1;

	if (op_ctx->client != NULL) {
		pclient->ssc_client = op_ctx->client;
		inc_gsh_client_refcount(op_ctx->client);
	}

	if (isFullDebug(COMPONENT_STATE)) {
		display_nsm_client(&dspbuf, pclient);
		LogFullDebug(COMPONENT_STATE, "New {%s}", str);
	}

	buffkey.addr = pclient;
	buffkey.len = sizeof(*pclient);
	buffval.addr = pclient;
	buffval.len = sizeof(*pclient);

	rc = hashtable_setlatched(ht_nsm_client, &buffval, &buffval, &latch,
				  false, NULL, NULL);

	/* An error occurred, return NULL */
	if (rc != HASHTABLE_SUCCESS) {
		display_nsm_client(&dspbuf, pclient);

		LogCrit(COMPONENT_STATE, "Error %s, inserting {%s}",
			hash_table_err_to_str(rc), str);

		PTHREAD_MUTEX_destroy(&pclient->ssc_mutex);
		free_nsm_client(pclient);

		return NULL;
	}

	if (care != CARE_MONITOR || nsm_monitor(pclient))
		return pclient;

	/* Failed to monitor, release client reference
	 * and almost certainly remove it from the hash table.
	 */
	dec_nsm_client_ref(pclient);

	return NULL;
}
Exemplo n.º 9
0
/**
 * @brief Initialize an NLM owner object
 *
 * @param[in] owner Stored owner
 */
static void init_nlm_owner(state_owner_t *owner)
{
	inc_nlm_client_ref(owner->so_owner.so_nlm_owner.so_client);

	glist_init(&owner->so_owner.so_nlm_owner.so_nlm_shares);
}
Exemplo n.º 10
0
/**
 * @brief adds a new state to a file
 *
 * This version of the function does not take the state lock on the
 * entry.  It exists to allow callers to integrate state into a larger
 * operation.
 *
 * The caller may have already allocated a state, in which case state
 * need not be NULL.
 *
 * @note state_lock MUST be held for write
 *
 * @param[in,out] obj         file to operate on
 * @param[in]     state_type  State to be defined
 * @param[in]     state_data  Data related to this state
 * @param[in]     owner_input Related open_owner
 * @param[in,out] state       The new state
 * @param[in]     refer       Reference to compound creating state
 *
 * @return Operation status
 */
state_status_t state_add_impl(struct fsal_obj_handle *obj,
			      enum state_type state_type,
			      union state_data *state_data,
			      state_owner_t *owner_input, state_t **state,
			      struct state_refer *refer)
{
	state_t *pnew_state = *state;
	struct state_hdl *ostate = obj->state_hdl;
	char str[DISPLAY_STATEID_OTHER_SIZE];
	struct display_buffer dspbuf = {sizeof(str), str, str};
	bool str_valid = false;
	bool got_export_ref = false;
	state_status_t status = 0;
	bool mutex_init = false;
	struct state_t *openstate = NULL;
	struct gsh_buffdesc fh_desc;

	if (isFullDebug(COMPONENT_STATE) && pnew_state != NULL) {
		display_stateid(&dspbuf, pnew_state);
		LogFullDebug(COMPONENT_STATE, "pnew_state=%s", str);
		display_reset_buffer(&dspbuf);
	}

	/* Attempt to get a reference to the export. */
	if (!export_ready(op_ctx->ctx_export)) {
		/* If we could not get a reference, return stale.
		 * Release attr_lock
		 */
		LogDebug(COMPONENT_STATE, "Stale export");
		status = STATE_ESTALE;
		goto errout;
	}

	get_gsh_export_ref(op_ctx->ctx_export);

	got_export_ref = true;

	if (pnew_state == NULL) {
		if (state_type == STATE_TYPE_LOCK)
			openstate = state_data->lock.openstate;

		pnew_state = op_ctx->fsal_export->exp_ops.alloc_state(
							op_ctx->fsal_export,
							state_type,
							openstate);
	}

	PTHREAD_MUTEX_init(&pnew_state->state_mutex, NULL);

	mutex_init = true;

	/* Add the stateid.other, this will increment cid_stateid_counter */
	nfs4_BuildStateId_Other(owner_input->so_owner.so_nfs4_owner.
				so_clientrec, pnew_state->stateid_other);

	/* Set the type and data for this state */
	memcpy(&(pnew_state->state_data), state_data, sizeof(*state_data));
	pnew_state->state_type = state_type;
	pnew_state->state_seqid = 0;	/* will be incremented to 1 later */
	pnew_state->state_refcount = 2; /* sentinel plus returned ref */

	if (refer)
		pnew_state->state_refer = *refer;

	if (isFullDebug(COMPONENT_STATE)) {
		display_stateid_other(&dspbuf, pnew_state->stateid_other);
		str_valid = true;

		LogFullDebug(COMPONENT_STATE,
			     "About to call nfs4_State_Set for %s",
			     str);
	}

	glist_init(&pnew_state->state_list);

	/* We need to initialize state_owner, state_export, and state_obj now so
	 * that the state can be indexed by owner/entry. We don't insert into
	 * lists and take references yet since no one else can see this state
	 * until we are completely done since we hold the state_lock.  Might as
	 * well grab export now also...
	 */
	pnew_state->state_export = op_ctx->ctx_export;
	pnew_state->state_owner = owner_input;
	fh_desc.addr = &pnew_state->state_obj.digest;
	fh_desc.len = sizeof(pnew_state->state_obj.digest);
	obj->obj_ops.handle_digest(obj, FSAL_DIGEST_NFSV4, &fh_desc);
	pnew_state->state_obj.len = fh_desc.len;

	/* Add the state to the related hashtable */
	if (!nfs4_State_Set(pnew_state)) {
		if (!str_valid)
			display_stateid_other(&dspbuf,
					      pnew_state->stateid_other);

		LogCrit(COMPONENT_STATE,
			"Can't create a new state id %s for the obj %p (F)",
			str, obj);

		/* Return STATE_MALLOC_ERROR since most likely the
		 * nfs4_State_Set failed to allocate memory.
		 */
		status = STATE_MALLOC_ERROR;
		goto errout;
	}

	/* Each of the following blocks takes the state_mutex and releases it
	 * because we always want state_mutex to be the last lock taken.
	 *
	 * NOTE: We don't have to worry about state_del/state_del_locked being
	 *       called in the midst of things because the state_lock is held.
	 */

	/* Attach this to an export */
	PTHREAD_RWLOCK_wrlock(&op_ctx->ctx_export->lock);
	PTHREAD_MUTEX_lock(&pnew_state->state_mutex);
	glist_add_tail(&op_ctx->ctx_export->exp_state_list,
		&pnew_state->state_export_list);
	PTHREAD_MUTEX_unlock(&pnew_state->state_mutex);
	PTHREAD_RWLOCK_unlock(&op_ctx->ctx_export->lock);

	/* Add state to list for file */
	PTHREAD_MUTEX_lock(&pnew_state->state_mutex);
	glist_add_tail(&ostate->file.list_of_states, &pnew_state->state_list);
	PTHREAD_MUTEX_unlock(&pnew_state->state_mutex);

	/* Add state to list for owner */
	PTHREAD_MUTEX_lock(&owner_input->so_mutex);
	PTHREAD_MUTEX_lock(&pnew_state->state_mutex);

	inc_state_owner_ref(owner_input);

	glist_add_tail(&owner_input->so_owner.so_nfs4_owner.so_state_list,
		       &pnew_state->state_owner_list);

	PTHREAD_MUTEX_unlock(&pnew_state->state_mutex);
	PTHREAD_MUTEX_unlock(&owner_input->so_mutex);


#ifdef DEBUG_SAL
	PTHREAD_MUTEX_lock(&all_state_v4_mutex);

	glist_add_tail(&state_v4_all, &pnew_state->state_list_all);

	PTHREAD_MUTEX_unlock(&all_state_v4_mutex);
#endif

	if (pnew_state->state_type == STATE_TYPE_DELEG &&
	    pnew_state->state_data.deleg.sd_type == OPEN_DELEGATE_WRITE)
		ostate->file.write_delegated = true;

	/* Copy the result */
	*state = pnew_state;

	if (str_valid)
		LogFullDebug(COMPONENT_STATE, "Add State: %p: %s",
			     pnew_state, str);

	/* Regular exit */
	status = STATE_SUCCESS;
	return status;

errout:

	if (mutex_init)
		PTHREAD_MUTEX_destroy(&pnew_state->state_mutex);

	if (pnew_state != NULL) {
		/* Make sure the new state is closed (may have been passed in
		 * with file open).
		 */
		(void) obj->obj_ops.close2(obj, pnew_state);

		pnew_state->state_exp->exp_ops.free_state(pnew_state);
	}

	if (got_export_ref)
		put_gsh_export(op_ctx->ctx_export);

	*state = NULL;

	return status;
}				/* state_add */
Exemplo n.º 11
0
void *_9p_socket_thread(void *Arg)
{
	long int tcp_sock = (long int)Arg;
	int rc = -1;
	struct pollfd fds[1];
	int fdcount = 1;
	static char my_name[MAXNAMLEN + 1];
	socklen_t addrpeerlen = 0;
	struct sockaddr_storage addrpeer;
	char strcaller[INET6_ADDRSTRLEN];
	request_data_t *req = NULL;
	int tag;
	unsigned long sequence = 0;
	unsigned int i = 0;
	char *_9pmsg = NULL;
	uint32_t msglen;

	struct _9p_conn _9p_conn;

	int readlen = 0;
	int total_readlen = 0;

	snprintf(my_name, MAXNAMLEN, "9p_sock_mgr#fd=%ld", tcp_sock);
	SetNameFunction(my_name);

	/* Init the struct _9p_conn structure */
	memset(&_9p_conn, 0, sizeof(_9p_conn));
	pthread_mutex_init(&_9p_conn.sock_lock, NULL);
	_9p_conn.trans_type = _9P_TCP;
	_9p_conn.trans_data.sockfd = tcp_sock;
	for (i = 0; i < FLUSH_BUCKETS; i++) {
		pthread_mutex_init(&_9p_conn.flush_buckets[i].lock, NULL);
		glist_init(&_9p_conn.flush_buckets[i].list);
	}
	atomic_store_uint32_t(&_9p_conn.refcount, 0);

	/* Init the fids pointers array */
	memset(&_9p_conn.fids, 0, _9P_FID_PER_CONN * sizeof(struct _9p_fid *));

	/* Set initial msize.
	 * Client may request a lower value during TVERSION */
	_9p_conn.msize = _9p_param._9p_tcp_msize;

	if (gettimeofday(&_9p_conn.birth, NULL) == -1)
		LogFatal(COMPONENT_9P, "Cannot get connection's time of birth");

	addrpeerlen = sizeof(addrpeer);
	rc = getpeername(tcp_sock, (struct sockaddr *)&addrpeer,
			 &addrpeerlen);
	if (rc == -1) {
		LogMajor(COMPONENT_9P,
			 "Cannot get peername to tcp socket for 9p, error %d (%s)",
			 errno, strerror(errno));
		/* XXX */
		strncpy(strcaller, "(unresolved)", INET6_ADDRSTRLEN);
		strcaller[12] = '\0';
	} else {
		switch (addrpeer.ss_family) {
		case AF_INET:
			inet_ntop(addrpeer.ss_family,
				  &((struct sockaddr_in *)&addrpeer)->
				  sin_addr, strcaller, INET6_ADDRSTRLEN);
			break;
		case AF_INET6:
			inet_ntop(addrpeer.ss_family,
				  &((struct sockaddr_in6 *)&addrpeer)->
				  sin6_addr, strcaller, INET6_ADDRSTRLEN);
			break;
		default:
			snprintf(strcaller, INET6_ADDRSTRLEN, "BAD ADDRESS");
			break;
		}

		LogEvent(COMPONENT_9P, "9p socket #%ld is connected to %s",
			 tcp_sock, strcaller);
		printf("9p socket #%ld is connected to %s\n", tcp_sock,
		       strcaller);
	}
	_9p_conn.client = get_gsh_client(&addrpeer, false);

	/* Set up the structure used by poll */
	memset((char *)fds, 0, sizeof(struct pollfd));
	fds[0].fd = tcp_sock;
	fds[0].events =
	    POLLIN | POLLPRI | POLLRDBAND | POLLRDNORM | POLLRDHUP | POLLHUP |
	    POLLERR | POLLNVAL;

	for (;;) {
		total_readlen = 0;  /* new message */
		rc = poll(fds, fdcount, -1);
		if (rc == -1) {
			/* timeout = -1 => Wait indefinitely for events */
			/* Interruption if not an issue */
			if (errno == EINTR)
				continue;

			LogCrit(COMPONENT_9P,
				"Got error %u (%s) on fd %ld connect to %s while polling on socket",
				errno, strerror(errno), tcp_sock, strcaller);
		}

		if (fds[0].revents & POLLNVAL) {
			LogEvent(COMPONENT_9P,
				 "Client %s on socket %lu produced POLLNVAL",
				 strcaller, tcp_sock);
			goto end;
		}

		if (fds[0].revents & (POLLERR | POLLHUP | POLLRDHUP)) {
			LogEvent(COMPONENT_9P,
				 "Client %s on socket %lu has shut down and closed",
				 strcaller, tcp_sock);
			goto end;
		}

		if (!(fds[0].revents & (POLLIN | POLLRDNORM)))
			continue;

		/* Prepare to read the message */
		_9pmsg = gsh_malloc(_9p_conn.msize);
		if (_9pmsg == NULL) {
			LogCrit(COMPONENT_9P,
				"Could not allocate 9pmsg buffer for client %s on socket %lu",
				strcaller, tcp_sock);
			goto end;
		}

		/* An incoming 9P request: the msg has a 4 bytes header
		   showing the size of the msg including the header */
		readlen = recv(fds[0].fd, _9pmsg,
			       _9P_HDR_SIZE, MSG_WAITALL);
		if (readlen != _9P_HDR_SIZE)
			goto badmsg;

		msglen = *(uint32_t *) _9pmsg;
		if (msglen > _9p_conn.msize) {
			LogCrit(COMPONENT_9P,
				"Message size too big! got %u, max = %u",
				msglen, _9p_conn.msize);
			goto end;
		}

		LogFullDebug(COMPONENT_9P,
			     "Received 9P/TCP message of size %u from client %s on socket %lu",
			     msglen, strcaller, tcp_sock);

		total_readlen += readlen;
		while (total_readlen < msglen) {
			readlen = recv(fds[0].fd,
				       _9pmsg + total_readlen,
				       msglen - total_readlen,
				       0);

			if (readlen > 0) {
				total_readlen += readlen;
				continue;
			}
			if (readlen == 0 ||
			    (readlen < 0 && errno != EINTR))
				goto badmsg;
		}	/* while */

		server_stats_transport_done(_9p_conn.client,
					    total_readlen, 1, 0,
					    0, 0, 0);

		/* Message is good. */
		req = pool_alloc(request_pool, NULL);

		req->rtype = _9P_REQUEST;
		req->r_u._9p._9pmsg = _9pmsg;
		req->r_u._9p.pconn = &_9p_conn;

		/* Add this request to the request list,
		 * should it be flushed later. */
		tag = *(u16 *) (_9pmsg + _9P_HDR_SIZE +
				_9P_TYPE_SIZE);
		_9p_AddFlushHook(&req->r_u._9p, tag,
				 sequence++);
		LogFullDebug(COMPONENT_9P,
			     "Request tag is %d\n", tag);

		/* Message was OK push it */
		DispatchWork9P(req);

		/* Not our buffer anymore */
		_9pmsg = NULL;
		continue;

badmsg:
		if (readlen == 0)
			LogEvent(COMPONENT_9P,
				 "Premature end for Client %s on socket %lu, total read = %u",
				 strcaller, tcp_sock, total_readlen);
		else if (readlen < 0) {
			LogEvent(COMPONENT_9P,
				 "Read error client %s on socket %lu errno=%d, total read = %u",
				 strcaller, tcp_sock,
				 errno, total_readlen);
		} else
			LogEvent(COMPONENT_9P,
				 "Header too small! for client %s on socket %lu: readlen=%u expected=%u",
				 strcaller, tcp_sock, readlen,
				 _9P_HDR_SIZE);

		/* Either way, we close the connection.
		 * It is not possible to survive
		 * once we get out of sync in the TCP stream
		 * with the client
		 */
		break; /* bail out */
	}			/* for( ;; ) */

end:
	LogEvent(COMPONENT_9P, "Closing connection on socket %lu", tcp_sock);
	close(tcp_sock);

	/* Free buffer if we encountered an error
	 * before we could give it to a worker */
	if (_9pmsg)
		gsh_free(_9pmsg);

	while (atomic_fetch_uint32_t(&_9p_conn.refcount)) {
		LogEvent(COMPONENT_9P, "Waiting for workers to release pconn");
		sleep(1);
	}

	_9p_cleanup_fids(&_9p_conn);

	if (_9p_conn.client != NULL)
		put_gsh_client(_9p_conn.client);

	pthread_exit(NULL);
}				/* _9p_socket_thread */
Exemplo n.º 12
0
int nfs4_op_exchange_id(struct nfs_argop4 *op, compound_data_t *data,
			struct nfs_resop4 *resp)
{
	nfs_client_record_t *client_record;
	nfs_client_id_t *conf;
	nfs_client_id_t *unconf;
	int rc;
	int len;
	char *temp;
	bool update;
	EXCHANGE_ID4args * const arg_EXCHANGE_ID4 =
	    &op->nfs_argop4_u.opexchange_id;
	EXCHANGE_ID4res * const res_EXCHANGE_ID4 =
	    &resp->nfs_resop4_u.opexchange_id;
	EXCHANGE_ID4resok * const res_EXCHANGE_ID4_ok =
	    (&resp->nfs_resop4_u.opexchange_id.EXCHANGE_ID4res_u.eir_resok4);
	uint32_t pnfs_flags;
	in_addr_t server_addr = 0;

	resp->resop = NFS4_OP_EXCHANGE_ID;

	if (data->minorversion == 0)
		return res_EXCHANGE_ID4->eir_status = NFS4ERR_INVAL;

	if ((arg_EXCHANGE_ID4->
	     eia_flags & ~(EXCHGID4_FLAG_SUPP_MOVED_REFER |
			   EXCHGID4_FLAG_SUPP_MOVED_MIGR |
			   EXCHGID4_FLAG_BIND_PRINC_STATEID |
			   EXCHGID4_FLAG_USE_NON_PNFS |
			   EXCHGID4_FLAG_USE_PNFS_MDS |
			   EXCHGID4_FLAG_USE_PNFS_DS |
			   EXCHGID4_FLAG_UPD_CONFIRMED_REC_A |
			   EXCHGID4_FLAG_CONFIRMED_R)) != 0)
		return res_EXCHANGE_ID4->eir_status = NFS4ERR_INVAL;

	/* If client did not ask for pNFS related server roles than just set
	   server roles */
	pnfs_flags = arg_EXCHANGE_ID4->eia_flags & EXCHGID4_FLAG_MASK_PNFS;
	if (pnfs_flags == 0) {
		if (nfs_param.nfsv4_param.pnfs_mds)
			pnfs_flags |= EXCHGID4_FLAG_USE_PNFS_MDS;
		if (nfs_param.nfsv4_param.pnfs_ds)
			pnfs_flags |= EXCHGID4_FLAG_USE_PNFS_DS;
		if (pnfs_flags == 0)
			pnfs_flags |= EXCHGID4_FLAG_USE_NON_PNFS;
	}
	/* If client did ask for pNFS related server roles than try to match the
	   server roles to the client request. */
	else {
		if ((arg_EXCHANGE_ID4->eia_flags & EXCHGID4_FLAG_USE_PNFS_MDS)
		    && (nfs_param.nfsv4_param.pnfs_mds))
			pnfs_flags |= EXCHGID4_FLAG_USE_PNFS_MDS;
		if ((arg_EXCHANGE_ID4->eia_flags & EXCHGID4_FLAG_USE_PNFS_DS)
		    && (nfs_param.nfsv4_param.pnfs_ds))
			pnfs_flags |= EXCHGID4_FLAG_USE_PNFS_DS;
		if (pnfs_flags == 0)
			pnfs_flags |= EXCHGID4_FLAG_USE_NON_PNFS;
	}
	LogDebug(COMPONENT_CLIENTID,
		"EXCHANGE_ID pnfs_flags 0x%08x eia_flags 0x%08x",
		 pnfs_flags, arg_EXCHANGE_ID4->eia_flags);

	update = (arg_EXCHANGE_ID4->eia_flags &
		  EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) != 0;

	server_addr = get_raddr(data->req->rq_xprt);

	/* Do we already have one or more records for client id (x)? */
	client_record =
	    get_client_record(arg_EXCHANGE_ID4->eia_clientowner.co_ownerid.
			      co_ownerid_val,
			      arg_EXCHANGE_ID4->eia_clientowner.co_ownerid.
			      co_ownerid_len,
			      pnfs_flags,
			      server_addr);

	if (client_record == NULL) {
		/* Some major failure */
		LogCrit(COMPONENT_CLIENTID, "EXCHANGE_ID failed");
		res_EXCHANGE_ID4->eir_status = NFS4ERR_SERVERFAULT;
		return res_EXCHANGE_ID4->eir_status;
	}

	/*
	 * The following checks are based on RFC5661
	 *
	 * This attempts to implement the logic described in
	 * 18.35.4. IMPLEMENTATION
	 */

	PTHREAD_MUTEX_lock(&client_record->cr_mutex);

	conf = client_record->cr_confirmed_rec;

	if (conf != NULL) {
		/* Need a reference to the confirmed record for below */
		inc_client_id_ref(conf);
	}

	if (conf != NULL && !update) {
		/* EXCHGID4_FLAG_UPD_CONFIRMED_REC_A not set
		 *
		 * Compare the client credentials, but don't compare
		 * the client address.  Doing so interferes with
		 * trunking and the ability of a client to reconnect
		 * after being assigned a new address.
		 */
		if (!nfs_compare_clientcred(&conf->cid_credential,
					    &data->credential)) {
			PTHREAD_MUTEX_lock(&conf->cid_mutex);
			if (!valid_lease(conf) || !client_id_has_state(conf)) {
				PTHREAD_MUTEX_unlock(&conf->cid_mutex);

				/* CASE 3, client collisions, old
				 * clientid is expired
				 *
				 * Expire clientid and release our reference.
				 */
				nfs_client_id_expire(conf, false);
				dec_client_id_ref(conf);
				conf = NULL;
			} else {
				PTHREAD_MUTEX_unlock(&conf->cid_mutex);
				/* CASE 3, client collisions, old
				 * clientid is not expired
				 */

				res_EXCHANGE_ID4->eir_status =
				    NFS4ERR_CLID_INUSE;

				/* Release our reference to the
				 * confirmed clientid.
				 */
				dec_client_id_ref(conf);
				goto out;
			}
		} else if (memcmp(arg_EXCHANGE_ID4->eia_clientowner.co_verifier,
				  conf->cid_incoming_verifier,
				  NFS4_VERIFIER_SIZE) == 0) {
			/* CASE 2, Non-Update on Existing Client ID
			 *
			 * Return what was last returned without
			 * changing any refcounts
			 */

			unconf = conf;
			res_EXCHANGE_ID4_ok->eir_flags |=
			    EXCHGID4_FLAG_CONFIRMED_R;
			goto return_ok;
		} else {
			/* CASE 5, client restart */
			/** @todo FSF: expire old clientid? */
		}
	} else if (conf != NULL) {
		/* EXCHGID4_FLAG_UPD_CONFIRMED_REC_A set */
		if (memcmp(arg_EXCHANGE_ID4->eia_clientowner.co_verifier,
			   conf->cid_incoming_verifier,
			   NFS4_VERIFIER_SIZE) == 0) {
			if (!nfs_compare_clientcred(&conf->cid_credential,
						    &data->credential)
			    || op_ctx->client == NULL
			    || conf->gsh_client == NULL
			    || op_ctx->client != conf->gsh_client) {
				/* CASE 9, Update but wrong principal */
				res_EXCHANGE_ID4->eir_status = NFS4ERR_PERM;
			} else {
				/* CASE 6, Update */
				/** @todo: this is not implemented,
				    the things it updates aren't even
				    tracked */
				LogMajor(COMPONENT_CLIENTID,
					 "EXCHANGE_ID Update not supported");
				res_EXCHANGE_ID4->eir_status = NFS4ERR_NOTSUPP;
			}
		} else {
			/* CASE 8, Update but wrong verifier */
			res_EXCHANGE_ID4->eir_status = NFS4ERR_NOT_SAME;
		}

		/* Release our reference to the confirmed clientid. */
		dec_client_id_ref(conf);

		goto out;
	} else if (conf == NULL && update) {
		res_EXCHANGE_ID4->eir_status = NFS4ERR_NOENT;
		goto out;
	}

	/* At this point, no matter what the case was above, we should
	 * remove any pre-existing unconfirmed record.
	 */

	unconf = client_record->cr_unconfirmed_rec;

	if (unconf != NULL) {
		/* CASE 4, replacement of unconfirmed record
		 *
		 * Delete the unconfirmed clientid record
		 * unhash the clientid record
		 */
		remove_unconfirmed_client_id(unconf);
	}

	/* Now we can proceed to build the new unconfirmed record. We
	 * have determined the clientid and setclientid_confirm values
	 * above.
	 */

	unconf = create_client_id(0,
				  client_record,
				  &data->credential,
				  data->minorversion);

	if (unconf == NULL) {
		/* Error already logged, return */
		res_EXCHANGE_ID4->eir_status = NFS4ERR_RESOURCE;
		goto out;
	}

	unconf->cid_create_session_sequence = 1;

	glist_init(&unconf->cid_cb.v41.cb_session_list);

	memcpy(unconf->cid_incoming_verifier,
	       arg_EXCHANGE_ID4->eia_clientowner.co_verifier,
	       NFS4_VERIFIER_SIZE);

	if (gethostname(unconf->cid_server_owner,
			sizeof(unconf->cid_server_owner)) == -1) {
		/* Free the clientid record and return */
		free_client_id(unconf);
		res_EXCHANGE_ID4->eir_status = NFS4ERR_SERVERFAULT;
		goto out;
	}

	snprintf(unconf->cid_server_scope,
		 sizeof(unconf->cid_server_scope),
		 "%s_NFS-Ganesha",
		 unconf->cid_server_owner);

	LogDebug(COMPONENT_CLIENTID, "Serving IP %s", unconf->cid_server_scope);

	rc = nfs_client_id_insert(unconf);

	if (rc != CLIENT_ID_SUCCESS) {
		/* Record is already freed, return. */
		res_EXCHANGE_ID4->eir_status = clientid_error_to_nfsstat(rc);

		goto out;
	}

 return_ok:

	/* Build the reply */
	res_EXCHANGE_ID4_ok->eir_clientid = unconf->cid_clientid;
	res_EXCHANGE_ID4_ok->eir_sequenceid =
	    unconf->cid_create_session_sequence;

	res_EXCHANGE_ID4_ok->eir_flags |= client_record->cr_pnfs_flags;
	res_EXCHANGE_ID4_ok->eir_flags |= EXCHGID4_FLAG_SUPP_MOVED_REFER;

	res_EXCHANGE_ID4_ok->eir_state_protect.spr_how = SP4_NONE;

	len = strlen(unconf->cid_server_owner);
	temp = gsh_malloc(len);

	if (temp == NULL) {
		/** @todo FSF: not the best way to handle this but
		    keeps from crashing */
		len = 0;
	} else
		memcpy(temp, unconf->cid_server_owner, len);

	res_EXCHANGE_ID4_ok->eir_server_owner.so_major_id.so_major_id_len = len;
	res_EXCHANGE_ID4_ok->eir_server_owner.so_major_id.so_major_id_val =
	    temp;

	res_EXCHANGE_ID4_ok->eir_server_owner.so_minor_id = 0;

	len = strlen(unconf->cid_server_scope);
	temp = gsh_malloc(len);
	if (temp == NULL) {
		/** @todo FSF: not the best way to handle this but
		    keeps from crashing */
		len = 0;
	} else
		memcpy(temp, unconf->cid_server_scope, len);

	res_EXCHANGE_ID4_ok->eir_server_scope.eir_server_scope_len = len;
	res_EXCHANGE_ID4_ok->eir_server_scope.eir_server_scope_val = temp;

	res_EXCHANGE_ID4_ok->eir_server_impl_id.eir_server_impl_id_len = 0;
	res_EXCHANGE_ID4_ok->eir_server_impl_id.eir_server_impl_id_val = NULL;

	res_EXCHANGE_ID4->eir_status = NFS4_OK;

 out:

	PTHREAD_MUTEX_unlock(&client_record->cr_mutex);

	/* Release our reference to the client record */
	dec_client_record_ref(client_record);

	return res_EXCHANGE_ID4->eir_status;
}
Exemplo n.º 13
0
int main(int argc, char **argv)
{
	GError     *error = NULL;
	GtkBuilder *builder;

#if defined(_WIN32) && defined(GFT_USE_MANIFEST)
	{
		INITCOMMONCONTROLSEX tim;
		memset(&tim, 0, sizeof tim);
		tim.dwSize = sizeof tim;
		tim.dwICC = ICC_ANIMATE_CLASS | ICC_BAR_CLASSES | ICC_COOL_CLASSES |
								ICC_DATE_CLASSES | ICC_HOTKEY_CLASS | ICC_INTERNET_CLASSES |
								ICC_LISTVIEW_CLASSES | ICC_NATIVEFNTCTL_CLASS |
								ICC_PAGESCROLLER_CLASS | ICC_PROGRESS_CLASS |
								ICC_TAB_CLASSES | ICC_TREEVIEW_CLASSES |
								ICC_UPDOWN_CLASS | ICC_USEREX_CLASSES | ICC_STANDARD_CLASSES;

		if(InitCommonControlsEx(&tim) == FALSE)
			fputs("warning: InitCommomControlsEx() failed\n", stderr);
	}
#endif

#ifndef _WIN32
	if(signal(SIGCHLD, SIG_IGN) == SIG_ERR)
		perror("signal(SIGCHLD)");
#endif

	ft_zero(&ft);
	ft_async(&ft) = 1;
	gtk_init(&argc, &argv); /* bail here if !$DISPLAY */

#ifdef _WIN32
	{
		int debug = 0;

		if(argc == 2){
			if(!strcmp(argv[1], "-d")){
				debug = 1;
				fprintf(stderr, "%s: debug on\n",
						*argv);
			}else{
usage:
				fprintf(stderr, "Usage: %s [-d]\n",
						*argv);
				return 1;
			}
		}else if(argc != 1)
			goto usage;

		if(!debug){
			fputs("gft: debug off\n", stderr);
			FreeConsole();
		}
	}
#else
	if(argc != 1){
		fprintf(stderr, "Usage: %s\n", *argv);
		return 1;
	}
#endif

	builder = gtk_builder_new();

	if(gladegen_init())
		return 1;

	if(!gtk_builder_add_from_file(builder, GLADE_XML_FILE, &error)){
		g_warning("%s", error->message);
		/*g_free(error);*/
		return 1;
	}
	gladegen_term();

	if(getobjects(builder))
		return 1;

	gtk_builder_connect_signals(builder, NULL);

	glist_init(&listTransfers, treeTransfers);

	/* don't need it anymore */
	g_object_unref(G_OBJECT(builder));

	/* signal setup */
	g_signal_connect(G_OBJECT(winMain), "delete-event" ,       G_CALLBACK(on_winMain_delete_event),    NULL);
	g_signal_connect(G_OBJECT(winMain), "destroy",             G_CALLBACK(on_winMain_destroy),         NULL);

	cfg_read(cboHost);
	tray_init(winMain, *argv);
	transfers_init(&listDone, treeDone);

	gtk_widget_set_sensitive(btnSend, FALSE);
	drag_init();

	cmds();
	gtk_widget_show_all(winMain);
	gtk_main();

	tray_term();

	return 0;
}