示例#1
0
/**
 * @brief Return gid given a group name
 *
 * @param[in]  name  group name
 * @param[out] gid   address for gid to be filled in
 *
 * @return 0 on success and errno on failure.
 *
 * NOTE: If a group name doesn't exist, getgrnam_r returns 0 with the
 * result pointer set to NULL. We turn that into ENOENT error! Also,
 * getgrnam_r fails with ERANGE if there is a group with a large number
 * of users that it can't fill all those users into the supplied buffer.
 * This need not be the group we are asking for! ERANGE is handled here,
 * so this function never ends up returning ERANGE back to the caller.
 */
static int name_to_gid(const char *name, gid_t *gid)
{
	struct group g;
	struct group *gres = NULL;
	char *buf;
	size_t buflen = sysconf(_SC_GETGR_R_SIZE_MAX);

	/* Upper bound on the buffer length. Just to bailout if there is
	 * a bug in getgrname_r returning ERANGE incorrectly. 64MB
	 * should be good enough for now.
	 */
	size_t maxlen = 64 * 1024 * 1024;
	int err;

	if (buflen == -1)
		buflen = PWENT_BEST_GUESS_LEN;

	do {
		buf = gsh_malloc(buflen);
		if (buf == NULL) {
			LogCrit(COMPONENT_IDMAPPER,
				"gsh_malloc failed, buflen: %zu", buflen);

			return ENOMEM;
		}

		err = getgrnam_r(name, &g, buf, buflen, &gres);
		if (err == ERANGE) {
			buflen *= 16;
			gsh_free(buf);
		}
	} while (buflen <= maxlen && err == ERANGE);

	if (err == 0) {
		if (gres == NULL)
			err = ENOENT;
		else
			*gid = gres->gr_gid;
	}

	if (err != ERANGE)
		gsh_free(buf);

	return err;
}
示例#2
0
/**
 * @brief Release previously-ref'd DRC.
 *
 * Release previously-ref'd DRC.  If its refcnt drops to 0, the DRC
 * is queued for later recycling.
 *
 * @param[in] xprt  The SVCXPRT associated with DRC, if applicable
 * @param[in] drc   The DRC
 * @param[in] flags Control flags
 */
void nfs_dupreq_put_drc(SVCXPRT *xprt, drc_t *drc, uint32_t flags)
{
	if (!(flags & DRC_FLAG_LOCKED))
		PTHREAD_MUTEX_lock(&drc->mtx);
	/* drc LOCKED */

	if (drc->refcnt == 0) {
		LogCrit(COMPONENT_DUPREQ,
			"drc %p refcnt will underrun refcnt=%u", drc,
			drc->refcnt);
	}

	nfs_dupreq_unref_drc(drc);

	LogFullDebug(COMPONENT_DUPREQ, "drc %p refcnt==%u", drc, drc->refcnt);

	switch (drc->type) {
	case DRC_UDP_V234:
		/* do nothing */
		break;
	case DRC_TCP_V4:
	case DRC_TCP_V3:
		if (drc->refcnt == 0) {
			if (!(drc->flags & DRC_FLAG_RECYCLE)) {
				/* note t's lock order wrt drc->mtx is
				 * the opposite of drc->xt[*].lock */
				drc->d_u.tcp.recycle_time = time(NULL);
				drc->flags |= DRC_FLAG_RECYCLE;
				PTHREAD_MUTEX_unlock(&drc->mtx); /* !LOCKED */
				DRC_ST_LOCK();
				TAILQ_INSERT_TAIL(&drc_st->tcp_drc_recycle_q,
						  drc, d_u.tcp.recycle_q);
				++(drc_st->tcp_drc_recycle_qlen);
				LogFullDebug(COMPONENT_DUPREQ,
					     "enqueue drc %p for recycle", drc);
				DRC_ST_UNLOCK();
				return;
			}
		}
	default:
		break;
	};

	PTHREAD_MUTEX_unlock(&drc->mtx); /* !LOCKED */
}
示例#3
0
fsal_fs_locations_t *nfs4_fs_locations_new(const char *fs_root,
					   const char *rootpath,
					   const unsigned int count)
{
	fsal_fs_locations_t *fs_locations;

	fs_locations = nfs4_fs_locations_alloc(count);
	if (fs_locations == NULL) {
		LogCrit(COMPONENT_NFS_V4, "Could not allocate fs_locations");
		return NULL;
	}

	fs_locations->fs_root = gsh_strdup(fs_root);
	fs_locations->rootpath = gsh_strdup(rootpath);
	fs_locations->ref = 1;

	return fs_locations;
}
示例#4
0
void TestCrit(int expect, char *buff, log_components_t component, char *string)
{
	char compare[2048];
	sprintf(compare, "%s: CRITICAL ERROR: %s",
		LogComponents[component].comp_str, string);
	buff[0] = '\0';
	LogCrit(component, "%s", string);
	if ((expect && (strcmp(compare, buff) != 0))
	    || (!expect && (buff[0] != '\0'))) {
		LogTest("FAILURE: %s produced \"%s\" expected \"%s\"", string,
			buff, compare);
		exit(1);
	}
	if (expect)
		LogTest("SUCCESS: %s produced \"%s\"", string, buff);
	else
		LogTest("SUCCESS: %s didn't produce anything", string);
}
示例#5
0
fsal_status_t POSIXFSAL_InitClientContext(fsal_op_context_t * thr_context)
{
  posixfsal_op_context_t * p_thr_context = (posixfsal_op_context_t *) thr_context;
  fsal_posixdb_status_t st;

  /* sanity check */
  if(!p_thr_context)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_InitClientContext);

  /* initialy set the export entry to none */
  p_thr_context->export_context = NULL;

  st = fsal_posixdb_connect(&global_posixdb_params, &(p_thr_context->p_conn));
  if(FSAL_POSIXDB_IS_ERROR(st))
    {
      LogCrit(COMPONENT_FSAL,
              "CRITICAL ERROR: Worker could not connect to database !!!");
      Return(ERR_FSAL_SERVERFAULT, 0, INDEX_FSAL_InitClientContext);
    }
  else
    {
      LogEvent(COMPONENT_FSAL, "Worker successfuly connected to database");
    }

  /* sets the credential time */
