Пример #1
0
static int unload_fsal(struct fsal_module *fsal_hdl)
{
	int retval = EBUSY;	/* someone still has a reference */

	pthread_mutex_lock(&fsal_lock);
	pthread_mutex_lock(&fsal_hdl->lock);
	if (fsal_hdl->refs != 0 || !glist_empty(&fsal_hdl->exports))
		goto err;
	if (fsal_hdl->dl_handle == NULL) {
		retval = EACCES;	/* cannot unload static linked fsals */
		goto err;
	}
	glist_del(&fsal_hdl->fsals);
	pthread_mutex_unlock(&fsal_hdl->lock);
	pthread_mutex_destroy(&fsal_hdl->lock);
	fsal_hdl->refs = 0;

	retval = dlclose(fsal_hdl->dl_handle);
	pthread_mutex_unlock(&fsal_lock);
	return retval;

 err:
	pthread_mutex_unlock(&fsal_hdl->lock);
	pthread_mutex_unlock(&fsal_lock);
	return retval;
}
Пример #2
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 */
int nfs4_op_release_lockowner(struct nfs_argop4 * op,
                              compound_data_t   * data,
                              struct nfs_resop4 * resp)
{
  nfs_client_id_t         * pnfs_client_id;
  state_owner_t           * plock_owner;
  state_nfs4_owner_name_t   owner_name;
  int                       rc;

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

  resp->resop = NFS4_OP_RELEASE_LOCKOWNER;
  res_RELEASE_LOCKOWNER4.status = NFS4_OK;

  /* Check clientid */
  rc = nfs_client_id_get_confirmed(arg_RELEASE_LOCKOWNER4.lock_owner.clientid,
                                   &pnfs_client_id);

  if(rc != CLIENT_ID_SUCCESS)
    {
      res_RELEASE_LOCKOWNER4.status = clientid_error_to_nfsstat(rc);
      goto out2;
    }

  P(pnfs_client_id->cid_mutex);

  if(!reserve_lease(pnfs_client_id))
    {
      V(pnfs_client_id->cid_mutex);

      dec_client_id_ref(pnfs_client_id);

      res_RELEASE_LOCKOWNER4.status = NFS4ERR_EXPIRED;
      goto out2;
    }

  V(pnfs_client_id->cid_mutex);

  /* look up the lock owner and see if we can find it */
  convert_nfs4_lock_owner(&arg_RELEASE_LOCKOWNER4.lock_owner, &owner_name);

  /* If this open owner is not known yet, allocated and set up a new one */
  plock_owner = create_nfs4_owner(&owner_name,
                                  pnfs_client_id,
                                  STATE_OPEN_OWNER_NFSV4,
                                  NULL,
                                  0,
                                  NULL,
                                  CARE_NOT);

  if(plock_owner == NULL)
    {
      /* the owner doesn't exist, we are done */
      LogDebug(COMPONENT_NFS_V4_LOCK,
               "lock owner does not exist");
      res_RELEASE_LOCKOWNER4.status = NFS4_OK;
      goto out1;
    }

  P(plock_owner->so_mutex);

  /* got the owner, does it still have any locks being held */
  if(!glist_empty(&plock_owner->so_lock_list))
    {
      V(plock_owner->so_mutex);

      res_RELEASE_LOCKOWNER4.status = NFS4ERR_LOCKS_HELD;
    }
  else
    {
      V(plock_owner->so_mutex);

      /* found the lock owner and it doesn't have any locks, release it */
      release_lockstate(plock_owner);

      res_RELEASE_LOCKOWNER4.status = NFS4_OK;
    }

  /* Release the reference to the lock owner acquired via create_nfs4_owner */
  dec_state_owner_ref(plock_owner);

 out1:

  /* Update the lease before exit */
  P(pnfs_client_id->cid_mutex);

  update_lease(pnfs_client_id);

  V(pnfs_client_id->cid_mutex);

  dec_client_id_ref(pnfs_client_id);

 out2:

  LogDebug(COMPONENT_NFS_V4_LOCK,
           "Leaving NFS v4 RELEASE_LOCKOWNER handler -----------------------------------------------------");

