Exemplo n.º 1
0
static void nfs4_acls_test(void)
{
    int i = 0;
    fsal_acl_data_t acldata, acldata2;
    fsal_ace_t *ace = NULL;
    fsal_acl_t *acl = NULL;
    fsal_acl_status_t status;

    acldata.naces = 3;
    acldata.aces = nfs4_ace_alloc(3);
    LogDebug(COMPONENT_NFS_V4_ACL, "acldata.aces = %p", acldata.aces);

    ace = acldata.aces;

    for (i = 0; i < 3; i++) {
        ace->type = i;
        ace->perm = i;
        ace->flag = i;
        ace->who.uid = i;
        ace++;
    }

    acl = nfs4_acl_new_entry(&acldata, &status);
    PTHREAD_RWLOCK_rdlock(&acl->lock);
    LogDebug(COMPONENT_NFS_V4_ACL, "acl = %p, ref = %u, status = %u", acl,
             acl->ref, status);
    PTHREAD_RWLOCK_unlock(&acl->lock);

    acldata2.naces = 3;
    acldata2.aces = nfs4_ace_alloc(3);

    LogDebug(COMPONENT_NFS_V4_ACL, "acldata2.aces = %p", acldata2.aces);

    ace = acldata2.aces;

    for (i = 0; i < 3; i++) {
        ace->type = i;
        ace->perm = i;
        ace->flag = i;
        ace->who.uid = i;
        ace++;
    }

    acl = nfs4_acl_new_entry(&acldata2, &status);
    PTHREAD_RWLOCK_rdlock(&acl->lock);
    LogDebug(COMPONENT_NFS_V4_ACL,
             "re-access: acl = %p, ref = %u, status = %u", acl, acl->ref,
             status);
    PTHREAD_RWLOCK_unlock(&acl->lock);

    nfs4_acl_release_entry(acl, &status);
    PTHREAD_RWLOCK_rdlock(&acl->lock);
    LogDebug(COMPONENT_NFS_V4_ACL,
             "release: acl = %p, ref = %u, status = %u", acl, acl->ref,
             status);
    PTHREAD_RWLOCK_unlock(&acl->lock);

    nfs4_acl_release_entry(acl, &status);
}
Exemplo n.º 2
0
static void nfs4_acls_test()
{
  int i = 0;
  fsal_acl_data_t acldata;
  fsal_ace_t *pace = NULL;
  fsal_acl_t *pacl = NULL;
  fsal_acl_status_t status;

  acldata.naces = 3;
  acldata.aces = nfs4_ace_alloc(3);
  LogDebug(COMPONENT_NFS_V4_ACL, "&acldata.aces = %p", &acldata.aces);

  pace = acldata.aces;

  for(i = 0; i < 3; i++)
    {
      pace->type = i;
      pace->perm = i;
      pace->flag = i;
      pace->who.uid = i;
      pace++;
    }

  pacl = nfs4_acl_new_entry(&acldata, &status);
  nfs4_acl_entry_inc_ref(pacl);
  P_r(&pacl->lock);
  LogDebug(COMPONENT_NFS_V4_ACL, "pacl = %p, ref = %u, status = %u", pacl, pacl->ref, status);
  V_r(&pacl->lock);

  pacl = nfs4_acl_new_entry(&acldata, &status);
  nfs4_acl_entry_inc_ref(pacl);
  P_r(&pacl->lock);
  LogDebug(COMPONENT_NFS_V4_ACL, "re-access: pacl = %p, ref = %u, status = %u", pacl, pacl->ref, status);
  V_r(&pacl->lock);

  nfs4_acl_release_entry(pacl, &status);
  P_r(&pacl->lock);
  LogDebug(COMPONENT_NFS_V4_ACL, "release: pacl = %p, ref = %u, status = %u", pacl, pacl->ref, status);
  V_r(&pacl->lock);

  nfs4_acl_release_entry(pacl, &status);
}
Exemplo n.º 3
0
/**
 * Garbagge NFS4 ACLs if any.
 */