/*  p_thr_context->credential.last_update = time( NULL );*/

  /* traces: prints p_credential structure */

  /*
     LogDebug(COMPONENT_FSAL, "credential created:");
     LogDebug(COMPONENT_FSAL, "\tuid = %d, gid = %d",
     p_thr_context->credential.hpss_usercred.SecPWent.Uid, p_thr_context->credential.hpss_usercred.SecPWent.Gid);
     LogDebug(COMPONENT_FSAL, "\tName = %s",
     p_thr_context->credential.hpss_usercred.SecPWent.Name);

     for ( i=0; i< p_thr_context->credential.hpss_usercred.NumGroups; i++ )
     LogDebug(COMPONENT_FSAL, "\tAlt grp: %d",
     p_thr_context->credential.hpss_usercred.AltGroups[i] );
   */
  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_InitClientContext);

}
示例#6
0
int mnt_Mnt(nfs_arg_t *arg,
	    nfs_worker_data_t *worker,
	    struct svc_req *req, nfs_res_t *res)
{
	struct gsh_export *export = NULL;
	struct fsal_obj_handle *pfsal_handle = NULL;
	int auth_flavor[NB_AUTH_FLAVOR];
	int index_auth = 0;
	int i = 0;
	char dumpfh[1024];
	int retval = NFS_REQ_OK;
	nfs_fh3 *fh3 = (nfs_fh3 *) &res->res_mnt3.mountres3_u.mountinfo.fhandle;
	cache_entry_t *entry = NULL;

	LogDebug(COMPONENT_NFSPROTO,
		 "REQUEST PROCESSING: Calling mnt_Mnt path=%s", arg->arg_mnt);

	/* Paranoid command to clean the result struct. */
	memset(res, 0, sizeof(nfs_res_t));

	/* Quick escape if an unsupported MOUNT version */
	if (req->rq_vers != MOUNT_V3) {
		res->res_mnt1.status = NFSERR_ACCES;
		goto out;
	}

	if (arg->arg_mnt == NULL) {
		LogCrit(COMPONENT_NFSPROTO,
			"NULL path passed as Mount argument !!!");
		retval = NFS_REQ_DROP;
		goto out;
	}

	/* If the path ends with a '/', get rid of it */
	/** @todo: should it be a while()?? */
	if (arg->arg_mnt[strlen(arg->arg_mnt) - 1] == '/')
		arg->arg_mnt[strlen(arg->arg_mnt) - 1] = '\0';

	/*  Find the export for the dirname (using as well Path or Tag) */
	if (arg->arg_mnt[0] == '/')
		export = get_gsh_export_by_path(arg->arg_mnt, false);
	else
		export = get_gsh_export_by_tag(arg->arg_mnt);
/**
 *
 * @brief Initialize the caching layer
 *
 * This function initializes the memory pools, lookup table, and weakref
 * table used for cache management.
 *
 * @return CACHE_INODE_SUCCESS or errors.
 *
 */
cache_inode_status_t cache_inode_init(void)
{
  cache_inode_status_t status = CACHE_INODE_SUCCESS;

  cache_inode_entry_pool = pool_init("Entry Pool",
                                     sizeof(cache_entry_t),
                                     pool_basic_substrate,
                                     NULL, NULL, NULL);
  if(!(cache_inode_entry_pool))
    {
      LogCrit(COMPONENT_CACHE_INODE,
              "Can't init Entry Pool");
      status = CACHE_INODE_INVALID_ARGUMENT;
    }

  cih_pkginit();

  return status;
}                               /* cache_inode_init */
示例#8
0
/**
 * @brief Initialize a shared duplicate request cache
 */
static inline void init_shared_drc()
{
	drc_t *drc = &drc_st->udp_drc;
	int ix, code __attribute__ ((unused)) = 0;

	drc->type = DRC_UDP_V234;
	drc->refcnt = 0;
	drc->retwnd = 0;
	drc->d_u.tcp.recycle_time = 0;
	drc->maxsize = nfs_param.core_param.drc.udp.size;
	drc->cachesz = nfs_param.core_param.drc.udp.cachesz;
	drc->npart = nfs_param.core_param.drc.udp.npart;
	drc->hiwat = nfs_param.core_param.drc.udp.hiwat;

	gsh_mutex_init(&drc->mtx, NULL);

	/* init dict */
	code =
	    rbtx_init(&drc->xt, dupreq_shared_cmpf, drc->npart,
		      RBT_X_FLAG_ALLOC | RBT_X_FLAG_CACHE_WT);
	assert(!code);

	/* completed requests */
	TAILQ_INIT(&drc->dupreq_q);

	/* init closed-form "cache" partition */
	for (ix = 0; ix < drc->npart; ++ix) {
		struct rbtree_x_part *xp = &(drc->xt.tree[ix]);
		drc->xt.cachesz = drc->cachesz;
		xp->cache =
		    gsh_calloc(drc->cachesz, sizeof(struct opr_rbtree_node *));
		if (unlikely(!xp->cache)) {
			LogCrit(COMPONENT_DUPREQ,
				"UDP DRC hash partition allocation "
				"failed (ix=%d)", ix);
			drc->cachesz = 0;
			break;
		}
	}

	return;
}
示例#9
0
/**
 * @brief Unlock Message
 *
 * @param[in]  args
 * @param[in]  req
 * @param[out] res
 *
 */
int nlm4_Unlock_Message(nfs_arg_t *args, struct svc_req *req, nfs_res_t *res)
{
	state_nlm_client_t *nlm_client = NULL;
	state_nsm_client_t *nsm_client;
	nlm4_unlockargs *arg = &args->arg_nlm4_unlock;
	int rc = NFS_REQ_OK;

	LogDebug(COMPONENT_NLM,
		 "REQUEST PROCESSING: Calling nlm_Unlock_Message");

	nsm_client = get_nsm_client(CARE_NO_MONITOR,
				    req->rq_xprt,
				    arg->alock.caller_name);

	if (nsm_client != NULL)
		nlm_client = get_nlm_client(CARE_NO_MONITOR,
					    req->rq_xprt, nsm_client,
					    arg->alock.caller_name);

	if (nlm_client == NULL)
		rc = NFS_REQ_DROP;
	else
		rc = nlm4_Unlock(args, req, res);

	if (rc == NFS_REQ_OK)
		rc = nlm_send_async_res_nlm4(nlm_client,
					     nlm4_unlock_message_resp,
					     res);

	if (rc == NFS_REQ_DROP) {
		if (nsm_client != NULL)
			dec_nsm_client_ref(nsm_client);

		if (nlm_client != NULL)
			dec_nlm_client_ref(nlm_client);

		LogCrit(COMPONENT_NLM,
			"Could not send async response for nlm_Unlock_Message");
	}

	return NFS_REQ_DROP;
}
示例#10
0
/**
 * @brief Construct the fs opaque part of a pseudofs nfsv4 handle
 *
 * Given the components of a pseudofs nfsv4 handle, the nfsv4 handle is
 * created by concatenating the components. This is the fs opaque piece
 * of struct file_handle_v4 and what is sent over the wire.
 *
 * @param[in] pseudopath Full patch of the pseudofs node
 * @param[in] len length of the pseudopath parameter
 * @param[in] hashkey a 64 bit hash of the pseudopath parameter
 *
 * @return The nfsv4 pseudofs file handle as a char *
 */
char *package_pseudo_handle(char *pseudopath, ushort len, uint64 hashkey)
{
	char *buff = NULL;
	int opaque_bytes_used = 0, pathlen = 0;

	/* This is the size of the v4 file handle opaque area used for pseudofs
	 * or FSAL file handles.
	 */
	buff = gsh_malloc(V4_FH_OPAQUE_SIZE);
	if (buff == NULL) {
		LogCrit(COMPONENT_NFS_V4_PSEUDO,
			"Failed to malloc space for pseudofs handle.");
		return NULL;
	}

	memcpy(buff, &hashkey, sizeof(hashkey));
	opaque_bytes_used += sizeof(hashkey);

	/* include length of the path in the handle.
	 * MAXPATHLEN=4096 ... max path length can be contained in a short int.
	 */
	memcpy(buff + opaque_bytes_used, &len, sizeof(ushort));
	opaque_bytes_used += sizeof(ushort);

	/* Either the nfsv4 fh opaque size or the length of the pseudopath.
	 * Ideally we can include entire pseudofs pathname for guaranteed
	 * uniqueness of pseudofs handles.
	 */
	pathlen = MIN(V4_FH_OPAQUE_SIZE - opaque_bytes_used, len);
	memcpy(buff + opaque_bytes_used, pseudopath, pathlen);
	opaque_bytes_used += pathlen;

	/* If there is more space in the opaque handle due to a short pseudofs
	 * path ... zero it.
	 */
	if (opaque_bytes_used < V4_FH_OPAQUE_SIZE) {
		memset(buff + opaque_bytes_used, 0,
		       V4_FH_OPAQUE_SIZE - opaque_bytes_used);
	}

	return buff;
}
示例#11
0
static fsal_status_t create(struct fsal_obj_handle *dir_hdl,
			    const char *name, struct attrlist *attrib,
			    struct fsal_obj_handle **handle)
{
	fsal_errors_t fsal_error = ERR_FSAL_NO_ERROR;
	int retval = 0;
	struct pt_fsal_obj_handle *hdl;
	fsal_status_t status;