  return res_RELEASE_LOCKOWNER4.status;
}                               /* nfs4_op_release_lock_owner */
Пример #4
0
/* This thread processes FSAL UP events. */
void *fsal_up_process_thread(void *UnUsedArg)
{
  struct timeval             now;
  struct timespec            timeout;
  fsal_up_event_t          * fupevent;
  int                        rc;

  SetNameFunction("fsal_up_process_thread");

  if (mark_thread_existing(&fsal_up_process_tcb) == PAUSE_EXIT)
    {
      /* Oops, that didn't last long... exit. */
      mark_thread_done(&fsal_up_process_tcb);
      LogDebug(COMPONENT_INIT,
               "FSAL_UP Process Thread: Exiting before initialization");
      return NULL;
    }

  LogFullDebug(COMPONENT_INIT,
               "FSAL_UP Process Thread: my pthread id is %p",
               (caddr_t) pthread_self());

  while(1)
    {
      /* Check without tcb lock*/
      if ((fsal_up_process_tcb.tcb_state != STATE_AWAKE) ||
          glist_empty(&fsal_up_process_queue))
        {
          while(1)
            {
              P(fsal_up_process_tcb.tcb_mutex);
              if ((fsal_up_process_tcb.tcb_state == STATE_AWAKE) &&
                  !glist_empty(&fsal_up_process_queue))
                {
                  V(fsal_up_process_tcb.tcb_mutex);
                  break;
                }
              switch(thread_sm_locked(&fsal_up_process_tcb))
                {
                  case THREAD_SM_RECHECK:
                  V(fsal_up_process_tcb.tcb_mutex);
                  continue;

                  case THREAD_SM_BREAK:
                  if (glist_empty(&fsal_up_process_queue))
                    {
                      gettimeofday(&now, NULL);
                      timeout.tv_sec = 10 + now.tv_sec;
                      timeout.tv_nsec = 0;
                      rc = pthread_cond_timedwait(&fsal_up_process_tcb.tcb_condvar,
                                                  &fsal_up_process_tcb.tcb_mutex,
                                                  &timeout);
                    }
                  V(fsal_up_process_tcb.tcb_mutex);
                  continue;

                  case THREAD_SM_EXIT:
                  V(fsal_up_process_tcb.tcb_mutex);
                  return NULL;
                }
             }
          }
        P(fsal_up_process_tcb.tcb_mutex);
        fupevent = glist_first_entry(&fsal_up_process_queue,
                                     fsal_up_event_t,
                                     event_list);
        if(fupevent != NULL)
          {
            /* Pull the event off of the list */
            glist_del(&fupevent->event_list);

            /* Release the mutex */
            V(fsal_up_process_tcb.tcb_mutex);
            fupevent->event_process_func(&fupevent->event_data);
            gsh_free(fupevent->event_data.event_context.fsal_data.fh_desc.start);
            pool_free(fsal_up_event_pool, fupevent);

            continue;
          }
        V(fsal_up_process_tcb.tcb_mutex);
    }
  tcb_remove(&fsal_up_process_tcb);
}
Пример #5
0
int nfs4_op_destroy_clientid(struct nfs_argop4 *op, compound_data_t *data,
			     struct nfs_resop4 *resp)
{
	DESTROY_CLIENTID4args * const arg_DESTROY_CLIENTID4 =
	    &op->nfs_argop4_u.opdestroy_clientid;
	DESTROY_CLIENTID4res * const res_DESTROY_CLIENTID4 =
	    &resp->nfs_resop4_u.opdestroy_clientid;
	nfs_client_record_t *client_record = NULL;
	nfs_client_id_t *conf = NULL, *unconf = NULL, *found = NULL;
	clientid4 clientid;
	int rc;

	resp->resop = NFS4_OP_DESTROY_CLIENTID;

	clientid = arg_DESTROY_CLIENTID4->dca_clientid;

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

		display_clientid(&dspbuf, clientid);

