/**
 *
 * cache_inode_create: creates an entry through the cache.
 *
 * Creates an entry through the cache.
 *
 * @param pentry_parent [IN] pointer to the pentry parent
 * @param pname         [IN] pointer to the name of the object in the destination directory.
 * @param type          [IN] type of the object to be created.
 * @param mode          [IN] mode to be used at file creation
 * @param pcreate_arg   [IN] additional argument for object creation
 * @param pattr         [OUT] attributes for the new object.
 * @param ht            [INOUT] hash table used for the cache.
 * @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\n
 * @return CACHE_INODE_BAD_TYPE either source or destination have incorrect type\n
 * @return CACHE_INODE_ENTRY_EXISTS entry of that name already exists in destination.
 *
 */
cache_entry_t *
cache_inode_create(cache_entry_t * pentry_parent,
                   fsal_name_t * pname,
                   cache_inode_file_type_t type,
                   fsal_accessmode_t mode,
                   cache_inode_create_arg_t * pcreate_arg,
                   fsal_attrib_list_t * pattr,
                   hash_table_t * ht,
                   cache_inode_client_t * pclient,
                   fsal_op_context_t * pcontext,
                   cache_inode_status_t * pstatus)
{
    cache_entry_t *pentry = NULL;
    fsal_status_t fsal_status;
#ifdef _USE_MFSL
    mfsl_object_t object_handle;
#else
    fsal_handle_t object_handle;
#endif
    fsal_attrib_list_t parent_attributes;
    fsal_attrib_list_t object_attributes;
    fsal_handle_t dir_handle;
    cache_inode_fsal_data_t fsal_data;
    cache_inode_status_t status;
    struct cache_inode_dir_begin__ *dir_begin;
    int pnfs_status;

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

    /* stats */
    pclient->stat.nb_call_total += 1;
    inc_func_call(pclient, CACHE_INODE_CREATE);
    /*
     * Check if the required type is correct, with this
     * function, we manage file, dir and symlink
     */
    if(type != REGULAR_FILE && type != DIR_BEGINNING && type != SYMBOLIC_LINK &&
       type != SOCKET_FILE && type != FIFO_FILE && type != CHARACTER_FILE &&
       type != BLOCK_FILE)
        {
            *pstatus = CACHE_INODE_BAD_TYPE;

            /* stats */
            inc_func_err_unrecover(pclient, CACHE_INODE_CREATE);
            return NULL;
        }
    /*
     * Check if caller is allowed to perform the operation
     */
    status = cache_inode_access(pentry_parent,
                                FSAL_W_OK, ht,
                                pclient, pcontext, &status);
    if (status != CACHE_INODE_SUCCESS)
        {
            *pstatus = status;

            /* stats */
            inc_func_err_unrecover(pclient, CACHE_INODE_CREATE);

            /* pentry is a directory */
            return NULL;
        }
    /*
     * Check if an entry of the same name exists
     */
    pentry = cache_inode_lookup(pentry_parent,
                                pname, &object_attributes,
                                ht, pclient, pcontext, pstatus);
    if (pentry != NULL)
        {
            *pstatus = CACHE_INODE_ENTRY_EXISTS;

            if(pentry->internal_md.type != type)
                {
                    /*
                     * Incompatible types, returns NULL
                     */
                    /* stats */
                    inc_func_err_unrecover(pclient, CACHE_INODE_CREATE);
                    return NULL;
                }
            else
                {
                    /* stats */
                    inc_func_success(pclient, CACHE_INODE_CREATE);
                    /*
                     * redondant creation, returned the
                     * previously created entry
                     */
                    return pentry;
                }
        }
    /*
     * At this point, the entry was not found, this means
     * that is doesn't exist is FSAL, we can create it
     */
    /* Get the lock for the parent */
    P_w(&pentry_parent->lock);

    if(pentry_parent->internal_md.type == DIR_BEGINNING)
        dir_handle = pentry_parent->object.dir_begin.handle;

    if(pentry_parent->internal_md.type == DIR_CONTINUE)
        {
            P_r(&pentry_parent->object.dir_cont.pdir_begin->lock);
            dir_handle = pentry_parent->object.dir_cont.pdir_begin->object.dir_begin.handle;
            V_r(&pentry_parent->object.dir_cont.pdir_begin->lock);
        }

    object_attributes.asked_attributes = pclient->attrmask;
    switch (type)
        {
        case REGULAR_FILE:
#ifdef _USE_MFSL
            cache_inode_get_attributes(pentry_parent, &parent_attributes);
            fsal_status = MFSL_create(&pentry_parent->mobject,
                                      pname, pcontext,
                                      &pclient->mfsl_context,
                                      mode, &object_handle,
                                      &object_attributes, &parent_attributes);
#else
            fsal_status = FSAL_create(&dir_handle,
                                      pname, pcontext, mode,
                                      &object_handle, &object_attributes);
#endif
            break;

        case DIR_BEGINNING:
#ifdef _USE_MFSL
            cache_inode_get_attributes(pentry_parent, &parent_attributes);
            fsal_status = MFSL_mkdir(&pentry_parent->mobject,
                                     pname, pcontext,
                                     &pclient->mfsl_context,
                                     mode, &object_handle,
                                     &object_attributes, &parent_attributes);
#else
            fsal_status = FSAL_mkdir(&dir_handle,
                                     pname, pcontext, mode,
                                     &object_handle, &object_attributes);
#endif
            break;

        case SYMBOLIC_LINK:
#ifdef _USE_MFSL
            cache_inode_get_attributes(pentry_parent, &object_attributes);
            fsal_status = MFSL_symlink(&pentry_parent->mobject,
                                       pname, &pcreate_arg->link_content,
                                       pcontext, &pclient->mfsl_context,
                                       mode, &object_handle, &object_attributes);
#else
            fsal_status = FSAL_symlink(&dir_handle,
                                       pname, &pcreate_arg->link_content,
                                       pcontext, mode, &object_handle,
                                       &object_attributes);
#endif
            break;

        case SOCKET_FILE:
#ifdef _USE_MFSL
            fsal_status = MFSL_mknode(&pentry_parent->mobject, pname,
                                      pcontext, &pclient->mfsl_context, mode,
                                      FSAL_TYPE_SOCK, NULL, /* no dev_t needed for socket file */
                                      &object_handle, &object_attributes);
#else
            fsal_status = FSAL_mknode(&dir_handle, pname, pcontext,
                                      mode, FSAL_TYPE_SOCK, NULL, /* no dev_t needed for socket file */
                                      &object_handle, &object_attributes);
#endif
            break;

        case FIFO_FILE:
#ifdef _USE_MFSL
            fsal_status = MFSL_mknode(&pentry_parent->mobject, pname,
                                      pcontext, &pclient->mfsl_context,
                                      mode, FSAL_TYPE_FIFO, NULL, /* no dev_t needed for FIFO file */
                                      &object_handle, &object_attributes);
#else
            fsal_status = FSAL_mknode(&dir_handle, pname, pcontext,
                                      mode, FSAL_TYPE_FIFO, NULL, /* no dev_t needed for FIFO file */
                                      &object_handle, &object_attributes);
#endif
            break;

        case BLOCK_FILE:
#ifdef _USE_MFSL
            fsal_status = MFSL_mknode(&pentry_parent->mobject,
                                      pname, pcontext,
                                      &pclient->mfsl_context,
                                      mode, FSAL_TYPE_BLK,
                                      &pcreate_arg->dev_spec,
                                      &object_handle, &object_attributes);
#else
            fsal_status = FSAL_mknode(&dir_handle,
                                      pname, pcontext,
                                      mode, FSAL_TYPE_BLK,
                                      &pcreate_arg->dev_spec,
                                      &object_handle, &object_attributes);
#endif
            break;

        case CHARACTER_FILE:
#ifdef _USE_MFSL
            fsal_status = MFSL_mknode(&pentry_parent->mobject,
                                      pname, pcontext,
                                      &pclient->mfsl_context,
                                      mode, FSAL_TYPE_CHR,
                                      &pcreate_arg->dev_spec,
                                      &object_handle, &object_attributes);
#else
            fsal_status = FSAL_mknode(&dir_handle,
                                      pname, pcontext,
                                      mode, FSAL_TYPE_CHR,
                                      &pcreate_arg->dev_spec,
                                      &object_handle, &object_attributes);
#endif
            break;

        default:
            /* we should never go there */
            *pstatus = CACHE_INODE_INCONSISTENT_ENTRY;
            V_w(&pentry_parent->lock);

            /* stats */
            inc_func_err_unrecover(pclient, CACHE_INODE_CREATE);

            return NULL;
            break;
        }

    /* Check for the result */
    if(FSAL_IS_ERROR(fsal_status))
        {
            *pstatus = cache_inode_error_convert(fsal_status);
            V_w(&pentry_parent->lock);

            if(fsal_status.major == ERR_FSAL_STALE)
                {
                    cache_inode_status_t kill_status;
                    LogEvent(COMPONENT_CACHE_INODE,
                             "cache_inode_create: Stale FSAL File Handle "
                             "detected for pentry = %p",
                             pentry_parent);

                    cache_inode_kill_entry(pentry_parent, ht,
                                           pclient, &kill_status);
                    if(kill_status != CACHE_INODE_SUCCESS)
                        LogCrit(COMPONENT_CACHE_INODE, "cache_inode_create: "
                                "Could not kill entry %p, status = %u",
                                pentry_parent, kill_status);
                    *pstatus = CACHE_INODE_FSAL_ESTALE;
                }
            /* stats */
            inc_func_err_unrecover(pclient, CACHE_INODE_CREATE);

            return NULL;
        }
    else
        {
#ifdef _USE_MFSL
            fsal_data.handle = object_handle.handle;
#else
            fsal_data.handle = object_handle;
#endif
            fsal_data.cookie = DIR_START;

            pentry = cache_inode_new_entry(&fsal_data, &object_attributes,
                                           type, pcreate_arg, NULL,
                                           ht, pclient, pcontext,
                                           TRUE, /* This is a creation and not a population */
                                           pstatus);
            if (pentry == NULL)
                {
                    *pstatus = CACHE_INODE_INSERT_ERROR;
                    V_w(&pentry_parent->lock);

                    /* stats */
                    inc_func_err_unrecover(pclient, CACHE_INODE_CREATE);
                    return NULL;
                }
#ifdef _USE_MFSL
            /* Copy the MFSL object to the cache */
            memcpy((char *)&(pentry->mobject),
                   (char *)&object_handle, sizeof(mfsl_object_t));
#endif

            /* Add this entry to the directory */
            status = cache_inode_add_cached_dirent(pentry_parent,
                                                   pname, pentry,
                                                   NULL, ht,
                                                   pclient, pcontext,
                                                   pstatus);
            if (status != CACHE_INODE_SUCCESS)
                {
                    V_w(&pentry_parent->lock);

                    /* stats */
                    inc_func_err_unrecover(pclient, CACHE_INODE_CREATE);
                    return NULL;
                }
        }

#ifdef _USE_PNFS
    if((type == REGULAR_FILE) &&
       (pcreate_arg != NULL) &&
       (pcreate_arg->use_pnfs == TRUE))
        {
            pnfs_status = pnfs_create_ds_file(&pclient->pnfsclient,
                                              pentry->object.file.attributes.fileid,
                                              &pentry->object.file.pnfs_file.ds_file);
            if (pnfs_status != NFS4_OK)
                {
                    V_w(&pentry_parent->lock);
                    LogDebug(COMPONENT_CACHE_INODE, "OPEN PNFS CREATE DS FILE : Error %u",
                             pnfs_status);

                    *pstatus = CACHE_INODE_IO_ERROR;
                    return NULL;
                }
        }
#endif

       /* Update the parent cached attributes */
       if(pentry_parent->internal_md.type == DIR_BEGINNING)
           dir_begin = &pentry_parent->object.dir_begin;
       else
           dir_begin = &pentry_parent->object.dir_cont.pdir_begin->object.dir_begin;

       dir_begin->attributes.mtime.seconds = time(NULL);
       dir_begin->attributes.mtime.nseconds = 0;
       dir_begin->attributes.ctime = dir_begin->attributes.mtime;
       /*
        * if the created object is a directory, it contains a link
        * to its parent : '..'. Thus the numlink attr must be increased.
        */
       if(type == DIR_BEGINNING)
           {
               dir_begin->attributes.numlinks++;
           }
       /* Get the attributes in return */
       *pattr = object_attributes;

       /* valid the parent */
       *pstatus = cache_inode_valid(pentry_parent,
                                    CACHE_INODE_OP_SET,
                                    pclient);
       /* release the lock for the parent */
       V_w(&pentry_parent->lock);

       /* stat */
       if(*pstatus != CACHE_INODE_SUCCESS)
           inc_func_err_retryable(pclient, CACHE_INODE_CREATE);
       else
           inc_func_success(pclient, CACHE_INODE_CREATE);

       return pentry;
}
示例#2
0
/**
 *
 * cache_inode_link: hardlinks a pentry to another.
 *
 * Hard links a pentry to another. This is basically a equivalent of FSAL_link in the cache inode layer.
 *
 * @param pentry_src [IN] entry pointer the entry to be linked. This can't be a directory.
 * @param pentry_dir_dest [INOUT] entry pointer for the destination directory in which the link will be created.
 * @param plink_name [IN] pointer to the name of the object in the destination directory.
 * @param pattr [OUT] attributes for the linked attributes after the operation.
 * @param ht [INOUT] hash table used for the cache.
 * @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\n
 * @return CACHE_INODE_BAD_TYPE either source or destination have incorrect type\n
 * @return CACHE_INODE_ENTRY_EXISTS entry of that name already exists in destination.
 *
 */