	ptfsal_handle_t *fh = alloca(sizeof(ptfsal_handle_t));

	*handle = NULL;		/* poison it */
	if (!dir_hdl->ops->handle_is(dir_hdl, DIRECTORY)) {
		LogCrit(COMPONENT_FSAL,
			"Parent handle is not a directory. hdl = 0x%p",
			dir_hdl);
		return fsalstat(ERR_FSAL_NOTDIR, 0);
	}
	memset(fh, 0, sizeof(ptfsal_handle_t));
	fh->data.handle.handle_size = FSI_CCL_PERSISTENT_HANDLE_N_BYTES;

	attrib->mask =
	    op_ctx->fsal_export->ops->fs_supported_attrs(op_ctx->fsal_export);
	status = PTFSAL_create(dir_hdl, name, op_ctx,
			       attrib->mode, fh, attrib);
	if (FSAL_IS_ERROR(status))
		return status;

	/* allocate an obj_handle and fill it up */
	hdl = alloc_handle(fh, attrib, NULL, NULL, NULL, op_ctx->fsal_export);
	if (hdl == NULL) {
		retval = ENOMEM;
		goto fileerr;
	}
	*handle = &hdl->obj_handle;
	return fsalstat(ERR_FSAL_NO_ERROR, 0);

 fileerr:
	fsal_error = posix2fsal_error(retval);
	return fsalstat(fsal_error, retval);
}
/**
 * @brief Clean resources associated with entry
 *
 * This function frees the various resources associated wiith a cache
 * entry.
 *
 * @param[in] entry Entry to be cleaned
 *
 * @return CACHE_INODE_SUCCESS or various errors
 */
cache_inode_status_t
cache_inode_clean_internal(cache_entry_t *entry)
{
     hash_buffer_t key, val;
     hash_error_t rc = 0;

     if (entry->fh_desc.start == 0)
         return CACHE_INODE_SUCCESS;

     key.pdata = entry->fh_desc.start;
     key.len = entry->fh_desc.len;


     val.pdata = entry;
     val.len = sizeof(cache_entry_t);

     rc = HashTable_DelSafe(fh_to_cache_entry_ht,
                            &key,
                            &val);

     /* Nonexistence is as good as success. */
     if ((rc != HASHTABLE_SUCCESS) &&
         (rc != HASHTABLE_ERROR_NO_SUCH_KEY)) {
          /* XXX this seems to logically prevent relcaiming the HashTable LRU
           * reference, and it seems to indicate a very serious problem */
          LogCrit(COMPONENT_CACHE_INODE,
                  "HashTable_Del error %d in cache_inode_clean_internal", rc);
          return CACHE_INODE_INCONSISTENT_ENTRY;
     }

     /* Delete from the weakref table */
     cache_inode_weakref_delete(&entry->weakref);

     if (entry->type == SYMBOLIC_LINK) {
          pthread_rwlock_wrlock(&entry->content_lock);
          cache_inode_release_symlink(entry);
          pthread_rwlock_unlock(&entry->content_lock);
     }

     return CACHE_INODE_SUCCESS;
} /* cache_inode_clean_internal */
示例#13
0
/**
 * nlm4_Lock_Message: Lock Message
 *
 *  @param parg        [IN]
 *  @param pexportlist [IN]
 *  @param pcontextp   [IN]
 *  @param pclient     [INOUT]
 *  @param ht          [INOUT]
 *  @param preq        [IN]
 *  @param pres        [OUT]
 *
 */
int nlm4_Lock_Message(nfs_arg_t * parg /* IN     */ ,
                      exportlist_t * pexport /* IN     */ ,
                      fsal_op_context_t * pcontext /* IN     */ ,
                      cache_inode_client_t * pclient /* INOUT  */ ,
                      hash_table_t * ht /* INOUT  */ ,
                      struct svc_req *preq /* IN     */ ,
                      nfs_res_t * pres /* OUT    */ )
{
  state_nlm_client_t * nlm_client = NULL;
  state_nsm_client_t * nsm_client;
  nlm4_lockargs      * arg = &parg->arg_nlm4_lock;
  int                  rc = NFS_REQ_OK;

  LogDebug(COMPONENT_NLM, "REQUEST PROCESSING: Calling nlm_Lock_Message");

  nsm_client = get_nsm_client(CARE_NO_MONITOR, preq->rq_xprt, arg->alock.caller_name);

  if(nsm_client != NULL)
    nlm_client = get_nlm_client(CARE_NO_MONITOR, preq->rq_xprt, nsm_client, arg->alock.caller_name);

  if(nlm_client == NULL)
    rc = NFS_REQ_DROP;
  else
    rc = nlm4_Lock(parg, pexport, pcontext, pclient, ht, preq, pres);

  if(rc == NFS_REQ_OK)
    rc = nlm_send_async_res_nlm4(nlm_client, nlm4_lock_message_resp, pres);

  if(rc == NFS_REQ_DROP)
    {
      if(nsm_client != NULL)
        dec_nsm_client_ref(nsm_client);
      if(nlm_client != NULL)
        dec_nlm_client_ref(nlm_client);
      LogCrit(COMPONENT_NLM,
            "Could not send async response for nlm_Lock_Message");
    }

  return NFS_REQ_DROP;

}
示例#14
0
/**
 * _9p_dispatcher_svc_run: main loop for 9p dispatcher
 *
 * This function is the main loop for the 9p dispatcher.
 * It never returns because it is an infinite loop.
 *
 * @param sock accept socket for 9p dispatch
 *
 * @return nothing (void function).
 *
 */
void _9p_dispatcher_svc_run(long int sock)
{
	int rc = 0;
	struct sockaddr_in addr;
	socklen_t addrlen = sizeof(addr);
	long int newsock = -1;
	pthread_attr_t attr_thr;
	pthread_t tcp_thrid;

	/* Init for thread parameter (mostly for scheduling) */
	if (pthread_attr_init(&attr_thr) != 0)
		LogDebug(COMPONENT_9P_DISPATCH,
			 "can't init pthread's attributes");

	if (pthread_attr_setscope(&attr_thr, PTHREAD_SCOPE_SYSTEM) != 0)
		LogDebug(COMPONENT_9P_DISPATCH, "can't set pthread's scope");

	if (pthread_attr_setdetachstate(&attr_thr,
					PTHREAD_CREATE_DETACHED) != 0)
		LogDebug(COMPONENT_9P_DISPATCH,
			 "can't set pthread's join state");

	LogEvent(COMPONENT_9P_DISPATCH, "9P dispatcher started");
	while (true) {
		newsock = accept(sock, (struct sockaddr *)&addr, &addrlen);
		if (newsock < 0) {
			LogCrit(COMPONENT_9P_DISPATCH, "accept failed");
			continue;
		}

		/* Starting the thread dedicated to signal handling */
		rc = pthread_create(&tcp_thrid, &attr_thr,
				    _9p_socket_thread, (void *)newsock);
		if (rc != 0) {
			LogFatal(COMPONENT_THREAD,
				 "Could not create 9p socket manager thread, error = %d (%s)",
				 errno, strerror(errno));
		}
	}			/* while */
	return;
}				/* _9p_dispatcher_svc_run */
示例#15
0
fsal_status_t vfs_open_my_fd(struct vfs_fsal_obj_handle *myself,
			     fsal_openflags_t openflags,
			     int posix_flags,
			     struct vfs_fd *my_fd)
{
	int fd;
	fsal_errors_t fsal_error = ERR_FSAL_NO_ERROR;
	int retval = 0;