		LogDebug(COMPONENT_CLIENTID,
			 "DESTROY_CLIENTID clientid=%s",
			 str);
	}

	res_DESTROY_CLIENTID4->dcr_status = NFS4_OK;

	/* First try to look up confirmed record */
	rc = nfs_client_id_get_confirmed(clientid, &conf);

	if (rc == CLIENT_ID_SUCCESS) {
		client_record = conf->cid_client_record;
		found = conf;
	} else {
		/* fall back to unconfirmed */
		rc = nfs_client_id_get_unconfirmed(clientid, &unconf);

		if (rc == CLIENT_ID_SUCCESS) {
			client_record = unconf->cid_client_record;
			found = unconf;
		}

		/* handle the perverse case of a clientid being confirmed
		 * in the above interval */
		rc = nfs_client_id_get_confirmed(clientid, &conf);

		if (rc == CLIENT_ID_SUCCESS) {
			if (found != NULL)
				dec_client_id_ref(found);
			client_record = conf->cid_client_record;
			found = conf;
		}
	}

	/* ref +1 */
	if (client_record == NULL) {
		/* Fine.  We're done. */
		res_DESTROY_CLIENTID4->dcr_status = NFS4ERR_STALE_CLIENTID;
		goto out;
	}

	(void) inc_client_record_ref(client_record);

	PTHREAD_MUTEX_lock(&client_record->cr_mutex);

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

		display_client_record(&dspbuf, client_record);

		LogFullDebug(COMPONENT_CLIENTID,
			     "Client Record %s cr_confirmed_rec=%p "
			     "cr_unconfirmed_rec=%p", str,
			     client_record->cr_confirmed_rec,
			     client_record->cr_unconfirmed_rec);
	}

	/* per Frank, we must check the confirmed and unconfirmed
	 * state of client_record again now that we hold cr_mutex
	 */
	conf = client_record->cr_confirmed_rec;
	unconf = client_record->cr_unconfirmed_rec;

	if ((!conf) && (!unconf)) {
		/* We raced a thread destroying clientid, and lost.
		 * We're done. */
		goto cleanup;
	}

	if (conf) {
		/* We MUST NOT destroy a clientid that has nfsv41 sessions or
		 * state. Since the minorversion is 4.1 or higher, this is
		 * equivalent to a session check.
		 */
		PTHREAD_MUTEX_lock(&conf->cid_mutex);
		if (!glist_empty(&conf->cid_cb.v41.cb_session_list)) {
			res_DESTROY_CLIENTID4->dcr_status =
							NFS4ERR_CLIENTID_BUSY;
			PTHREAD_MUTEX_unlock(&conf->cid_mutex);
			goto cleanup;
		}
		PTHREAD_MUTEX_unlock(&conf->cid_mutex);

		/* Delete the confirmed clientid record. Because we
		 * have the cr_mutex, we have won any race to deal
		 * with this clientid record.
		 */
		if (isFullDebug(COMPONENT_CLIENTID)) {
			char str[LOG_BUFF_LEN];
			struct display_buffer dspbuf = {sizeof(str), str, str};

			display_client_id_rec(&dspbuf, conf);

			LogDebug(COMPONENT_CLIENTID,
				 "Removing confirmed clientid %s", str);
		}

		/* unhash the clientid record */
		(void)remove_confirmed_client_id(conf);
	}

	if (unconf) {
		/* Delete the unconfirmed clientid record. Because we
		 * have the cr_mutex, we have won any race to deal
		 * with this clientid record.
		 */
		if (isFullDebug(COMPONENT_CLIENTID)) {
			char str[LOG_BUFF_LEN];
			struct display_buffer dspbuf = {sizeof(str), str, str};

			display_client_id_rec(&dspbuf, unconf);

			LogDebug(COMPONENT_CLIENTID,
				 "Removing unconfirmed clientid %s", str);
		}

		/* unhash the clientid record */
		(void)remove_unconfirmed_client_id(unconf);
	}

 cleanup:

	PTHREAD_MUTEX_unlock(&client_record->cr_mutex);
	dec_client_record_ref(client_record);	/* ref +0 */

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

 out:

	return res_DESTROY_CLIENTID4->dcr_status;
}
Пример #6
0
/**
 * @brief Check and look up the supplied stateid
 *
 * This function yields the state for the stateid if it is valid.
 *
 * @param[in]  stateid     Stateid to look up
 * @param[in]  entry       Associated file (if any)
 * @param[out] state       Found state
 * @param[in]  data        Compound data
 * @param[in]  flags       Flags governing special stateids
 * @param[in]  owner_seqid seqid on v4.0 owner
 * @param[in]  check_seqid Whether to validate owner_seqid
 * @param[in]  tag     Arbitrary string for logging/debugging
 *
 * @return NFSv4 status codes
 */