static void cache_inode_gc_acl(cache_entry_t * pentry)
{
  fsal_acl_status_t status = NFS_V4_ACL_SUCCESS;
  fsal_acl_t *pacl = NULL;

  switch (pentry->internal_md.type)
    {
    case REGULAR_FILE:
      pacl = pentry->object.file.attributes.acl;
      break;

    case SYMBOLIC_LINK:
      pacl = pentry->object.symlink.attributes.acl;
      break;

    case FS_JUNCTION:
    case DIR_BEGINNING:
      pacl = pentry->object.dir_begin.attributes.acl;
      break;

    case DIR_CONTINUE:
      pacl = pentry->object.dir_cont.pdir_begin->object.dir_begin.attributes.acl;
      break;

    case SOCKET_FILE:
    case FIFO_FILE:
    case BLOCK_FILE:
    case CHARACTER_FILE:
      pacl = pentry->object.special_obj.attributes.acl;
      break;

    case UNASSIGNED:
    case RECYCLED:
      LogDebug(COMPONENT_CACHE_INODE_GC,
                   "Unexpected UNNASIGNED or RECYLCED type in cache_inode_gc_acl");
      break;
    }

  /* Release an acl. */
  if(pacl)
    {
      LogDebug(COMPONENT_CACHE_INODE_GC, "cache_inode_gc_acl: md_type = %d, acl  = %p",
               pentry->internal_md.type, pacl);

      nfs4_acl_release_entry(pacl, &status);

      if(status != NFS_V4_ACL_SUCCESS)
        LogEvent(COMPONENT_CACHE_INODE_GC, "cache_inode_gc_acl: Failed to gc acl, status=%d", status);
    }
}                               /* cache_inode_gc_acl */
Exemplo n.º 4
0
fsal_status_t lzfs_int_getacl(struct lzfs_fsal_export *lzfs_export, uint32_t inode,
                              uint32_t owner_id, fsal_acl_t **fsal_acl) {
	if (*fsal_acl) {
		int acl_status = nfs4_acl_release_entry(*fsal_acl);
		if (acl_status != NFS_V4_ACL_SUCCESS) {
			LogCrit(COMPONENT_FSAL, "Failed to release old acl, status=%d", acl_status);
		}
		*fsal_acl = NULL;
	}

	liz_acl_t *acl = NULL;
	int rc = liz_cred_getacl(lzfs_export->lzfs_instance, op_ctx->creds, inode, &acl);
	if (rc < 0) {
		LogFullDebug(COMPONENT_FSAL, "getacl status=%s export=%" PRIu16 " inode=%" PRIu32,
		             liz_error_string(liz_last_err()), lzfs_export->export.export_id, inode);
		return lzfs_fsal_last_err();
	}
Exemplo n.º 5
0
/**
 * @brief Convert FSAL ACLs to PanFS ACLs
 *
 * @param[in] attrib	Source FSAL attribute list
 * @param[in] panacl	Target PanFS ACL set
 * @return FSAL Status
 */
static fsal_status_t fsal_acl_2_panfs_acl(struct attrlist *attrib,
		struct pan_fs_acl_s *panacl)
{
	fsal_errors_t ret = ERR_FSAL_NO_ERROR;
	struct pan_fs_ace_s *panace;
	fsal_ace_t *ace = NULL;
	fsal_acl_t *acl = NULL;

	/* sanity checks */
	if (!attrib || !attrib->acl || !panacl)
		return fsalstat(ERR_FSAL_FAULT, EFAULT);

	if (attrib->acl->naces > panacl->naces) {
		/* Too many ACEs for storing */
		return fsalstat(ERR_FSAL_INVAL, EFAULT);
	}

	/* Create Panfs acl data. */
	panacl->naces = attrib->acl->naces;
	LogDebug(COMPONENT_FSAL, "Converting %u aces:", panacl->naces);

	for (ace = attrib->acl->aces, panace = panacl->aces;
	     ace < attrib->acl->aces + attrib->acl->naces; ace++, panace++) {
		fsal_print_ace(COMPONENT_FSAL, NIV_DEBUG, ace);
		panace->info = fsal_to_panace_info(ace->type, ace->flag);
		if (panace->info == (uint16_t)-1) {
			ret = ERR_FSAL_INVAL;
			goto fail;
		}
		panace->permissions = fsal_perm_to_panace_perm(ace->perm);
		fsal_id_to_panace_id(ace, &panace->identity);
	}

	return fsalstat(ERR_FSAL_NO_ERROR, 0);
fail:
	(void)nfs4_acl_release_entry(acl);
	return fsalstat(ret, 0);
}
Exemplo n.º 6
0
/**
 * @brief Set the attributes for a file.
 *
 * This function sets the attributes of a file, both in the cache and
 * in the underlying filesystem.
 *
 * @param[in]     entry   Entry whose attributes are to be set
 * @param[in,out] attr    Attributes to set/result of set
 *
 * @retval CACHE_INODE_SUCCESS if operation is a success
 */
cache_inode_status_t
cache_inode_setattr(cache_entry_t *entry,
		    struct attrlist *attr,
		    bool is_open_write)
{
	struct fsal_obj_handle *obj_handle = entry->obj_handle;
	fsal_status_t fsal_status = { 0, 0 };
	fsal_acl_t *saved_acl = NULL;
	fsal_acl_status_t acl_status = 0;
	cache_inode_status_t status = CACHE_INODE_SUCCESS;
	uint64_t before;

	/* True if we have taken the content lock on 'entry' */
	bool content_locked = false;

	if ((attr->mask & (ATTR_SIZE | ATTR4_SPACE_RESERVED))
	     && (entry->type != REGULAR_FILE)) {
		LogWarn(COMPONENT_CACHE_INODE,
			"Attempt to truncate non-regular file: type=%d",
			entry->type);
		status = CACHE_INODE_BAD_TYPE;
	}

	/* Is it allowed to change times ? */
	if (!op_ctx->fsal_export->ops->fs_supports(op_ctx->fsal_export,
						    fso_cansettime)
	    &&
	    (FSAL_TEST_MASK
	     (attr->mask,
	      (ATTR_ATIME | ATTR_CREATION | ATTR_CTIME | ATTR_MTIME)))) {
		status = CACHE_INODE_INVALID_ARGUMENT;
		goto out;
	}

	/* Get wrlock on attr_lock and verify attrs */
	status = cache_inode_lock_trust_attrs(entry, true);
	if (status != CACHE_INODE_SUCCESS)
		return status;

	/* Do permission checks */
	status = cache_inode_check_setattr_perms(entry, attr, is_open_write);
	if (status != CACHE_INODE_SUCCESS)
		goto unlock;

	if (attr->mask & (ATTR_SIZE | ATTR4_SPACE_RESERVED)) {
		PTHREAD_RWLOCK_wrlock(&entry->content_lock);
		content_locked = true;
	}

	saved_acl = obj_handle->attributes.acl;
	before = obj_handle->attributes.change;
	fsal_status = obj_handle->ops->setattrs(obj_handle, attr);
	if (FSAL_IS_ERROR(fsal_status)) {
		status = cache_inode_error_convert(fsal_status);
		if (fsal_status.major == ERR_FSAL_STALE) {
			LogEvent(COMPONENT_CACHE_INODE,
				 "FSAL returned STALE from truncate");
			cache_inode_kill_entry(entry);
		}
		goto unlock;
	}
	fsal_status = obj_handle->ops->getattrs(obj_handle);
	*attr = obj_handle->attributes;
	if (FSAL_IS_ERROR(fsal_status)) {
		status = cache_inode_error_convert(fsal_status);
		if (fsal_status.major == ERR_FSAL_STALE) {
			LogEvent(COMPONENT_CACHE_INODE,
				 "FSAL returned STALE from setattrs");
			cache_inode_kill_entry(entry);
		}
		goto unlock;
	}
	if (before == obj_handle->attributes.change)
		obj_handle->attributes.change++;
	/* Decrement refcount on saved ACL */
	nfs4_acl_release_entry(saved_acl, &acl_status);
	if (acl_status != NFS_V4_ACL_SUCCESS)
		LogCrit(COMPONENT_CACHE_INODE,
			"Failed to release old acl, status=%d", acl_status);

	cache_inode_fixup_md(entry);

	/* Copy the complete set of new attributes out. */

	*attr = entry->obj_handle->attributes;

	status = CACHE_INODE_SUCCESS;

unlock:
	if (content_locked)
		PTHREAD_RWLOCK_unlock(&entry->content_lock);
	PTHREAD_RWLOCK_unlock(&entry->attr_lock);

out:
	return status;
}
Exemplo n.º 7
0
/**
 * @brief Implement actual work of removing file
 *
 * Actually remove an entry from the directory.  Assume that the
 * directory contents and attributes are locked for writes.  The
 * attribute lock is released unless keep_md_lock is TRUE.
 *
 * @param[in] entry   Entry for the parent directory to be managed.
 * @param[in] name    Name of the entry that we are looking for in the cache.
 * @param[in] context FSAL credentials
 * @param[in] status  Returned status
 * @param[in] flags   Flags to control lock retention
 *
 * @return CACHE_INODE_SUCCESS if operation is a success
 *
 */
cache_inode_status_t
cache_inode_remove_impl(cache_entry_t *entry,
                        fsal_name_t *name,
                        fsal_op_context_t *context,
                        cache_inode_status_t *status,
                        uint32_t flags)
{
     cache_entry_t *to_remove_entry = NULL;
     fsal_status_t fsal_status = {0, 0};
#ifdef _USE_NFS4_ACL
     fsal_acl_t *saved_acl = NULL;
     fsal_acl_status_t acl_status = 0;
#endif /* _USE_NFS4_ACL */

     if(entry->type != DIRECTORY) {
          *status = CACHE_INODE_BAD_TYPE;
          goto out;
     }

     if (!(flags & CACHE_INODE_FLAG_CONTENT_HAVE)) {
          pthread_rwlock_rdlock(&entry->content_lock);
          flags |= CACHE_INODE_FLAG_CONTENT_HAVE;
     }

     /* Factor this somewhat.  In the case where the directory hasn't
        been populated, the entry may not exist in the cache and we'd
        be bringing it in just to dispose of it. */

     /* Looks up for the entry to remove */
     if ((to_remove_entry
          = cache_inode_lookup_impl(entry,
                                    name,
                                    context,
                                    status)) == NULL) {
          goto out;
     }

     /* Lock the attributes (so we can decrement the link count) */
     pthread_rwlock_wrlock(&to_remove_entry->attr_lock);

     LogDebug(COMPONENT_CACHE_INODE,
              "---> Cache_inode_remove : %s", name->name);


#ifdef _USE_NFS4_ACL
     saved_acl = entry->attributes.acl;
#endif /* _USE_NFS4_ACL */
     fsal_status = FSAL_unlink(&entry->handle,
                               name,
                               context,
                               &entry->attributes);

     if (FSAL_IS_ERROR(fsal_status)) {
          *status = cache_inode_error_convert(fsal_status);
          if (fsal_status.major == ERR_FSAL_STALE) {
               cache_inode_kill_entry(entry);
          }
          goto unlock;
     } else {
#ifdef _USE_NFS4_ACL
          /* Decrement refcount on saved ACL */
          nfs4_acl_release_entry(saved_acl, &acl_status);
          if (acl_status != NFS_V4_ACL_SUCCESS) {
               LogCrit(COMPONENT_CACHE_INODE,
                       "Failed to release old acl, status=%d",
                       acl_status);
          }
#endif /* _USE_NFS4_ACL */
     }
     cache_inode_fixup_md(entry);

     if ((flags & CACHE_INODE_FLAG_ATTR_HAVE) &&
         !(flags & CACHE_INODE_FLAG_ATTR_HOLD)) {
          pthread_rwlock_unlock(&entry->attr_lock);
     }

     /* Remove the entry from parent dir_entries avl */
     cache_inode_remove_cached_dirent(entry, name, status);

     LogFullDebug(COMPONENT_CACHE_INODE,
                  "cache_inode_remove_cached_dirent: status=%d", *status);

     /* Update the attributes for the removed entry */

     if ((to_remove_entry->type != DIRECTORY) &&
         (to_remove_entry->attributes.numlinks > 1)) {
          if ((*status = cache_inode_refresh_attrs(to_remove_entry,
                                                   context))
              != CACHE_INODE_SUCCESS) {
               goto unlock;
          }
     } else {
          /* Otherwise our count is zero, or it was an empty
             directory. */
          to_remove_entry->attributes.numlinks = 0;
     }

     /* Now, delete "to_remove_entry" from the cache inode and free
        its associated resources, but only if numlinks == 0 */
     if (to_remove_entry->attributes.numlinks == 0) {
          /* Destroy the entry when everyone's references to it have
             been relinquished.  Most likely now. */
          pthread_rwlock_unlock(&to_remove_entry->attr_lock);
          /* Kill off the sentinel reference (and mark the entry so
             it doesn't get recycled while a reference exists.) */
          cache_inode_lru_kill(to_remove_entry);
     } else {
     unlock:

          pthread_rwlock_unlock(&to_remove_entry->attr_lock);
     }

out:
     if ((flags & CACHE_INODE_FLAG_CONTENT_HAVE) &&
         !(flags & CACHE_INODE_FLAG_CONTENT_HOLD)) {
          pthread_rwlock_unlock(&entry->content_lock);
     }

     /* This is for the reference taken by lookup */
     if (to_remove_entry)
       {
         cache_inode_put(to_remove_entry);
       }

     return *status;
}
Exemplo n.º 8
0
/**
 *
 * cache_inode_setattrs: set the attributes for an entry located in the cache by its address. 
 * 
 * Sets the attributes for an entry located in the cache by its address. Attributes are provided 
 * with compliance to the underlying FSAL semantics. Attributes that are set are returned in "*pattr".
 *
 * @param pentry_parent [IN] entry for the parent directory to be managed.
 * @param pattr [INOUT] attributes for the entry that we have found. Out: attributes set.
 * @param ht [INOUT] hash table used for the cache, unused in this call.
 * @param pclient [INOUT] ressource allocated by the client for the nfs management.
 * @param pcontext [IN] FSAL credentials 
 * @param pstatus [OUT] returned status.
 * 
 * @return CACHE_INODE_SUCCESS if operation is a success \n
 * @return CACHE_INODE_LRU_ERROR if allocation error occured when validating the entry
 *
 */
cache_inode_status_t cache_inode_setattr(cache_entry_t * pentry, fsal_attrib_list_t * pattr, hash_table_t * ht, /* Unused, kept for protototype's homogeneity */
                                         cache_inode_client_t * pclient,
                                         fsal_op_context_t * pcontext,
                                         cache_inode_status_t * pstatus)
{
  fsal_handle_t *pfsal_handle = NULL;
  fsal_status_t fsal_status;
  fsal_attrib_list_t *p_object_attributes = NULL;
  fsal_attrib_list_t result_attributes;
  fsal_attrib_list_t truncate_attributes;

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

  /* stat */
  pclient->stat.nb_call_total += 1;
  pclient->stat.func_stats.nb_call[CACHE_INODE_SETATTR] += 1;

  /* Lock the entry */
  P_w(&pentry->lock);

  switch (pentry->internal_md.type)
    {
    case REGULAR_FILE:
      pfsal_handle = &pentry->object.file.handle;
      break;

    case SYMBOLIC_LINK:
      assert(pentry->object.symlink);
      pfsal_handle = &pentry->object.symlink->handle;
      break;

    case FS_JUNCTION:
    case DIRECTORY:
      pfsal_handle = &pentry->object.dir.handle;
      break;

    case CHARACTER_FILE:
    case BLOCK_FILE:
    case SOCKET_FILE:
    case FIFO_FILE:
      pfsal_handle = &pentry->object.special_obj.handle;
      break;

    case UNASSIGNED:
    case RECYCLED:
      LogCrit(COMPONENT_CACHE_INODE,
              "WARNING: unknown source pentry type: internal_md.type=%d, line %d in file %s",
              pentry->internal_md.type, __LINE__, __FILE__);
      *pstatus = CACHE_INODE_BAD_TYPE;
      return *pstatus;
    }

  /* Call FSAL to set the attributes */
  /* result_attributes.asked_attributes = pattr->asked_attributes ; */

  /* mod Th.Leibovici on 2006/02/13
   * We ask back all standard attributes, in case they have been modified
   * by another program (pftp, rcpd...)
   */

  memset(&result_attributes, 0, sizeof(fsal_attrib_list_t));
  result_attributes.asked_attributes = pclient->attrmask;
  /* end of mod */

#ifdef _USE_MFSL
  fsal_status =
      MFSL_setattrs(&pentry->mobject, pcontext, &pclient->mfsl_context, pattr,
                    &result_attributes, NULL);
#else
  fsal_status = FSAL_setattrs(pfsal_handle, pcontext, pattr, &result_attributes);
#endif
  if(FSAL_IS_ERROR(fsal_status))
    {
      *pstatus = cache_inode_error_convert(fsal_status);
      V_w(&pentry->lock);

      /* stat */
      pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_SETATTR] += 1;

      if(fsal_status.major == ERR_FSAL_STALE)
        {
          cache_inode_status_t kill_status;

          LogEvent(COMPONENT_CACHE_INODE,
                   "cache_inode_setattr: Stale FSAL File Handle detected for pentry = %p",
                   pentry);

          if(cache_inode_kill_entry(pentry, NO_LOCK, ht, pclient, &kill_status) !=
             CACHE_INODE_SUCCESS)
            LogCrit(COMPONENT_CACHE_INODE,
                    "cache_inode_setattr: Could not kill entry %p, status = %u",
                    pentry, kill_status);

          *pstatus = CACHE_INODE_FSAL_ESTALE;
        }

      return *pstatus;
    }

  if(pattr->asked_attributes & FSAL_ATTR_SIZE)
    {
      truncate_attributes.asked_attributes = pclient->attrmask;

      fsal_status = FSAL_truncate(pfsal_handle,
                                  pcontext, pattr->filesize, NULL, &truncate_attributes);
      if(FSAL_IS_ERROR(fsal_status))
        {
          *pstatus = cache_inode_error_convert(fsal_status);
          V_w(&pentry->lock);

          /* stat */
          pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_SETATTR] += 1;

          if(fsal_status.major == ERR_FSAL_STALE)
            {
              cache_inode_status_t kill_status;

              LogEvent(COMPONENT_CACHE_INODE,
                       "cache_inode_setattr: Stale FSAL File Handle detected for pentry = %p",
                       pentry);

              if(cache_inode_kill_entry(pentry, NO_LOCK, ht, pclient, &kill_status) !=
                 CACHE_INODE_SUCCESS)
                LogCrit(COMPONENT_CACHE_INODE,
                        "cache_inode_setattr: Could not kill entry %p, status = %u",
                        pentry, kill_status);

              *pstatus = CACHE_INODE_FSAL_ESTALE;
            }

          return *pstatus;
        }

    }

  /* Keep the new attribute in cache */
  switch (pentry->internal_md.type)
    {
    case REGULAR_FILE:
      p_object_attributes = &(pentry->object.file.attributes);
      break;

    case SYMBOLIC_LINK:
      assert(pentry->object.symlink);
      p_object_attributes = &(pentry->object.symlink->attributes);
      break;

    case FS_JUNCTION:
    case DIRECTORY:
      p_object_attributes = &(pentry->object.dir.attributes);
      break;

    case CHARACTER_FILE:
    case BLOCK_FILE:
    case SOCKET_FILE:
    case FIFO_FILE:
      p_object_attributes = &(pentry->object.special_obj.attributes);
      break;

    case UNASSIGNED:
    case RECYCLED:
      LogCrit(COMPONENT_CACHE_INODE,
              "WARNING: unknown source pentry type: internal_md.type=%d, line %d in file %s",
              pentry->internal_md.type, __LINE__, __FILE__);
      *pstatus = CACHE_INODE_BAD_TYPE;
      return *pstatus;
    }

  /* Update the cached attributes */
  if((result_attributes.asked_attributes & FSAL_ATTR_SIZE) ||
     (result_attributes.asked_attributes & FSAL_ATTR_SPACEUSED))
    {

      if(pentry->internal_md.type == REGULAR_FILE)
        {
          if(pentry->object.file.pentry_content == NULL)
            {
              /* Operation on a non data cached file */
              p_object_attributes->filesize = result_attributes.filesize;
              p_object_attributes->spaceused = result_attributes.filesize;      /* Unclear hook here. BUGAZOMEU */
            }
          else
            {
              /* Data cached file */
              /* Do not set the p_object_attributes->filesize and p_object_attributes->spaceused  in this case 
               * This will lead to a situation where (for example) untar-ing a file will produced invalid files 
               * with a size of 0 despite the fact that they are not empty */

              LogFullDebug(COMPONENT_CACHE_INODE,
                           "cache_inode_setattr with FSAL_ATTR_SIZE on data cached entry");
            }
        }
      else if(pattr->asked_attributes & FSAL_ATTR_SIZE)
        LogCrit(COMPONENT_CACHE_INODE,
                "WARNING !!! cache_inode_setattr tried to set size on a non REGULAR_FILE type=%d",
                pentry->internal_md.type);
    }

  if(result_attributes.asked_attributes &
     (FSAL_ATTR_MODE | FSAL_ATTR_OWNER | FSAL_ATTR_GROUP))
    {
      if(result_attributes.asked_attributes & FSAL_ATTR_MODE)
        p_object_attributes->mode = result_attributes.mode;

      if(result_attributes.asked_attributes & FSAL_ATTR_OWNER)
        p_object_attributes->owner = result_attributes.owner;

      if(result_attributes.asked_attributes & FSAL_ATTR_GROUP)
        p_object_attributes->group = result_attributes.group;
    }

  if(result_attributes.asked_attributes &
     (FSAL_ATTR_ATIME | FSAL_ATTR_CTIME | FSAL_ATTR_MTIME))
    {
      if(result_attributes.asked_attributes & FSAL_ATTR_ATIME)
        p_object_attributes->atime = result_attributes.atime;

      if(result_attributes.asked_attributes & FSAL_ATTR_CTIME)
        p_object_attributes->ctime = result_attributes.ctime;

      if(result_attributes.asked_attributes & FSAL_ATTR_MTIME)
        p_object_attributes->mtime = result_attributes.mtime;
    }
  