	LogFullDebug(COMPONENT_FSAL,
		     "my_fd->fd = %d openflags = %x, posix_flags = %x",
		     my_fd->fd, openflags, posix_flags);

	assert(my_fd->fd == -1
	       && my_fd->openflags == FSAL_O_CLOSED && openflags != 0);

	LogFullDebug(COMPONENT_FSAL,
		     "openflags = %x, posix_flags = %x",
		     openflags, posix_flags);

	fd = vfs_fsal_open(myself, posix_flags, &fsal_error);

	if (fd < 0) {
		retval = -fd;
	} else {
		/* Save the file descriptor, make sure we only save the
		 * open modes that actually represent the open file.
		 */
		LogFullDebug(COMPONENT_FSAL,
			     "fd = %d, new openflags = %x",
			     fd, openflags);
		if (fd == 0)
			LogCrit(COMPONENT_FSAL,
				"fd = %d, new openflags = %x",
				fd, openflags);
		my_fd->fd = fd;
		my_fd->openflags = openflags;
	}

	return fsalstat(fsal_error, retval);
}
示例#16
0
int mnt_UmntAll(nfs_arg_t * parg /* IN     */ ,
                exportlist_t * pexport /* IN     */ ,
                fsal_op_context_t * pcontext /* IN     */ ,
                cache_inode_client_t * pclient /* INOUT  */ ,
                hash_table_t * ht /* INOUT  */ ,
                struct svc_req *preq /* IN     */ ,
                nfs_res_t * pres /* OUT    */ )
{
    LogFullDebug(COMPONENT_NFSPROTO,
                 "REQUEST PROCESSING: Calling mnt_UmntAll");

    /* Just empty the Mount list, take void as argument and returns void */
    if(!nfs_Purge_MountList())
    {
        /* Purge mount list failed */
        LogCrit(COMPONENT_NFSPROTO,
                "UMOUNT ALL: Error when emptying the mount list");
    }

    return NFS_REQ_OK;
}                               /* mnt_UmntAll */
示例#17
0
static fsal_status_t pt_lookup(struct fsal_obj_handle *parent,
			       const char *path,
			       struct fsal_obj_handle **handle)
{
	fsal_errors_t fsal_error = ERR_FSAL_NO_ERROR;
	int retval = 0;
	fsal_status_t status;
	struct pt_fsal_obj_handle *hdl;
	struct attrlist attrib;
	ptfsal_handle_t *fh = alloca(sizeof(ptfsal_handle_t));

	*handle = NULL;		/* poison it first */
	if (!path)
		return fsalstat(ERR_FSAL_FAULT, 0);
	memset(fh, 0, sizeof(ptfsal_handle_t));
	fh->data.handle.handle_size = FSI_CCL_PERSISTENT_HANDLE_N_BYTES;
	if (!parent->ops->handle_is(parent, DIRECTORY)) {
		LogCrit(COMPONENT_FSAL,
			"Parent handle is not a directory. hdl = 0x%p", parent);
		return fsalstat(ERR_FSAL_NOTDIR, 0);
	}
	attrib.mask = parent->attributes.mask;
	status = PTFSAL_lookup(op_ctx, parent, path, &attrib, fh);
	if (FSAL_IS_ERROR(status))
		return status;

	/* allocate an obj_handle and fill it up */
	hdl = alloc_handle(fh, &attrib, NULL, NULL, NULL,
			   op_ctx->fsal_export);
	if (hdl == NULL) {
		retval = ENOMEM;
		goto hdlerr;
	}
	*handle = &hdl->obj_handle;
	return fsalstat(ERR_FSAL_NO_ERROR, 0);

