cache_entry_t *cache_inode_weakref_get(gweakref_t *ref,
                                       uint32_t flags)
{
    pthread_rwlock_t *lock = NULL;
    cache_entry_t *entry =
        (cache_entry_t *) gweakref_lookupex(cache_inode_wt, ref, &lock);

    if (entry) {
        if (cache_inode_lru_ref(entry, flags)
            != CACHE_INODE_SUCCESS) {
            pthread_rwlock_unlock(lock);
            return NULL;
        }
        pthread_rwlock_unlock(lock);
    }

    return (entry);
}
Exemplo n.º 2
0
/**
 *
 * @brief invalidates an entry in the cache
 *
 * This function invalidates the related cache entry correponding to a
 * FSAL handle. It is designed to be called when an FSAL upcall is
 * triggered.
 *
 * @param[in]  handle FSAL handle for the entry to be invalidated
 * @param[out] status Returned status
 *
 * @retval CACHE_INODE_SUCCESS if operation is a success
 * @retval CACHE_INODE_INVALID_ARGUMENT bad parameter(s) as input
 * @retval CACHE_INODE_NOT_FOUND if entry is not cached
 * @retval CACHE_INODE_STATE_CONFLICT if invalidating this entry would
 *                                    result is state conflict
 * @retval CACHE_INODE_INCONSISTENT_ENTRY if entry is not consistent
 * @retval Other errors shows a FSAL error.
 *
 */