cache_inode_status_t cache_inode_link(cache_entry_t * pentry_src,
                                      cache_entry_t * pentry_dir_dest,
                                      fsal_name_t * plink_name,
                                      fsal_attrib_list_t * pattr,
                                      hash_table_t * ht,
                                      cache_inode_client_t * pclient,
                                      fsal_op_context_t * pcontext,
                                      cache_inode_status_t * pstatus)
{
    fsal_status_t fsal_status;
    fsal_handle_t handle_src;
    fsal_handle_t handle_dest;
    fsal_attrib_list_t link_attributes;
#ifdef _USE_MFSL
    fsal_attrib_list_t dirdest_attributes;
#endif
    cache_inode_status_t status;
    cache_entry_t *pentry_lookup = NULL;
    fsal_attrib_list_t lookup_attributes;

    fsal_size_t save_size = 0;
    fsal_size_t save_spaceused = 0;
    fsal_time_t save_mtime = {
        .seconds = 0,
        .nseconds = 0
    };

    fsal_accessflags_t access_mask = 0;

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

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

    /* Is the destination a directory ? */
    if(pentry_dir_dest->internal_md.type != DIR_BEGINNING &&
            pentry_dir_dest->internal_md.type != DIR_CONTINUE)
    {
        /* Bad type .... */
        *pstatus = CACHE_INODE_BAD_TYPE;
        pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_LINK] += 1;

        return *pstatus;
    }

    /* Check if caller is allowed to perform the operation */
    access_mask = FSAL_MODE_MASK_SET(FSAL_W_OK) |
                  FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_ADD_FILE);
    if((status = cache_inode_access(pentry_dir_dest,
                                    access_mask,
                                    ht, pclient, pcontext, &status)) != CACHE_INODE_SUCCESS)
    {
        *pstatus = status;

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

        /* pentry is a directory */
        return *pstatus;
    }

    /* Check if an entry of the same name doesn't exist in the destination directory */
    if((pentry_lookup = cache_inode_lookup(pentry_dir_dest,
                                           plink_name,
                                           &lookup_attributes,
                                           ht, pclient, pcontext, pstatus)) != NULL)
    {
        /* There exists such an entry... */
        *pstatus = CACHE_INODE_ENTRY_EXISTS;
        pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_LINK] += 1;

        return *pstatus;
    }

    /* The pentry to be hardlinked can't be a DIR_BEGINNING or a DIR_CONTINUE */
    if(pentry_src->internal_md.type == DIR_BEGINNING ||
            pentry_src->internal_md.type == DIR_CONTINUE)
    {
        /* Bad type .... */
        *pstatus = CACHE_INODE_BAD_TYPE;
        pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_LINK] += 1;

        return *pstatus;
    }

#if 0
    if( pentry_src->internal_md.type == REGULAR_FILE )
        printf( "=== link === %p | inode=%llu\n", pentry_src, pentry_src->object.file.attributes.fileid ) ;
#endif

    /* At this point, we know that the entry does not exist in destination directory, we know that the
     * destination is actually a directory and that the source is no directory */

    /* Lock the source */
    P_w(&pentry_src->lock);

    /* Lock the target dir */
    P_w(&pentry_dir_dest->lock);

    /* Get the handles */
    switch (pentry_src->internal_md.type)
    {
    case REGULAR_FILE:
        handle_src = pentry_src->object.file.handle;
        break;

    case SYMBOLIC_LINK:
        handle_src = pentry_src->object.symlink.handle;
        break;

    case FS_JUNCTION:
    case DIR_BEGINNING:
        handle_src = pentry_src->object.dir_begin.handle;
        break;

    case DIR_CONTINUE:
        /* lock the related dir_begin (dir begin are garbagge collected AFTER their related dir_cont)
         * this means that if a DIR_CONTINUE exists, its pdir pointer is not endless */
        P_r(&pentry_src->object.dir_cont.pdir_begin->lock);
        handle_src = pentry_src->object.dir_cont.pdir_begin->object.dir_begin.handle;
        V_r(&pentry_src->object.dir_cont.pdir_begin->lock);
        break;

    case CHARACTER_FILE:
    case BLOCK_FILE:
    case SOCKET_FILE:
    case FIFO_FILE:
        handle_src = pentry_src->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_src->internal_md.type, __LINE__, __FILE__);
        *pstatus = CACHE_INODE_BAD_TYPE;
        pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_LINK] += 1;
        return *pstatus;
    }

    switch (pentry_dir_dest->internal_md.type)
    {
    case FS_JUNCTION:
    case DIR_BEGINNING:
        handle_dest = pentry_dir_dest->object.dir_begin.handle;
        break;

    case DIR_CONTINUE:
        /* lock the related dir_begin (dir begin are garbagge collected AFTER their related dir_cont)
         * this means that if a DIR_CONTINUE exists, its pdir pointer is not endless */
        P_r(&pentry_dir_dest->object.dir_cont.pdir_begin->lock);
        handle_dest = pentry_src->object.dir_cont.pdir_begin->object.dir_begin.handle;
        V_r(&pentry_dir_dest->object.dir_cont.pdir_begin->lock);
        break;

    default:
        LogCrit(COMPONENT_CACHE_INODE,
                "WARNING: unknown source pentry type: internal_md.type=%d, line %d in file %s",
                pentry_src->internal_md.type, __LINE__, __FILE__);
        *pstatus = CACHE_INODE_BAD_TYPE;
        pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_LINK] += 1;
        return *pstatus;
    }

    /* If object is a data cached regular file, keeps it mtime and size, STEP 1 */
    if((pentry_src->internal_md.type == REGULAR_FILE)
            && (pentry_src->object.file.pentry_content != NULL))
    {
        save_mtime = pentry_src->object.file.attributes.mtime;
        save_size = pentry_src->object.file.attributes.filesize;
        save_spaceused = pentry_src->object.file.attributes.spaceused;
    }

    /* Do the link at FSAL level */
    link_attributes.asked_attributes = pclient->attrmask;
#ifdef _USE_MFSL
    cache_inode_get_attributes(pentry_src, &link_attributes);
    cache_inode_get_attributes(pentry_dir_dest, &dirdest_attributes);
    fsal_status =
        MFSL_link(&pentry_src->mobject, &pentry_dir_dest->mobject, plink_name, pcontext,
                  &pclient->mfsl_context, &link_attributes, NULL);
#else
    fsal_status =
        FSAL_link(&handle_src, &handle_dest, plink_name, pcontext, &link_attributes);
#endif
    if(FSAL_IS_ERROR(fsal_status))
    {
        *pstatus = cache_inode_error_convert(fsal_status);
        V_w(&pentry_dir_dest->lock);
        V_w(&pentry_src->lock);

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

            LogEvent(COMPONENT_CACHE_INODE,
                     "cache_inode_link: Stale FSAL File Handle detected for at least one in pentry = %p and pentry = %p",
                     pentry_src, pentry_dir_dest);

            /* Use FSAL_getattrs to find which entry is staled */
            getattr_status = FSAL_getattrs(&handle_src, pcontext, &link_attributes);
            if(getattr_status.major == ERR_FSAL_ACCESS)
            {
                LogEvent(COMPONENT_CACHE_INODE,
                         "cache_inode_link: Stale FSAL File Handle detected for pentry = %p",
                         pentry_src);

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

            getattr_status = FSAL_getattrs(&handle_dest, pcontext, &link_attributes);
            if(getattr_status.major == ERR_FSAL_ACCESS)
            {
                LogEvent(COMPONENT_CACHE_INODE,
                         "cache_inode_link: Stale FSAL File Handle detected for pentry = %p",
                         pentry_dir_dest);

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

        }
        *pstatus = CACHE_INODE_FSAL_ESTALE;

        return *pstatus;
    }

    /* If object is a data cached regular file, keeps it mtime and size, STEP 2 */
    if((pentry_src->internal_md.type == REGULAR_FILE)
            && (pentry_src->object.file.pentry_content != NULL))
    {
        link_attributes.mtime = save_mtime;
        link_attributes.filesize = save_size;
        link_attributes.spaceused = save_spaceused;
    }

    /* Update cached attributes */
    cache_inode_set_attributes(pentry_src, &link_attributes);

    /* Add the new entry in the destination directory */
    if(cache_inode_add_cached_dirent(pentry_dir_dest,
                                     plink_name,
                                     pentry_src,
                                     NULL,
                                     ht, pclient, pcontext, &status) != CACHE_INODE_SUCCESS)
    {
        V_w(&pentry_dir_dest->lock);
        V_w(&pentry_src->lock);
        return *pstatus;
    }

    /* Regular exit */

    /* return the attributes */
    *pattr = link_attributes;

    /* Validate the entries */
    *pstatus = cache_inode_valid(pentry_src, CACHE_INODE_OP_SET, pclient);

    /* Release the target dir */
    V_w(&pentry_dir_dest->lock);

    /* Release the source */
    V_w(&pentry_src->lock);

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

    return *pstatus;
}
cache_inode_status_t
cache_inode_remove(cache_entry_t *entry,
		   const char *name,
		   struct req_op_context *req_ctx)
{
     cache_entry_t *to_remove_entry = NULL;
     fsal_status_t fsal_status = {0, 0};
     cache_inode_status_t status = CACHE_INODE_SUCCESS;
     cache_inode_status_t status_ref_entry = CACHE_INODE_SUCCESS;
     cache_inode_status_t status_ref_to_remove_entry = CACHE_INODE_SUCCESS;
     fsal_accessflags_t access_mask = 0;

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