 hdlerr:
	fsal_error = posix2fsal_error(retval);
	return fsalstat(fsal_error, retval);
}
fsal_status_t
fsal_proxy_create_rpc_clnt(proxyfsal_op_context_t * ctx)
{
  int sock;
  struct sockaddr_in addr_rpc;
  struct timeval timeout = TIMEOUTRPC;
  int rc;
  int priv_port = 0 ; 
  fsal_status_t fsal_status;
  char addr[INET_ADDRSTRLEN];

  memset(&addr_rpc, 0, sizeof(addr_rpc));
  addr_rpc.sin_port = ctx->srv_port;
  addr_rpc.sin_family = AF_INET;
  addr_rpc.sin_addr.s_addr = ctx->srv_addr;

  if(!strcmp(ctx->srv_proto, "udp"))
    {
      if((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
        ReturnCode(ERR_FSAL_FAULT, errno);

      ctx->rpc_client = clntudp_bufcreate(&addr_rpc,
                                          ctx->srv_prognum,
                                          FSAL_PROXY_NFS_V4,
                                          (struct timeval){ 25, 0},
                                          &sock,
                                          ctx->srv_sendsize,
                                          ctx->srv_recvsize);

      if(ctx->rpc_client == NULL)
        {

          LogCrit(COMPONENT_FSAL,
                  "Cannot contact server addr=%s port=%u prognum=%u using NFSv4 protocol",
                  inet_ntop(AF_INET, &ctx->srv_addr, addr, sizeof(addr)),
                  ntohs(ctx->srv_port), ctx->srv_prognum);

          ReturnCode(ERR_FSAL_INVAL, 0);
        }
    }
示例#19
0
/**
 *
 *  utf82gid: converts a utf8 string descriptorto a gid .
 *
 * Converts a utf8 string descriptor to a gid .
 *
 * @param utf8str [IN]  group's name as UTF8 string.
 * @param Gid     [OUT] pointer to the computed gid.
 *
 * @return 0 in all cases
 */
int utf82gid(utf8string * utf8str, gid_t * Gid)
{
  char buff[2 * NFS4_MAX_DOMAIN_LEN];
  char gidname[NFS4_MAX_DOMAIN_LEN];
#ifndef _USE_NFSIDMAP
  char domainname[NFS4_MAX_DOMAIN_LEN];
#endif
  int  rc;

  if(utf8str->utf8string_len == 0)
    {
      *Gid = -1;                /* Nobody */
      LogCrit(COMPONENT_IDMAPPER,
              "utf82gid: empty group name");
      return 0;
    }

  utf82str(buff, sizeof(buff), utf8str);

#ifndef _USE_NFSIDMAP
  /* Group is shown as a string 'group@domain' , remove it if libnfsidmap is not used */
  nfs4_stringid_split(buff, gidname, domainname);
#else
  strncpy(gidname, buff, NFS4_MAX_DOMAIN_LEN);
#endif

  rc = name2gid(gidname, Gid);

  if(rc == 0)
    {
      *Gid = -1;                /* Nobody */
      return 0;
    }

  LogDebug(COMPONENT_IDMAPPER,
           "utf82gid: Mapped %s to gid = %d",
           buff, *Gid);

  return 0;
}                               /* utf82gid */
示例#20
0
fsal_status_t GPFSFSAL_CleanUpExportContext(fsal_export_context_t * export_context) 
{
  gpfsfsal_export_context_t *p_export_context = (gpfsfsal_export_context_t *)export_context;

  if(export_context == NULL) 
  {
    LogCrit(COMPONENT_FSAL,
            "NULL mandatory argument passed to %s()", __FUNCTION__);
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_CleanUpExportContext);
  }

  if(p_export_context->mount_root_fd != 0)
    close(p_export_context->mount_root_fd);

  if(p_export_context->fe_fsal_up_ctx != NULL)
    {
      /* Start to clean up FSAL_UP stuff. There is actually more to do here...*/
      glist_del(&p_export_context->fe_list);
    }

  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_CleanUpExportContext);
}
示例#21
0
void InitLogging()
{
  int i;
  char *env_value;
  int newlevel, component, oldlevel;

  /* Initialisation du tableau des familys */
  tab_family[0].num_family = 0;
  tab_family[0].tab_err = (family_error_t *) tab_system_err;
  strcpy(tab_family[0].name_family, "Errors Systeme UNIX");

  for(i = 1; i < MAX_NUM_FAMILY; i++)
    tab_family[i].num_family = UNUSED_SLOT;

  ArmSignal(SIGUSR1, IncrementLevelDebug);
  ArmSignal(SIGUSR2, DecrementLevelDebug);

  for(component = COMPONENT_ALL; component < COMPONENT_COUNT; component++)
    {
      env_value = getenv(LogComponents[component].comp_name);
      if (env_value == NULL)
        continue;
      newlevel = ReturnLevelAscii(env_value);
      if (newlevel == -1) {
        LogCrit(COMPONENT_LOG,
                "Environment variable %s exists, but the value %s is not a"
                " valid log level.",
                LogComponents[component].comp_name, env_value);
        continue;
      }
      oldlevel = LogComponents[component].comp_log_level;
      LogComponents[component].comp_log_level = newlevel;
      LogChanges("Using environment variable to switch log level for %s from "
                 "%s to %s",
                 LogComponents[component].comp_name, ReturnLevelInt(oldlevel),
                 ReturnLevelInt(newlevel));
    }

}                               /* InitLogging */
示例#22
0
int vfs_get_root_handle(struct vfs_filesystem *vfs_fs,
			struct vfs_fsal_export *exp)
{
	int retval = 0;

	vfs_fs->root_fd = open(vfs_fs->fs->path, O_RDONLY | O_DIRECTORY);

	if (vfs_fs->root_fd < 0) {
		retval = errno;
		LogMajor(COMPONENT_FSAL,
			 "Could not open VFS mount point %s: rc = %s (%d)",
			 vfs_fs->fs->path, strerror(retval), retval);
		return retval;
	}

	/* Check if we have to re-index the fsid based on config */
	if (exp->fsid_type != -1 &&
	    exp->fsid_type != vfs_fs->fs->fsid_type) {
		retval = -change_fsid_type(vfs_fs->fs, exp->fsid_type);
		if (retval != 0) {
			LogCrit(COMPONENT_FSAL,
				"Can not change fsid type of %s to %d, error %s",
				vfs_fs->fs->path, exp->fsid_type,
				strerror(retval));
			return retval;
		}

		LogInfo(COMPONENT_FSAL,
			"Reindexed filesystem %s to "
			"fsid=0x%016"PRIx64".0x%016"PRIx64,
			vfs_fs->fs->path,
			vfs_fs->fs->fsid.major,
			vfs_fs->fs->fsid.minor);
	}

	/* May reindex for some platforms */
	return vfs_re_index(vfs_fs, exp);
}
示例#23
0
/*
 * Parse FS specific option string to build the export entry option.
 */
fsal_status_t dpmfsal_BuildExportContext(
                                      dpmfsal_export_context_t * p_export_context, // OUT
                                      fsal_path_t * p_export_path, // IN
                                      char *fs_specific_options // IN
)
{
    char subopts[256];
    char *p_subop;
    char *value;
    int rc;

    // Sanity checks.
    if (!p_export_context)
        Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_BuildExportContext);

    if ((fs_specific_options != NULL) && (fs_specific_options[0] != '\0')) {

        // copy the option string (because it is modified by getsubopt call)
        strncpy(subopts, fs_specific_options, 256);
        p_subop = subopts; // set initial pointer

        // parse the FS specific option string
        switch (Getsubopt(&p_subop, fs_specific_opts, &value)) {
        // Add options here, if any
        default: {
            LogCrit(COMPONENT_CONFIG,
                    "FSAL LOAD PARAMETER: ERROR: Invalid suboption found in EXPORT::FS_Specific : %s : xxxxxx expected.",
                    value);
            Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_BuildExportContext);
        }
        }
    }