nfsstat4 nfs4_Check_Stateid(stateid4 *stateid, cache_entry_t *entry,
			    state_t **state, compound_data_t *data, int flags,
			    seqid4 owner_seqid, bool check_seqid,
			    const char *tag)
{
	uint32_t epoch = 0;
	uint64_t epoch_low = ServerEpoch & 0xFFFFFFFF;
	state_t *state2 = NULL;

	/* string str has to accomodate stateid->other(OTHERSIZE * 2 ),
	 * stateid->seqid(max 10 bytes),
	 * a colon (:) and a terminating null character.
	 */
	char str[OTHERSIZE * 2 + 10 + 2];
	int32_t diff;
	clientid4 clientid;
	nfs_client_id_t *pclientid;
	int rc;
	nfsstat4 status;

	if (isDebug(COMPONENT_STATE)) {
		sprint_mem(str, (char *)stateid->other, OTHERSIZE);
		sprintf(str + OTHERSIZE * 2, ":%u",
			(unsigned int)stateid->seqid);
	}

	LogFullDebug(COMPONENT_STATE, "Check %s stateid flags%s%s%s%s%s%s%s",
		     tag, flags & STATEID_SPECIAL_ALL_0 ? " ALL_0" : "",
		     flags & STATEID_SPECIAL_ALL_1 ? " ALL_1" : "",
		     flags & STATEID_SPECIAL_CURRENT ? " CURRENT" : "",
		     flags & STATEID_SPECIAL_CLOSE_40 ? " CLOSE_40" : "",
		     flags & STATEID_SPECIAL_CLOSE_41 ? " CLOSE_41" : "",
		     flags & STATEID_SPECIAL_FREE ? " FREE" : "",
		     flags == 0 ? " NONE" : "");

	/* Test for OTHER is all zeros */
	if (memcmp(stateid->other, all_zero, OTHERSIZE) == 0) {
		if (stateid->seqid == 0 &&
		    (flags & STATEID_SPECIAL_ALL_0) != 0) {
			/* All 0 stateid */
			LogDebug(COMPONENT_STATE,
				 "Check %s stateid found special all 0 stateid",
				 tag);

			/** @todo FSF: eventually this may want to return an
			 * actual state for use in temporary locks for I/O.
			 */
			data->current_stateid_valid = false;
			goto success;
		}
		if (stateid->seqid == 1
		    && (flags & STATEID_SPECIAL_CURRENT) != 0) {
			/* Special current stateid */
			LogDebug(COMPONENT_STATE,
				 "Check %s stateid found special 'current' stateid",
				 tag);
			if (!data->current_stateid_valid) {
				LogDebug(COMPONENT_STATE,
					 "Check %s stateid STATEID_SPECIAL_CURRENT - current stateid is bad",
					 tag);
				status = NFS4ERR_BAD_STATEID;
				goto failure;
			}

			/* Copy current stateid in and proceed to checks */
			*stateid = data->current_stateid;
			goto check_it;
		}

		LogDebug(COMPONENT_STATE,
			 "Check %s stateid with OTHER all zeros, seqid %u unexpected",
			 tag, (unsigned int)stateid->seqid);
		status = NFS4ERR_BAD_STATEID;
		goto failure;
	}

	/* Test for OTHER is all ones */
	if (memcmp(stateid->other, all_ones, OTHERSIZE) == 0) {
		/* Test for special all ones stateid */
		if (stateid->seqid == seqid_all_one &&
		    (flags & STATEID_SPECIAL_ALL_1) != 0) {
			/* All 1 stateid */
			LogDebug(COMPONENT_STATE,
				 "Check %s stateid found special all 1 stateid",
				 tag);

			/** @todo FSF: eventually this may want to return an
			 * actual state for use in temporary locks for I/O.
			 */
			data->current_stateid_valid = false;
			goto success;
		}

		LogDebug(COMPONENT_STATE,
			 "Check %s stateid with OTHER all ones, seqid %u unexpected",
			 tag, (unsigned int)stateid->seqid);
		status = NFS4ERR_BAD_STATEID;
		goto failure;
	}

 check_it:

	/* Extract the clientid from the stateid other field */
	memcpy(&clientid, stateid->other, sizeof(clientid));

	/* Extract the epoch from the clientid */
	epoch = clientid >> (clientid4) 32;

	/* Check if stateid was made from this server instance */
	if (epoch != epoch_low) {
		LogDebug(COMPONENT_STATE,
			 "Check %s stateid found stale stateid %s", tag, str);
		status = NFS4ERR_STALE_STATEID;
		goto failure;
	}

	/* Try to get the related state */
	if (!nfs4_State_Get_Pointer(stateid->other, &state2)) {
		/* We matched this server's epoch, but could not find the
		 * stateid. Chances are, the client was expired and the state
		 * has all been freed.
		 *
		 * We could use another check here for a BAD stateid
		 */
		LogDebug(COMPONENT_STATE,
			 "Check %s stateid could not find state %s", tag, str);

		/* Try and find the clientid */
		rc = nfs_client_id_get_confirmed(clientid, &pclientid);

		if (rc != CLIENT_ID_SUCCESS) {
			/* Unknown client id (or other problem),
			 * return that result.
			 */
			status = clientid_error_to_nfsstat(rc);
			goto failure;
		}

		if ((flags & (STATEID_SPECIAL_CLOSE_40 |
			      STATEID_SPECIAL_CLOSE_41)) != 0) {
			/* This is a close with a valid clientid, but invalid
			 * stateid counter. We will assume this is a replayed
			 * close.
			 */
			if (data->preserved_clientid != NULL) {
				/* We don't expect this, but, just in case...
				 * Update and release already reserved lease.
				 */
				pthread_mutex_lock(&data->preserved_clientid
						   ->cid_mutex);
				update_lease(data->preserved_clientid);
				pthread_mutex_unlock(&data->preserved_clientid
						     ->cid_mutex);
				data->preserved_clientid = NULL;
			}

			/* Check if lease is expired and reserve it */
			pthread_mutex_lock(&pclientid->cid_mutex);

			if (!reserve_lease(pclientid)) {
				LogDebug(COMPONENT_STATE,
					 "Returning NFS4ERR_EXPIRED");
				pthread_mutex_unlock(&pclientid->cid_mutex);
				status = NFS4ERR_EXPIRED;
				goto failure;
			}

			if ((flags & STATEID_SPECIAL_CLOSE_40) != 0) {
				/* Just update the lease and leave the reserved
				 * clientid NULL.
				 */
				update_lease(pclientid);
			} else {
				/* Remember the reserved clientid for the rest
				 * of the compound.
				 */
				data->preserved_clientid = pclientid;
			}
			pthread_mutex_unlock(&pclientid->cid_mutex);

			/* Replayed close, it's ok, but stateid doesn't exist */
			LogDebug(COMPONENT_STATE,
				 "Check %s stateid is a replayed close", tag);
			data->current_stateid_valid = false;
			goto success;
		}

		/* Release the clientid reference we just acquired. */
		dec_client_id_ref(pclientid);

		status = NFS4ERR_BAD_STATEID;
		goto failure;
	}

	/* Now, if this lease is not already reserved, reserve it */
	if (data->preserved_clientid !=
	    state2->state_owner->so_owner.so_nfs4_owner.so_clientrec) {
		if (data->preserved_clientid != NULL) {
			/* We don't expect this to happen, but, just in case...
			 * Update and release already reserved lease.
			 */
			pthread_mutex_lock(&data->preserved_clientid
					   ->cid_mutex);

			update_lease(data->preserved_clientid);

			pthread_mutex_unlock(&data->preserved_clientid
					     ->cid_mutex);

			data->preserved_clientid = NULL;
		}

		/* Check if lease is expired and reserve it */
		pthread_mutex_lock(&state2->state_owner->so_owner
				   .so_nfs4_owner.so_clientrec->cid_mutex);

		if (!reserve_lease
		    (state2->state_owner->so_owner.so_nfs4_owner.
		     so_clientrec)) {
			LogDebug(COMPONENT_STATE, "Returning NFS4ERR_EXPIRED");

			pthread_mutex_unlock(&state2->state_owner->so_owner
					     .so_nfs4_owner.so_clientrec
					     ->cid_mutex);

			status = NFS4ERR_EXPIRED;
			goto failure;
		}

		data->preserved_clientid =
		    state2->state_owner->so_owner.so_nfs4_owner.so_clientrec;

		pthread_mutex_unlock(&state2->state_owner->so_owner
				     .so_nfs4_owner.so_clientrec->cid_mutex);
	}

	/* Sanity check : Is this the right file ? */
	if ((entry != NULL) && (state2->state_entry != entry)) {
		LogDebug(COMPONENT_STATE,
			 "Check %s stateid found stateid %s has wrong file",
			 tag, str);
		status = NFS4ERR_BAD_STATEID;
		goto failure;
	}

	/* Whether stateid.seqid may be zero depends on the state type
	   exclusively, See RFC 5661 pp. 161,287-288. */
	if ((state2->state_type == STATE_TYPE_LAYOUT) ||
	    (stateid->seqid != 0)) {
		/* Check seqid in stateid */

		/**
		 * @todo fsf: maybe change to simple comparison:
		 *            stateid->seqid < state2->state_seqid
		 *            as good enough and maybe makes pynfs happy.
		 */
		diff = stateid->seqid - state2->state_seqid;
		if (diff < 0) {
			/* if this is NFSv4.0 and stateid's seqid is one less
			 * than current AND if owner_seqid is current
			 * pass state back to allow replay check
			 */
			if ((check_seqid)
			    && ((diff == -1)
				|| ((state2->state_seqid == 1)
				    && (stateid->seqid == seqid_all_one)))
			    && (owner_seqid ==
				state2->state_owner->so_owner.so_nfs4_owner.
				so_seqid)) {
				LogDebug(COMPONENT_STATE, "possible replay?");
				*state = state2;
				status = NFS4ERR_REPLAY;
				goto replay;
			}
			/* OLD_STATEID */
			LogDebug(COMPONENT_STATE,
				 "Check %s stateid found OLD stateid %s, expected seqid %u",
				 tag, str, (unsigned int)state2->state_seqid);
			status = NFS4ERR_OLD_STATEID;
			goto failure;
		}

		/* stateid seqid is current and owner seqid is previous,
		 * replay (should be an error condition that did not change
		 * the stateid, no real need to check since the operation
		 * must be the same)
		 */
		else if ((diff == 0) && (check_seqid)
			 && (owner_seqid ==
			     state2->state_owner->so_owner.so_nfs4_owner.
			     so_seqid)) {
			LogDebug(COMPONENT_STATE, "possible replay?");
			*state = state2;
			status = NFS4ERR_REPLAY;
			goto replay;
		} else if (diff > 0) {
			/* BAD_STATEID */
			LogDebug(COMPONENT_STATE,
				 "Check %s stateid found BAD stateid %s, expected seqid %u",
				 tag, str, (unsigned int)state2->state_seqid);
			status = NFS4ERR_BAD_STATEID;
			goto failure;
		}
	}

	if ((flags & STATEID_SPECIAL_FREE) != 0) {
		switch (state2->state_type) {
		case STATE_TYPE_LOCK:
			PTHREAD_RWLOCK_rdlock(&state2->state_entry->state_lock);
			if (glist_empty
			    (&state2->state_data.lock.state_locklist)) {
				LogFullDebug(COMPONENT_STATE,
					     "Check %s stateid %s has no locks, ok to free",
					     tag, str);
				PTHREAD_RWLOCK_unlock(&state2->state_entry->
						      state_lock);
				break;
			}
			PTHREAD_RWLOCK_unlock(&state2->state_entry->state_lock);
			/* Fall through for failure */

		case STATE_TYPE_NONE:
		case STATE_TYPE_SHARE:
		case STATE_TYPE_DELEG:
		case STATE_TYPE_LAYOUT:
			LogDebug(COMPONENT_STATE,
				 "Check %s stateid found stateid %s with locks held",
				 tag, str);

			status = NFS4ERR_LOCKS_HELD;
			goto failure;
		}
	}

	data->current_stateid_valid = true;

	LogFullDebug(COMPONENT_STATE,
		     "Check %s stateid found valid stateid %s - %p", tag, str,
		     state2);

	/* Copy stateid into current for later use */
	data->current_stateid = *stateid;
	data->current_stateid.seqid = state2->state_seqid;

 success:

	*state = state2;
	return NFS4_OK;

 failure:

	*state = NULL;

 replay:

	data->current_stateid_valid = false;
	return status;
}