     /* Check if caller is allowed to perform the operation */
     access_mask = (FSAL_MODE_MASK_SET(FSAL_W_OK) |
		    FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_DELETE_CHILD));

     status = cache_inode_access(entry,
                                 access_mask,
                                 req_ctx);
     if (status != CACHE_INODE_SUCCESS) {
          goto out;
     }

     /* 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 */
     PTHREAD_RWLOCK_rdlock(&entry->content_lock);
     status = cache_inode_lookup_impl(entry,
				      name,
				      req_ctx,
				      &to_remove_entry);
     PTHREAD_RWLOCK_unlock(&entry->content_lock);

     if (to_remove_entry == NULL) {
	 goto out;
     }

     status = cache_inode_check_sticky(entry, to_remove_entry, req_ctx);
     if (status != CACHE_INODE_SUCCESS) {
         goto out;
     }

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


     if (is_open(to_remove_entry)) {
	 /* entry is not locked and seems to be open for fd caching purpose.
	  * candidate for closing since unlink of an open file results in 'silly
	  * rename' on certain platforms */
	 status = cache_inode_close(to_remove_entry,
                                    CACHE_INODE_FLAG_REALLYCLOSE);
	 if (status != CACHE_INODE_SUCCESS) {
	     /* non-fatal error. log the warning and move on */
	     LogCrit(COMPONENT_CACHE_INODE,
                   "Error closing file before unlink: %d.",
                   status);
	 }
     }

     fsal_status = entry->obj_handle->ops->unlink(entry->obj_handle, req_ctx,
                                                  name);
     if (FSAL_IS_ERROR(fsal_status)) {
         status = cache_inode_error_convert(fsal_status);
	 if(to_remove_entry->type == DIRECTORY &&
	    status == CACHE_INODE_DIR_NOT_EMPTY) {
	     /* its dirent tree is probably stale, flush it
	      * to try and make things right again */
	     PTHREAD_RWLOCK_wrlock(&to_remove_entry->content_lock);
	     (void)cache_inode_invalidate_all_cached_dirent(to_remove_entry);
	     PTHREAD_RWLOCK_unlock(&to_remove_entry->content_lock);
	 }
         goto out;
     }

     /* Remove the entry from parent dir_entries avl */
     PTHREAD_RWLOCK_wrlock(&entry->content_lock);
     cache_inode_remove_cached_dirent(entry, name, req_ctx);
     PTHREAD_RWLOCK_unlock(&entry->content_lock);

     status_ref_entry = cache_inode_refresh_attrs_locked(entry, req_ctx);
     if(FSAL_IS_ERROR(fsal_status)) {
         status = cache_inode_error_convert(fsal_status);
         goto out;
     }

     /* Update the attributes for the removed entry */
     status_ref_to_remove_entry = cache_inode_refresh_attrs_locked(to_remove_entry, req_ctx);
     if (status_ref_to_remove_entry == CACHE_INODE_FSAL_ESTALE) {
             status_ref_to_remove_entry = CACHE_INODE_SUCCESS;
     }

     if (((status = status_ref_entry) != CACHE_INODE_SUCCESS) ||
         ((status = status_ref_to_remove_entry) != CACHE_INODE_SUCCESS)) {
         goto out;
     }

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

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

     return status;
}
示例#4
0
int _9p_lopen( _9p_request_data_t * preq9p, 
                  void  * pworker_data,
                  u32 * plenout, 
                  char * preply)
{
  char * cursor = preq9p->_9pmsg + _9P_HDR_SIZE + _9P_TYPE_SIZE ;
  int rc = 0 ;
  u32 err = 0 ;
  nfs_worker_data_t * pwkrdata = (nfs_worker_data_t *)pworker_data ;

  u16 * msgtag = NULL ;
  u32 * fid    = NULL ;
  u32 * mode   = NULL ;

  fsal_accessflags_t fsalaccess ;
  cache_inode_status_t cache_status ;

  if ( !preq9p || !pworker_data || !plenout || !preply )
   return -1 ;

  _9p_fid_t * pfid = NULL ;

  /* Get data */
  _9p_getptr( cursor, msgtag, u16 ) ; 
  _9p_getptr( cursor, fid,    u32 ) ; 
  _9p_getptr( cursor, mode,   u32 ) ; 
  
  LogDebug( COMPONENT_9P, "TLOPEN: tag=%u fid=%u mode=0x%x",
            (u32)*msgtag, *fid, *mode  ) ;

   if( *fid >= _9P_FID_PER_CONN )
    {
      err = ERANGE ;
      rc = _9p_rerror( preq9p, msgtag, &err, plenout, preply ) ;
      return rc ;
    }
 
   pfid =  &preq9p->pconn->fids[*fid] ;

  _9p_tools_acess2fsal( mode, &fsalaccess ) ;

  /* Perform the 'access' call */
  if(cache_inode_access( pfid->pentry,
                         fsalaccess,
                         pwkrdata->ht,
                         &pwkrdata->cache_inode_client,
                         &pfid->fsal_op_context, 
                         &cache_status ) != CACHE_INODE_SUCCESS )
   {
     err = EPERM ;
     rc = _9p_rerror( preq9p, msgtag, &err, plenout, preply ) ;
     return rc ;
   }

   /* iounit = 0 by default */
   pfid->specdata.iounit = 0 ;

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

  _9p_setqid( cursor, pfid->qid ) ;
  _9p_setptr( cursor, &pfid->specdata.iounit, u32 ) ; 
   
  _9p_setendptr( cursor, preply ) ;
  _9p_checkbound( cursor, preply, plenout ) ;

  LogDebug( COMPONENT_9P, "RLOPEN: tag=%u fid=%u qid=(type=%u,version=%u,path=%llu) iounit=%u", 
            *msgtag, *fid, (u32)pfid->qid.type, pfid->qid.version, (unsigned long long)pfid->qid.path, pfid->specdata.iounit ) ;

  return 1 ;
}
示例#5
0
int nfs_Read(nfs_arg_t *parg,
             exportlist_t *pexport,
             fsal_op_context_t *pcontext,
             nfs_worker_data_t *pworker,
             struct svc_req *preq,
             nfs_res_t *pres)
{
  cache_entry_t *pentry;
  fsal_attrib_list_t attr;
  fsal_attrib_list_t pre_attr;
  cache_inode_status_t cache_status = CACHE_INODE_SUCCESS;
  size_t size = 0;
  size_t read_size = 0;
  fsal_off_t offset = 0;
  void *data = NULL;
  cache_inode_file_type_t filetype;
  fsal_boolean_t eof_met=FALSE;
  int rc = NFS_REQ_OK;

  if(isDebug(COMPONENT_NFSPROTO))
    {
      char str[LEN_FH_STR];

      switch (preq->rq_vers)
        {
        case NFS_V2:
          offset = parg->arg_read2.offset;
          size = parg->arg_read2.count;
          break;
        case NFS_V3:
          offset = parg->arg_read3.offset;
          size = parg->arg_read3.count;
        }

      nfs_FhandleToStr(preq->rq_vers,
                       &(parg->arg_read2.file),
                       &(parg->arg_read3.file),
                       NULL,
                       str);
      LogDebug(COMPONENT_NFSPROTO,
               "REQUEST PROCESSING: Calling nfs_Read handle: %s start: %llx len: %llx",
               str, (unsigned long long) offset, (unsigned long long) size);
    }

  if(preq->rq_vers == NFS_V3)
    {
      /* to avoid setting it on each error case */
      pres->res_read3.READ3res_u.resfail.file_attributes.attributes_follow = FALSE;
      /* initialize for read of size 0 */
      pres->res_read3.READ3res_u.resok.eof = FALSE;
      pres->res_read3.READ3res_u.resok.count = 0;
      pres->res_read3.READ3res_u.resok.data.data_val = NULL;
      pres->res_read3.READ3res_u.resok.data.data_len = 0;
      pres->res_read3.status = NFS3_OK;
    }
  else if(preq->rq_vers == NFS_V2)
    {
      /* initialize for read of size 0 */
      pres->res_read2.READ2res_u.readok.data.nfsdata2_val = NULL;
      pres->res_read2.READ2res_u.readok.data.nfsdata2_len = 0;
      pres->res_attr2.status = NFS_OK;
    }

  /* Convert file handle into a cache entry */
  if((pentry = nfs_FhandleToCache(preq->rq_vers,
                                  &(parg->arg_read2.file),
                                  &(parg->arg_read3.file),
                                  NULL,
                                  &(pres->res_read2.status),
                                  &(pres->res_read3.status),
                                  NULL, &pre_attr, pcontext, &rc)) == NULL)
    {
      /* Stale NFS FH ? */
      goto out;
    }

  if((preq->rq_vers == NFS_V3) && (nfs3_Is_Fh_Xattr(&(parg->arg_read3.file))))
  {
    rc = nfs3_Read_Xattr(parg, pexport, pcontext, preq, pres);
    goto out;
  }

  if(cache_inode_access(pentry,
                        FSAL_READ_ACCESS,
                        pcontext,
                        &cache_status) != CACHE_INODE_SUCCESS)
    {
      switch (preq->rq_vers)
        {
        case NFS_V2:
          pres->res_attr2.status = nfs2_Errno(cache_status);
          break;

        case NFS_V3:
          pres->res_read3.status = nfs3_Errno(cache_status);
          break;
        }
      rc = NFS_REQ_OK;
      goto out;
    }

  /* Extract the filetype */
  filetype = cache_inode_fsal_type_convert(pre_attr.type);

  /* Sanity check: read only from a regular file */
  if(filetype != REGULAR_FILE)
    {
      switch (preq->rq_vers)
        {
        case NFS_V2:
          /*
           * In the RFC tell it not good but it does
           * not tell what to do ... 
           */
          pres->res_attr2.status = NFSERR_ISDIR;
          break;

        case NFS_V3:
          if(filetype == DIRECTORY)
            pres->res_read3.status = NFS3ERR_ISDIR;
          else
            pres->res_read3.status = NFS3ERR_INVAL;
          break;
        }

      rc = NFS_REQ_OK;
      goto out;
    }

  /* For MDONLY export, reject write operation */
  /* Request of type MDONLY_RO were rejected at the nfs_rpc_dispatcher level */
  /* This is done by replying EDQUOT (this error is known for not disturbing the client's requests cache */
  if(pexport->access_type == ACCESSTYPE_MDONLY
     || pexport->access_type == ACCESSTYPE_MDONLY_RO)
    {
      switch (preq->rq_vers)
        {
        case NFS_V2:
          pres->res_attr2.status = NFSERR_DQUOT;
          break;

        case NFS_V3:
          pres->res_read3.status = NFS3ERR_DQUOT;
          break;
        }

      nfs_SetFailedStatus(pcontext, pexport,
                          preq->rq_vers,
                          cache_status,
                          &pres->res_read2.status,
                          &pres->res_read3.status,
                          pentry,
                          &(pres->res_read3.READ3res_u.resfail.file_attributes),
                          NULL, NULL, NULL, NULL, NULL, NULL);

      rc = NFS_REQ_OK;
      goto out;
    }

  /* Extract the argument from the request */
  switch (preq->rq_vers)
    {
    case NFS_V2:
      offset = parg->arg_read2.offset;  /* beginoffset is obsolete */
      size = parg->arg_read2.count;     /* totalcount is obsolete  */
      break;

    case NFS_V3:
      offset = parg->arg_read3.offset;
      size = parg->arg_read3.count;
      break;
    }

  /* 
   * do not exceed maxium READ offset if set 
   */
  if((pexport->options & EXPORT_OPTION_MAXOFFSETREAD) == EXPORT_OPTION_MAXOFFSETREAD)
    {
      LogFullDebug(COMPONENT_NFSPROTO,
                   "-----> Read offset=%llu count=%llu MaxOffSet=%llu",
                   (unsigned long long) offset,
                   (unsigned long long) size,
                   (unsigned long long) pexport->MaxOffsetRead);

      if((fsal_off_t) (offset + size) > pexport->MaxOffsetRead)
        {
          LogEvent(COMPONENT_NFSPROTO,
                   "NFS READ: A client tryed to violate max file size %llu for exportid #%hu",
                   (unsigned long long) pexport->MaxOffsetRead, pexport->id);

          switch (preq->rq_vers)
            {
            case NFS_V2:
              pres->res_attr2.status = NFSERR_DQUOT;
              break;

            case NFS_V3:
              pres->res_read3.status = NFS3ERR_INVAL;
              break;
            }

          nfs_SetFailedStatus(pcontext, pexport,
                              preq->rq_vers,
                              cache_status,
                              &pres->res_read2.status,
                              &pres->res_read3.status,
                              pentry,
                              &(pres->res_read3.READ3res_u.resfail.file_attributes),
                              NULL, NULL, NULL, NULL, NULL, NULL);

          rc = NFS_REQ_OK;
          goto out;
        }
    }

  /*
   * We should not exceed the FSINFO rtmax field for
   * the size 
   */
  if(((pexport->options & EXPORT_OPTION_MAXREAD) == EXPORT_OPTION_MAXREAD) &&
     size > pexport->MaxRead)
    {
      /*
       * The client asked for too much, normally
       * this should not happen because the client
       * is calling nfs_Fsinfo at mount time and so
       * is aware of the server maximum write size 
       */
      size = pexport->MaxRead;
    }

  if(size == 0)
    {
      nfs_read_ok(pexport, preq, pres, NULL, 0, &pre_attr, 0);
      rc = NFS_REQ_OK;
      goto out;
    }
  else
    {
      data = gsh_malloc(size);
      if(data == NULL)
        {
          rc = NFS_REQ_DROP;
          goto out;
        }

      if((cache_inode_rdwr(pentry,
                           CACHE_INODE_READ,
                           offset,
                           size,
                           &read_size,
                           data,
                           &eof_met,
                           pcontext,
                           CACHE_INODE_SAFE_WRITE_TO_FS,
                           &cache_status) == CACHE_INODE_SUCCESS) &&
         (cache_inode_getattr(pentry, &attr, pcontext,
                              &cache_status)) == CACHE_INODE_SUCCESS)

        {
          nfs_read_ok(pexport, preq, pres, data, read_size, &attr, 
                      ((offset + read_size) >= attr.filesize));
          rc = NFS_REQ_OK;
          goto out;
        }
      gsh_free(data);
    }

  /* If we are here, there was an error */
  if(nfs_RetryableError(cache_status))
    {
      rc = NFS_REQ_DROP;
      goto out;
    }

  nfs_SetFailedStatus(pcontext, pexport,
                      preq->rq_vers,
                      cache_status,
                      &pres->res_read2.status,
                      &pres->res_read3.status,
                      pentry,
                      &(pres->res_read3.READ3res_u.resfail.file_attributes),
                      NULL, NULL, NULL, NULL, NULL, NULL);

  rc = NFS_REQ_OK;

out:
  /* return references */
  if (pentry)
      cache_inode_put(pentry);

  return (rc);

}                               /* nfs_Read */
示例#6
0
int nfs41_op_open(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp)
{
    cache_entry_t *pentry_parent = NULL;
    cache_entry_t *pentry_lookup = NULL;
    cache_entry_t *pentry_newfile = NULL;
    fsal_handle_t *pnewfsal_handle = NULL;
    fsal_attrib_list_t attr_parent;
    fsal_attrib_list_t attr;
    fsal_attrib_list_t attr_newfile;
    fsal_attrib_list_t sattr;
    fsal_openflags_t openflags = 0;
    cache_inode_status_t cache_status;
    nfsstat4 rc;
    int retval;
    fsal_name_t filename;
    bool_t AttrProvided = FALSE;
    fsal_accessmode_t mode = 0600;
    nfs_fh4 newfh4;
    nfs_client_id_t nfs_clientid;
    nfs_worker_data_t *pworker = NULL;
    int convrc = 0;
    char __attribute__ ((__unused__)) funcname[] = "nfs4_op_open";

    cache_inode_state_data_t candidate_data;
    cache_inode_state_type_t candidate_type;
    cache_inode_state_t *pfile_state = NULL;
    cache_inode_state_t *pstate_found_iterate = NULL;
    cache_inode_state_t *pstate_previous_iterate = NULL;
    cache_inode_state_t *pstate_found_same_owner = NULL;

    cache_inode_open_owner_name_t owner_name;
    cache_inode_open_owner_name_t *powner_name = NULL;
    cache_inode_open_owner_t *powner = NULL;
    bool_t open_owner_known = FALSE;

    resp->resop = NFS4_OP_OPEN;
    res_OPEN4.status = NFS4_OK;

    uint32_t tmp_attr[2];
    uint_t tmp_int = 2;

    int pnfs_status;
    cache_inode_create_arg_t create_arg;

    pworker = (nfs_worker_data_t *) data->pclient->pworker;

    /* If there is no FH */
    if(nfs4_Is_Fh_Empty(&(data->currentFH)))
    {
        res_OPEN4.status = NFS4ERR_NOFILEHANDLE;
        return res_OPEN4.status;
    }

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

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

    /* This can't be done on the pseudofs */
    if(nfs4_Is_Fh_Pseudo(&(data->currentFH)))
    {
        res_OPEN4.status = NFS4ERR_ROFS;
        return res_OPEN4.status;
    }

    /* If Filehandle points to a xattr object, manage it via the xattrs specific functions */
    if(nfs4_Is_Fh_Xattr(&(data->currentFH)))
        return nfs4_op_open_xattr(op, data, resp);

    /* If data->current_entry is empty, repopulate it */
    if(data->current_entry == NULL)
    {
        if((data->current_entry = nfs_FhandleToCache(NFS_V4,
                                  NULL,
                                  NULL,
                                  &(data->currentFH),
                                  NULL,
                                  NULL,
                                  &(res_OPEN4.status),
                                  &attr,
                                  data->pcontext,
                                  data->pclient,
                                  data->ht, &retval)) == NULL)
        {
            res_OPEN4.status = NFS4ERR_SERVERFAULT;
            return res_OPEN4.status;
        }
    }

    /* Set parent */
    pentry_parent = data->current_entry;

    /* First switch is based upon claim type */
    switch (arg_OPEN4.claim.claim)
    {
    case CLAIM_DELEGATE_CUR:
    case CLAIM_DELEGATE_PREV:
        /* Check for name length */
        if(arg_OPEN4.claim.open_claim4_u.file.utf8string_len > FSAL_MAX_NAME_LEN)
        {
            res_OPEN4.status = NFS4ERR_NAMETOOLONG;
            return res_OPEN4.status;
        }

        /* get the filename from the argument, it should not be empty */
        if(arg_OPEN4.claim.open_claim4_u.file.utf8string_len == 0)
        {
            res_OPEN4.status = NFS4ERR_INVAL;
            return res_OPEN4.status;
        }

        res_OPEN4.status = NFS4ERR_NOTSUPP;
        return res_OPEN4.status;
        break;

    case CLAIM_NULL:
        /* Check for name length */
        if(arg_OPEN4.claim.open_claim4_u.file.utf8string_len > FSAL_MAX_NAME_LEN)
        {
            res_OPEN4.status = NFS4ERR_NAMETOOLONG;
            return res_OPEN4.status;
        }

        /* get the filename from the argument, it should not be empty */
        if(arg_OPEN4.claim.open_claim4_u.file.utf8string_len == 0)
        {
            res_OPEN4.status = NFS4ERR_INVAL;
            return res_OPEN4.status;
        }

        /* Check if asked attributes are correct */
        if(arg_OPEN4.openhow.openflag4_u.how.mode == GUARDED4 ||
                arg_OPEN4.openhow.openflag4_u.how.mode == UNCHECKED4)
        {
            if(!nfs4_Fattr_Supported
                    (&arg_OPEN4.openhow.openflag4_u.how.createhow4_u.createattrs))
            {
                res_OPEN4.status = NFS4ERR_ATTRNOTSUPP;
                return res_OPEN4.status;
            }

            /* Do not use READ attr, use WRITE attr */
            if(!nfs4_Fattr_Check_Access
                    (&arg_OPEN4.openhow.openflag4_u.how.createhow4_u.createattrs,
                     FATTR4_ATTR_WRITE))
            {
                res_OPEN4.status = NFS4ERR_INVAL;
                return res_OPEN4.status;
            }
        }

        /* Check if filename is correct */
        if((cache_status =
                    cache_inode_error_convert(FSAL_buffdesc2name
                                              ((fsal_buffdesc_t *) & arg_OPEN4.claim.open_claim4_u.
                                               file, &filename))) != CACHE_INODE_SUCCESS)
        {
            res_OPEN4.status = nfs4_Errno(cache_status);
            return res_OPEN4.status;
        }

        /* Check parent */
        pentry_parent = data->current_entry;

        /* Parent must be a directory */
        if((pentry_parent->internal_md.type != DIR_BEGINNING) &&
                (pentry_parent->internal_md.type != DIR_CONTINUE))
        {
            /* Parent object is not a directory... */
            if(pentry_parent->internal_md.type == SYMBOLIC_LINK)
                res_OPEN4.status = NFS4ERR_SYMLINK;
            else
                res_OPEN4.status = NFS4ERR_NOTDIR;

            return res_OPEN4.status;
        }

        /* What kind of open is it ? */

        LogFullDebug(COMPONENT_NFS_V4,
                     "     OPEN: Claim type = %d   Open Type = %d  Share Deny = %d   Share Access = %d \n",
                     arg_OPEN4.claim.claim, arg_OPEN4.openhow.opentype, arg_OPEN4.share_deny,
                     arg_OPEN4.share_access);


        /* It this a known client id ? */
        LogDebug(COMPONENT_NFS_V4, "OPEN Client id = %llx", arg_OPEN4.owner.clientid);

        /* Is this open_owner known ? */
        if(!nfs_convert_open_owner(&arg_OPEN4.owner, &owner_name))
        {
            res_OPEN4.status = NFS4ERR_SERVERFAULT;
            return res_OPEN4.status;
        }

        if(!nfs_open_owner_Get_Pointer(&owner_name, &powner))
        {
            /* This open owner is not known yet, allocated and set up a new one */
            GET_PREALLOC(powner,
                         data->pclient->pool_open_owner,
                         data->pclient->nb_pre_state_v4, cache_inode_open_owner_t, next);

            GET_PREALLOC(powner_name,
                         data->pclient->pool_open_owner_name,
                         data->pclient->nb_pre_state_v4,
                         cache_inode_open_owner_name_t, next);

            if(powner == NULL || powner_name == NULL)
            {
                res_OPEN4.status = NFS4ERR_SERVERFAULT;
                return res_OPEN4.status;
            }

            memcpy((char *)powner_name, (char *)&owner_name,
                   sizeof(cache_inode_open_owner_name_t));

            /* set up the content of the open_owner */
            powner->confirmed = FALSE;
            powner->seqid = 1;    /* NFSv4.1 specific, initial seqid is 1 */
            powner->related_owner = NULL;
            powner->next = NULL;
            powner->clientid = arg_OPEN4.owner.clientid;
            powner->owner_len = arg_OPEN4.owner.owner.owner_len;
            memcpy((char *)powner->owner_val, (char *)arg_OPEN4.owner.owner.owner_val,
                   arg_OPEN4.owner.owner.owner_len);
            powner->owner_val[powner->owner_len] = '\0';

            pthread_mutex_init(&powner->lock, NULL);

            if(!nfs_open_owner_Set(powner_name, powner))
            {
                res_OPEN4.status = NFS4ERR_SERVERFAULT;
                return res_OPEN4.status;
            }

        }

        /* Status of parent directory before the operation */
        if((cache_status = cache_inode_getattr(pentry_parent,
                                               &attr_parent,
                                               data->ht,
                                               data->pclient,
                                               data->pcontext,
                                               &cache_status)) != CACHE_INODE_SUCCESS)
        {
            res_OPEN4.status = nfs4_Errno(cache_status);
            return res_OPEN4.status;
        }
        memset(&(res_OPEN4.OPEN4res_u.resok4.cinfo.before), 0, sizeof(changeid4));
        res_OPEN4.OPEN4res_u.resok4.cinfo.before =
            (changeid4) pentry_parent->internal_md.mod_time;

        /* CLient may have provided fattr4 to set attributes at creation time */
        if(arg_OPEN4.openhow.openflag4_u.how.mode == GUARDED4 ||
                arg_OPEN4.openhow.openflag4_u.how.mode == UNCHECKED4)
        {
            if(arg_OPEN4.openhow.openflag4_u.how.createhow4_u.createattrs.attrmask.
                    bitmap4_len != 0)
            {
                /* Convert fattr4 so nfs4_sattr */
                convrc =
                    nfs4_Fattr_To_FSAL_attr(&sattr,
                                            &(arg_OPEN4.openhow.openflag4_u.how.
                                              createhow4_u.createattrs));

                if(convrc == 0)
                {
                    res_OPEN4.status = NFS4ERR_ATTRNOTSUPP;
                    return res_OPEN4.status;
                }

                if(convrc == -1)
                {
                    res_OPEN4.status = NFS4ERR_BADXDR;
                    return res_OPEN4.status;
                }

                AttrProvided = TRUE;
            }

        }

        /* Second switch is based upon "openhow" */
        switch (arg_OPEN4.openhow.opentype)
        {
        case OPEN4_CREATE:
            /* a new file is to be created */

            /* Does a file with this name already exist ? */
            pentry_lookup = cache_inode_lookup(pentry_parent,
                                               &filename,
                                               &attr_newfile,
                                               data->ht,
                                               data->pclient,
                                               data->pcontext, &cache_status);

            if(cache_status != CACHE_INODE_NOT_FOUND)
            {
                /* if open is UNCHECKED, return NFS4_OK (RFC3530 page 172) */
                if(arg_OPEN4.openhow.openflag4_u.how.mode == UNCHECKED4
                        && (cache_status == CACHE_INODE_SUCCESS))
                {
                    /* If the file is opened for write, OPEN4 while deny share write access,
                     * in this case, check caller has write access to the file */
                    if(arg_OPEN4.share_deny & OPEN4_SHARE_DENY_WRITE)
                    {
                        if(cache_inode_access(pentry_lookup,
                                              FSAL_W_OK,
                                              data->ht,
                                              data->pclient,
                                              data->pcontext,
                                              &cache_status) != CACHE_INODE_SUCCESS)
                        {
                            res_OPEN4.status = NFS4ERR_ACCESS;
                            return res_OPEN4.status;
                        }
                        openflags = FSAL_O_WRONLY;
                    }

                    /* Same check on read: check for readability of a file before opening it for read */
                    if(arg_OPEN4.share_access & OPEN4_SHARE_ACCESS_READ)
                    {
                        if(cache_inode_access(pentry_lookup,
                                              FSAL_R_OK,
                                              data->ht,
                                              data->pclient,
                                              data->pcontext,
                                              &cache_status) != CACHE_INODE_SUCCESS)
                        {
                            res_OPEN4.status = NFS4ERR_ACCESS;
                            return res_OPEN4.status;
                        }
                        openflags = FSAL_O_RDONLY;
                    }

                    if(AttrProvided == TRUE)      /* Set the attribute if provided */
                    {
                        if((cache_status = cache_inode_setattr(pentry_lookup,
                                                               &sattr,
                                                               data->ht,
                                                               data->pclient,
                                                               data->pcontext,
                                                               &cache_status)) !=
                                CACHE_INODE_SUCCESS)
                        {
                            res_OPEN4.status = nfs4_Errno(cache_status);
                            return res_OPEN4.status;
                        }

                        res_OPEN4.OPEN4res_u.resok4.attrset =
                            arg_OPEN4.openhow.openflag4_u.how.createhow4_u.createattrs.
                            attrmask;
                    }
                    else
                        res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_len = 0;

                    /* Same check on write */
                    if(arg_OPEN4.share_access & OPEN4_SHARE_ACCESS_WRITE)
                    {
                        if(cache_inode_access(pentry_lookup,
                                              FSAL_W_OK,
                                              data->ht,
                                              data->pclient,
                                              data->pcontext,
                                              &cache_status) != CACHE_INODE_SUCCESS)
                        {
                            res_OPEN4.status = NFS4ERR_ACCESS;
                            return res_OPEN4.status;
                        }
                        openflags = FSAL_O_RDWR;
                    }

                    /* Set the state for the related file */

                    /* Prepare state management structure */
                    candidate_type = CACHE_INODE_STATE_SHARE;
                    candidate_data.share.share_deny = arg_OPEN4.share_deny;
                    candidate_data.share.share_access = arg_OPEN4.share_access;

                    if(cache_inode_add_state(pentry_lookup,
                                             candidate_type,
                                             &candidate_data,
                                             powner,
                                             data->pclient,
                                             data->pcontext,
                                             &pfile_state,
                                             &cache_status) != CACHE_INODE_SUCCESS)
                    {
                        /* Seqid has to be incremented even in this case */
                        P(powner->lock);
                        powner->seqid += 1;
                        V(powner->lock);

                        res_OPEN4.status = NFS4ERR_SHARE_DENIED;
                        return res_OPEN4.status;
                    }

                    /* Open the file */
                    if(cache_inode_open_by_name(pentry_parent,
                                                &filename,
                                                pentry_lookup,
                                                data->pclient,
                                                openflags,
                                                data->pcontext,
                                                &cache_status) != CACHE_INODE_SUCCESS)
                    {
                        /* Seqid has to be incremented even in this case */
                        P(powner->lock);
                        powner->seqid += 1;
                        V(powner->lock);

                        res_OPEN4.status = NFS4ERR_SHARE_DENIED;
                        res_OPEN4.status = NFS4ERR_ACCESS;
                        return res_OPEN4.status;
                    }

                    res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_len = 2;
                    if((res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_val =
                                (uint32_t *) Mem_Alloc(res_OPEN4.OPEN4res_u.resok4.attrset.
                                                       bitmap4_len * sizeof(uint32_t))) == NULL)
                    {
                        res_OPEN4.status = NFS4ERR_SERVERFAULT;
                        return res_OPEN4.status;
                    }

                    memset(&(res_OPEN4.OPEN4res_u.resok4.cinfo.after), 0,
                           sizeof(changeid4));
                    res_OPEN4.OPEN4res_u.resok4.cinfo.after =
                        (changeid4) pentry_parent->internal_md.mod_time;
                    res_OPEN4.OPEN4res_u.resok4.cinfo.atomic = TRUE;

                    res_OPEN4.OPEN4res_u.resok4.stateid.seqid = pfile_state->seqid;
                    memcpy(res_OPEN4.OPEN4res_u.resok4.stateid.other,
                           pfile_state->stateid_other, 12);

                    /* No delegation */
                    res_OPEN4.OPEN4res_u.resok4.delegation.delegation_type =
                        OPEN_DELEGATE_NONE;
                    res_OPEN4.OPEN4res_u.resok4.rflags = OPEN4_RESULT_LOCKTYPE_POSIX;

                    /* Now produce the filehandle to this file */
                    if((pnewfsal_handle =
                                cache_inode_get_fsal_handle(pentry_lookup, &cache_status)) == NULL)
                    {
                        res_OPEN4.status = nfs4_Errno(cache_status);
                        return res_OPEN4.status;
                    }

                    /* Allocation of a new file handle */
                    if((rc = nfs4_AllocateFH(&newfh4)) != NFS4_OK)
                    {
                        res_OPEN4.status = rc;
                        return res_OPEN4.status;
                    }

                    /* Building a new fh */
                    if(!nfs4_FSALToFhandle(&newfh4, pnewfsal_handle, data))
                    {
                        res_OPEN4.status = NFS4ERR_SERVERFAULT;
                        return res_OPEN4.status;
                    }

                    /* This new fh replaces the current FH */
                    data->currentFH.nfs_fh4_len = newfh4.nfs_fh4_len;
                    memcpy(data->currentFH.nfs_fh4_val, newfh4.nfs_fh4_val,
                           newfh4.nfs_fh4_len);

                    data->current_entry = pentry_lookup;
                    data->current_filetype = REGULAR_FILE;

                    res_OPEN4.status = NFS4_OK;
                    return res_OPEN4.status;
                }

                /* if open is EXCLUSIVE, but verifier is the same, return NFS4_OK (RFC3530 page 173) */
                if(arg_OPEN4.openhow.openflag4_u.how.mode == EXCLUSIVE4)
                {
                    if((pentry_lookup != NULL)
                            && (pentry_lookup->internal_md.type == REGULAR_FILE))
                    {
                        pstate_found_iterate = NULL;
                        pstate_previous_iterate = NULL;

                        do
                        {
                            cache_inode_state_iterate(pentry_lookup,
                                                      &pstate_found_iterate,
                                                      pstate_previous_iterate,
                                                      data->pclient,
                                                      data->pcontext, &cache_status);
                            if(cache_status == CACHE_INODE_STATE_ERROR)
                                break;

                            if(cache_status == CACHE_INODE_INVALID_ARGUMENT)
                            {
                                /* Seqid has to be incremented even in this case */
                                P(powner->lock);
                                powner->seqid += 1;
                                V(powner->lock);

                                res_OPEN4.status = NFS4ERR_INVAL;
                                return res_OPEN4.status;
                            }

                            /* Check is open_owner is the same */
                            if(pstate_found_iterate != NULL)
                            {
                                if((pstate_found_iterate->state_type ==
                                        CACHE_INODE_STATE_SHARE)
                                        && !memcmp(arg_OPEN4.owner.owner.owner_val,
                                                   pstate_found_iterate->powner->owner_val,
                                                   pstate_found_iterate->powner->owner_len)
                                        && !memcmp(pstate_found_iterate->state_data.share.
                                                   oexcl_verifier,
                                                   arg_OPEN4.openhow.openflag4_u.how.
                                                   createhow4_u.createverf, NFS4_VERIFIER_SIZE))
                                {

                                    /* A former open EXCLUSIVE with same owner and verifier was found, resend it */
                                    res_OPEN4.OPEN4res_u.resok4.stateid.seqid =
                                        pstate_found_iterate->seqid;
                                    memcpy(res_OPEN4.OPEN4res_u.resok4.stateid.other,
                                           pstate_found_iterate->stateid_other, 12);

                                    memset(&(res_OPEN4.OPEN4res_u.resok4.cinfo.after), 0,
                                           sizeof(changeid4));
                                    res_OPEN4.OPEN4res_u.resok4.cinfo.after =
                                        (changeid4) pentry_parent->internal_md.mod_time;
                                    res_OPEN4.OPEN4res_u.resok4.cinfo.atomic = TRUE;

                                    /* No delegation */
                                    res_OPEN4.OPEN4res_u.resok4.delegation.delegation_type =
                                        OPEN_DELEGATE_NONE;
                                    res_OPEN4.OPEN4res_u.resok4.rflags =
                                        OPEN4_RESULT_LOCKTYPE_POSIX;

                                    /* Now produce the filehandle to this file */
                                    if((pnewfsal_handle =
                                                cache_inode_get_fsal_handle(pentry_lookup,
                                                                            &cache_status)) == NULL)
                                    {
                                        res_OPEN4.status = nfs4_Errno(cache_status);
                                        return res_OPEN4.status;
                                    }

                                    /* Allocation of a new file handle */
                                    if((rc = nfs4_AllocateFH(&newfh4)) != NFS4_OK)
                                    {
                                        res_OPEN4.status = rc;
                                        return res_OPEN4.status;
                                    }

                                    /* Building a new fh */
                                    if(!nfs4_FSALToFhandle(&newfh4, pnewfsal_handle, data))
                                    {
                                        res_OPEN4.status = NFS4ERR_SERVERFAULT;
                                        return res_OPEN4.status;
                                    }

                                    /* This new fh replaces the current FH */
                                    data->currentFH.nfs_fh4_len = newfh4.nfs_fh4_len;
                                    memcpy(data->currentFH.nfs_fh4_val, newfh4.nfs_fh4_val,
                                           newfh4.nfs_fh4_len);

                                    data->current_entry = pentry_lookup;
                                    data->current_filetype = REGULAR_FILE;

                                    /* regular exit */
                                    res_OPEN4.status = NFS4_OK;
                                    return res_OPEN4.status;
                                }

                            }
                            /* if( pstate_found_iterate != NULL ) */
                            pstate_previous_iterate = pstate_found_iterate;
                        }
                        while(pstate_found_iterate != NULL);
                    }
                }

                /* Managing GUARDED4 mode */
                if(cache_status != CACHE_INODE_SUCCESS)
                    res_OPEN4.status = nfs4_Errno(cache_status);
                else
                    res_OPEN4.status = NFS4ERR_EXIST;       /* File already exists */
                return res_OPEN4.status;
            }

            /*  if( cache_status != CACHE_INODE_NOT_FOUND ), if file already exists basically */
            LogFullDebug(COMPONENT_NFS_V4, "    OPEN open.how = %d\n", arg_OPEN4.openhow.openflag4_u.how.mode);

            create_arg.use_pnfs = FALSE;
#ifdef _USE_PNFS
            /*  set the file has "managed via pNFS" */
            if(data->pexport->options & EXPORT_OPTION_USE_PNFS)
                create_arg.use_pnfs = TRUE;
#endif                          /* _USE_PNFS */

            /* Create the file, if we reach this point, it does not exist, we can create it */
            if((pentry_newfile = cache_inode_create(pentry_parent,
                                                    &filename,
                                                    REGULAR_FILE,
                                                    mode,
                                                    &create_arg,
                                                    &attr_newfile,
                                                    data->ht,
                                                    data->pclient,
                                                    data->pcontext, &cache_status)) == NULL)
            {
                /* If the file already exists, this is not an error if open mode is UNCHECKED */
                if(cache_status != CACHE_INODE_ENTRY_EXISTS)
                {
                    res_OPEN4.status = nfs4_Errno(cache_status);
                    return res_OPEN4.status;
                }
                else
                {
                    /* If this point is reached, then the file already exists, cache_status == CACHE_INODE_ENTRY_EXISTS and pentry_newfile == NULL
                       This probably means EXCLUSIVE4 mode is used and verifier matches. pentry_newfile is then set to pentry_lookup */
                    pentry_newfile = pentry_lookup;
                }
            }

            /* Prepare state management structure */
            candidate_type = CACHE_INODE_STATE_SHARE;
            candidate_data.share.share_deny = arg_OPEN4.share_deny;
            candidate_data.share.share_access = arg_OPEN4.share_access;
            candidate_data.share.lockheld = 0;

            /* If file is opened under mode EXCLUSIVE4, open verifier should be kept to detect non vicious double open */
            if(arg_OPEN4.openhow.openflag4_u.how.mode == EXCLUSIVE4)
            {
                strncpy(candidate_data.share.oexcl_verifier,
                        arg_OPEN4.openhow.openflag4_u.how.createhow4_u.createverf,
                        NFS4_VERIFIER_SIZE);
            }

            if(cache_inode_add_state(pentry_newfile,
                                     candidate_type,
                                     &candidate_data,
                                     powner,
                                     data->pclient,
                                     data->pcontext,
                                     &pfile_state, &cache_status) != CACHE_INODE_SUCCESS)
            {
                /* Seqid has to be incremented even in this case */
                P(powner->lock);
                powner->seqid += 1;
                V(powner->lock);

                res_OPEN4.status = NFS4ERR_SHARE_DENIED;
                return res_OPEN4.status;
            }

            if(AttrProvided == TRUE)      /* Set the attribute if provided */
            {
                if((cache_status = cache_inode_setattr(pentry_newfile,
                                                       &sattr,
                                                       data->ht,
                                                       data->pclient,
                                                       data->pcontext,
                                                       &cache_status)) !=
                        CACHE_INODE_SUCCESS)
                {
                    res_OPEN4.status = nfs4_Errno(cache_status);
                    return res_OPEN4.status;
                }

            }

            /* Set the openflags variable */
            if(arg_OPEN4.share_deny & OPEN4_SHARE_DENY_WRITE)
                openflags |= FSAL_O_RDONLY;
            if(arg_OPEN4.share_deny & OPEN4_SHARE_DENY_READ)
                openflags |= FSAL_O_WRONLY;
            if(arg_OPEN4.share_access & OPEN4_SHARE_ACCESS_WRITE)
                openflags = FSAL_O_RDWR;
            if(arg_OPEN4.share_access != 0)
                openflags = FSAL_O_RDWR;    /* @todo : BUGAZOMEU : Something better later */

            /* Open the file */
            if(cache_inode_open_by_name(pentry_parent,
                                        &filename,
                                        pentry_newfile,
                                        data->pclient,
                                        openflags,
                                        data->pcontext,
                                        &cache_status) != CACHE_INODE_SUCCESS)
            {
                /* Seqid has to be incremented even in this case */
                P(powner->lock);
                powner->seqid += 1;
                V(powner->lock);

                res_OPEN4.status = NFS4ERR_ACCESS;
                return res_OPEN4.status;
            }

            break;

        case OPEN4_NOCREATE:
            /* It was not a creation, but a regular open */
            /* The filehandle to the new file replaces the current filehandle */
            if(pentry_newfile == NULL)
            {
                if((pentry_newfile = cache_inode_lookup(pentry_parent,
                                                        &filename,
                                                        &attr_newfile,
                                                        data->ht,
                                                        data->pclient,
                                                        data->pcontext,
                                                        &cache_status)) == NULL)
                {
                    res_OPEN4.status = nfs4_Errno(cache_status);
                    return res_OPEN4.status;
                }
            }

            /* OPEN4 is to be done on a file */
            if(pentry_newfile->internal_md.type != REGULAR_FILE)
            {
                if(pentry_newfile->internal_md.type == DIR_BEGINNING
                        || pentry_newfile->internal_md.type == DIR_CONTINUE)
                {
                    res_OPEN4.status = NFS4ERR_ISDIR;
                    return res_OPEN4.status;
                }
                else if(pentry_newfile->internal_md.type == SYMBOLIC_LINK)
                {
                    res_OPEN4.status = NFS4ERR_SYMLINK;
                    return res_OPEN4.status;
                }
                else
                {
                    res_OPEN4.status = NFS4ERR_INVAL;
                    return res_OPEN4.status;
                }
            }

            /* If the file is opened for write, OPEN4 while deny share write access,
             * in this case, check caller has write access to the file */
            if(arg_OPEN4.share_deny & OPEN4_SHARE_DENY_WRITE)
            {
                if(cache_inode_access(pentry_newfile,
                                      FSAL_W_OK,
                                      data->ht,
                                      data->pclient,
                                      data->pcontext, &cache_status) != CACHE_INODE_SUCCESS)
                {
                    res_OPEN4.status = NFS4ERR_ACCESS;
                    return res_OPEN4.status;
                }
                openflags = FSAL_O_WRONLY;
            }

            /* Same check on read: check for readability of a file before opening it for read */
            if(arg_OPEN4.share_access & OPEN4_SHARE_ACCESS_READ)
            {
                if(cache_inode_access(pentry_newfile,
                                      FSAL_R_OK,
                                      data->ht,
                                      data->pclient,
                                      data->pcontext, &cache_status) != CACHE_INODE_SUCCESS)
                {
                    res_OPEN4.status = NFS4ERR_ACCESS;
                    return res_OPEN4.status;
                }
                openflags = FSAL_O_RDONLY;
            }

            /* Same check on write */
            if(arg_OPEN4.share_access & OPEN4_SHARE_ACCESS_WRITE)
            {
                if(cache_inode_access(pentry_newfile,
                                      FSAL_W_OK,
                                      data->ht,
                                      data->pclient,
                                      data->pcontext, &cache_status) != CACHE_INODE_SUCCESS)
                {
                    res_OPEN4.status = NFS4ERR_ACCESS;
                    return res_OPEN4.status;
                }
                openflags = FSAL_O_RDWR;
            }

            /* Try to find if the same open_owner already has acquired a stateid for this file */
            pstate_found_iterate = NULL;
            pstate_previous_iterate = NULL;
            do
            {
                cache_inode_state_iterate(pentry_newfile,
                                          &pstate_found_iterate,
                                          pstate_previous_iterate,
                                          data->pclient, data->pcontext, &cache_status);
                if(cache_status == CACHE_INODE_STATE_ERROR)
                    break;          /* Get out of the loop */

                if(cache_status == CACHE_INODE_INVALID_ARGUMENT)
                {
                    res_OPEN4.status = NFS4ERR_INVAL;
                    return res_OPEN4.status;
                }

                /* Check is open_owner is the same */
                if(pstate_found_iterate != NULL)
                {
                    if((pstate_found_iterate->state_type == CACHE_INODE_STATE_SHARE) &&
                            (pstate_found_iterate->powner->clientid == arg_OPEN4.owner.clientid)
                            &&
                            ((pstate_found_iterate->powner->owner_len ==
                              arg_OPEN4.owner.owner.owner_len)
                             &&
                             (!memcmp
                              (arg_OPEN4.owner.owner.owner_val,
                               pstate_found_iterate->powner->owner_val,
                               pstate_found_iterate->powner->owner_len))))
                    {
                        /* We'll be re-using the found state */
                        pstate_found_same_owner = pstate_found_iterate;
                    }
                    else
                    {

                        /* This is a different owner, check for possible conflicts */

                        if(memcmp(arg_OPEN4.owner.owner.owner_val,
                                  pstate_found_iterate->powner->owner_val,
                                  pstate_found_iterate->powner->owner_len))
                        {
                            switch (pstate_found_iterate->state_type)
                            {
                            case CACHE_INODE_STATE_SHARE:
                                if((pstate_found_iterate->state_data.share.
                                        share_access & OPEN4_SHARE_ACCESS_WRITE)
                                        && (arg_OPEN4.share_deny & OPEN4_SHARE_DENY_WRITE))
                                {
                                    res_OPEN4.status = NFS4ERR_SHARE_DENIED;
                                    return res_OPEN4.status;
                                }

                                break;
                            }
                        }

                    }

                    /* In all cases opening in read access a read denied file or write access to a write denied file
                     * should fail, even if the owner is the same, see discussion in 14.2.16 and 8.9 */
                    if(pstate_found_iterate->state_type == CACHE_INODE_STATE_SHARE)
                    {
                        /* deny read access on read denied file */
                        if((pstate_found_iterate->state_data.share.
                                share_deny & OPEN4_SHARE_DENY_READ)
                                && (arg_OPEN4.share_access & OPEN4_SHARE_ACCESS_READ))
                        {
                            /* Seqid has to be incremented even in this case */
                            P(powner->lock);
                            powner->seqid += 1;
                            V(powner->lock);

                            powner->seqid += 1;
                            res_OPEN4.status = NFS4ERR_SHARE_DENIED;
                            return res_OPEN4.status;
                        }

                        /* deny write access on write denied file */
                        if((pstate_found_iterate->state_data.share.
                                share_deny & OPEN4_SHARE_DENY_WRITE)
                                && (arg_OPEN4.share_access & OPEN4_SHARE_ACCESS_WRITE))
                        {
                            /* Seqid has to be incremented even in this case */
                            P(powner->lock);
                            powner->seqid += 1;
                            V(powner->lock);

                            res_OPEN4.status = NFS4ERR_SHARE_DENIED;
                            return res_OPEN4.status;
                        }

                    }

                }
                /*  if( pstate_found_iterate != NULL ) */
                pstate_previous_iterate = pstate_found_iterate;
            }
            while(pstate_found_iterate != NULL);

            if(pstate_found_same_owner != NULL)
            {
                pfile_state = pstate_found_same_owner;
                pfile_state->seqid += 1;

                P(powner->lock);
                powner->seqid += 1;
                V(powner->lock);

            }
            else
            {
                /* Set the state for the related file */
                /* Prepare state management structure */
                candidate_type = CACHE_INODE_STATE_SHARE;
                candidate_data.share.share_deny = arg_OPEN4.share_deny;
                candidate_data.share.share_access = arg_OPEN4.share_access;

                if(cache_inode_add_state(pentry_newfile,
                                         candidate_type,
                                         &candidate_data,
                                         powner,
                                         data->pclient,
                                         data->pcontext,
                                         &pfile_state,
                                         &cache_status) != CACHE_INODE_SUCCESS)
                {
                    /* Seqid has to be incremented even in this case */
                    P(powner->lock);
                    powner->seqid += 1;
                    V(powner->lock);

                    res_OPEN4.status = NFS4ERR_SHARE_DENIED;
                    return res_OPEN4.status;
                }
            }

            /* Open the file */
            if(cache_inode_open_by_name(pentry_parent,
                                        &filename,
                                        pentry_newfile,
                                        data->pclient,
                                        openflags,
                                        data->pcontext,
                                        &cache_status) != CACHE_INODE_SUCCESS)
            {
                /* Seqid has to be incremented even in this case */
                P(powner->lock);
                powner->seqid += 1;
                V(powner->lock);

                res_OPEN4.status = NFS4ERR_ACCESS;
                return res_OPEN4.status;
            }
            break;

        default:
            /* Seqid has to be incremented even in this case */
            if(powner != NULL)
            {
                P(powner->lock);
                powner->seqid += 1;
                V(powner->lock);
            }

            res_OPEN4.status = NFS4ERR_INVAL;
            return res_OPEN4.status;
            break;
        }                       /* switch( arg_OPEN4.openhow.opentype ) */

        break;

    case CLAIM_PREVIOUS:
        break;

    default:
        /* Seqid has to be incremented even in this case */
        if(powner != NULL)
        {
            P(powner->lock);
            powner->seqid += 1;
            V(powner->lock);
        }

        res_OPEN4.status = NFS4ERR_INVAL;
        return res_OPEN4.status;
        break;
    }                           /*  switch(  arg_OPEN4.claim.claim ) */

    /* Now produce the filehandle to this file */
    if((pnewfsal_handle =
                cache_inode_get_fsal_handle(pentry_newfile, &cache_status)) == NULL)
    {
        res_OPEN4.status = nfs4_Errno(cache_status);
        return res_OPEN4.status;
    }

    /* Allocation of a new file handle */
    if((rc = nfs4_AllocateFH(&newfh4)) != NFS4_OK)
    {
        res_OPEN4.status = rc;
        return res_OPEN4.status;
    }

    /* Building a new fh */
    if(!nfs4_FSALToFhandle(&newfh4, pnewfsal_handle, data))
    {
        res_OPEN4.status = NFS4ERR_SERVERFAULT;
        return res_OPEN4.status;
    }

    /* This new fh replaces the current FH */
    data->currentFH.nfs_fh4_len = newfh4.nfs_fh4_len;
    memcpy(data->currentFH.nfs_fh4_val, newfh4.nfs_fh4_val, newfh4.nfs_fh4_len);

    data->current_entry = pentry_newfile;
    data->current_filetype = REGULAR_FILE;

    /* No do not need newfh any more */
    Mem_Free((char *)newfh4.nfs_fh4_val);

    /* Status of parent directory after the operation */
    if((cache_status = cache_inode_getattr(pentry_parent,
                                           &attr_parent,
                                           data->ht,
                                           data->pclient,
                                           data->pcontext,
                                           &cache_status)) != CACHE_INODE_SUCCESS)
    {
        res_OPEN4.status = nfs4_Errno(cache_status);
        return res_OPEN4.status;
    }

    res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_len = 2;
    if((res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_val =
                (uint32_t *) Mem_Alloc(res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_len *
                                       sizeof(uint32_t))) == NULL)
    {
        res_OPEN4.status = NFS4ERR_SERVERFAULT;
        return res_OPEN4.status;
    }
    res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_val[0] = 0;       /* No Attributes set */
    res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_val[1] = 0;       /* No Attributes set */

    if(arg_OPEN4.openhow.opentype == OPEN4_CREATE)
    {
        tmp_int = 2;
        tmp_attr[0] = FATTR4_SIZE;
        tmp_attr[1] = FATTR4_MODE;
        nfs4_list_to_bitmap4(&(res_OPEN4.OPEN4res_u.resok4.attrset), &tmp_int, tmp_attr);
        res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_len = 2;
    }

    res_OPEN4.OPEN4res_u.resok4.cinfo.after =
        (changeid4) pentry_parent->internal_md.mod_time;
    res_OPEN4.OPEN4res_u.resok4.cinfo.atomic = TRUE;

    res_OPEN4.OPEN4res_u.resok4.stateid.seqid = powner->seqid;
    memcpy(res_OPEN4.OPEN4res_u.resok4.stateid.other, pfile_state->stateid_other, 12);

    /* No delegation */
    res_OPEN4.OPEN4res_u.resok4.delegation.delegation_type = OPEN_DELEGATE_NONE;

    res_OPEN4.OPEN4res_u.resok4.rflags = OPEN4_RESULT_LOCKTYPE_POSIX;

    /* regular exit */
    res_OPEN4.status = NFS4_OK;
    return res_OPEN4.status;
}                               /* nfs41_op_open */
cache_inode_status_t
cache_inode_create(cache_entry_t *parent,
                   const char *name,
                   object_file_type_t type,
                   uint32_t mode,
                   cache_inode_create_arg_t *create_arg,
                   struct req_op_context *req_ctx,
                   cache_entry_t **entry)
{
     cache_inode_status_t status = CACHE_INODE_SUCCESS;
     fsal_status_t fsal_status = {0, 0};
     struct fsal_obj_handle *object_handle;
     struct attrlist object_attributes;
     struct fsal_obj_handle *dir_handle;
     cache_inode_create_arg_t zero_create_arg;
     fsal_accessflags_t access_mask = 0;

     memset(&zero_create_arg, 0, sizeof(zero_create_arg));
     memset(&object_attributes, 0, sizeof(object_attributes));

     if (create_arg == NULL) {
          create_arg = &zero_create_arg;
     }

     if ((type != REGULAR_FILE) && (type != DIRECTORY) &&
         (type != SYMBOLIC_LINK) && (type != SOCKET_FILE) &&
         (type != FIFO_FILE) && (type != CHARACTER_FILE) &&
         (type != BLOCK_FILE)) {
          status = CACHE_INODE_BAD_TYPE;

          *entry = NULL;
          goto out;
        }

    /*
     * Check if caller is allowed to perform the operation
     */
    access_mask = FSAL_MODE_MASK_SET(FSAL_W_OK) |
                  FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_ADD_FILE |
                                     FSAL_ACE_PERM_ADD_SUBDIRECTORY);
    status = cache_inode_access(parent,
                                access_mask,
                                req_ctx);
    if (status != CACHE_INODE_SUCCESS)
        {
          *entry = NULL;
          goto out;
        }

    /* Try to create it first */

    dir_handle = parent->obj_handle;