cache_inode_status_t
cache_inode_invalidate(cache_inode_fsal_data_t *fsal_data,
                       cache_inode_status_t *status,
                       uint32_t flags)
{
     hash_buffer_t key, value;
     int rc = 0 ;
     cache_entry_t *entry;
     struct hash_latch latch;

     if (status == NULL || fsal_data == NULL) {
          *status = CACHE_INODE_INVALID_ARGUMENT;
          goto out;
     }

     /* Locate the entry in the cache */
     FSAL_ExpandHandle(NULL,  /* pcontext but not used... */
                       FSAL_DIGEST_SIZEOF,
                       &fsal_data->fh_desc);

     /* Turn the input to a hash key */
     key.pdata = fsal_data->fh_desc.start;
     key.len = fsal_data->fh_desc.len;

     if ((rc = HashTable_GetLatch(fh_to_cache_entry_ht,
                                  &key,
                                  &value,
                                  FALSE,
                                  &latch)) == HASHTABLE_ERROR_NO_SUCH_KEY) {
          /* Entry is not cached */
          HashTable_ReleaseLatched(fh_to_cache_entry_ht, &latch);
          *status = CACHE_INODE_NOT_FOUND;
          return *status;
     } else if (rc != HASHTABLE_SUCCESS) {
          LogCrit(COMPONENT_CACHE_INODE,
                  "Unexpected error %u while calling HashTable_GetLatch", rc) ;
          *status = CACHE_INODE_INVALID_ARGUMENT;
          goto out;
     }

     entry = value.pdata;
     if (cache_inode_lru_ref(entry, 0) != CACHE_INODE_SUCCESS) {
          HashTable_ReleaseLatched(fh_to_cache_entry_ht, &latch);
          *status = CACHE_INODE_NOT_FOUND;
          return *status;
     }
     HashTable_ReleaseLatched(fh_to_cache_entry_ht, &latch);

     PTHREAD_RWLOCK_WRLOCK(&entry->attr_lock);
     PTHREAD_RWLOCK_WRLOCK(&entry->content_lock);

     /* We can invalidate entries with state just fine.  We force
        Cache_inode to contact the FSAL for any use of content or
        attributes, and if the FSAL indicates the entry is stale, it
        can be disposed of then. */

     /* We should have a way to invalidate content and attributes
        separately.  Or at least a way to invalidate attributes
        without invalidating content (since any change in content
        really ought to modify mtime, at least.) */

     if ((flags & CACHE_INODE_INVALIDATE_CLEARBITS) != 0)
       atomic_clear_uint32_t_bits(&entry->flags,
                                  CACHE_INODE_TRUST_ATTRS |
                                  CACHE_INODE_DIR_POPULATED |
                                  CACHE_INODE_TRUST_CONTENT);

     /* The main reason for holding the lock at this point is so we
        don't clear the trust bits while someone is populating the
        directory or refreshing attributes. */

     if (((flags & CACHE_INODE_INVALIDATE_CLOSE) != 0) &&
         (entry->type == REGULAR_FILE)) {
          cache_inode_close(entry,
                            NULL,
                            (CACHE_INODE_FLAG_REALLYCLOSE |
                             CACHE_INODE_FLAG_CONTENT_HAVE |
                             CACHE_INODE_FLAG_CONTENT_HOLD),
                            status);
     }

     PTHREAD_RWLOCK_UNLOCK(&entry->attr_lock);
     PTHREAD_RWLOCK_UNLOCK(&entry->content_lock);

     cache_inode_lru_unref(entry, 0);

out:

     /* Memory copying attributes with every call is expensive.
        Let's not do it.  */

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

  /* First of all, set the reply to zero to make sure it contains no
     parasite information */
  memset(resp, 0, sizeof(struct nfs_resop4));

  resp->resop = NFS4_OP_RESTOREFH;
  res_RESTOREFH.status = NFS4_OK;

  /* If there is no currentFH, teh return an error */
  if(nfs4_Is_Fh_Empty(&(data->savedFH)))
    {
      /* There is no current FH, return NFS4ERR_RESTOREFH (cg RFC3530,
         page 202) */
      res_RESTOREFH.status = NFS4ERR_RESTOREFH;
      return res_RESTOREFH.status;
    }

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

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

  /* If data->exportp is null, a junction from pseudo fs was
     traversed, credp and exportp have to be updated */
  if(data->pexport == NULL)
    {
      res_RESTOREFH.status = nfs4_SetCompoundExport(data);
      if(res_RESTOREFH.status != NFS4_OK)
        {
          LogCrit(COMPONENT_NFS_V4,
                  "Error %d in nfs4_SetCompoundExport", res_RESTOREFH.status);
          return res_RESTOREFH.status;
        }
    }

  /* Copy the data from current FH to saved FH */
  memcpy(data->currentFH.nfs_fh4_val,
         data->savedFH.nfs_fh4_val,
         data->savedFH.nfs_fh4_len);

  data->currentFH.nfs_fh4_len = data->savedFH.nfs_fh4_len;

  /* If current and saved entry are identical, get no references and
     make no changes. */

  if (data->current_entry == data->saved_entry) {
      goto out;
  }

  if (data->current_entry) {
      cache_inode_put(data->current_entry);
      data->current_entry = NULL;
  }

  data->current_entry = data->saved_entry;
  data->current_filetype = data->saved_filetype;

  /* Take another reference.  As of now the filehandle is both saved
     and current and both must be counted.  Protect in case of
     pseudofs handle. */

  if (data->current_entry) {
       if (cache_inode_lru_ref(data->current_entry,
                               LRU_FLAG_NONE) != CACHE_INODE_SUCCESS) {
            resp->nfs_resop4_u.opgetfh.status = NFS4ERR_STALE;
            data->current_entry = NULL;
            return resp->nfs_resop4_u.opgetfh.status;
       }
  }

 out:

  if(isFullDebug(COMPONENT_NFS_V4))
    {
      char str[LEN_FH_STR];
      sprint_fhandle4(str, &data->currentFH);
      LogFullDebug(COMPONENT_NFS_V4,
                   "RESTORE FH: Current FH %s", str);
    }


  return NFS4_OK;
}                               /* nfs4_op_restorefh */
Exemplo n.º 4
0
int _9p_walk(struct _9p_request_data *req9p, void *worker_data,
	     u32 *plenout, char *preply)
{
	char *cursor = req9p->_9pmsg + _9P_HDR_SIZE + _9P_TYPE_SIZE;
	unsigned int i = 0;

	u16 *msgtag = NULL;
	u32 *fid = NULL;
	u32 *newfid = NULL;
	u16 *nwname = NULL;
	u16 *wnames_len;
	char *wnames_str;
	uint64_t fileid;
	cache_inode_status_t cache_status;
	cache_entry_t *pentry = NULL;
	char name[MAXNAMLEN];

	u16 *nwqid;

	struct _9p_fid *pfid = NULL;
	struct _9p_fid *pnewfid = NULL;

	/* Now Get data */
	_9p_getptr(cursor, msgtag, u16);
	_9p_getptr(cursor, fid, u32);
	_9p_getptr(cursor, newfid, u32);
	_9p_getptr(cursor, nwname, u16);

	LogDebug(COMPONENT_9P, "TWALK: tag=%u fid=%u newfid=%u nwname=%u",
		 (u32) *msgtag, *fid, *newfid, *nwname);

	if (*fid >= _9P_FID_PER_CONN)
		return _9p_rerror(req9p, worker_data, msgtag, ERANGE, plenout,
				  preply);

	if (*newfid >= _9P_FID_PER_CONN)
		return _9p_rerror(req9p, worker_data, msgtag, ERANGE, plenout,
				  preply);

	pfid = req9p->pconn->fids[*fid];
	/* Check that it is a valid fid */
	if (pfid == NULL || pfid->pentry == NULL) {
		LogDebug(COMPONENT_9P, "request on invalid fid=%u", *fid);
		return _9p_rerror(req9p, worker_data, msgtag, EIO, plenout,
				  preply);
	}
	op_ctx = &pfid->op_context;
	pnewfid = gsh_calloc(1, sizeof(struct _9p_fid));
	if (pnewfid == NULL)
		return _9p_rerror(req9p, worker_data, msgtag, ERANGE, plenout,
				  preply);

	/* Is this a lookup or a fid cloning operation ? */
	if (*nwname == 0) {
		/* Cloning operation */
		memcpy((char *)pnewfid, (char *)pfid, sizeof(struct _9p_fid));

		/* Set the new fid id */
		pnewfid->fid = *newfid;

		/* This is not a TATTACH fid */
		pnewfid->from_attach = false;

		/* Increments refcount */
		(void) cache_inode_lru_ref(pnewfid->pentry, LRU_REQ_STALE_OK);
	} else {
		/* the walk is in fact a lookup */
		pentry = pfid->pentry;

		for (i = 0; i < *nwname; i++) {
			_9p_getstr(cursor, wnames_len, wnames_str);
			snprintf(name, MAXNAMLEN, "%.*s", *wnames_len,
				 wnames_str);

			LogDebug(COMPONENT_9P,
				 "TWALK (lookup): tag=%u fid=%u newfid=%u (component %u/%u :%s)",
				 (u32) *msgtag, *fid, *newfid, i + 1, *nwname,
				 name);

			if (pnewfid->pentry == pentry)
				pnewfid->pentry = NULL;

			/* refcount +1 */
			cache_status =
			    cache_inode_lookup(pentry, name, &pnewfid->pentry);

			if (pnewfid->pentry == NULL) {
				gsh_free(pnewfid);
				return _9p_rerror(req9p, worker_data, msgtag,
						  _9p_tools_errno(cache_status),
						  plenout, preply);
			}

			if (pentry != pfid->pentry)
				cache_inode_put(pentry);

			pentry = pnewfid->pentry;
		}

		pnewfid->fid = *newfid;
		pnewfid->op_context = pfid->op_context;
		pnewfid->ppentry = pfid->pentry;
		strncpy(pnewfid->name, name, MAXNAMLEN-1);

		/* gdata ref is not hold : the pfid, which use same gdata */
		/*  will be clunked after pnewfid */
		/* This clunk release the gdata */
		pnewfid->gdata = pfid->gdata;

		/* This is not a TATTACH fid */
		pnewfid->from_attach = false;

		cache_status = cache_inode_fileid(pnewfid->pentry, &fileid);
		if (cache_status != CACHE_INODE_SUCCESS) {
			gsh_free(pnewfid);
			return _9p_rerror(req9p, worker_data, msgtag,
					  _9p_tools_errno(cache_status),
					  plenout, preply);
		}

		/* Build the qid */
		/* No cache, we want the client to stay synchronous
		 * with the server */
		pnewfid->qid.version = 0;
		pnewfid->qid.path = fileid;

		pnewfid->specdata.xattr.xattr_id = 0;
		pnewfid->specdata.xattr.xattr_content = NULL;

		switch (pnewfid->pentry->type) {
		case REGULAR_FILE:
		case CHARACTER_FILE:
		case BLOCK_FILE:
		case SOCKET_FILE:
		case FIFO_FILE:
			pnewfid->qid.type = _9P_QTFILE;
			break;

		case SYMBOLIC_LINK:
			pnewfid->qid.type = _9P_QTSYMLINK;
			break;

		case DIRECTORY:
			pnewfid->qid.type = _9P_QTDIR;
			break;

		default:
			LogMajor(COMPONENT_9P,
				 "implementation error, you should not see this message !!!!!!");
			gsh_free(pnewfid);
			return _9p_rerror(req9p, worker_data, msgtag, EINVAL,
					  plenout, preply);
			break;
		}

	}

	/* keep info on new fid */
	req9p->pconn->fids[*newfid] = pnewfid;

	/* As much qid as requested fid */
	nwqid = nwname;

	/* Hold refcount on gdata */
	uid2grp_hold_group_data(pnewfid->gdata);

	/* Build the reply */
	_9p_setinitptr(cursor, preply, _9P_RWALK);
	_9p_setptr(cursor, msgtag, u16);

	_9p_setptr(cursor, nwqid, u16);
	for (i = 0; i < *nwqid; i++) {
		/** @todo: should be different qids
		 * for each directory walked through */
		_9p_setqid(cursor, pnewfid->qid);
	}

	_9p_setendptr(cursor, preply);
	_9p_checkbound(cursor, preply, plenout);

	LogDebug(COMPONENT_9P,
		 "RWALK: tag=%u fid=%u newfid=%u nwqid=%u fileid=%llu pentry=%p refcount=%i",
		 (u32) *msgtag, *fid, *newfid, *nwqid,
		 (unsigned long long)pnewfid->qid.path, pnewfid->pentry,
		 pnewfid->pentry->lru.refcnt);

	return 1;
}
Exemplo n.º 5
0
int _9p_xattrwalk(struct _9p_request_data *req9p, u32 *plenout, char *preply)
{
	char *cursor = req9p->_9pmsg + _9P_HDR_SIZE + _9P_TYPE_SIZE;
	u16 *msgtag = NULL;
	u32 *fid = NULL;
	u32 *attrfid = NULL;
	u16 *name_len;
	char *name_str;
	size_t attrsize = 0;

	fsal_status_t fsal_status;
	char name[MAXNAMLEN];
	fsal_xattrent_t xattrs_arr[XATTRS_ARRAY_LEN];
	int eod_met = false;
	unsigned int nb_xattrs_read = 0;
	unsigned int i = 0;
	char *xattr_cursor = NULL;
	unsigned int tmplen = 0;

	struct _9p_fid *pfid = NULL;
	struct _9p_fid *pxattrfid = NULL;

	/* Get data */
	_9p_getptr(cursor, msgtag, u16);
	_9p_getptr(cursor, fid, u32);
	_9p_getptr(cursor, attrfid, u32);

	LogDebug(COMPONENT_9P, "TXATTRWALK: tag=%u fid=%u attrfid=%u",
		 (u32) *msgtag, *fid, *attrfid);

	_9p_getstr(cursor, name_len, name_str);

	if (*name_len == 0)
		LogDebug(COMPONENT_9P,
			 "TXATTRWALK (component): tag=%u fid=%u attrfid=%u name=(LIST XATTR)",
			 (u32) *msgtag, *fid, *attrfid);
	else
		LogDebug(COMPONENT_9P,
			 "TXATTRWALK (component): tag=%u fid=%u attrfid=%u name=%.*s",
			 (u32) *msgtag, *fid, *attrfid, *name_len, name_str);

	if (*fid >= _9P_FID_PER_CONN)
		return _9p_rerror(req9p, msgtag, ERANGE, plenout, preply);

	if (*attrfid >= _9P_FID_PER_CONN)
		return _9p_rerror(req9p, msgtag, ERANGE, plenout, preply);

	pfid = req9p->pconn->fids[*fid];
	/* Check that it is a valid fid */
	if (pfid == NULL || pfid->pentry == NULL) {
		LogDebug(COMPONENT_9P, "request on invalid fid=%u", *fid);
		return _9p_rerror(req9p, msgtag, EIO, plenout, preply);
	}

	pxattrfid = gsh_calloc(1, sizeof(struct _9p_fid));
	if (pxattrfid == NULL)
		return _9p_rerror(req9p, msgtag, ENOMEM, plenout, preply);

	/* set op_ctx, it will be useful if FSAL is later called */
	_9p_init_opctx(pfid, req9p);

	/* Initiate xattr's fid by copying file's fid in it */
	memcpy((char *)pxattrfid, (char *)pfid, sizeof(struct _9p_fid));

	snprintf(name, MAXNAMLEN, "%.*s", *name_len, name_str);

	pxattrfid->specdata.xattr.xattr_content = gsh_malloc(XATTR_BUFFERSIZE);
	if (pxattrfid->specdata.xattr.xattr_content == NULL) {
		gsh_free(pxattrfid);
		return _9p_rerror(req9p, msgtag, ENOMEM, plenout, preply);
	}

	if (*name_len == 0) {
		/* xattrwalk is used with an empty name,
		 * this is a listxattr request */
		fsal_status =
		    pxattrfid->pentry->obj_handle->obj_ops.list_ext_attrs(
			pxattrfid->pentry->obj_handle,
			FSAL_XATTR_RW_COOKIE,	/* Start with RW cookie,
						 * hiding RO ones */
			 xattrs_arr,
			 XATTRS_ARRAY_LEN, /** @todo fix static length */
			 &nb_xattrs_read,
			 &eod_met);

		if (FSAL_IS_ERROR(fsal_status)) {
			gsh_free(pxattrfid->specdata.xattr.xattr_content);
			gsh_free(pxattrfid);
			return _9p_rerror(req9p, msgtag,
					  _9p_tools_errno
					  (cache_inode_error_convert
					   (fsal_status)), plenout, preply);
		}

		/* if all xattrent are not read,
		 * returns ERANGE as listxattr does */
		if (eod_met != true) {
			gsh_free(pxattrfid->specdata.xattr.xattr_content);
			gsh_free(pxattrfid);
			return _9p_rerror(req9p, msgtag, ERANGE,
					  plenout, preply);
		}

		xattr_cursor = pxattrfid->specdata.xattr.xattr_content;
		attrsize = 0;
		for (i = 0; i < nb_xattrs_read; i++) {
			tmplen =
			    snprintf(xattr_cursor, MAXNAMLEN, "%s",
				     xattrs_arr[i].xattr_name);
			xattr_cursor[tmplen] = '\0';	/* Just to be sure */
			/* +1 for trailing '\0' */
			xattr_cursor += tmplen + 1;
			attrsize += tmplen + 1;

			/* Make sure not to go beyond the buffer */
			if (attrsize > XATTR_BUFFERSIZE) {
				gsh_free(pxattrfid->specdata.xattr.
					 xattr_content);
				gsh_free(pxattrfid);
				return _9p_rerror(req9p, msgtag, ERANGE,
						  plenout, preply);
			}
		}
	} else {
		/* xattrwalk has a non-empty name, use regular setxattr */
		fsal_status =
		    pxattrfid->pentry->obj_handle->obj_ops.
		    getextattr_id_by_name(pxattrfid->pentry->obj_handle,
					  name,
					  &pxattrfid->specdata.xattr.xattr_id);


		if (FSAL_IS_ERROR(fsal_status)) {
			gsh_free(pxattrfid->specdata.xattr.xattr_content);
			gsh_free(pxattrfid);

			/* ENOENT for xattr is ENOATTR */
			if (fsal_status.major == ERR_FSAL_NOENT)
				return _9p_rerror(req9p, msgtag, ENOATTR,
						  plenout, preply);
			else
				return _9p_rerror(req9p, msgtag,
						  _9p_tools_errno
						  (cache_inode_error_convert
						   (fsal_status)), plenout,
						  preply);
		}

		fsal_status =
		    pxattrfid->pentry->obj_handle->obj_ops.
		    getextattr_value_by_name(pxattrfid->pentry->obj_handle,
					     name,
					     pxattrfid->specdata.xattr.
					     xattr_content, XATTR_BUFFERSIZE,
					     &attrsize);

		if (FSAL_IS_ERROR(fsal_status)) {
			gsh_free(pxattrfid->specdata.xattr.xattr_content);
			gsh_free(pxattrfid);

			/* fsal_status.minor is a valid errno code */
			return _9p_rerror(req9p, msgtag,
					  fsal_status.minor, plenout, preply);
		}
	}

	req9p->pconn->fids[*attrfid] = pxattrfid;

	/* Increments refcount as we're manually making a new copy */
	(void) cache_inode_lru_ref(pfid->pentry, LRU_REQ_STALE_OK);

	/* hold reference on gdata */
	uid2grp_hold_group_data(pxattrfid->gdata);

	get_gsh_export_ref(pfid->export);
	get_9p_user_cred_ref(pfid->ucred);

	/* Build the reply */
	_9p_setinitptr(cursor, preply, _9P_RXATTRWALK);
	_9p_setptr(cursor, msgtag, u16);

	_9p_setvalue(cursor, attrsize, u64);

	_9p_setendptr(cursor, preply);
	_9p_checkbound(cursor, preply, plenout);

	LogDebug(COMPONENT_9P,
		 "RXATTRWALK: tag=%u fid=%u attrfid=%u name=%.*s size=%llu",
		 (u32) *msgtag, *fid, *attrfid, *name_len, name_str,
		 (unsigned long long)attrsize);

	return 1;
}				/* _9p_xattrwalk */
Exemplo n.º 6
0
/**
 *
 * @brief Gets an entry by using its fsdata as a key and caches it if needed.
 *
 * Gets an entry by using its fsdata as a key and caches it if needed.
 *
 * If a cache entry is returned, its refcount is incremented by one.
 *
 * It turns out we do need cache_inode_get_located functionality for
 * cases like lookupp on an entry returning itself when it isn't a
 * root.  Therefore, if the 'associated' parameter is equal to the got
 * cache entry, a reference count is incremented but the structure
 * pointed to by attr is NOT filled in.
 *
 * @param[in]     fsdata     File system data
 * @param[out]    attr       The attributes of the got entry
 * @param[in]     context    FSAL credentials
 * @param[in]     associated Entry that may be equal to the got entry
 * @param[out]    status     Returned status
 *
 * @return If successful, the pointer to the entry; NULL otherwise
 *
 */