    // Put DPM specific export initialization handling here (if necessary)

    Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_BuildExportContext);
}
示例#24
0
void FreeXprt(SVCXPRT *xprt)
{
  if(!xprt)
    {
      LogFullDebug(COMPONENT_RPC,
                   "Attempt to free NULL xprt");
      return;
      
    }

  LogFullDebug(COMPONENT_RPC,
               "FreeXprt xprt=%p", xprt);
  if(xprt->xp_ops == &Svcudp_op)
    {
      xp_free(Su_data(xprt));
      xp_free(rpc_buffer(xprt));
    }
  else if (xprt->xp_ops == &Svctcp_op)
    {
      struct tcp_conn *cd = (struct tcp_conn *)xprt->xp_p1;
      XDR_DESTROY(&(cd->xdrs));
      xp_free(xprt->xp_p1); /* cd */
    }
  else if (xprt->xp_ops == &Svctcp_rendezvous_op)
    {
      xp_free(xprt->xp_p1); /* r */
    }
  else
    {
      LogCrit(COMPONENT_RPC,
              "Attempt to free unknown xprt %p",
              xprt);
      return;
    }

  Mem_Free(xprt);
}
示例#25
0
文件: nfs4_acls.c 项目: ic-hep/emi3
int nfs4_acls_init()
{
  LogDebug(COMPONENT_NFS_V4_ACL, "Initialize NFSv4 ACLs");
  LogDebug(COMPONENT_NFS_V4_ACL, "sizeof(fsal_ace_t)=%lu, sizeof(fsal_acl_t)=%lu", sizeof(fsal_ace_t), sizeof(fsal_acl_t));

  /* Initialize memory pool of ACLs. */
  MakePool(&fsal_acl_pool, nb_pool_prealloc, fsal_acl_t, NULL, NULL);

  /* Initialize memory pool of ACL keys. */
  MakePool(&fsal_acl_key_pool, nb_pool_prealloc, fsal_acl_key_t, NULL, NULL);

  /* Create hash table. */
  fsal_acl_hash = HashTable_Init(fsal_acl_hash_config);

  if(!fsal_acl_hash)
    {
      LogCrit(COMPONENT_NFS_V4_ACL, "ERROR creating hash table for NFSv4 ACLs");
      return NFS_V4_ACL_INTERNAL_ERROR;
    }

  nfs4_acls_test();

  return NFS_V4_ACL_SUCCESS;
}
示例#26
0
/**
 * _9p_dispatcher_thread: thread used for RPC dispatching.
 *
 * Thead used for RPC dispatching. It gets the requests and then spool it to
 * one of the worker's LRU.  The worker chosen is the one with the smaller load
 * (its LRU is the shorter one).
 *
 * @param Arg (unused)
 *
 * @return Pointer to the result (but this function will mostly loop forever).
 *
 */
void *_9p_dispatcher_thread(void *Arg)
{
	int _9p_socket = -1;

	SetNameFunction("_9p_disp");

	/* Calling dispatcher main loop */
	LogInfo(COMPONENT_9P_DISPATCH, "Entering nfs/rpc dispatcher");

	LogDebug(COMPONENT_9P_DISPATCH, "My pthread id is %p",
		 (caddr_t) pthread_self());

	/* Set up the _9p_socket */
	_9p_socket = _9p_create_socket();
	if (_9p_socket == -1) {
		LogCrit(COMPONENT_9P_DISPATCH,
			"Can't get socket for 9p dispatcher");
		exit(1);
	}

	_9p_dispatcher_svc_run(_9p_socket);

	return NULL;
}				/* _9p_dispatcher_thread */
示例#27
0
/**
 * @brief Initialize the file-specific delegation statistics
 *
 * Initialize the file-specific delegation statistics used later for deciding
 * if a delegation should be granted on this file based on heuristics.
 *
 * @param[in] entry Inode entry the delegation will be on.
 */