/* we pass in attributes to the create.  We will get them back below */
    FSAL_SET_MASK(object_attributes.mask, ATTR_MODE|ATTR_OWNER|ATTR_GROUP);
    object_attributes.owner = req_ctx->creds->caller_uid;
    object_attributes.group = req_ctx->creds->caller_gid; /* be more selective? */
    object_attributes.mode = mode;

    switch (type) {
    case REGULAR_FILE:
            fsal_status = dir_handle->ops->create(dir_handle, req_ctx,
                                                  name,
                                                  &object_attributes,
                                                  &object_handle);
            break;

    case DIRECTORY:
            fsal_status = dir_handle->ops->mkdir(dir_handle, req_ctx,
                                                 name,
                                                 &object_attributes,
                                                 &object_handle);
            break;

    case SYMBOLIC_LINK:
            fsal_status = dir_handle->ops->symlink(dir_handle, req_ctx,
                                                   name,
                                                   create_arg->link_content,
                                                   &object_attributes,
                                                   &object_handle);
            break;

        case SOCKET_FILE:
        case FIFO_FILE:
            fsal_status = dir_handle->ops->mknode(dir_handle, req_ctx,
                                                  name,
                                                  type,
                                                  NULL, /* no dev_t needed */
                                                  &object_attributes,
                                                  &object_handle);
            break;

        case BLOCK_FILE:
        case CHARACTER_FILE:
            fsal_status = dir_handle->ops->mknode(dir_handle, req_ctx,
                                                  name,
                                                  type,
                                                  &create_arg->dev_spec,
                                                  &object_attributes,
                                                  &object_handle);
            break;

    default:
            /* we should never go there */
            status = CACHE_INODE_INCONSISTENT_ENTRY;
            *entry = NULL;
            goto out;
            break;
    }

     cache_inode_refresh_attrs_locked(parent, req_ctx);

     /* Check for the result */
     if (FSAL_IS_ERROR(fsal_status)) {
          if (fsal_status.major == ERR_FSAL_STALE) {
               LogEvent(COMPONENT_CACHE_INODE,
                        "FSAL returned STALE on create type %d", type);
               cache_inode_kill_entry(parent);
          } else if (fsal_status.major == ERR_FSAL_EXIST) {
               /* Already exists. Check if type if correct */
               status = cache_inode_lookup(parent,
                                           name,
                                           req_ctx,
                                           entry);
               if (*entry != NULL) {
                    status = CACHE_INODE_ENTRY_EXISTS;
                    if ((*entry)->type != type) {
                         /* Incompatible types, returns NULL */
                         cache_inode_put(*entry);
                         *entry = NULL;
                    }
                    goto out;
               }

               if (status == CACHE_INODE_NOT_FOUND) {
                    /* Too bad, FSAL insist the file exists when we try to
                     * create it, but lookup couldn't find it, retry. */
                    status = CACHE_INODE_INCONSISTENT_ENTRY;
                    goto out;
               }
          }

          status = cache_inode_error_convert(fsal_status);
          *entry = NULL;
          goto out;
     }
     status = cache_inode_new_entry(object_handle,
				    CACHE_INODE_FLAG_CREATE,
				    entry);
     if (*entry == NULL) {
          goto out;
     }

     PTHREAD_RWLOCK_wrlock(&parent->content_lock);
     /* Add this entry to the directory (also takes an internal ref) */
     status = cache_inode_add_cached_dirent(parent,
					    name,
					    *entry,
					    NULL);
     PTHREAD_RWLOCK_unlock(&parent->content_lock);
     if (status != CACHE_INODE_SUCCESS) {
          cache_inode_put(*entry);
          *entry = NULL;
          goto out;
     }