cache_entry_t *
cache_inode_get(cache_inode_fsal_data_t *fsdata,
                fsal_attrib_list_t *attr,
                fsal_op_context_t *context,
                cache_entry_t *associated,
                cache_inode_status_t *status)
{
    hash_buffer_t key, value;
    cache_entry_t *entry = NULL;
    fsal_status_t fsal_status = {0, 0};
    cache_inode_create_arg_t create_arg = {
        .newly_created_dir = FALSE
    };
    cache_inode_file_type_t type = UNASSIGNED;
    hash_error_t hrc = 0;
    fsal_attrib_list_t fsal_attributes;
    fsal_handle_t *file_handle;
    struct hash_latch latch;

    /* Set the return default to CACHE_INODE_SUCCESS */
    *status = CACHE_INODE_SUCCESS;

    /* Turn the input to a hash key on our own.
     */
    key.pdata = fsdata->fh_desc.start;
    key.len = fsdata->fh_desc.len;

    hrc = HashTable_GetLatch(fh_to_cache_entry_ht, &key, &value,
                             FALSE,
                             &latch);

    if ((hrc != HASHTABLE_SUCCESS) &&
            (hrc != HASHTABLE_ERROR_NO_SUCH_KEY)) {
        /* This should not happened */
        *status = CACHE_INODE_HASH_TABLE_ERROR;
        LogCrit(COMPONENT_CACHE_INODE,
                "Hash access failed with code %d"
                " - this should not have happened",
                hrc);
        return NULL;
    }

    if (hrc == HASHTABLE_SUCCESS) {
        /* Entry exists in the cache and was found */
        entry = value.pdata;
        /* take an extra reference within the critical section */
        if (cache_inode_lru_ref(entry, LRU_REQ_INITIAL) !=
                CACHE_INODE_SUCCESS) {
            /* Dead entry.  Treat like a lookup failure. */
            entry = NULL;
        } else {
            if (entry == associated) {
                /* Take a quick exit so we don't invert lock
                   ordering. */
                HashTable_ReleaseLatched(fh_to_cache_entry_ht, &latch);
                return entry;
            }
        }
    }
    HashTable_ReleaseLatched(fh_to_cache_entry_ht, &latch);

    if (!context) {
        /* Upcalls have no access to fsal_op_context_t,
           so just return the entry without revalidating it or
           creating a new one. */
        if (entry == NULL) {
            *status = CACHE_INODE_NOT_FOUND;
        }
        return entry;
    }

    if (!entry) {
        /* Cache miss, allocate a new entry */
        file_handle = (fsal_handle_t *) fsdata->fh_desc.start;
        /* First, call FSAL to know what the object is */
        fsal_attributes.asked_attributes = cache_inode_params.attrmask;
        fsal_status
            = FSAL_getattrs(file_handle, context, &fsal_attributes);
        if (FSAL_IS_ERROR(fsal_status)) {
            *status = cache_inode_error_convert(fsal_status);
            LogDebug(COMPONENT_CACHE_INODE,
                     "cache_inode_get: cache_inode_status=%u "
                     "fsal_status=%u,%u ", *status,
                     fsal_status.major,
                     fsal_status.minor);
            return NULL;
        }

        /* The type has to be set in the attributes */
        if (!FSAL_TEST_MASK(fsal_attributes.supported_attributes,
                            FSAL_ATTR_TYPE)) {
            *status = CACHE_INODE_FSAL_ERROR;
            return NULL;
        }

        /* Get the cache_inode file type */
        type = cache_inode_fsal_type_convert(fsal_attributes.type);
        if (type == SYMBOLIC_LINK) {
            fsal_attributes.asked_attributes = cache_inode_params.attrmask;
            fsal_status =
                FSAL_readlink(file_handle, context,
                              &create_arg.link_content,
                              &fsal_attributes);

            if (FSAL_IS_ERROR(fsal_status)) {
                *status = cache_inode_error_convert(fsal_status);
                return NULL;
            }
        }
        if ((entry
                = cache_inode_new_entry(fsdata,
                                        &fsal_attributes,
                                        type,
                                        &create_arg,
                                        status)) == NULL) {
            return NULL;
        }

    }

    *status = CACHE_INODE_SUCCESS;

    /* This is the replacement for cache_inode_renew_entry.  Rather
       than calling that function at the start of every cache_inode
       call with the inode locked, we call cache_inode_check trust to
       perform 'heavyweight' (timed expiration of cached attributes,
       getattr-based directory trust) checks the first time after
       getting an inode.  It does all of the checks read-locked and
       only acquires a write lock if there's something requiring a
       change.

       There is a second light-weight check done before use of cached
       data that checks whether the bits saying that inode attributes
       or inode content are trustworthy have been cleared by, for
       example, FSAL_CB.

       To summarize, the current implementation is that policy-based
       trust of validity is checked once per logical series of
       operations at cache_inode_get, and asynchronous trust is
       checked with use (when the attributes are locked for reading,
       for example.) */

    if ((*status = cache_inode_check_trust(entry,
                                           context))
            != CACHE_INODE_SUCCESS) {
        goto out_put;
    }

    /* Set the returned attributes */
    *status = cache_inode_lock_trust_attrs(entry, context);

    /* cache_inode_lock_trust_attrs may fail, in that case, the
       attributes are wrong and pthread_rwlock_unlock can't be called
       again */
    if(*status != CACHE_INODE_SUCCESS)
    {
        goto out_put;
    }
    *attr = entry->attributes;
    pthread_rwlock_unlock(&entry->attr_lock);

    return entry;

out_put:
    cache_inode_put(entry);
    entry = NULL;
    return entry;
} /* cache_inode_get */
Exemplo n.º 7
0
int _9p_xattrwalk(struct _9p_request_data *req9p, void *worker_data,
		  u32 *plenout, char *preply)
{
	char *cursor = req9p->_9pmsg + _9P_HDR_SIZE + _9P_TYPE_SIZE;
	u16 *msgtag = NULL;
	u32 *fid = NULL;
	u32 *attrfid = NULL;
	u16 *name_len;
	char *name_str;
	u64 attrsize = 0LL;

	fsal_status_t fsal_status;
	char name[MAXNAMLEN];
	fsal_xattrent_t xattrs_tab[255];
	int eod_met = false;
	unsigned int nb_xattrs_read = 0;
	unsigned int i = 0;
	char *xattr_cursor = NULL;
	unsigned int tmplen = 0;

	struct _9p_fid *pfid = NULL;
	struct _9p_fid *pxattrfid = NULL;

	/* Get data */
	_9p_getptr(cursor, msgtag, u16);
	_9p_getptr(cursor, fid, u32);
	_9p_getptr(cursor, attrfid, u32);

	LogDebug(COMPONENT_9P, "TXATTRWALK: tag=%u fid=%u attrfid=%u",
		 (u32) *msgtag, *fid, *attrfid);

	_9p_getstr(cursor, name_len, name_str);

	if (*name_len == 0)
		LogDebug(COMPONENT_9P,
			 "TXATTRWALK (component): tag=%u fid=%u attrfid=%u name=(LIST XATTR)",
			 (u32) *msgtag, *fid, *attrfid);
	else
		LogDebug(COMPONENT_9P,
			 "TXATTRWALK (component): tag=%u fid=%u attrfid=%u name=%.*s",
			 (u32) *msgtag, *fid, *attrfid, *name_len, name_str);

	if (*fid >= _9P_FID_PER_CONN)
		return _9p_rerror(req9p, worker_data, msgtag, ERANGE, plenout,
				  preply);

	if (*attrfid >= _9P_FID_PER_CONN)
		return _9p_rerror(req9p, worker_data, msgtag, ERANGE, plenout,
				  preply);

	pfid = req9p->pconn->fids[*fid];
	/* Check that it is a valid fid */
	if (pfid == NULL || pfid->pentry == NULL) {
		LogDebug(COMPONENT_9P, "request on invalid fid=%u", *fid);
		return _9p_rerror(req9p, worker_data, msgtag, EIO, plenout,
				  preply);
	}

	pxattrfid = gsh_calloc(1, sizeof(struct _9p_fid));
	if (pxattrfid == NULL)
		return _9p_rerror(req9p, worker_data, msgtag, ENOMEM, plenout,
				  preply);

	/* Initiate xattr's fid by copying file's fid in it */
	memcpy((char *)pxattrfid, (char *)pfid, sizeof(struct _9p_fid));

	snprintf(name, MAXNAMLEN, "%.*s", *name_len, name_str);

	pxattrfid->specdata.xattr.xattr_content = gsh_malloc(XATTR_BUFFERSIZE);
	if (pxattrfid->specdata.xattr.xattr_content == NULL) {
		gsh_free(pxattrfid);
		return _9p_rerror(req9p, worker_data, msgtag, ENOMEM, plenout,
				  preply);
	}

	if (*name_len == 0) {
		/* xattrwalk is used with an empty name,
		 * this is a listxattr request */
		fsal_status =
		    pxattrfid->pentry->obj_handle->ops->list_ext_attrs(
			pxattrfid->pentry->obj_handle, &pfid->op_context,
			FSAL_XATTR_RW_COOKIE,	/* Start with RW cookie,
						 * hiding RO ones */
			 xattrs_tab, 100,	/* static array size for now */
			 &nb_xattrs_read,
			 &eod_met);

		if (FSAL_IS_ERROR(fsal_status)) {
			gsh_free(pxattrfid->specdata.xattr.xattr_content);
			gsh_free(pxattrfid);
			return _9p_rerror(req9p, worker_data, msgtag,
					  _9p_tools_errno
					  (cache_inode_error_convert
					   (fsal_status)), plenout, preply);
		}

		/* if all xattrent are not read,
		 * returns ERANGE as listxattr does */
		if (eod_met != TRUE) {
			gsh_free(pxattrfid->specdata.xattr.xattr_content);
			gsh_free(pxattrfid);
			return _9p_rerror(req9p, worker_data, msgtag, ERANGE,
					  plenout, preply);
		}

		xattr_cursor = pxattrfid->specdata.xattr.xattr_content;
		attrsize = 0LL;
		for (i = 0; i < nb_xattrs_read; i++) {
			tmplen =
			    snprintf(xattr_cursor, MAXNAMLEN, "%s",
				     xattrs_tab[i].xattr_name);
			xattr_cursor[tmplen] = '\0';	/* Just to be sure */
			/* +1 for trailing '\0' */
			xattr_cursor += tmplen + 1;
			attrsize += tmplen + 1;

			/* Make sure not to go beyond the buffer */
			if (attrsize > XATTR_BUFFERSIZE) {
				gsh_free(pxattrfid->specdata.xattr.
					 xattr_content);
				gsh_free(pxattrfid);
				return _9p_rerror(req9p, worker_data, msgtag,
						  ERANGE, plenout, preply);
			}
		}
	} else {
		/* xattrwalk has a non-empty name, use regular setxattr */
		fsal_status =
		    pxattrfid->pentry->obj_handle->ops->
		    getextattr_id_by_name(pxattrfid->pentry->obj_handle,
					  &pfid->op_context, name,
					  &pxattrfid->specdata.xattr.xattr_id);


		if (FSAL_IS_ERROR(fsal_status)) {
			gsh_free(pxattrfid->specdata.xattr.xattr_content);
			gsh_free(pxattrfid);

			/* Hook dedicated to ACL management. When attributes
			 * system.posix_acl_access is used, it can't be
			 * created, but can be written anyway.
			 * To do this, return ENODATA instead of ENOATTR
			 * In this case, we do created what's needed to
			 * setxattr() into the special xattr */
			if (!strncmp(name,
				     "system.posix_acl_access",
				     MAXNAMLEN))
				return _9p_rerror(req9p, worker_data, msgtag,
						  ENODATA, plenout, preply);
			/* ENOENT for xattr is ENOATTR */
			if (fsal_status.major == ERR_FSAL_NOENT)
				return _9p_rerror(req9p, worker_data, msgtag,
						  ENOATTR, plenout, preply);
			else
				return _9p_rerror(req9p, worker_data, msgtag,
						  _9p_tools_errno
						  (cache_inode_error_convert
						   (fsal_status)), plenout,
						  preply);
		}

		fsal_status =
		    pxattrfid->pentry->obj_handle->ops->
		    getextattr_value_by_name(pxattrfid->pentry->obj_handle,
					     &pfid->op_context, name,
					     pxattrfid->specdata.xattr.
					     xattr_content, XATTR_BUFFERSIZE,
					     &attrsize);

		if (FSAL_IS_ERROR(fsal_status)) {
			gsh_free(pxattrfid->specdata.xattr.xattr_content);
			gsh_free(pxattrfid);

			if (fsal_status.minor == ENODATA) {
				return _9p_rerror(req9p, worker_data, msgtag,
						  ENODATA, plenout, preply);
			}

			return _9p_rerror(req9p, worker_data, msgtag,
					  _9p_tools_errno
					  (cache_inode_error_convert
					   (fsal_status)), plenout, preply);
		}
	}

	req9p->pconn->fids[*attrfid] = pxattrfid;

	/* Increments refcount so it won't fall below 0 when we clunk later */
	cache_inode_lru_ref(pxattrfid->pentry, LRU_REQ_INITIAL);

	/* Build the reply */
	_9p_setinitptr(cursor, preply, _9P_RXATTRWALK);
	_9p_setptr(cursor, msgtag, u16);

	_9p_setvalue(cursor, attrsize, u64);

	_9p_setendptr(cursor, preply);
	_9p_checkbound(cursor, preply, plenout);

	LogDebug(COMPONENT_9P,
		 "RXATTRWALK: tag=%u fid=%u attrfid=%u name=%.*s size=%llu",
		 (u32) *msgtag, *fid, *attrfid, *name_len, name_str,
		 (unsigned long long)attrsize);

	return 1;
}				/* _9p_xattrwalk */