#ifdef _USE_NFS4_ACL
  if(result_attributes.asked_attributes & FSAL_ATTR_ACL)
    {
      LogDebug(COMPONENT_CACHE_INODE, "cache_inode_setattr: old acl = %p, new acl = %p",
               p_object_attributes->acl, result_attributes.acl);

      /* Release previous acl entry. */
      if(p_object_attributes->acl)
        {
          fsal_acl_status_t status;
          nfs4_acl_release_entry(p_object_attributes->acl, &status);
          if(status != NFS_V4_ACL_SUCCESS)
            LogEvent(COMPONENT_CACHE_INODE, "cache_inode_setattr: Failed to release old acl:"
                     " status = %d", status);
        }

      /* Update with new acl entry. */
      p_object_attributes->acl = result_attributes.acl;
    }
#endif                          /* _USE_NFS4_ACL */

  /* Return the attributes as set */
  *pattr = *p_object_attributes;

  /* validate the entry */
  *pstatus = cache_inode_valid(pentry, CACHE_INODE_OP_SET, pclient);

  /* Release the entry */
  V_w(&pentry->lock);

  /* stat */
  if(*pstatus != CACHE_INODE_SUCCESS)
    pclient->stat.func_stats.nb_err_retryable[CACHE_INODE_SETATTR] += 1;
  else
    pclient->stat.func_stats.nb_success[CACHE_INODE_SETATTR] += 1;

  return *pstatus;
}                               /* cache_inode_setattr */
/**
 * @brief Set the attributes for a file.
 *
 * This function sets the attributes of a file, both in the cache and
 * in the underlying filesystem.
 *
 * @param[in]     entry   Entry whose attributes are to be set
 * @param[in,out] attr    Attributes to set/result of set
 *
 * @retval CACHE_INODE_SUCCESS if operation is a success
 */