out:
     return status;
}
示例#8
0
int nfs4_op_access(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp)
{
  char __attribute__ ((__unused__)) funcname[] = "nfs4_op_access";

  fsal_attrib_list_t   attr;
  fsal_accessflags_t   access_mask = 0;
  cache_inode_status_t cache_status;
  uint32_t max_access = (ACCESS4_READ | ACCESS4_LOOKUP | ACCESS4_MODIFY |
                         ACCESS4_EXTEND | ACCESS4_DELETE | ACCESS4_EXECUTE);

  /* initialize output */
  res_ACCESS4.ACCESS4res_u.resok4.supported = 0;
  res_ACCESS4.ACCESS4res_u.resok4.access = 0;

  resp->resop = NFS4_OP_ACCESS;
  res_ACCESS4.status = NFS4_OK;

  /* Do basic checks on a filehandle */
  res_ACCESS4.status = nfs4_sanity_check_FH(data, 0LL);
  if(res_ACCESS4.status != NFS4_OK)
    return res_ACCESS4.status;

  /* If Filehandle points to a pseudo fs entry, manage it via pseudofs specific functions */
  if(nfs4_Is_Fh_Pseudo(&(data->currentFH)))
    return nfs4_op_access_pseudo(op, data, resp);

  /* If Filehandle points to a xattr object, manage it via the xattrs specific functions */
  if(nfs4_Is_Fh_Xattr(&(data->currentFH)))
    return nfs4_op_access_xattr(op, data, resp);

  /* Check for input parameter's sanity */
  if(arg_ACCESS4.access > max_access)
    {
      res_ACCESS4.status = NFS4ERR_INVAL;
      return res_ACCESS4.status;
    }

  /* Get the attributes for the object */
  attr = data->current_entry->attributes;

  /* determine the rights to be tested in FSAL */

  if(arg_ACCESS4.access & ACCESS4_READ)
    {
      res_ACCESS4.ACCESS4res_u.resok4.supported |= ACCESS4_READ;
      access_mask |= nfs_get_access_mask(ACCESS4_READ, &attr);
    }

  if((arg_ACCESS4.access & ACCESS4_LOOKUP) && (attr.type == FSAL_TYPE_DIR))
    {
      res_ACCESS4.ACCESS4res_u.resok4.supported |= ACCESS4_LOOKUP;
      access_mask |= nfs_get_access_mask(ACCESS4_LOOKUP, &attr);
    }

  if(arg_ACCESS4.access & ACCESS4_MODIFY)
    {
      res_ACCESS4.ACCESS4res_u.resok4.supported |= ACCESS4_MODIFY;
      access_mask |= nfs_get_access_mask(ACCESS4_MODIFY, &attr);
    }

  if(arg_ACCESS4.access & ACCESS4_EXTEND)
    {
      res_ACCESS4.ACCESS4res_u.resok4.supported |= ACCESS4_EXTEND;
      access_mask |= nfs_get_access_mask(ACCESS4_EXTEND, &attr);
    }

  if((arg_ACCESS4.access & ACCESS4_DELETE) && (attr.type == FSAL_TYPE_DIR))
    {
      res_ACCESS4.ACCESS4res_u.resok4.supported |= ACCESS4_DELETE;
      access_mask |= nfs_get_access_mask(ACCESS4_DELETE, &attr);
    }

  if((arg_ACCESS4.access & ACCESS4_EXECUTE) && (attr.type != FSAL_TYPE_DIR))
    {
      res_ACCESS4.ACCESS4res_u.resok4.supported |= ACCESS4_EXECUTE;
      access_mask |= nfs_get_access_mask(ACCESS4_EXECUTE, &attr);
    }

  nfs4_access_debug("requested access", arg_ACCESS4.access, FSAL_ACE4_MASK(access_mask));

  /* Perform the 'access' call */
  if(cache_inode_access(data->current_entry,
                        access_mask,
                        data->pcontext, &cache_status) == CACHE_INODE_SUCCESS)
        {
      res_ACCESS4.ACCESS4res_u.resok4.access = res_ACCESS4.ACCESS4res_u.resok4.supported;
      nfs4_access_debug("granted access", arg_ACCESS4.access, 0);
    }

  if(cache_status == CACHE_INODE_FSAL_EACCESS)
        {
      /*
       * We have to determine which access bits are good one by one
       */
      res_ACCESS4.ACCESS4res_u.resok4.access = 0;

      access_mask = nfs_get_access_mask(ACCESS4_READ, &attr);
      if(cache_inode_access(data->current_entry,
                            access_mask,
                            data->pcontext, &cache_status) == CACHE_INODE_SUCCESS)
        res_ACCESS4.ACCESS4res_u.resok4.access |= ACCESS4_READ;

      if(attr.type == FSAL_TYPE_DIR)
        {
          access_mask = nfs_get_access_mask(ACCESS4_LOOKUP, &attr);
          if(cache_inode_access(data->current_entry,
                                access_mask,
                                data->pcontext, &cache_status) == CACHE_INODE_SUCCESS)
            res_ACCESS4.ACCESS4res_u.resok4.access |= ACCESS4_LOOKUP;
    }

      access_mask = nfs_get_access_mask(ACCESS4_MODIFY, &attr);
      if(cache_inode_access(data->current_entry,
                            access_mask,
                            data->pcontext, &cache_status) == CACHE_INODE_SUCCESS)
        res_ACCESS4.ACCESS4res_u.resok4.access |= ACCESS4_MODIFY;

      access_mask = nfs_get_access_mask(ACCESS4_EXTEND, &attr);
      if(cache_inode_access(data->current_entry,
                            access_mask,
                            data->pcontext, &cache_status) == CACHE_INODE_SUCCESS)
        res_ACCESS4.ACCESS4res_u.resok4.access |= ACCESS4_EXTEND;

      if(attr.type == FSAL_TYPE_DIR)
        {
          access_mask = nfs_get_access_mask(ACCESS4_DELETE, &attr);
          if(cache_inode_access(data->current_entry,
                                access_mask,
                                data->pcontext, &cache_status) == CACHE_INODE_SUCCESS)
            res_ACCESS4.ACCESS4res_u.resok4.access |= ACCESS4_DELETE;
        }

      if(attr.type != FSAL_TYPE_DIR)
        {
          access_mask = nfs_get_access_mask(ACCESS4_EXECUTE, &attr);
          if(cache_inode_access(data->current_entry,
                                access_mask,
                                data->pcontext, &cache_status) == CACHE_INODE_SUCCESS)
            res_ACCESS4.ACCESS4res_u.resok4.access |= ACCESS4_EXECUTE;
        }

      nfs4_access_debug("reduced access", res_ACCESS4.ACCESS4res_u.resok4.access, 0);
    }

  res_ACCESS4.status = NFS4_OK;

  return res_ACCESS4.status;
}                               /* nfs4_op_access */