bool init_deleg_heuristics(cache_entry_t *entry)
{
	struct file_deleg_heuristics *statistics;

	if (entry->type != REGULAR_FILE) {
		LogCrit(COMPONENT_STATE,
			"Initialization of delegation stats for an entry that is NOT a regular file!");
		return false;
	}

	statistics = &entry->object.file.deleg_heuristics;
	statistics->curr_delegations = 0;
	statistics->deleg_type = OPEN_DELEGATE_NONE;
	statistics->disabled = false;
	statistics->delegation_count = 0;
	statistics->recall_count = 0;
	statistics->last_delegation = 0;
	statistics->last_recall = 0;
	statistics->avg_hold = 0;
	statistics->num_opens = 0;
	statistics->first_open = 0;

	return true;
}
示例#28
0
/* One pool can be used for all FSAL_UP used for exports. */
void nfs_Init_FSAL_UP()
{
  memset(&nfs_param.fsal_up_param, 0, sizeof(nfs_param.fsal_up_param));
  nfs_param.fsal_up_param.nb_event_data_prealloc = 2;

  /* DEBUGGING */
  LogDebug(COMPONENT_INIT,
           "FSAL_UP: Initializing FSAL UP data pool");
  /* Allocation of the FSAL UP pool */
  MakePool(&nfs_param.fsal_up_param.event_pool,
           nfs_param.fsal_up_param.nb_event_data_prealloc,
           fsal_up_event_t,
           constructor_fsal_up_event_t, NULL);
  NamePool(&nfs_param.fsal_up_param.event_pool, "FSAL UP Data Pool");
  if(!IsPoolPreallocated(&nfs_param.fsal_up_param.event_pool))
    {
      LogCrit(COMPONENT_INIT,
              "Error while allocating FSAL UP data pool");
      LogError(COMPONENT_INIT, ERR_SYS, ERR_MALLOC, errno);
      Fatal();
    }

  return;
}
示例#29
0
static int file_attributes_to_xattr_attrs(struct attrlist *file_attrs,
					  struct attrlist *xattr_attrs,
					  unsigned int attr_index)
{
	/* supported attributes are:
	 * - owner (same as the objet)
	 * - group (same as the objet)
	 * - type FSAL_TYPE_XATTR
	 * - fileid (attr index ? or (fileid^((index+1)<<24)) )
	 * - mode (config & file)
	 * - atime, mtime, ctime = these of the object ?
	 * - size=1block, used=1block
	 * - rdev=0
	 * - nlink=1
	 */
	attrmask_t supported =
		(ATTR_MODE | ATTR_FILEID | ATTR_TYPE |
		 ATTR_OWNER | ATTR_GROUP |
		 ATTR_ATIME | ATTR_MTIME | ATTR_CTIME |
		 ATTR_CREATION | ATTR_CHGTIME
		 | ATTR_SIZE | ATTR_SPACEUSED |
		 ATTR_NUMLINKS | ATTR_RAWDEV |
		 ATTR_FSID);
	attrmask_t unsupp;

	if (xattr_attrs->mask == 0) {
		xattr_attrs->mask = supported;

		LogCrit(COMPONENT_FSAL,
			"Error: xattr_attrs->mask was 0");
	}

	unsupp = xattr_attrs->mask & (~supported);

	if (unsupp) {
		LogDebug(COMPONENT_FSAL,
			 "Asking for unsupported attributes: %#llX removing it from asked attributes",
			 (long long unsigned int)unsupp);

		xattr_attrs->mask &= (~unsupp);
	}

	if (xattr_attrs->mask & ATTR_MODE) {
		xattr_attrs->mode = file_attrs->mode;

		if (attr_is_read_only(attr_index))
			xattr_attrs->mode &= ~(0222);
	}

	if (xattr_attrs->mask & ATTR_FILEID) {
		unsigned int i;
		unsigned long hash = attr_index + 1;
		char *str = (char *)&file_attrs->fileid;

		for (i = 0; i < sizeof(xattr_attrs->fileid); i++, str++)
			hash = (hash << 5) - hash + (unsigned long)(*str);
		xattr_attrs->fileid = hash;
	}

	if (xattr_attrs->mask & ATTR_TYPE)
		xattr_attrs->type = EXTENDED_ATTR;

	if (xattr_attrs->mask & ATTR_OWNER)
		xattr_attrs->owner = file_attrs->owner;

	if (xattr_attrs->mask & ATTR_GROUP)
		xattr_attrs->group = file_attrs->group;

	if (xattr_attrs->mask & ATTR_ATIME)
		xattr_attrs->atime = file_attrs->atime;

	if (xattr_attrs->mask & ATTR_MTIME)
		xattr_attrs->mtime = file_attrs->mtime;

	if (xattr_attrs->mask & ATTR_CTIME)
		xattr_attrs->ctime = file_attrs->ctime;

	if (xattr_attrs->mask & ATTR_CREATION)
		xattr_attrs->creation = file_attrs->creation;

	if (xattr_attrs->mask & ATTR_CHGTIME) {
		xattr_attrs->chgtime = file_attrs->chgtime;
		xattr_attrs->change = xattr_attrs->chgtime.tv_sec;
	}

	if (xattr_attrs->mask & ATTR_SIZE)
		xattr_attrs->filesize = DEV_BSIZE;

	if (xattr_attrs->mask & ATTR_SPACEUSED)
		xattr_attrs->spaceused = DEV_BSIZE;

	if (xattr_attrs->mask & ATTR_NUMLINKS)
		xattr_attrs->numlinks = 1;

	if (xattr_attrs->mask & ATTR_RAWDEV) {
		xattr_attrs->rawdev.major = 0;
		xattr_attrs->rawdev.minor = 0;
	}

	if (xattr_attrs->mask & ATTR_FSID)
		xattr_attrs->fsid = file_attrs->fsid;

	/* if mode==0, then owner is set to root and mode is set to 0600 */
	if ((xattr_attrs->mask & ATTR_OWNER)
	    && (xattr_attrs->mask & ATTR_MODE) && (xattr_attrs->mode == 0)) {
		xattr_attrs->owner = 0;
		xattr_attrs->mode = 0600;
		if (attr_is_read_only(attr_index))
			xattr_attrs->mode &= ~(0200);
	}

	return 0;

}
示例#30
0
int nfs4_op_setclientid(struct nfs_argop4 *op, compound_data_t *data,
			struct nfs_resop4 *resp)
{
	SETCLIENTID4args * const arg_SETCLIENTID4 =
	    &op->nfs_argop4_u.opsetclientid;
	SETCLIENTID4res * const res_SETCLIENTID4 =
	    &resp->nfs_resop4_u.opsetclientid;
	clientaddr4 * const res_SETCLIENTID4_INUSE =
	    &resp->nfs_resop4_u.opsetclientid.SETCLIENTID4res_u.client_using;
	char str_verifier[NFS4_VERIFIER_SIZE * 2 + 1];
	char str_client[NFS4_OPAQUE_LIMIT * 2 + 1];
	char str_client_addr[SOCK_NAME_MAX + 1];
	nfs_client_record_t *client_record;
	nfs_client_id_t *conf;
	nfs_client_id_t *unconf;
	clientid4 clientid;
	verifier4 verifier;
	sockaddr_t client_addr;
	int rc;

	resp->resop = NFS4_OP_SETCLIENTID;

	if (data->minorversion > 0) {
		res_SETCLIENTID4->status = NFS4ERR_NOTSUPP;
		return res_SETCLIENTID4->status;
	}

	copy_xprt_addr(&client_addr, data->req->rq_xprt);

	if (isDebug(COMPONENT_CLIENTID)) {
		sprint_sockip(&client_addr, str_client_addr,
			      sizeof(str_client_addr));

		DisplayOpaqueValue(arg_SETCLIENTID4->client.id.id_val,
				   arg_SETCLIENTID4->client.id.id_len,
				   str_client);

		sprint_mem(str_verifier, arg_SETCLIENTID4->client.verifier,
			   NFS4_VERIFIER_SIZE);
	}

	LogDebug(COMPONENT_CLIENTID,
		 "SETCLIENTID Client addr=%s id=%s verf=%s callback={program=%u r_addr=%s r_netid=%s} ident=%u",
		 str_client_addr, str_client, str_verifier,
		 arg_SETCLIENTID4->callback.cb_program,
		 arg_SETCLIENTID4->callback.cb_location.r_addr,
		 arg_SETCLIENTID4->callback.cb_location.r_netid,
		 arg_SETCLIENTID4->callback_ident);

	/* Do we already have one or more records for client id (x)? */
	client_record = get_client_record(arg_SETCLIENTID4->client.id.id_val,
					  arg_SETCLIENTID4->client.id.id_len,
					  0,
					  0);