cache_inode_status_t
cache_inode_setattr(cache_entry_t *entry,
		    struct attrlist *attr,
		    bool is_open_write)
{
	struct fsal_obj_handle *obj_handle = entry->obj_handle;
	fsal_status_t fsal_status = { 0, 0 };
	fsal_acl_t *saved_acl = NULL;
	fsal_acl_status_t acl_status = 0;
	cache_inode_status_t status = CACHE_INODE_SUCCESS;
	uint64_t before;
	const struct user_cred *creds = op_ctx->creds;

	/* True if we have taken the content lock on 'entry' */
	bool content_locked = false;

	if ((attr->mask & (ATTR_SIZE | ATTR4_SPACE_RESERVED))
	     && (entry->type != REGULAR_FILE)) {
		LogWarn(COMPONENT_CACHE_INODE,
			"Attempt to truncate non-regular file: type=%d",
			entry->type);
		status = CACHE_INODE_BAD_TYPE;
		goto out;
	}

	/* Is it allowed to change times ? */
	if (!op_ctx->fsal_export->exp_ops.fs_supports(op_ctx->fsal_export,
						    fso_cansettime)
	    &&
	    (FSAL_TEST_MASK
	     (attr->mask,
	      (ATTR_ATIME | ATTR_CREATION | ATTR_CTIME | ATTR_MTIME)))) {
		status = CACHE_INODE_INVALID_ARGUMENT;
		goto out;
	}

	/* Get wrlock on attr_lock and verify attrs */
	status = cache_inode_lock_trust_attrs(entry, true);
	if (status != CACHE_INODE_SUCCESS)
		return status;

	/* Do permission checks */
	status = cache_inode_check_setattr_perms(entry, attr, is_open_write);
	if (status != CACHE_INODE_SUCCESS)
		goto unlock;

	if (attr->mask & (ATTR_SIZE | ATTR4_SPACE_RESERVED)) {
		PTHREAD_RWLOCK_wrlock(&entry->content_lock);
		content_locked = true;
	}

	/* Test for the following condition from chown(2):
	 *
	 *     When the owner or group of an executable file are changed by an
	 *     unprivileged user the S_ISUID and S_ISGID mode bits are cleared.
	 *     POSIX does not specify whether this also should happen when
	 *     root does the chown(); the Linux behavior depends on the kernel
	 *     version.  In case of a non-group-executable file (i.e., one for
	 *     which the S_IXGRP bit is not set) the S_ISGID bit indicates
	 *     mandatory locking, and is not cleared by a chown().
	 *
	 */
	if (creds->caller_uid != 0 &&
	    (FSAL_TEST_MASK(attr->mask, ATTR_OWNER) ||
	     FSAL_TEST_MASK(attr->mask, ATTR_GROUP)) &&
	    ((entry->obj_handle->attrs->mode &
	      (S_IXOTH | S_IXUSR | S_IXGRP)) != 0) &&
	    ((entry->obj_handle->attrs->mode &
	      (S_ISUID | S_ISGID)) != 0)) {
		/* Non-priviledged user changing ownership on an executable
		 * file with S_ISUID or S_ISGID bit set, need to be cleared.
		 */
		if (!FSAL_TEST_MASK(attr->mask, ATTR_MODE)) {
			/* Mode wasn't being set, so set it now, start with
			 * the current attributes.
			 */
			attr->mode = entry->obj_handle->attrs->mode;
			FSAL_SET_MASK(attr->mask, ATTR_MODE);
		}

		/* Don't clear S_ISGID if the file isn't group executable.
		 * In that case, S_ISGID indicates mandatory locking and
		 * is not cleared by chown.
		 */
		if ((entry->obj_handle->attrs->mode & S_IXGRP) != 0)
			attr->mode &= ~S_ISGID;

		/* Clear S_ISUID. */
		attr->mode &= ~S_ISUID;
	}

	/* Test for the following condition from chmod(2):
	 *
	 *     If the calling process is not privileged (Linux: does not have
	 *     the CAP_FSETID capability), and the group of the file does not
	 *     match the effective group ID of the process or one of its
	 *     supplementary group IDs, the S_ISGID bit will be turned off,
	 *     but this will not cause an error to be returned.
	 *
	 * We test the actual mode being set before testing for group
	 * membership since that is a bit more expensive.
	 */
	if (creds->caller_uid != 0 &&
	    FSAL_TEST_MASK(attr->mask, ATTR_MODE) &&
	    (attr->mode & S_ISGID) != 0 &&
	    not_in_group_list(entry->obj_handle->attrs->group)) {
		/* Clear S_ISGID */
		attr->mode &= ~S_ISGID;
	}

	saved_acl = entry->obj_handle->attrs->acl;
	before = entry->obj_handle->attrs->change;
	fsal_status = obj_handle->obj_ops.setattrs(obj_handle, attr);
	if (FSAL_IS_ERROR(fsal_status)) {
		status = cache_inode_error_convert(fsal_status);
		if (fsal_status.major == ERR_FSAL_STALE) {
			LogEvent(COMPONENT_CACHE_INODE,
				 "FSAL returned STALE from setattrs");
			cache_inode_kill_entry(entry);
		}
		goto unlock;
	}
	fsal_status = obj_handle->obj_ops.getattrs(obj_handle);
	*attr = *entry->obj_handle->attrs;
	if (FSAL_IS_ERROR(fsal_status)) {
		status = cache_inode_error_convert(fsal_status);
		if (fsal_status.major == ERR_FSAL_STALE) {
			LogEvent(COMPONENT_CACHE_INODE,
				 "FSAL returned STALE from getattrs");
			cache_inode_kill_entry(entry);
		}
		goto unlock;
	}
	if (before == entry->obj_handle->attrs->change)
		entry->obj_handle->attrs->change++;
	/* Decrement refcount on saved ACL */
	nfs4_acl_release_entry(saved_acl, &acl_status);
	if (acl_status != NFS_V4_ACL_SUCCESS)
		LogCrit(COMPONENT_CACHE_INODE,
			"Failed to release old acl, status=%d", acl_status);

	cache_inode_fixup_md(entry);

	/* Copy the complete set of new attributes out. */

	*attr = *entry->obj_handle->attrs;

	status = CACHE_INODE_SUCCESS;

unlock:
	if (content_locked)
		PTHREAD_RWLOCK_unlock(&entry->content_lock);
	PTHREAD_RWLOCK_unlock(&entry->attr_lock);

out:
	return status;
}
Exemplo n.º 10
0
/**
 *  @brief convert GPFS xstat to FSAl attributes
 *
 *  @param gpfs_buf Reference to GPFS stat buffer
 *  @param fsal_attr Reference to attribute list
 *  @param use_acl Bool whether ACL are used
 *  @return FSAL status
 *
 *  Same function as posixstat64_2_fsal_attributes. When NFS4 ACL support
 *  is enabled, this will replace posixstat64_2_fsal_attributes.
 */
