int fsal_internal_proxy_fsal_name_2_utf8(fsal_name_t * pname, utf8string * utf8str) { char tmpstr[FSAL_MAX_NAME_LEN]; fsal_status_t fsal_status; if(pname == NULL || utf8str == NULL) return FALSE; fsal_status = FSAL_name2str(pname, tmpstr, FSAL_MAX_NAME_LEN); if(fsal_status.major != ERR_FSAL_NO_ERROR) return FALSE; if(utf8str->utf8string_len == 0) { if((utf8str->utf8string_val = (char *)Mem_Alloc_Label(pname->len, "fsal_internal_proxy_fsal_name_2_utf8")) == NULL) return FALSE; else utf8str->utf8string_len = pname->len; } if(str2utf8(tmpstr, utf8str) == -1) return FALSE; return TRUE; } /* fsal_internal_proxy_fsal_name_2_utf8 */
/** * FSAL_link: * Create a hardlink. * * \param exttarget (input): * Handle of the target object. * \param extdir (input): * Pointer to the directory handle where * the hardlink is to be created. * \param link_name (input): * Pointer to the name of the hardlink to be created. * \param extcontext (input): * Authentication context for the operation (user,...). * \param accessmode (input): * Mode for the directory to be created. * (the umask defined into the FSAL configuration file * will be applied on it). * \param attributes (optionnal input/output): * The post_operation attributes of the linked object. * As input, it defines the attributes that the caller * wants to retrieve (by positioning flags into this structure) * and the output is built considering this input * (it fills the structure according to the flags it contains). * May be NULL. * * \return Major error codes : * - ERR_FSAL_NO_ERROR (no error) * - ERR_FSAL_STALE (target or dir does not address an existing object) * - ERR_FSAL_FAULT (a NULL pointer was passed as mandatory argument) * - Other error codes can be returned : * ERR_FSAL_ACCESS, ERR_FSAL_EXIST, ERR_FSAL_IO, ... * * NB: if getting postop attributes failed, * the function does not return an error * but the FSAL_ATTR_RDATTR_ERR bit is set in * the attributes->asked_attributes field. */ fsal_status_t CEPHFSAL_link(fsal_handle_t * exttarget, fsal_handle_t * extdir, fsal_name_t * link_name, fsal_op_context_t * extcontext, fsal_attrib_list_t * attributes) { int rc; struct stat st; char strname[FSAL_MAX_NAME_LEN]; cephfsal_handle_t* target = (cephfsal_handle_t*) exttarget; cephfsal_handle_t* dir = (cephfsal_handle_t*) extdir; cephfsal_op_context_t* context = (cephfsal_op_context_t*) context; struct ceph_mount_info *cmount = context->export_context->cmount; int uid = FSAL_OP_CONTEXT_TO_UID(context); int gid = FSAL_OP_CONTEXT_TO_GID(context); /* sanity checks. * note : attributes is optional. */ if(!target || !dir || !context || !link_name) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_link); memset(target, 0, sizeof(cephfsal_handle_t)); /* Tests if hardlinking is allowed by configuration. */ if(!global_fs_info.link_support) Return(ERR_FSAL_NOTSUPP, 0, INDEX_FSAL_link); FSAL_name2str(link_name, strname, FSAL_MAX_NAME_LEN); TakeTokenFSCall(); rc = ceph_ll_link(cmount, VINODE(target), VINODE(dir), strname, &st, uid, gid); ReleaseTokenFSCall(); if (rc < 0) Return(posix2fsal_error(rc), 0, INDEX_FSAL_link); if(attributes) { fsal_status_t status; status = posix2fsal_attributes(&st, attributes); if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(attributes->asked_attributes); FSAL_SET_MASK(attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_link); } } /* OK */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_link); }
/** * FSAL_lookup : * Looks up for an object into a directory. * * Note : if parent handle and filename are NULL, * this retrieves root's handle. * * \param parent_directory_handle (input) * Handle of the parent directory to search the object in. * \param filename (input) * The name of the object to find. * \param p_context (input) * Authentication context for the operation (user,...). * \param object_handle (output) * The handle of the object corresponding to filename. * \param object_attributes (optional input/output) * Pointer to the attributes of the object we found. * As input, it defines the attributes that the caller * wants to retrieve (by positioning flags into this structure) * and the output is built considering this input * (it fills the structure according to the flags it contains). * It can be NULL (increases performances). * * \return Major error codes : * - ERR_FSAL_NO_ERROR (no error) * - ERR_FSAL_STALE (parent_directory_handle does not address an existing object) * - ERR_FSAL_NOTDIR (parent_directory_handle does not address a directory) * - ERR_FSAL_NOENT (the object designated by p_filename does not exist) * - ERR_FSAL_XDEV (tried to operate a lookup on a filesystem junction. * Use FSAL_lookupJunction instead) * - ERR_FSAL_FAULT (a NULL pointer was passed as mandatory argument) * - Other error codes can be returned : * ERR_FSAL_ACCESS, ERR_FSAL_IO, ... * */ fsal_status_t CEPHFSAL_lookup(fsal_handle_t * extparent, fsal_name_t * filename, fsal_op_context_t * extcontext, fsal_handle_t * exthandle, fsal_attrib_list_t * object_attributes) { int rc; struct stat st; fsal_status_t status; cephfsal_handle_t* parent = (cephfsal_handle_t*) extparent; cephfsal_op_context_t* context = (cephfsal_op_context_t*) extcontext; cephfsal_handle_t* handle = (cephfsal_handle_t*) exthandle; char str[FSAL_MAX_NAME_LEN+1]; struct ceph_mount_info *cmount = context->export_context->cmount; /* sanity checks * note : object_attributes is optionnal * parent_directory_handle may be null for getting FS root. */ if(!handle || !context) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_lookup); memset(handle, 0, sizeof(cephfsal_handle_t)); /* retrieves root handle */ if(!parent) { /* check that filename is NULL, * else, parent should not * be NULL. */ if(filename != NULL) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_lookup); /* Ceph seems to have a constant identifying the root inode. Possible source of bugs, so check here if trouble */ VINODE(handle).ino.val = CEPH_INO_ROOT; VINODE(handle).snapid.val = CEPH_NOSNAP; if(object_attributes) { status = CEPHFSAL_getattrs(exthandle, extcontext, object_attributes); if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(object_attributes->asked_attributes); FSAL_SET_MASK(object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } } else /* this is a real lookup(parent, name) */ { /* the filename should not be null */ if(filename == NULL) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_lookup); FSAL_name2str(filename, str, FSAL_MAX_NAME_LEN); /* Ceph returns POSIX errors, so let's use them */ rc = ceph_ll_lookup(cmount, VINODE(parent), str, &st, FSAL_OP_CONTEXT_TO_UID(context), FSAL_OP_CONTEXT_TO_GID(context)); if(rc) { Return(posix2fsal_error(rc), 0, INDEX_FSAL_lookup); } rc = stat2fsal_fh(cmount, &st, handle); if (rc < 0) Return(posix2fsal_error(rc), 0, INDEX_FSAL_create); if(object_attributes) { /* convert attributes */ status = posix2fsal_attributes(&st, object_attributes); if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(object_attributes->asked_attributes); FSAL_SET_MASK(object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_lookup); } } } /* lookup complete ! */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_lookup); }
int nfs3_Readdirplus(nfs_arg_t * parg, exportlist_t * pexport, fsal_op_context_t * pcontext, cache_inode_client_t * pclient, hash_table_t * ht, struct svc_req *preq, nfs_res_t * pres) { static char __attribute__ ((__unused__)) funcName[] = "nfs3_Readdirplus"; typedef char entry_name_array_item_t[FSAL_MAX_NAME_LEN]; typedef char fh3_buffer_item_t[NFS3_FHSIZE]; unsigned int delta = 0; cache_entry_t *dir_pentry = NULL; cache_entry_t *pentry_dot_dot = NULL; unsigned long dircount; unsigned long maxcount; fsal_attrib_list_t dir_attr; fsal_attrib_list_t entry_attr; uint64_t begin_cookie; uint64_t end_cookie; uint64_t cache_inode_cookie; cache_inode_dir_entry_t **dirent_array = NULL; cookieverf3 cookie_verifier; int rc; unsigned int i = 0; unsigned int num_entries; unsigned long space_used; unsigned long estimated_num_entries; unsigned long asked_num_entries; cache_inode_file_type_t dir_filetype; cache_inode_endofdir_t eod_met = UNASSIGNED_EOD; cache_inode_status_t cache_status; cache_inode_status_t cache_status_gethandle; fsal_handle_t *pfsal_handle = NULL; entry_name_array_item_t *entry_name_array = NULL; fh3_buffer_item_t *fh3_array = NULL; entryplus3 reference_entry; READDIRPLUS3resok reference_reply; int dir_pentry_unlock = FALSE; if(isDebug(COMPONENT_NFSPROTO) || isDebug(COMPONENT_NFS_READDIR)) { char str[LEN_FH_STR]; log_components_t component; sprint_fhandle3(str, &(parg->arg_readdirplus3.dir)); if(isDebug(COMPONENT_NFSPROTO)) component = COMPONENT_NFSPROTO; else component = COMPONENT_NFS_READDIR; LogDebug(component, "REQUEST PROCESSING: Calling nfs3_Readdirplus handle: %s", str); } /* to avoid setting it on each error case */ pres->res_readdir3.READDIR3res_u.resfail.dir_attributes.attributes_follow = FALSE; dircount = parg->arg_readdirplus3.dircount; maxcount = parg->arg_readdirplus3.maxcount; begin_cookie = (unsigned int)parg->arg_readdirplus3.cookie; /* FIXME: This calculation over estimates the number of bytes that * READDIRPLUS3resok will use on the wire by 4 bytes on x86_64. */ space_used = sizeof(reference_reply.dir_attributes.attributes_follow) + sizeof(reference_reply.dir_attributes.post_op_attr_u.attributes) + sizeof(reference_reply.cookieverf) + sizeof(reference_reply.reply.eof); estimated_num_entries = (dircount - space_used + sizeof(entry3 *)) / (sizeof(entry3) - sizeof(char *)*2); // estimated_num_entries *= 4; LogFullDebug(COMPONENT_NFS_READDIR, "nfs3_Readdirplus: dircount=%lu maxcount=%lu begin_cookie=%" PRIu64" space_used=%lu estimated_num_entries=%lu", dircount, maxcount, begin_cookie, space_used, estimated_num_entries); /* Is this a xattr FH ? */ if(nfs3_Is_Fh_Xattr(&(parg->arg_readdirplus3.dir))) return nfs3_Readdirplus_Xattr(parg, pexport, pcontext, pclient, ht, preq, pres); /* Convert file handle into a vnode */ if((dir_pentry = nfs_FhandleToCache(preq->rq_vers, NULL, &(parg->arg_readdirplus3.dir), NULL, NULL, &(pres->res_readdirplus3.status), NULL, &dir_attr, pcontext, pclient, ht, &rc)) == NULL) { /* return NFS_REQ_DROP ; */ return rc; } /* Extract the filetype */ dir_filetype = cache_inode_fsal_type_convert(dir_attr.type); /* Sanity checks -- must be a directory */ if(dir_filetype != DIRECTORY) { pres->res_readdirplus3.status = NFS3ERR_NOTDIR; return NFS_REQ_OK; } /* switch */ memset(cookie_verifier, 0, sizeof(cookieverf3)); /* * If cookie verifier is used, then an non-trivial value is * returned to the client This value is the mtime of * the directory. If verifier is unused (as in many NFS * Servers) then only a set of zeros is returned (trivial * value) */ if(pexport->UseCookieVerifier) memcpy(cookie_verifier, &(dir_attr.mtime), sizeof(dir_attr.mtime)); /* * nothing to do if != 0 because the area is already full of * zero */ if(pexport->UseCookieVerifier && (begin_cookie != 0)) { /* * Not the first call, so we have to check the cookie * verifier */ if(memcmp(cookie_verifier, parg->arg_readdirplus3.cookieverf, NFS3_COOKIEVERFSIZE) != 0) { pres->res_readdirplus3.status = NFS3ERR_BAD_COOKIE; return NFS_REQ_OK; } } if((dirent_array = (cache_inode_dir_entry_t **) Mem_Alloc_Label( estimated_num_entries * sizeof(cache_inode_dir_entry_t*), "cache_inode_dir_entry_t in nfs3_Readdirplus")) == NULL) { pres->res_readdirplus3.status = NFS3ERR_IO; return NFS_REQ_DROP; } pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries = NULL; pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.eof = FALSE; /** @todo XXXX fix this--compare nfs4_op_readdir */ /* How many entries will we retry from cache_inode ? */ if(begin_cookie > 1) { asked_num_entries = estimated_num_entries; cache_inode_cookie = begin_cookie; } else { asked_num_entries = ((estimated_num_entries > 2) ? estimated_num_entries - 2 : 0); /* Keep space for '.' and '..' */ cache_inode_cookie = 0; } /* A definition that will be very useful to avoid very long names for variables */ #define RES_READDIRPLUS_REPLY pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply /* Call readdir */ if(cache_inode_readdir(dir_pentry, pexport->cache_inode_policy, cache_inode_cookie, asked_num_entries, &num_entries, &end_cookie, &eod_met, dirent_array, ht, &dir_pentry_unlock, pclient, pcontext, &cache_status) == CACHE_INODE_SUCCESS) { LogFullDebug(COMPONENT_NFS_READDIR, "Readdirplus3 -> Call to cache_inode_readdir( cookie=%" PRIu64", asked=%lu ) -> num_entries = %u", cache_inode_cookie, asked_num_entries, num_entries); if(eod_met == END_OF_DIR) { LogFullDebug(COMPONENT_NFS_READDIR, "+++++++++++++++++++++++++++++++++++++++++> EOD MET "); } /* If nothing was found, return nothing, but if cookie=0, we should return . and .. */ if((num_entries == 0) && (asked_num_entries != 0) && (begin_cookie > 1)) { pres->res_readdirplus3.status = NFS3_OK; pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries = NULL; pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.eof = TRUE; nfs_SetPostOpAttr(pcontext, pexport, dir_pentry, NULL, &(pres->res_readdirplus3.READDIRPLUS3res_u.resok. dir_attributes)); memcpy(pres->res_readdirplus3.READDIRPLUS3res_u.resok.cookieverf, cookie_verifier, sizeof(cookieverf3)); } else { /* Allocation of the structure for reply */ entry_name_array = (entry_name_array_item_t *) Mem_Alloc_Label(estimated_num_entries * (FSAL_MAX_NAME_LEN + 1), "entry_name_array in nfs3_Readdirplus"); if(entry_name_array == NULL) { /* after successful cache_inode_readdir, dir_pentry may be * read locked */ if (dir_pentry_unlock) V_r(&dir_pentry->lock); if( !CACHE_INODE_KEEP_CONTENT( dir_pentry->policy ) ) cache_inode_release_dirent( dirent_array, num_entries, pclient ) ; Mem_Free((char *)dirent_array); return NFS_REQ_DROP; } pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries = (entryplus3 *) Mem_Alloc_Label(estimated_num_entries * sizeof(entryplus3), "READDIRPLUS3res_u.resok.reply.entries"); if(pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries == NULL) { /* after successful cache_inode_readdir, dir_pentry may be * read locked */ if (dir_pentry_unlock) V_r(&dir_pentry->lock); if( !CACHE_INODE_KEEP_CONTENT( dir_pentry->policy ) ) cache_inode_release_dirent( dirent_array, num_entries, pclient ) ; Mem_Free((char *)dirent_array); Mem_Free((char *)entry_name_array); return NFS_REQ_DROP; } /* Allocation of the file handles */ fh3_array = (fh3_buffer_item_t *) Mem_Alloc_Label(estimated_num_entries * NFS3_FHSIZE, "Filehandle V3 in nfs3_Readdirplus"); if(fh3_array == NULL) { /* after successful cache_inode_readdir, dir_pentry may be * read locked */ if (dir_pentry_unlock) V_r(&dir_pentry->lock); if( !CACHE_INODE_KEEP_CONTENT( dir_pentry->policy ) ) cache_inode_release_dirent( dirent_array, num_entries, pclient ) ; Mem_Free((char *)dirent_array); Mem_Free((char *)entry_name_array); return NFS_REQ_DROP; } delta = 0; /* manage . and .. */ if(begin_cookie == 0) { /* Fill in '.' */ if(estimated_num_entries > 0) { if((pfsal_handle = cache_inode_get_fsal_handle(dir_pentry, &cache_status_gethandle)) == NULL) { /* after successful cache_inode_readdir, dir_pentry * may be read locked */ if (dir_pentry_unlock) V_r(&dir_pentry->lock); if( !CACHE_INODE_KEEP_CONTENT( dir_pentry->policy ) ) cache_inode_release_dirent( dirent_array, num_entries, pclient ) ; Mem_Free((char *)dirent_array); Mem_Free((char *)entry_name_array); Mem_Free((char *)fh3_array); pres->res_readdirplus3.status = nfs3_Errno(cache_status_gethandle); return NFS_REQ_OK; } FSAL_DigestHandle(FSAL_GET_EXP_CTX(pcontext), FSAL_DIGEST_FILEID3, pfsal_handle, (caddr_t) & (RES_READDIRPLUS_REPLY.entries[0]. fileid)); RES_READDIRPLUS_REPLY.entries[0].name = entry_name_array[0]; strcpy(RES_READDIRPLUS_REPLY.entries[0].name, "."); RES_READDIRPLUS_REPLY.entries[0].cookie = 1; pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[0]. name_handle.post_op_fh3_u.handle.data.data_val = (char *)fh3_array[0]; if(nfs3_FSALToFhandle (&pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[0]. name_handle.post_op_fh3_u.handle, pfsal_handle, pexport) == 0) { /* after successful cache_inode_readdir, dir_pentry may * be read locked */ if (dir_pentry_unlock) V_r(&dir_pentry->lock); if( !CACHE_INODE_KEEP_CONTENT( dir_pentry->policy ) ) cache_inode_release_dirent( dirent_array, num_entries, pclient ) ; Mem_Free((char *)dirent_array); Mem_Free((char *)entry_name_array); Mem_Free((char *)fh3_array); pres->res_readdirplus3.status = NFS3ERR_BADHANDLE; return NFS_REQ_OK; } RES_READDIRPLUS_REPLY.entries[0].name_attributes.attributes_follow = FALSE; RES_READDIRPLUS_REPLY.entries[0].name_handle.handle_follows = FALSE; entry_attr = dir_pentry->attributes; /* Set PostPoFh3 structure */ pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[0]. name_handle.handle_follows = TRUE; pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[0]. name_handle.post_op_fh3_u.handle.data.data_len = sizeof(file_handle_v3_t); nfs_SetPostOpAttr(pcontext, pexport, dir_pentry, &entry_attr, &(pres->res_readdirplus3.READDIRPLUS3res_u.resok. reply.entries[0].name_attributes)); LogFullDebug(COMPONENT_NFS_READDIR, "Readdirplus3 -> i=0 num_entries=%d space_used=%lu maxcount=%lu Name=. FileId=%016llx Cookie=%llu", num_entries, space_used, maxcount, RES_READDIRPLUS_REPLY.entries[0].fileid, RES_READDIRPLUS_REPLY.entries[0].cookie); delta += 1; } } /* Fill in '..' */ if(begin_cookie <= 1) { if(estimated_num_entries > delta) { if((pentry_dot_dot = cache_inode_lookupp_sw(dir_pentry, ht, pclient, pcontext, &cache_status_gethandle, !dir_pentry_unlock)) == NULL) { /* after successful cache_inode_readdir, dir_pentry may * be read locked */ if (dir_pentry_unlock) V_r(&dir_pentry->lock); if( !CACHE_INODE_KEEP_CONTENT( dir_pentry->policy ) ) cache_inode_release_dirent( dirent_array, num_entries, pclient ) ; Mem_Free((char *)dirent_array); Mem_Free((char *)entry_name_array); Mem_Free((char *)fh3_array); pres->res_readdirplus3.status = nfs3_Errno(cache_status_gethandle); return NFS_REQ_OK; } if((pfsal_handle = cache_inode_get_fsal_handle(pentry_dot_dot, &cache_status_gethandle)) == NULL) { /* after successful cache_inode_readdir, dir_pentry may * be read locked */ if (dir_pentry_unlock) V_r(&dir_pentry->lock); if( !CACHE_INODE_KEEP_CONTENT( dir_pentry->policy ) ) cache_inode_release_dirent( dirent_array, num_entries, pclient ) ; Mem_Free((char *)dirent_array); Mem_Free((char *)entry_name_array); Mem_Free((char *)fh3_array); pres->res_readdirplus3.status = nfs3_Errno(cache_status_gethandle); return NFS_REQ_OK; } FSAL_DigestHandle(FSAL_GET_EXP_CTX(pcontext), FSAL_DIGEST_FILEID3, pfsal_handle, (caddr_t) & (RES_READDIRPLUS_REPLY.entries[delta]. fileid)); RES_READDIRPLUS_REPLY.entries[delta].name = entry_name_array[delta]; strcpy(RES_READDIRPLUS_REPLY.entries[delta].name, ".."); /* Getting a file handle */ pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[delta]. name_handle.post_op_fh3_u.handle.data.data_val = (char *)fh3_array[delta]; if(nfs3_FSALToFhandle (&pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[delta]. name_handle.post_op_fh3_u.handle, pfsal_handle, pexport) == 0) { /* after successful cache_inode_readdir, dir_pentry may * be read locked */ if (dir_pentry_unlock) V_r(&dir_pentry->lock); if( !CACHE_INODE_KEEP_CONTENT( dir_pentry->policy ) ) cache_inode_release_dirent( dirent_array, num_entries, pclient ) ; Mem_Free((char *)dirent_array); Mem_Free((char *)entry_name_array); Mem_Free((char *)fh3_array); pres->res_readdirplus3.status = NFS3ERR_BADHANDLE; return NFS_REQ_OK; } RES_READDIRPLUS_REPLY.entries[delta].cookie = 2; RES_READDIRPLUS_REPLY.entries[delta].name_attributes.attributes_follow = FALSE; RES_READDIRPLUS_REPLY.entries[delta].name_handle.handle_follows = FALSE; entry_attr = pentry_dot_dot->attributes; /* Set PostPoFh3 structure */ pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[delta]. name_handle.handle_follows = TRUE; pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[delta]. name_handle.post_op_fh3_u.handle.data.data_len = sizeof(file_handle_v3_t); nfs_SetPostOpAttr(pcontext, pexport, pentry_dot_dot, &entry_attr, &(pres->res_readdirplus3.READDIRPLUS3res_u.resok. reply.entries[delta].name_attributes)); LogFullDebug(COMPONENT_NFS_READDIR, "Readdirplus3 -> i=%d num_entries=%d space_used=%lu maxcount=%lu Name=.. FileId=%016llx Cookie=%llu", delta, num_entries, space_used, maxcount, RES_READDIRPLUS_REPLY.entries[delta].fileid, RES_READDIRPLUS_REPLY.entries[delta].cookie); } RES_READDIRPLUS_REPLY.entries[0].nextentry = &(RES_READDIRPLUS_REPLY.entries[delta]); if(num_entries > delta + 1) /* not 0 ??? */ RES_READDIRPLUS_REPLY.entries[delta].nextentry = &(RES_READDIRPLUS_REPLY.entries[delta + 1]); else RES_READDIRPLUS_REPLY.entries[delta].nextentry = NULL; delta += 1; } /* if( begin_cookie == 0 ) */ for(i = delta; i < num_entries + delta; i++) { unsigned long needed; /* maxcount is the size with the FH and attributes overhead, * so entryplus3 is used instead of entry3. The data structures * in nfs23.h have funny padding depending on the arch (32 or 64). * We can't get an accurate estimate by simply using * sizeof(entryplus3). */ /* FIXME: There is still a 4 byte over estimate here on x86_64. */ /** @todo Remove cookie offset calculation in readdir and readdirplus (obsoleted) */ needed = sizeof(reference_entry) + NFS3_FHSIZE + ((strlen(dirent_array[i - delta]->name.name) + 3) & ~3); /* if delta == 1 or 2, then "." and ".." have already been added * to the readdirplus reply. */ if (i == delta) { needed += needed*delta /* size of a dir entry in reply */ - ((strlen(dirent_array[i - delta]->name.name) + 3) & ~3)*delta /* size of filename for current entry */ + 4*delta; /* size of "." and ".." filenames in reply */ } if((space_used += needed) > maxcount) { /* If delta != 0, then we already added "." or ".." to the reply. */ if(i == delta && delta == 0) { /* Not enough room to make even a single reply */ /* after successful cache_inode_readdir, dir_pentry may * be read locked */ if (dir_pentry_unlock) V_r(&dir_pentry->lock); if( !CACHE_INODE_KEEP_CONTENT( dir_pentry->policy ) ) cache_inode_release_dirent( dirent_array, num_entries, pclient ) ; Mem_Free((char *)dirent_array); Mem_Free((char *)entry_name_array); Mem_Free((char *)fh3_array); pres->res_readdirplus3.status = NFS3ERR_TOOSMALL; return NFS_REQ_OK; } break; /* Make post traitement */ } /* * Get information specific to this entry */ if((pfsal_handle = cache_inode_get_fsal_handle(dirent_array[i - delta]->pentry, &cache_status_gethandle)) == NULL) { /* after successful cache_inode_readdir, dir_pentry may be * read locked */ if (dir_pentry_unlock) V_r(&dir_pentry->lock); if( !CACHE_INODE_KEEP_CONTENT( dir_pentry->policy ) ) cache_inode_release_dirent( dirent_array, num_entries, pclient ) ; Mem_Free((char *)dirent_array); Mem_Free((char *)entry_name_array); Mem_Free((char *)fh3_array); pres->res_readdirplus3.status = nfs3_Errno(cache_status_gethandle); return NFS_REQ_OK; } /* Now fill in the replyed entryplus3 list */ FSAL_DigestHandle(FSAL_GET_EXP_CTX(pcontext), FSAL_DIGEST_FILEID3, pfsal_handle, (caddr_t) & (RES_READDIRPLUS_REPLY.entries[i].fileid)); FSAL_name2str(&dirent_array[i - delta]->name, entry_name_array[i], FSAL_MAX_NAME_LEN); RES_READDIRPLUS_REPLY.entries[i].name = entry_name_array[i]; LogFullDebug(COMPONENT_NFS_READDIR, "Readdirplus3 -> i=%u num_entries=%u delta=%u " "num_entries + delta - 1=%u end_cookie=%"PRIu64, i, num_entries, delta, num_entries + delta - 1, end_cookie); if(i != num_entries + delta - 1) RES_READDIRPLUS_REPLY.entries[i].cookie = dirent_array[i - delta]->cookie; else RES_READDIRPLUS_REPLY.entries[i].cookie = end_cookie; RES_READDIRPLUS_REPLY.entries[i].name_attributes.attributes_follow = FALSE; RES_READDIRPLUS_REPLY.entries[i].name_handle.handle_follows = FALSE; entry_attr = dirent_array[i - delta]->pentry->attributes; pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[i].name_handle.post_op_fh3_u.handle.data.data_val = (char *)fh3_array[i]; /* Compute the NFSv3 file handle */ if(nfs3_FSALToFhandle (&pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[i]. name_handle.post_op_fh3_u.handle, pfsal_handle, pexport) == 0) { /* after successful cache_inode_readdir, dir_pentry may be * read locked */ if (dir_pentry_unlock) V_r(&dir_pentry->lock); if( !CACHE_INODE_KEEP_CONTENT( dir_pentry->policy ) ) cache_inode_release_dirent( dirent_array, num_entries, pclient ) ; Mem_Free((char *)dirent_array); Mem_Free((char *)entry_name_array); Mem_Free((char *)fh3_array); pres->res_readdirplus3.status = NFS3ERR_BADHANDLE; return NFS_REQ_OK; } /* Set PostPoFh3 structure */ pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[i].name_handle.handle_follows = TRUE; pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[i].name_handle.post_op_fh3_u.handle.data.data_len = sizeof(file_handle_v3_t); nfs_SetPostOpAttr(pcontext, pexport, dirent_array[i - delta]->pentry, &entry_attr, &(pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[i].name_attributes)); LogFullDebug(COMPONENT_NFS_READDIR, "Readdirplus3 -> i=%d, num_entries=%d needed=%lu space_used=%lu maxcount=%lu Name=%s FileId=%016llx Cookie=%llu", i, num_entries, needed, space_used, maxcount, dirent_array[i - delta]->name.name, RES_READDIRPLUS_REPLY.entries[i].fileid, RES_READDIRPLUS_REPLY.entries[i].cookie); RES_READDIRPLUS_REPLY.entries[i].nextentry = NULL; if(i != 0) RES_READDIRPLUS_REPLY.entries[i - 1].nextentry = &(RES_READDIRPLUS_REPLY.entries[i]); } pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.eof = FALSE; } nfs_SetPostOpAttr(pcontext, pexport, dir_pentry, &dir_attr, &(pres->res_readdirplus3.READDIRPLUS3res_u.resok.dir_attributes)); memcpy(pres->res_readdirplus3.READDIRPLUS3res_u.resok.cookieverf, cookie_verifier, sizeof(cookieverf3)); pres->res_readdirplus3.status = NFS3_OK; if((eod_met == END_OF_DIR) && (i == num_entries + delta)) { /* End of directory */ LogFullDebug(COMPONENT_NFS_READDIR, "============================================================> EOD MET !!!!!!"); pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.eof = TRUE; } else pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.eof = FALSE; nfs_SetPostOpAttr(pcontext, pexport, dir_pentry, &dir_attr, &(pres->res_readdirplus3.READDIRPLUS3res_u.resok.dir_attributes)); memcpy(pres->res_readdirplus3.READDIRPLUS3res_u.resok.cookieverf, cookie_verifier, sizeof(cookieverf3)); LogFullDebug(COMPONENT_NFS_READDIR, "============================================================"); /* after successful cache_inode_readdir, dir_pentry may be * read locked */ if (dir_pentry_unlock) V_r(&dir_pentry->lock); /* Free the memory */ if( !CACHE_INODE_KEEP_CONTENT( dir_pentry->policy ) ) cache_inode_release_dirent( dirent_array, num_entries, pclient ) ; Mem_Free((char *)dirent_array); return NFS_REQ_OK; } /* If we are here, there was an error */ /* after successful cache_inode_readdir, dir_pentry may be * read locked */ if (dir_pentry_unlock) V_r(&dir_pentry->lock); /* Free the memory */ if( !CACHE_INODE_KEEP_CONTENT( dir_pentry->policy ) ) cache_inode_release_dirent( dirent_array, num_entries, pclient ) ; Mem_Free((char *)dirent_array); Mem_Free((char *)entry_name_array); Mem_Free((char *)fh3_array); /* Is this a retryable error */ if(nfs_RetryableError(cache_status)) return NFS_REQ_DROP; /* Set failed status */ nfs_SetFailedStatus(pcontext, pexport, NFS_V3, cache_status, NULL, &pres->res_readdirplus3.status, dir_pentry, &(pres->res_readdirplus3.READDIRPLUS3res_u.resfail.dir_attributes), NULL, NULL, NULL, NULL, NULL, NULL); return NFS_REQ_OK; } /* nfs3_Readdirplus */
int nfs3_Readdirplus(nfs_arg_t * parg, exportlist_t * pexport, fsal_op_context_t * pcontext, cache_inode_client_t * pclient, hash_table_t * ht, struct svc_req *preq, nfs_res_t * pres) { static char __attribute__ ((__unused__)) funcName[] = "nfs3_Readdirplus"; typedef char entry_name_array_item_t[FSAL_MAX_NAME_LEN]; typedef char fh3_buffer_item_t[NFS3_FHSIZE]; unsigned int delta = 0; cache_entry_t *dir_pentry = NULL; cache_entry_t *pentry_dot_dot = NULL; unsigned long dircount; unsigned long maxcount; fsal_attrib_list_t dir_attr; fsal_attrib_list_t entry_attr; unsigned int begin_cookie; unsigned int end_cookie; unsigned int cache_inode_cookie; cache_inode_dir_entry_t *dirent_array = NULL; unsigned int *cookie_array = NULL; cookieverf3 cookie_verifier; int rc; unsigned int i = 0; unsigned int num_entries; unsigned long space_used; unsigned long estimated_num_entries; unsigned long asked_num_entries; cache_inode_file_type_t dir_filetype; cache_inode_endofdir_t eod_met = UNASSIGNED_EOD; cache_inode_status_t cache_status; cache_inode_status_t cache_status_gethandle; fsal_handle_t *pfsal_handle = NULL; entry_name_array_item_t *entry_name_array = NULL; fh3_buffer_item_t *fh3_array = NULL; /* to avoid setting it on each error case */ pres->res_readdir3.READDIR3res_u.resfail.dir_attributes.attributes_follow = FALSE; dircount = parg->arg_readdirplus3.dircount; maxcount = parg->arg_readdirplus3.maxcount; begin_cookie = (unsigned int)parg->arg_readdirplus3.cookie; space_used = sizeof(READDIRPLUS3resok); estimated_num_entries = dircount / sizeof(entryplus3); LogFullDebug(COMPONENT_NFS_READDIR, "---> nfs3_Readdirplus: dircount=%d maxcount=%d begin_cookie=%d space_used=%d estimated_num_entries=%d\n", dircount, maxcount, begin_cookie, space_used, estimated_num_entries); /* Is this a xattr FH ? */ if(nfs3_Is_Fh_Xattr(&(parg->arg_readdirplus3.dir))) return nfs3_Readdirplus_Xattr(parg, pexport, pcontext, pclient, ht, preq, pres); /* Convert file handle into a vnode */ /* BUGAZOMEU : rajouter acces direct au DIR_CONTINUE */ if((dir_pentry = nfs_FhandleToCache(preq->rq_vers, NULL, &(parg->arg_readdirplus3.dir), NULL, NULL, &(pres->res_readdirplus3.status), NULL, &dir_attr, pcontext, pclient, ht, &rc)) == NULL) { /* return NFS_REQ_DROP ; */ return rc; } /* Extract the filetype */ dir_filetype = cache_inode_fsal_type_convert(dir_attr.type); /* Sanity checks -- must be a directory */ if((dir_filetype != DIR_BEGINNING) && (dir_filetype != DIR_CONTINUE)) { pres->res_readdirplus3.status = NFS3ERR_NOTDIR; return NFS_REQ_OK; } /* switch */ memset(cookie_verifier, 0, sizeof(cookieverf3)); /* * If cookie verifier is used, then an non-trivial value is * returned to the client This value is the mtime of * the directory. If verifier is unused (as in many NFS * Servers) then only a set of zeros is returned (trivial * value) */ if(pexport->UseCookieVerifier) memcpy(cookie_verifier, &(dir_attr.mtime), sizeof(dir_attr.mtime)); /* * nothing to do if != 0 because the area is already full of * zero */ if(pexport->UseCookieVerifier && (begin_cookie != 0)) { /* * Not the first call, so we have to check the cookie * verifier */ if(memcmp(cookie_verifier, parg->arg_readdirplus3.cookieverf, NFS3_COOKIEVERFSIZE) != 0) { pres->res_readdirplus3.status = NFS3ERR_BAD_COOKIE; return NFS_REQ_OK; } } #ifdef _DEBUG_MEMLEAKS /* For debugging memory leaks */ BuddySetDebugLabel("cache_inode_dir_entry_t in nfs3_Readdirplus"); #endif if((dirent_array = (cache_inode_dir_entry_t *) Mem_Alloc(estimated_num_entries * sizeof(cache_inode_dir_entry_t))) == NULL) { pres->res_readdirplus3.status = NFS3ERR_IO; return NFS_REQ_DROP; } #ifdef _DEBUG_MEMLEAKS /* For debugging memory leaks */ BuddySetDebugLabel("cookie array in nfs3_Readdirplus"); #endif if((cookie_array = (unsigned int *)Mem_Alloc(estimated_num_entries * sizeof(unsigned int))) == NULL) { Mem_Free((char *)dirent_array); pres->res_readdirplus3.status = NFS3ERR_IO; return NFS_REQ_DROP; } pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries = NULL; pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.eof = FALSE; /* How many entries will we retry from cache_inode ? */ if(begin_cookie > 1) { asked_num_entries = estimated_num_entries; cache_inode_cookie = begin_cookie - 2; } else { asked_num_entries = ((estimated_num_entries > 2) ? estimated_num_entries - 2 : 0); /* Keep space for '.' and '..' */ cache_inode_cookie = 0; } /* A definition that will be very useful to avoid very long names for variables */ #define RES_READDIRPLUS_REPLY pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply /* Call readdir */ if(cache_inode_readdir(dir_pentry, cache_inode_cookie, asked_num_entries, &num_entries, &end_cookie, &eod_met, dirent_array, cookie_array, ht, pclient, pcontext, &cache_status) == CACHE_INODE_SUCCESS) { LogFullDebug(COMPONENT_NFS_READDIR, "-- Readdirplus3 -> Call to cache_inode_readdir( cookie=%d, asked=%d ) -> num_entries = %d\n", cache_inode_cookie, asked_num_entries, num_entries); if(eod_met == END_OF_DIR) { LogFullDebug(COMPONENT_NFS_READDIR, "+++++++++++++++++++++++++++++++++++++++++> EOD MET \n"); } /* If nothing was found, return nothing, but if cookie=0, we should return . and .. */ if((num_entries == 0) && (asked_num_entries != 0) && (begin_cookie > 1)) { pres->res_readdirplus3.status = NFS3_OK; pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries = NULL; pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.eof = TRUE; nfs_SetPostOpAttr(pcontext, pexport, dir_pentry, NULL, &(pres->res_readdirplus3.READDIRPLUS3res_u.resok. dir_attributes)); memcpy(pres->res_readdirplus3.READDIRPLUS3res_u.resok.cookieverf, cookie_verifier, sizeof(cookieverf3)); } else { #ifdef _DEBUG_MEMLEAKS /* For debugging memory leaks */ BuddySetDebugLabel("entry_name_array in nfs3_Readdirplus"); #endif /* Allocation of the structure for reply */ entry_name_array = (entry_name_array_item_t *) Mem_Alloc(estimated_num_entries * (FSAL_MAX_NAME_LEN + 1)); if(entry_name_array == NULL) { Mem_Free((char *)dirent_array); Mem_Free((char *)cookie_array); return NFS_REQ_DROP; } #ifdef _DEBUG_MEMLEAKS /* For debugging memory leaks */ BuddySetDebugLabel("READDIRPLUS3res_u.resok.reply.entries"); #endif pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries = (entryplus3 *) Mem_Alloc(estimated_num_entries * sizeof(entryplus3)); if(pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries == NULL) { Mem_Free((char *)dirent_array); Mem_Free((char *)cookie_array); Mem_Free((char *)entry_name_array); return NFS_REQ_DROP; } /* Allocation of the file handles */ #ifdef _DEBUG_MEMLEAKS /* For debugging memory leaks */ BuddySetDebugLabel("Filehandle V3 in nfs3_Readdirplus"); #endif fh3_array = (fh3_buffer_item_t *) Mem_Alloc(estimated_num_entries * NFS3_FHSIZE); #ifdef _DEBUG_MEMLEAKS /* For debugging memory leaks */ BuddySetDebugLabel("N/A"); #endif if(fh3_array == NULL) { Mem_Free((char *)dirent_array); Mem_Free((char *)cookie_array); Mem_Free((char *)entry_name_array); return NFS_REQ_DROP; } delta = 0; /* manage . and .. */ if(begin_cookie == 0) { /* Fill in '.' */ if(estimated_num_entries > 0) { if((pfsal_handle = cache_inode_get_fsal_handle(dir_pentry, &cache_status_gethandle)) == NULL) { Mem_Free((char *)dirent_array); Mem_Free((char *)cookie_array); Mem_Free((char *)entry_name_array); Mem_Free((char *)fh3_array); pres->res_readdirplus3.status = nfs3_Errno(cache_status_gethandle); return NFS_REQ_OK; } FSAL_DigestHandle(FSAL_GET_EXP_CTX(pcontext), FSAL_DIGEST_FILEID3, pfsal_handle, (caddr_t) & (RES_READDIRPLUS_REPLY.entries[0]. fileid)); RES_READDIRPLUS_REPLY.entries[0].name = entry_name_array[0]; strcpy(RES_READDIRPLUS_REPLY.entries[0].name, "."); RES_READDIRPLUS_REPLY.entries[0].cookie = 1; pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[0]. name_handle.post_op_fh3_u.handle.data.data_val = (char *)fh3_array[0]; if(nfs3_FSALToFhandle (&pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[0]. name_handle.post_op_fh3_u.handle, pfsal_handle, pexport) == 0) { Mem_Free((char *)dirent_array); Mem_Free((char *)cookie_array); Mem_Free((char *)entry_name_array); Mem_Free((char *)fh3_array); pres->res_readdirplus3.status = NFS3ERR_BADHANDLE; return NFS_REQ_OK; } RES_READDIRPLUS_REPLY.entries[0].name_attributes.attributes_follow = FALSE; RES_READDIRPLUS_REPLY.entries[0].name_handle.handle_follows = FALSE; cache_inode_get_attributes(dir_pentry, &entry_attr); /* Set PostPoFh3 structure */ pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[0]. name_handle.handle_follows = TRUE; pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[0]. name_handle.post_op_fh3_u.handle.data.data_len = sizeof(file_handle_v3_t); nfs_SetPostOpAttr(pcontext, pexport, dir_pentry, &entry_attr, &(pres->res_readdirplus3.READDIRPLUS3res_u.resok. reply.entries[0].name_attributes)); delta += 1; } } /* Fill in '..' */ if(begin_cookie <= 1) { if(estimated_num_entries > delta) { if((pentry_dot_dot = cache_inode_lookupp(dir_pentry, ht, pclient, pcontext, &cache_status_gethandle)) == NULL) { Mem_Free((char *)dirent_array); Mem_Free((char *)cookie_array); Mem_Free((char *)entry_name_array); Mem_Free((char *)fh3_array); pres->res_readdirplus3.status = nfs3_Errno(cache_status_gethandle); return NFS_REQ_OK; } if((pfsal_handle = cache_inode_get_fsal_handle(pentry_dot_dot, &cache_status_gethandle)) == NULL) { Mem_Free((char *)dirent_array); Mem_Free((char *)cookie_array); Mem_Free((char *)entry_name_array); Mem_Free((char *)fh3_array); pres->res_readdirplus3.status = nfs3_Errno(cache_status_gethandle); return NFS_REQ_OK; } FSAL_DigestHandle(FSAL_GET_EXP_CTX(pcontext), FSAL_DIGEST_FILEID3, pfsal_handle, (caddr_t) & (RES_READDIRPLUS_REPLY.entries[delta]. fileid)); RES_READDIRPLUS_REPLY.entries[delta].name = entry_name_array[delta]; strcpy(RES_READDIRPLUS_REPLY.entries[delta].name, ".."); /* Getting a file handle */ pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[delta]. name_handle.post_op_fh3_u.handle.data.data_val = (char *)fh3_array[delta]; if(nfs3_FSALToFhandle (&pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[0]. name_handle.post_op_fh3_u.handle, pfsal_handle, pexport) == 0) { Mem_Free((char *)dirent_array); Mem_Free((char *)cookie_array); Mem_Free((char *)entry_name_array); Mem_Free((char *)fh3_array); pres->res_readdirplus3.status = NFS3ERR_BADHANDLE; return NFS_REQ_OK; } RES_READDIRPLUS_REPLY.entries[delta].cookie = 2; RES_READDIRPLUS_REPLY.entries[delta].name_attributes.attributes_follow = FALSE; RES_READDIRPLUS_REPLY.entries[delta].name_handle.handle_follows = FALSE; cache_inode_get_attributes(pentry_dot_dot, &entry_attr); /* Set PostPoFh3 structure */ pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[delta]. name_handle.handle_follows = TRUE; pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[delta]. name_handle.post_op_fh3_u.handle.data.data_len = sizeof(file_handle_v3_t); nfs_SetPostOpAttr(pcontext, pexport, pentry_dot_dot, &entry_attr, &(pres->res_readdirplus3.READDIRPLUS3res_u.resok. reply.entries[delta].name_attributes)); } RES_READDIRPLUS_REPLY.entries[0].nextentry = &(RES_READDIRPLUS_REPLY.entries[delta]); if(num_entries > delta + 1) /* not 0 ??? */ RES_READDIRPLUS_REPLY.entries[delta].nextentry = &(RES_READDIRPLUS_REPLY.entries[delta + 1]); else RES_READDIRPLUS_REPLY.entries[delta].nextentry = NULL; delta += 1; } /* if( begin_cookie == 0 ) */ for(i = delta; i < num_entries + delta; i++) { unsigned long needed; /* dircount is the size without the FH and attributes overhead, so entry3 is used intead of entryplus3 */ needed = sizeof(entry3) + ((strlen(dirent_array[i - delta].name.name) + 3) & ~3); /* LogFullDebug(COMPONENT_NFS_READDIR, "==============> i=%d sizeof(entryplus3)=%d needed=%d space_used=%d maxcount=%d num_entries=%d asked_num_entries=%d\n", i, sizeof( entryplus3 ), needed, space_used, maxcount, num_entries, asked_num_entries ) ; */ if((space_used += needed) > maxcount) { if(i == delta) { /* * Not enough room to make even a single reply */ Mem_Free((char *)dirent_array); Mem_Free((char *)cookie_array); Mem_Free((char *)entry_name_array); Mem_Free((char *)fh3_array); pres->res_readdirplus3.status = NFS3ERR_TOOSMALL; return NFS_REQ_OK; } break; /* Make post traitement */ } /* * Get information specific to this entry */ if((pfsal_handle = cache_inode_get_fsal_handle(dirent_array[i - delta].pentry, &cache_status_gethandle)) == NULL) { Mem_Free((char *)dirent_array); Mem_Free((char *)cookie_array); Mem_Free((char *)entry_name_array); Mem_Free((char *)fh3_array); pres->res_readdirplus3.status = nfs3_Errno(cache_status_gethandle); return NFS_REQ_OK; } /* Now fill in the replyed entryplus3 list */ FSAL_DigestHandle(FSAL_GET_EXP_CTX(pcontext), FSAL_DIGEST_FILEID3, pfsal_handle, (caddr_t) & (RES_READDIRPLUS_REPLY.entries[i].fileid)); FSAL_name2str(&dirent_array[i - delta].name, entry_name_array[i], FSAL_MAX_NAME_LEN); RES_READDIRPLUS_REPLY.entries[i].name = entry_name_array[i]; if(i != num_entries + delta - 1) RES_READDIRPLUS_REPLY.entries[i].cookie = cookie_array[i + 1 - delta] + 2; else RES_READDIRPLUS_REPLY.entries[i].cookie = end_cookie + 2; RES_READDIRPLUS_REPLY.entries[i].name_attributes.attributes_follow = FALSE; RES_READDIRPLUS_REPLY.entries[i].name_handle.handle_follows = FALSE; cache_inode_get_attributes(dirent_array[i - delta].pentry, &entry_attr); pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[i].name_handle. post_op_fh3_u.handle.data.data_val = (char *)fh3_array[i]; /* Compute the NFSv3 file handle */ if(nfs3_FSALToFhandle (&pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[i]. name_handle.post_op_fh3_u.handle, pfsal_handle, pexport) == 0) { Mem_Free((char *)dirent_array); Mem_Free((char *)cookie_array); Mem_Free((char *)entry_name_array); Mem_Free((char *)fh3_array); pres->res_readdirplus3.status = NFS3ERR_BADHANDLE; return NFS_REQ_OK; } LogFullDebug(COMPONENT_NFS_READDIR, "-- Readdirplus3 -> i=%d num_entries=%d needed=%d space_used=%lu maxcount=%lu Name=%s FileId=%llu Cookie=%llu\n", i, num_entries, needed, space_used, maxcount, dirent_array[i - delta].name.name, RES_READDIRPLUS_REPLY.entries[i].fileid, RES_READDIRPLUS_REPLY.entries[i].cookie); /* Set PostPoFh3 structure */ pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[i].name_handle. handle_follows = TRUE; pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[i].name_handle. post_op_fh3_u.handle.data.data_len = sizeof(file_handle_v3_t); nfs_SetPostOpAttr(pcontext, pexport, dirent_array[i - delta].pentry, &entry_attr, &(pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply. entries[i].name_attributes)); RES_READDIRPLUS_REPLY.entries[i].nextentry = NULL; if(i != 0) RES_READDIRPLUS_REPLY.entries[i - 1].nextentry = &(RES_READDIRPLUS_REPLY.entries[i]); } pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.eof = FALSE; } nfs_SetPostOpAttr(pcontext, pexport, dir_pentry, &dir_attr, &(pres->res_readdirplus3.READDIRPLUS3res_u.resok.dir_attributes)); memcpy(pres->res_readdirplus3.READDIRPLUS3res_u.resok.cookieverf, cookie_verifier, sizeof(cookieverf3)); pres->res_readdirplus3.status = NFS3_OK; if((eod_met == END_OF_DIR) && (i == num_entries + delta)) { /* End of directory */ LogFullDebug(COMPONENT_NFS_READDIR, "============================================================> EOD MET !!!!!!\n"); pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.eof = TRUE; } else pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.eof = FALSE; nfs_SetPostOpAttr(pcontext, pexport, dir_pentry, &dir_attr, &(pres->res_readdirplus3.READDIRPLUS3res_u.resok.dir_attributes)); memcpy(pres->res_readdirplus3.READDIRPLUS3res_u.resok.cookieverf, cookie_verifier, sizeof(cookieverf3)); LogFullDebug(COMPONENT_NFS_READDIR,"============================================================\n"); /* Free the memory */ Mem_Free((char *)dirent_array); Mem_Free((char *)cookie_array); return NFS_REQ_OK; } /* If we are here, there was an error */ /* Free the memory */ Mem_Free((char *)dirent_array); Mem_Free((char *)cookie_array); Mem_Free((char *)entry_name_array); Mem_Free((char *)fh3_array); /* Is this a retryable error */ if(nfs_RetryableError(cache_status)) return NFS_REQ_DROP; /* Set failed status */ nfs_SetFailedStatus(pcontext, pexport, NFS_V3, cache_status, NULL, &pres->res_readdirplus3.status, dir_pentry, &(pres->res_readdirplus3.READDIRPLUS3res_u.resfail.dir_attributes), NULL, NULL, NULL, NULL, NULL, NULL); return NFS_REQ_OK; } /* nfs3_Readdirplus */
fsal_status_t CEPHFSAL_rename(fsal_handle_t * extold_parent, fsal_name_t * old_name, fsal_handle_t * extnew_parent, fsal_name_t * new_name, fsal_op_context_t * extcontext, fsal_attrib_list_t * src_dir_attributes, fsal_attrib_list_t * tgt_dir_attributes) { int rc; cephfsal_handle_t* old_parent = (cephfsal_handle_t*) extold_parent; cephfsal_handle_t* new_parent = (cephfsal_handle_t*) extnew_parent; cephfsal_op_context_t* context = (cephfsal_op_context_t*) extcontext; char oldstr[FSAL_MAX_NAME_LEN+1]; char newstr[FSAL_MAX_NAME_LEN+1]; int uid = FSAL_OP_CONTEXT_TO_UID(context); int gid = FSAL_OP_CONTEXT_TO_GID(context); /* sanity checks. * note : src/tgt_dir_attributes are optional. */ if(!old_parent || !new_parent || !old_name || !new_name || !context) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_rename); if(src_dir_attributes) { fsal_status_t status = CEPHFSAL_getattrs(extold_parent, extcontext, src_dir_attributes); if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(src_dir_attributes->asked_attributes); FSAL_SET_MASK(src_dir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } if(tgt_dir_attributes) { fsal_status_t status; /* optimization when src=tgt : */ if(!CEPHFSAL_handlecmp(extold_parent, extnew_parent, &status) && src_dir_attributes) { /* If source dir = target dir, we just copy the attributes. * to avoid doing another getattr. */ (*tgt_dir_attributes) = (*src_dir_attributes); } else { status = CEPHFSAL_getattrs(extnew_parent, extcontext, tgt_dir_attributes); if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(tgt_dir_attributes->asked_attributes); FSAL_SET_MASK(tgt_dir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } } FSAL_name2str(old_name, oldstr, FSAL_MAX_NAME_LEN); FSAL_name2str(new_name, newstr, FSAL_MAX_NAME_LEN); rc = ceph_ll_rename(context->export_context->cmount, VINODE(old_parent), oldstr, VINODE(new_parent), newstr, uid, gid); if (rc < 0) Return(posix2fsal_error(rc), 0, INDEX_FSAL_rename); /* OK */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_rename); }
/** * * cache_inode_renew_entry: Renews the attributes for an entry. * * Sets the attributes for an entry located in the cache by its address. Attributes are provided * with compliance to the underlying FSAL semantics. Attributes that are set are returned in "*pattr". * * @param pentry_parent [IN] entry for the parent directory to be managed. * @param pattr [OUT] renewed attributes for the entry that we have found. * @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 Other errors shows a FSAL error. * */ cache_inode_status_t cache_inode_renew_entry(cache_entry_t * pentry, 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_handle_t *pfsal_handle = NULL; fsal_status_t fsal_status; fsal_attrib_list_t object_attributes; fsal_path_t link_content; time_t current_time = time(NULL); time_t entry_time = pentry->internal_md.refresh_time; /* If we do nothing (no expiration) then everything is all right */ *pstatus = CACHE_INODE_SUCCESS; if(isFullDebug(COMPONENT_CACHE_INODE)) { char *type; char grace[20], grace2[20]; unsigned int elapsed = (unsigned int)current_time - (unsigned int)entry_time; int print = 1; cache_inode_expire_to_str(pclient->expire_type_attr, pclient->grace_period_attr, grace); switch(pentry->internal_md.type) { case UNASSIGNED: type = "UNASSIGNED"; break; case REGULAR_FILE: type = "REGULAR_FILE"; break; case CHARACTER_FILE: type = "CHARACTER_FILE"; break; case BLOCK_FILE: type = "BLOCK_FILE"; break; case SYMBOLIC_LINK: print = 0; cache_inode_expire_to_str(pclient->expire_type_link, pclient->grace_period_link, grace2); LogDebug(COMPONENT_CACHE_INODE, "Renew Entry test of %p for SYMBOLIC_LINK elapsed time=%u, grace_period_attr=%s, grace_period_link=%s", pentry, elapsed, grace, grace2); break; case SOCKET_FILE: type = "SOCKET_FILE"; break; case FIFO_FILE: type = "FIFO_FILE"; break; case DIRECTORY: print = 0; cache_inode_expire_to_str(pclient->expire_type_dirent, pclient->grace_period_dirent, grace2); LogDebug(COMPONENT_CACHE_INODE, "Renew Entry test of %p for DIRECTORY elapsed time=%u, grace_period_attr=%s, grace_period_dirent=%s, has_been_readdir=%u", pentry, elapsed, grace, grace2, pentry->object.dir.has_been_readdir); break; case FS_JUNCTION: type = "FS_JUNCTION"; break; case RECYCLED: type = "RECYCLED"; break; default: type = "UNKNOWN"; break; } if(print) { LogDebug(COMPONENT_CACHE_INODE, "Renew Entry test of %p for %s elapsed time=%u, grace_period_attr=%s", pentry, type, elapsed, grace); } } /* An entry that is a regular file with an associated File Content Entry won't * expire until data exists in File Content Cache, to avoid attributes incoherency */ /* @todo: BUGAZOMEU: I got serious doubts on the following blocks: possible trouble if using data caching */ if(pentry->internal_md.type == REGULAR_FILE && pentry->object.file.pentry_content != NULL) { /* Successfull exit without having nothing to do ... */ LogDebug(COMPONENT_CACHE_INODE, "Entry %p is a REGULAR_FILE with associated data cached %p, no expiration", pentry, pentry->object.file.pentry_content); *pstatus = CACHE_INODE_SUCCESS; return *pstatus; } LogDebug(COMPONENT_CACHE_INODE, "cache_inode_renew_entry use getattr/mtime checking %d, is dir " "beginning %d, has bit in mask %d, has been readdir %d state %d", pclient->getattr_dir_invalidation, pentry->internal_md.type == DIRECTORY, (int) FSAL_TEST_MASK(pclient->attrmask, FSAL_ATTR_MTIME), pentry->object.dir.has_been_readdir, pentry->internal_md.valid_state); /* Do we use getattr/mtime checking */ if(pclient->getattr_dir_invalidation && pentry->internal_md.type == DIRECTORY && FSAL_TEST_MASK(pclient->attrmask, FSAL_ATTR_MTIME) /*&& pentry->object.dir.has_been_readdir == CACHE_INODE_YES*/) { /* This checking is to be done ... */ LogDebug(COMPONENT_CACHE_INODE, "cache_inode_renew_entry testing directory mtime"); pfsal_handle = &pentry->object.dir.handle; /* Call FSAL to get the attributes */ object_attributes.asked_attributes = pclient->attrmask; fsal_status = FSAL_getattrs(pfsal_handle, pcontext, &object_attributes); if(FSAL_IS_ERROR(fsal_status)) { *pstatus = cache_inode_error_convert(fsal_status); if(fsal_status.major == ERR_FSAL_STALE) { cache_inode_status_t kill_status; LogEvent(COMPONENT_CACHE_INODE, "cache_inode_renew_entry: Stale FSAL File Handle detected for pentry = %p, line %u, fsal_status=(%u,%u)", pentry, __LINE__, fsal_status.major, fsal_status.minor); if(cache_inode_kill_entry(pentry, NO_LOCK, ht, pclient, &kill_status) != CACHE_INODE_SUCCESS) LogCrit(COMPONENT_CACHE_INODE, "cache_inode_renew_entry: Could not kill entry %p, status = %u", pentry, kill_status); *pstatus = CACHE_INODE_FSAL_ESTALE; } /* stats */ (pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_RENEW_ENTRY])++; LogDebug(COMPONENT_CACHE_INODE, "cache_inode_renew_entry: returning %d (%s) from FSAL_getattrs for getattr/mtime checking", *pstatus, cache_inode_err_str(*pstatus)); return *pstatus; } LogDebug(COMPONENT_CACHE_INODE, "cache_inode_renew_entry: Entry=%p, type=%d, Cached Time=%d, FSAL Time=%d", pentry, pentry->internal_md.type, pentry->object.dir.attributes.mtime.seconds, object_attributes.mtime.seconds); /* Compare the FSAL mtime and the cached mtime */ if(pentry->object.dir.attributes.mtime.seconds < object_attributes.mtime.seconds) { /* Cached directory content is obsolete, it must be renewed */ cache_inode_set_attributes(pentry, &object_attributes); /* Return the attributes as set */ if(pattr != NULL) *pattr = object_attributes; /* Set the directory content as "to be renewed" */ /* Next call to cache_inode_readdir will repopulate the dirent array */ pentry->object.dir.has_been_readdir = CACHE_INODE_RENEW_NEEDED; /* Set the refresh time for the cache entry */ pentry->internal_md.refresh_time = time(NULL); LogDebug(COMPONENT_CACHE_INODE, "cache_inode_renew_entry: cached directory content for entry %p must be renewed, due to getattr mismatch", pentry); if(cache_inode_invalidate_all_cached_dirent(pentry, ht, pclient, pstatus) != CACHE_INODE_SUCCESS) { /* Should never happen */ LogCrit(COMPONENT_CACHE_INODE, "cache_inode_invalidate_all_cached_dirent returned %d (%s)", *pstatus, cache_inode_err_str(*pstatus)); return *pstatus; } } /* if( pentry->object.dir.attributes.mtime < object_attributes.asked_attributes.mtime ) */ } /* if( pclient->getattr_dir_invalidation && ... */ /* Check for dir content expiration and/or staleness */ if(pentry->internal_md.type == DIRECTORY && pclient->expire_type_dirent != CACHE_INODE_EXPIRE_NEVER && pentry->object.dir.has_been_readdir == CACHE_INODE_YES && ((current_time - entry_time >= pclient->grace_period_dirent) || (pentry->internal_md.valid_state == STALE))) { /* Would be better if state was a flag that we could and/or the bits but * in any case we need to get rid of stale so we only go through here * once. */ if ( pentry->internal_md.valid_state == STALE ) pentry->internal_md.valid_state = VALID; /* stats */ (pclient->stat.func_stats.nb_call[CACHE_INODE_RENEW_ENTRY])++; /* Log */ LogDebug(COMPONENT_CACHE_INODE, "Case 1: cached directory entries for entry %p must be renewed" " (has been readdir)", pentry); if(isFullDebug(COMPONENT_CACHE_INODE)) { char name[1024]; struct avltree_node *d_node; cache_inode_dir_entry_t *d_dirent; int i = 0; d_node = avltree_first(&pentry->object.dir.dentries); do { d_dirent = avltree_container_of(d_node, cache_inode_dir_entry_t, node_n); if (d_dirent->pentry->internal_md.valid_state == VALID) { FSAL_name2str(&(d_dirent->name), name, 1023); LogDebug(COMPONENT_CACHE_INODE, "cache_inode_renew_entry: Entry %d %s", i, name); } i++; } while ((d_node = avltree_next(d_node))); } /* Do the getattr if it had not being done before */ if(pfsal_handle == NULL) { pfsal_handle = &pentry->object.dir.handle; /* Call FSAL to get the attributes */ object_attributes.asked_attributes = pclient->attrmask; fsal_status = FSAL_getattrs(pfsal_handle, pcontext, &object_attributes); if(FSAL_IS_ERROR(fsal_status)) { *pstatus = cache_inode_error_convert(fsal_status); /* stats */ (pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_RENEW_ENTRY])++; if(fsal_status.major == ERR_FSAL_STALE) { cache_inode_status_t kill_status; LogEvent(COMPONENT_CACHE_INODE, "cache_inode_renew_entry: Stale FSAL File Handle detected for pentry = %p, line %u, fsal_status=(%u,%u)", pentry, __LINE__,fsal_status.major, fsal_status.minor ); if(cache_inode_kill_entry(pentry, NO_LOCK, ht, pclient, &kill_status) != CACHE_INODE_SUCCESS) LogCrit(COMPONENT_CACHE_INODE, "cache_inode_renew_entry: Could not kill entry %p, status = %u", pentry, kill_status); *pstatus = CACHE_INODE_FSAL_ESTALE; } LogDebug(COMPONENT_CACHE_INODE, "cache_inode_renew_entry returning %d (%s) from FSAL_getattrs for directory entries (1)", *pstatus, cache_inode_err_str(*pstatus)); return *pstatus; } } cache_inode_set_attributes(pentry, &object_attributes); /* Return the attributes as set */ if(pattr != NULL) *pattr = object_attributes; /* Set the directory content as "to be renewed" */ /* Next call to cache_inode_readdir will repopulate the dirent array */ pentry->object.dir.has_been_readdir = CACHE_INODE_RENEW_NEEDED; /* Set the refresh time for the cache entry */ pentry->internal_md.refresh_time = time(NULL); } /* if( pentry->internal_md.type == DIRECTORY && ... */ /* if the directory has not been readdir, only update its attributes */ else if(pentry->internal_md.type == DIRECTORY && pclient->expire_type_attr != CACHE_INODE_EXPIRE_NEVER && pentry->object.dir.has_been_readdir != CACHE_INODE_YES && ((current_time - entry_time >= pclient->grace_period_attr) || (pentry->internal_md.valid_state == STALE))) { /* Would be better if state was a flag that we could and/or the bits but * in any case we need to get rid of stale so we only go through here * once. */ if ( pentry->internal_md.valid_state == STALE ) pentry->internal_md.valid_state = VALID; /* stats */ (pclient->stat.func_stats.nb_call[CACHE_INODE_RENEW_ENTRY])++; /* Log */ LogDebug(COMPONENT_CACHE_INODE, "Case 2: cached directory entries for entry %p must be renewed (has not been readdir)", pentry); if(isFullDebug(COMPONENT_CACHE_INODE)) { char name[1024]; struct avltree_node *d_node; cache_inode_dir_entry_t *d_dirent; int i = 0; d_node = avltree_first(&pentry->object.dir.dentries); do { d_dirent = avltree_container_of(d_node, cache_inode_dir_entry_t, node_n); if (d_dirent->pentry->internal_md.valid_state == VALID) { FSAL_name2str(&(d_dirent->name), name, 1023); LogDebug(COMPONENT_CACHE_INODE, "cache_inode_renew_entry: Entry %d %s", i, name); } i++; } while ((d_node = avltree_next(d_node))); } pfsal_handle = &pentry->object.dir.handle; /* Call FSAL to get the attributes */ object_attributes.asked_attributes = pclient->attrmask; fsal_status = FSAL_getattrs(pfsal_handle, pcontext, &object_attributes); if(FSAL_IS_ERROR(fsal_status)) { *pstatus = cache_inode_error_convert(fsal_status); /* stats */ (pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_RENEW_ENTRY])++; if(fsal_status.major == ERR_FSAL_STALE) { cache_inode_status_t kill_status; LogEvent(COMPONENT_CACHE_INODE, "cache_inode_renew_entry: Stale FSAL File Handle detected for pentry = %p, line %u, fsal_status=(%u,%u)", pentry, __LINE__,fsal_status.major, fsal_status.minor ); if(cache_inode_kill_entry(pentry, NO_LOCK, ht, pclient, &kill_status) != CACHE_INODE_SUCCESS) LogCrit(COMPONENT_CACHE_INODE, "cache_inode_renew_entry: Could not kill entry %p, status = %u", pentry, kill_status); *pstatus = CACHE_INODE_FSAL_ESTALE; } LogDebug(COMPONENT_CACHE_INODE, "cache_inode_renew_entry returning %d (%s) from FSAL_getattrs for directory entries (2)", *pstatus, cache_inode_err_str(*pstatus)); return *pstatus; } cache_inode_set_attributes(pentry, &object_attributes); /* Return the attributes as set */ if(pattr != NULL) *pattr = object_attributes; /* Set the refresh time for the cache entry */ pentry->internal_md.refresh_time = time(NULL); } /* else if( pentry->internal_md.type == DIRECTORY && ... */ /* Check for attributes expiration in other cases */ else if(pentry->internal_md.type != DIRECTORY && pclient->expire_type_attr != CACHE_INODE_EXPIRE_NEVER && ((current_time - entry_time >= pclient->grace_period_attr) || (pentry->internal_md.valid_state == STALE))) { /* Would be better if state was a flag that we could and/or the bits but * in any case we need to get rid of stale so we only go through here * once. */ if ( pentry->internal_md.valid_state == STALE ) pentry->internal_md.valid_state = VALID; /* stats */ (pclient->stat.func_stats.nb_call[CACHE_INODE_RENEW_ENTRY])++; /* Log */ LogDebug(COMPONENT_CACHE_INODE, "Attributes for entry %p must be renewed", pentry); switch (pentry->internal_md.type) { case REGULAR_FILE: pfsal_handle = &pentry->object.file.handle; break; case SYMBOLIC_LINK: assert(pentry->object.symlink); pfsal_handle = &pentry->object.symlink->handle; break; case SOCKET_FILE: case FIFO_FILE: case CHARACTER_FILE: case BLOCK_FILE: pfsal_handle = &pentry->object.special_obj.handle; break; case DIRECTORY: case FS_JUNCTION: case UNASSIGNED: case RECYCLED: LogCrit(COMPONENT_CACHE_INODE, "WARNING: unknown source pentry type: internal_md.type=%d, line %d in file %s", pentry->internal_md.type, __LINE__, __FILE__); *pstatus = CACHE_INODE_BAD_TYPE; return *pstatus; } /* Call FSAL to get the attributes */ object_attributes.asked_attributes = pclient->attrmask; #ifdef _USE_MFSL fsal_status = FSAL_getattrs_descriptor(&(cache_inode_fd(pentry)->fsal_file), pfsal_handle, pcontext, &object_attributes); #else fsal_status = FSAL_getattrs_descriptor(cache_inode_fd(pentry), pfsal_handle, pcontext, &object_attributes); #endif if(FSAL_IS_ERROR(fsal_status) && fsal_status.major == ERR_FSAL_NOT_OPENED) { //TODO: LOOKATME !!!!! fsal_status = FSAL_getattrs(pfsal_handle, pcontext, &object_attributes); } if(FSAL_IS_ERROR(fsal_status)) { *pstatus = cache_inode_error_convert(fsal_status); /* stats */ (pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_RENEW_ENTRY])++; if(fsal_status.major == ERR_FSAL_STALE) { cache_inode_status_t kill_status; LogEvent(COMPONENT_CACHE_INODE, "cache_inode_renew_entry: Stale FSAL File Handle detected for pentry = %p, line %u, fsal_status=(%u,%u)", pentry, __LINE__,fsal_status.major, fsal_status.minor ); if(cache_inode_kill_entry(pentry, NO_LOCK, ht, pclient, &kill_status) != CACHE_INODE_SUCCESS) LogCrit(COMPONENT_CACHE_INODE, "cache_inode_renew_entry: Could not kill entry %p, status = %u", pentry, kill_status); *pstatus = CACHE_INODE_FSAL_ESTALE; } LogDebug(COMPONENT_CACHE_INODE, "cache_inode_renew_entry returning %d (%s) from FSAL_getattrs for non directories", *pstatus, cache_inode_err_str(*pstatus)); return *pstatus; } /* Keep the new attribute in cache */ cache_inode_set_attributes(pentry, &object_attributes); /* Return the attributes as set */ if(pattr != NULL) *pattr = object_attributes; /* Set the refresh time for the cache entry */ pentry->internal_md.refresh_time = time(NULL); } /* if( pentry->internal_md.type != DIR_CONTINUE && ... */ /* Check for link content expiration */ if(pentry->internal_md.type == SYMBOLIC_LINK && pclient->expire_type_link != CACHE_INODE_EXPIRE_NEVER && ((current_time - entry_time >= pclient->grace_period_link) || (pentry->internal_md.valid_state == STALE))) { assert(pentry->object.symlink); pfsal_handle = &pentry->object.symlink->handle; /* Would be better if state was a flag that we could and/or the bits but * in any case we need to get rid of stale so we only go through here * once. */ if ( pentry->internal_md.valid_state == STALE ) pentry->internal_md.valid_state = VALID; assert(pentry->object.symlink); pfsal_handle = &pentry->object.symlink->handle; /* Log */ LogDebug(COMPONENT_CACHE_INODE, "cached link content for entry %p must be renewed", pentry); FSAL_CLEAR_MASK(object_attributes.asked_attributes); FSAL_SET_MASK(object_attributes.asked_attributes, pclient->attrmask); if( CACHE_INODE_KEEP_CONTENT( pentry->policy ) ) { #ifdef _USE_MFSL fsal_status = MFSL_readlink(&pentry->mobject, pcontext, &pclient->mfsl_context, &link_content, &object_attributes, NULL); #else fsal_status = FSAL_readlink(pfsal_handle, pcontext, &link_content, &object_attributes); #endif } else { fsal_status.major = ERR_FSAL_NO_ERROR ; fsal_status.minor = 0 ; } if(FSAL_IS_ERROR(fsal_status)) { *pstatus = cache_inode_error_convert(fsal_status); /* stats */ pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_RENEW_ENTRY] += 1; if(fsal_status.major == ERR_FSAL_STALE) { cache_inode_status_t kill_status; LogEvent(COMPONENT_CACHE_INODE, "cache_inode_renew_entry: Stale FSAL File Handle detected for pentry = %p, line %u, fsal_status=(%u,%u)", pentry, __LINE__,fsal_status.major, fsal_status.minor ); if(cache_inode_kill_entry(pentry, NO_LOCK, ht, pclient, &kill_status) != CACHE_INODE_SUCCESS) LogCrit(COMPONENT_CACHE_INODE, "cache_inode_renew_entry: Could not kill entry %p, status = %u", pentry, kill_status); *pstatus = CACHE_INODE_FSAL_ESTALE; } } else { assert(pentry->object.symlink); fsal_status = FSAL_pathcpy(&pentry->object.symlink->content, &link_content); /* copy ctor? */ if(FSAL_IS_ERROR(fsal_status)) { *pstatus = cache_inode_error_convert(fsal_status); /* stats */ pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_RENEW_ENTRY] += 1; } } /* Set the refresh time for the cache entry */ pentry->internal_md.refresh_time = time(NULL); } /* if( pentry->internal_md.type == SYMBOLIC_LINK && ... */ LogDebug(COMPONENT_CACHE_INODE, "cache_inode_renew_entry returning %d (%s)", *pstatus, cache_inode_err_str(*pstatus)); return *pstatus; } /* cache_inode_renew_entry */
/** * FSAL_create: * Create a regular file. * * \param extparent (input): * Handle of the parent directory where the file is to be created. * \param filename (input): * Pointer to the name of the file to be created. * \param context (input): * Authentication context for the operation (user, export...). * \param accessmode (input): * Mode for the file to be created. * (the umask defined into the FSAL configuration file * will be applied on it). * \param object_handle (output): * Pointer to the handle of the created file. * \param object_attributes (optionnal input/output): * The postop attributes of the created file. * As input, it defines the attributes that the caller * wants to retrieve (by positioning flags into this structure) * and the output is built considering this input * (it fills the structure according to the flags it contains). * Can be NULL. * * \return Major error codes : * - ERR_FSAL_NO_ERROR (no error) * - ERR_FSAL_STALE (parent_directory_handle does not address an existing object) * - ERR_FSAL_FAULT (a NULL pointer was passed as mandatory argument) * - Other error codes can be returned : * ERR_FSAL_ACCESS, ERR_FSAL_EXIST, ERR_FSAL_IO, ... * * NB: if getting postop attributes failed, * the function does not return an error * but the FSAL_ATTR_RDATTR_ERR bit is set in * the object_attributes->asked_attributes field. */ fsal_status_t CEPHFSAL_create(fsal_handle_t * extparent, fsal_name_t * filename, fsal_op_context_t * extcontext, fsal_accessmode_t accessmode, fsal_handle_t * object_handle, fsal_attrib_list_t * object_attributes) { int rc; mode_t mode; struct Fh *fd; struct stat st; char strname[FSAL_MAX_NAME_LEN]; cephfsal_handle_t* parent = (cephfsal_handle_t*) extparent; cephfsal_op_context_t* context = (cephfsal_op_context_t*) extcontext; struct ceph_mount_info *cmount = context->export_context->cmount; int uid = FSAL_OP_CONTEXT_TO_UID(context); int gid = FSAL_OP_CONTEXT_TO_GID(context); /* sanity checks. * note : object_attributes is optional. */ if(!parent || !context || !object_handle || !filename) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_create); memset(object_handle, 0, sizeof(cephfsal_handle_t)); mode = fsal2unix_mode(accessmode); mode = mode & ~global_fs_info.umask; FSAL_name2str(filename, strname, FSAL_MAX_NAME_LEN); TakeTokenFSCall(); rc = ceph_ll_create(cmount, VINODE(parent), strname, mode, 0, &fd, &st, uid, gid); ceph_ll_close(cmount, fd); ReleaseTokenFSCall(); if (rc < 0) Return(posix2fsal_error(rc), 0, INDEX_FSAL_create); rc = stat2fsal_fh(cmount, &st, (cephfsal_handle_t*) object_handle); if (rc < 0) Return(posix2fsal_error(rc), 0, INDEX_FSAL_create); if(object_attributes) { fsal_status_t status; status = posix2fsal_attributes(&st, object_attributes); if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(object_attributes->asked_attributes); FSAL_SET_MASK(object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_create); } } /* OK */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_create); }