	if (client_record == NULL) {
		/* Some major failure */
		LogCrit(COMPONENT_CLIENTID, "SETCLIENTID failed");

		res_SETCLIENTID4->status = NFS4ERR_SERVERFAULT;
		return res_SETCLIENTID4->status;
	}

	/* The following checks are based on RFC3530bis draft 16
	 *
	 * This attempts to implement the logic described in
	 * 15.35.5. IMPLEMENTATION Consider the major bullets as CASE
	 * 1, CASE 2, CASE 3, CASE 4, and CASE 5.
	 */

	pthread_mutex_lock(&client_record->cr_mutex);

	if (isFullDebug(COMPONENT_CLIENTID)) {
		char str[HASHTABLE_DISPLAY_STRLEN];

		display_client_record(client_record, str);

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

	conf = client_record->cr_confirmed_rec;

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

		if (!nfs_compare_clientcred(&conf->cid_credential,
					    &data->credential)
		    || !cmp_sockaddr(&conf->cid_client_addr,
				     &client_addr,
				     true)) {
			/* CASE 1:
			 *
			 * Confirmed record exists and not the same principal
			 */
			if (isDebug(COMPONENT_CLIENTID)) {
				char confirmed_addr[SOCK_NAME_MAX + 1];

				sprint_sockip(&conf->cid_client_addr,
					      confirmed_addr,
					      sizeof(confirmed_addr));

				LogDebug(COMPONENT_CLIENTID,
					 "Confirmed ClientId %" PRIx64
					 "->'%s': Principals do not match... confirmed addr=%s Return NFS4ERR_CLID_INUSE",
					 conf->cid_clientid, str_client,
					 confirmed_addr);
			}

			res_SETCLIENTID4->status = NFS4ERR_CLID_INUSE;
			res_SETCLIENTID4_INUSE->r_netid =
			    (char *)netid_nc_table[conf->cid_cb.v40.cb_addr.nc]
			    .netid;
			res_SETCLIENTID4_INUSE->r_addr =
			    gsh_strdup(conf->cid_cb.v40.cb_client_r_addr);

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

		/* Check if confirmed record is for (v, x, c, l, s) */
		if (memcmp
		    (arg_SETCLIENTID4->client.verifier,
		     conf->cid_incoming_verifier, NFS4_VERIFIER_SIZE) == 0) {
			/* CASE 2:
			 *
			 * A confirmed record exists for this long
			 * form client id and verifier.
			 *
			 * Consider this to be a possible update of
			 * the call-back information.
			 *
			 * Remove any pre-existing unconfirmed record
			 * for (v, x, c).
			 *
			 * Return the same short form client id (c),
			 * but a new setclientid_confirm verifier (t).
			 */
			LogFullDebug(COMPONENT_CLIENTID,
				     "Update ClientId %" PRIx64 "->%s",
				     conf->cid_clientid, str_client);

			clientid = conf->cid_clientid;
			new_clientid_verifier(verifier);
		} else {
			/* Must be CASE 3 or CASE 4
			 *
			 * Confirmed record is for (u, x, c, l, s).
			 *
			 * These are actually the same, doesn't really
			 * matter if an unconfirmed record exists or
			 * not. Any existing unconfirmed record will
			 * be removed and a new unconfirmed record
			 * added.
			 *
			 * Return a new short form clientid (d) and a
			 * new setclientid_confirm verifier (t). (Note
			 * the spec calls the values e and r for CASE
			 * 4).
			 */
			LogFullDebug(COMPONENT_CLIENTID,
				     "Replace ClientId %" PRIx64 "->%s",
				     conf->cid_clientid, str_client);

			clientid = new_clientid();
			new_clientid_verifier(verifier);
		}

		/* Release our reference to the confirmed clientid. */
		dec_client_id_ref(conf);
	} else {
		/* CASE 5:
		 *
		 *
		 * Remove any existing unconfirmed record.
		 *
		 * Return a new short form clientid (d) and a new
		 * setclientid_confirm verifier (t).
		 */
		LogFullDebug(COMPONENT_CLIENTID, "New client");
		clientid = new_clientid();
		new_clientid_verifier(verifier);
	}

	/* 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) {
		/* Delete the unconfirmed clientid record. Because we
		 * have the cr_mutex, we have won any race to deal
		 * with this clientid record (whether we raced with a
		 * SETCLIENTID_CONFIRM or the reaper thread (if either
		 * of those operations had won the race,
		 * cr_punconfirmed_id would have been NULL).
		 */
		if (isDebug(COMPONENT_CLIENTID)) {
			char str[HASHTABLE_DISPLAY_STRLEN];

			display_client_id_rec(unconf, str);

			LogDebug(COMPONENT_CLIENTID, "Replacing %s", str);
		}

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

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

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

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

	if (strmaxcpy(unconf->cid_cb.v40.cb_client_r_addr,
		      arg_SETCLIENTID4->callback.cb_location.r_addr,
		      sizeof(unconf->cid_cb.v40.cb_client_r_addr)) == -1) {
		LogCrit(COMPONENT_CLIENTID, "Callback r_addr %s too long",
			arg_SETCLIENTID4->callback.cb_location.r_addr);
		res_SETCLIENTID4->status = NFS4ERR_INVAL;

		goto out;
	}

	nfs_set_client_location(unconf,
				&arg_SETCLIENTID4->callback.cb_location);

	memcpy(unconf->cid_incoming_verifier,
	       arg_SETCLIENTID4->client.verifier,
	       NFS4_VERIFIER_SIZE);

	memcpy(unconf->cid_verifier, verifier, sizeof(NFS4_write_verifier));

	unconf->cid_cb.v40.cb_program = arg_SETCLIENTID4->callback.cb_program;
	unconf->cid_cb.v40.cb_callback_ident = arg_SETCLIENTID4->callback_ident;

	rc = nfs_client_id_insert(unconf);

	if (rc != CLIENT_ID_SUCCESS) {
		/* Record is already freed, return. */
		res_SETCLIENTID4->status = clientid_error_to_nfsstat(rc);
		goto out;
	}

	if (isDebug(COMPONENT_CLIENTID)) {
		char str[HASHTABLE_DISPLAY_STRLEN];

		sprint_mem(str_verifier, verifier, NFS4_VERIFIER_SIZE);

		display_client_id_rec(unconf, str);
		LogDebug(COMPONENT_CLIENTID, "SETCLIENTID reply Verifier=%s %s",
			 str_verifier, str);
	}

	res_SETCLIENTID4->status = NFS4_OK;
	res_SETCLIENTID4->SETCLIENTID4res_u.resok4.clientid = clientid;
	memcpy(res_SETCLIENTID4->SETCLIENTID4res_u.resok4.setclientid_confirm,
	       &verifier, NFS4_VERIFIER_SIZE);

 out:

	pthread_mutex_unlock(&client_record->cr_mutex);

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

	return res_SETCLIENTID4->status;
}