fsal_status_t
gpfsfsal_xstat_2_fsal_attributes(gpfsfsal_xstat_t *gpfs_buf,
				 struct attrlist *fsal_attr, bool use_acl)
{
	struct stat *p_buffstat;

	/* sanity checks */
	if (!gpfs_buf || !fsal_attr)
		return fsalstat(ERR_FSAL_FAULT, 0);

	p_buffstat = &gpfs_buf->buffstat;

	LogDebug(COMPONENT_FSAL, "inode %ld", p_buffstat->st_ino);

	/* Fills the output struct */
	if (FSAL_TEST_MASK(fsal_attr->mask, ATTR_TYPE)) {
		fsal_attr->type = posix2fsal_type(p_buffstat->st_mode);
		LogFullDebug(COMPONENT_FSAL, "type = 0x%x",
			     fsal_attr->type);
	}
	if (FSAL_TEST_MASK(fsal_attr->mask, ATTR_SIZE)) {
		fsal_attr->filesize = p_buffstat->st_size;
		LogFullDebug(COMPONENT_FSAL, "filesize = %llu",
			     (unsigned long long)fsal_attr->filesize);
	}
	if (FSAL_TEST_MASK(fsal_attr->mask, ATTR_FSID)) {
		fsal_attr->fsid = gpfs_buf->fsal_fsid;
		LogFullDebug(COMPONENT_FSAL,
			     "fsid=0x%016"PRIx64".0x%016"PRIx64,
			     fsal_attr->fsid.major,
			     fsal_attr->fsid.minor);
	}
	if (FSAL_TEST_MASK(fsal_attr->mask, ATTR_ACL)) {
		if (fsal_attr->acl != NULL) {
			/* We should never be passed attributes that have an
			 * ACL attached, but just in case some future code
			 * path changes that assumption, let's not release the
			 * old ACL properly.
			 */
			int acl_status;

			acl_status = nfs4_acl_release_entry(fsal_attr->acl);

			if (acl_status != NFS_V4_ACL_SUCCESS)
				LogCrit(COMPONENT_FSAL,
					"Failed to release old acl, status=%d",
					acl_status);

			fsal_attr->acl = NULL;
		}

		if (use_acl && gpfs_buf->attr_valid & XATTR_ACL) {
			/* ACL is valid, so try to convert fsal acl. */
			gpfs_acl_2_fsal_acl(fsal_attr,
					    (gpfs_acl_t *) gpfs_buf->buffacl);
		}
		LogFullDebug(COMPONENT_FSAL, "acl = %p", fsal_attr->acl);
	}
	if (FSAL_TEST_MASK(fsal_attr->mask, ATTR_FILEID)) {
		fsal_attr->fileid = (uint64_t) (p_buffstat->st_ino);
		LogFullDebug(COMPONENT_FSAL, "fileid = %" PRIu64,
			     fsal_attr->fileid);
	}

	if (FSAL_TEST_MASK(fsal_attr->mask, ATTR_MODE)) {
		fsal_attr->mode = unix2fsal_mode(p_buffstat->st_mode);
		LogFullDebug(COMPONENT_FSAL, "mode = %"PRIu32,
			     fsal_attr->mode);
	}
	if (FSAL_TEST_MASK(fsal_attr->mask, ATTR_NUMLINKS)) {
		fsal_attr->numlinks = p_buffstat->st_nlink;
		LogFullDebug(COMPONENT_FSAL, "numlinks = %u",
			     fsal_attr->numlinks);
	}
	if (FSAL_TEST_MASK(fsal_attr->mask, ATTR_OWNER)) {
		fsal_attr->owner = p_buffstat->st_uid;
		LogFullDebug(COMPONENT_FSAL, "owner = %" PRIu64,
			     fsal_attr->owner);
	}
	if (FSAL_TEST_MASK(fsal_attr->mask, ATTR_GROUP)) {
		fsal_attr->group = p_buffstat->st_gid;
		LogFullDebug(COMPONENT_FSAL, "group = %" PRIu64,
			     fsal_attr->group);
	}
	if (FSAL_TEST_MASK(fsal_attr->mask, ATTR_ATIME)) {
		fsal_attr->atime =
		    posix2fsal_time(p_buffstat->st_atime,
				    p_buffstat->st_atim.tv_nsec);
		LogFullDebug(COMPONENT_FSAL, "atime = %lu",
			     fsal_attr->atime.tv_sec);
	}

	if (FSAL_TEST_MASK(fsal_attr->mask, ATTR_CTIME)) {
		fsal_attr->ctime =
		    posix2fsal_time(p_buffstat->st_ctime,
				    p_buffstat->st_ctim.tv_nsec);
		LogFullDebug(COMPONENT_FSAL, "ctime = %lu",
			     fsal_attr->ctime.tv_sec);
	}
	if (FSAL_TEST_MASK(fsal_attr->mask, ATTR_MTIME)) {
		fsal_attr->mtime =
		    posix2fsal_time(p_buffstat->st_mtime,
				    p_buffstat->st_mtim.tv_nsec);
		LogFullDebug(COMPONENT_FSAL, "mtime = %lu",
			     fsal_attr->mtime.tv_sec);
	}

	if (FSAL_TEST_MASK(fsal_attr->mask, ATTR_CHGTIME)) {
		if (p_buffstat->st_mtime == p_buffstat->st_ctime) {
			if (p_buffstat->st_mtim.tv_nsec >
			    p_buffstat->st_ctim.tv_nsec)
				fsal_attr->chgtime =
				    posix2fsal_time(p_buffstat->st_mtime,
						    p_buffstat->st_mtim.
						    tv_nsec);
			else
				fsal_attr->chgtime =
				    posix2fsal_time(p_buffstat->st_ctime,
						    p_buffstat->st_ctim.
						    tv_nsec);
		} else if (p_buffstat->st_mtime > p_buffstat->st_ctime) {
			fsal_attr->chgtime =
			    posix2fsal_time(p_buffstat->st_mtime,
					    p_buffstat->st_mtim.tv_nsec);
		} else {
			fsal_attr->chgtime =
			    posix2fsal_time(p_buffstat->st_ctime,
					    p_buffstat->st_ctim.tv_nsec);
		}
		fsal_attr->change =
		    (uint64_t) fsal_attr->chgtime.tv_sec +
		    (uint64_t) fsal_attr->chgtime.tv_nsec;
		LogFullDebug(COMPONENT_FSAL, "chgtime = %lu",
			     fsal_attr->chgtime.tv_sec);

	}

	if (FSAL_TEST_MASK(fsal_attr->mask, ATTR_SPACEUSED)) {
		fsal_attr->spaceused = p_buffstat->st_blocks * S_BLKSIZE;
		LogFullDebug(COMPONENT_FSAL, "spaceused = %llu",
			     (unsigned long long)fsal_attr->spaceused);
	}

	if (FSAL_TEST_MASK(fsal_attr->mask, ATTR_RAWDEV)) {
		fsal_attr->rawdev = posix2fsal_devt(p_buffstat->st_rdev);
		LogFullDebug(COMPONENT_FSAL, "rawdev major = %u, minor = %u",
			     (unsigned int)fsal_attr->rawdev.major,
			     (unsigned int)fsal_attr->rawdev.minor);
	}

	/* everything has been copied ! */

	return fsalstat(ERR_FSAL_NO_ERROR, 0);
}
Exemplo n.º 11
0
cache_inode_status_t
cache_inode_setattr(cache_entry_t *entry,
                    fsal_attrib_list_t *attr,
                    fsal_op_context_t *context,
                    int is_open_write,
                    cache_inode_status_t *status)
{
     fsal_status_t fsal_status = {0, 0};
     int           got_content_lock = FALSE;
#ifdef _USE_NFS4_ACL
     fsal_acl_t *saved_acl = NULL;
     fsal_acl_status_t acl_status = 0;
#endif /* _USE_NFS4_ACL */

     if ((entry->type == UNASSIGNED) ||
         (entry->type == RECYCLED)) {
          LogWarn(COMPONENT_CACHE_INODE,
                  "WARNING: unknown source entry type: type=%d, "
                  "line %d in file %s", entry->type, __LINE__, __FILE__);
          *status = CACHE_INODE_BAD_TYPE;
          goto out;
     }

     if ((attr->asked_attributes & FSAL_ATTR_SIZE) &&
         (entry->type != REGULAR_FILE)) {
          LogWarn(COMPONENT_CACHE_INODE,
                   "Attempt to truncate non-regular file: type=%d",
                   entry->type);
          *status = CACHE_INODE_BAD_TYPE;
          goto out;
     }

     /* Get wrlock on attr_lock and verify attrs */
     *status = cache_inode_lock_trust_attrs(entry, context, TRUE);
     if(*status != CACHE_INODE_SUCCESS)
       return *status;

     /* Do permission checks */
     if(cache_inode_check_setattr_perms(entry,
                                        attr,
                                        context,
                                        is_open_write,
                                        status) != CACHE_INODE_SUCCESS)
       {
         goto unlock;
       }

     if (attr->asked_attributes & FSAL_ATTR_SIZE) {
          PTHREAD_RWLOCK_WRLOCK(&entry->content_lock);
          got_content_lock = TRUE;
     }

#ifdef _USE_NFS4_ACL
     saved_acl = entry->attributes.acl;
#endif /* _USE_NFS4_ACL */
     fsal_status = FSAL_setattrs(&entry->handle, context, attr,
                                 &entry->attributes);
     if (FSAL_IS_ERROR(fsal_status)) {
          *status = cache_inode_error_convert(fsal_status);
          if (fsal_status.major == ERR_FSAL_STALE) {
               LogEvent(COMPONENT_CACHE_INODE,
                       "FSAL returned STALE from setattrs");
               cache_inode_kill_entry(entry);
          }
          goto unlock;
     } else {
#ifdef _USE_NFS4_ACL
          /* Decrement refcount on saved ACL */
         nfs4_acl_release_entry(saved_acl, &acl_status);
         if (acl_status != NFS_V4_ACL_SUCCESS) {
              LogCrit(COMPONENT_CACHE_INODE,
                      "Failed to release old acl, status=%d",
                      acl_status);
         }
#endif /* _USE_NFS4_ACL */
     }

     cache_inode_fixup_md(entry);
     /* Copy the complete set of new attributes out. */

     *attr = entry->attributes;
     set_mounted_on_fileid(entry, attr, context->export_context->fe_export);

     *status = CACHE_INODE_SUCCESS;

unlock:
     if(got_content_lock) {
          PTHREAD_RWLOCK_UNLOCK(&entry->content_lock);
     }
     PTHREAD_RWLOCK_UNLOCK(&entry->attr_lock);

out:

     return *status;
} /* cache_inode_setattr */
Exemplo n.º 12
0
/*
 * Read the ACL in GlusterFS format and convert it into fsal ACL before
 * storing it in fsalattr
 */
fsal_status_t glusterfs_get_acl(struct glusterfs_export *glfs_export,
				struct glfs_object *glhandle,
				glusterfs_fsal_xstat_t *buffxstat,
				struct attrlist *fsalattr)
{
	fsal_status_t status = { ERR_FSAL_NO_ERROR, 0 };
	fsal_acl_data_t acldata;
	fsal_acl_status_t aclstatus;
	fsal_ace_t *pace = NULL;
	int e_count = 0, i_count = 0, new_count = 0, new_i_count = 0;

	if (fsalattr->acl != NULL) {
		/* We should never be passed attributes that have an
		 * ACL attached, but just in case some future code
		 * path changes that assumption, let's release the
		 * old ACL properly.
		 */
		int acl_status;

		acl_status = nfs4_acl_release_entry(fsalattr->acl);

		if (acl_status != NFS_V4_ACL_SUCCESS)
			LogCrit(COMPONENT_FSAL,
				"Failed to release old acl, status=%d",
				acl_status);

		fsalattr->acl = NULL;
	}

	if (NFSv4_ACL_SUPPORT) {

		buffxstat->e_acl = glfs_h_acl_get(glfs_export->gl_fs->fs,
						glhandle, ACL_TYPE_ACCESS);

		if (!buffxstat->e_acl) {
			status = gluster2fsal_error(errno);
			return status;
		}

		e_count = ace_count(buffxstat->e_acl);

		if (buffxstat->is_dir) {
			buffxstat->i_acl =
					 glfs_h_acl_get(glfs_export->gl_fs->fs,
						glhandle, ACL_TYPE_DEFAULT);
			i_count = ace_count(buffxstat->i_acl);
		}

		/* Allocating memory for both ALLOW and DENY entries */
		acldata.naces = 2 * (e_count  + i_count);

		LogDebug(COMPONENT_FSAL, "No of aces present in fsal_acl_t = %d"
					, acldata.naces);
		if (!acldata.naces)
			return status;

		FSAL_SET_MASK(buffxstat->attr_valid, XATTR_ACL);

		acldata.aces = (fsal_ace_t *) nfs4_ace_alloc(acldata.naces);
		pace = acldata.aces;

		new_count = posix_acl_2_fsal_acl(buffxstat->e_acl,
					buffxstat->is_dir, false, &pace);
		if (new_count < 0)
			return fsalstat(ERR_FSAL_NO_ACE, -1);

		if (i_count > 0) {
			new_i_count = posix_acl_2_fsal_acl(buffxstat->i_acl,
							true, true, &pace);
			if (new_i_count > 0)
				new_count += new_i_count;
			else
				LogDebug(COMPONENT_FSAL,
				"Inherit acl is not set for this directory");
		}

		/* Reallocating acldata into the required size */
		acldata.aces = (fsal_ace_t *) gsh_realloc(acldata.aces,
				new_count*sizeof(fsal_ace_t));
		acldata.naces = new_count;

		fsalattr->acl = nfs4_acl_new_entry(&acldata, &aclstatus);
		LogDebug(COMPONENT_FSAL, "fsal acl = %p, fsal_acl_status = %u",
				fsalattr->acl, aclstatus);
		if (fsalattr->acl == NULL) {
			LogCrit(COMPONENT_FSAL,
			"failed to create a new acl entry");
			return fsalstat(ERR_FSAL_NOMEM, -1);
		}

		fsalattr->valid_mask |= ATTR_ACL;
	} else {
		/* We were asked for ACL but do not support. */
		status = fsalstat(ERR_FSAL_NOTSUPP, 0);
	}

	return status;

}