int nfs3_commit(nfs_arg_t *arg, struct svc_req *req, nfs_res_t *res) { cache_inode_status_t cache_status; cache_entry_t *entry = NULL; int rc = NFS_REQ_OK; if (isDebug(COMPONENT_NFSPROTO)) { char str[LEN_FH_STR]; sprint_fhandle3(str, &(arg->arg_commit3.file)); LogDebug(COMPONENT_NFSPROTO, "REQUEST PROCESSING: Calling nfs3_commit handle: %s", str); } /* To avoid setting it on each error case */ res->res_commit3.COMMIT3res_u.resfail.file_wcc.before. attributes_follow = FALSE; res->res_commit3.COMMIT3res_u.resfail.file_wcc.after.attributes_follow = FALSE; entry = nfs3_FhandleToCache(&arg->arg_commit3.file, &res->res_commit3.status, &rc); if (entry == NULL) { /* Status and rc have been set by nfs3_FhandleToCache */ goto out; } cache_status = cache_inode_commit(entry, arg->arg_commit3.offset, arg->arg_commit3.count); if (cache_status != CACHE_INODE_SUCCESS) { res->res_commit3.status = nfs3_Errno(cache_status); nfs_SetWccData(NULL, entry, &(res->res_commit3.COMMIT3res_u.resfail. file_wcc)); rc = NFS_REQ_OK; goto out; } nfs_SetWccData(NULL, entry, &(res->res_commit3.COMMIT3res_u.resok.file_wcc)); /* Set the write verifier */ memcpy(res->res_commit3.COMMIT3res_u.resok.verf, NFS3_write_verifier, sizeof(writeverf3)); res->res_commit3.status = NFS3_OK; out: if (entry) cache_inode_put(entry); return rc; } /* nfs3_commit */
int nfs3_pathconf(nfs_arg_t *arg, nfs_worker_data_t *worker, struct svc_req *req, nfs_res_t *res) { cache_entry_t *entry = NULL; int rc = NFS_REQ_OK; struct fsal_export *exp_hdl = op_ctx->fsal_export; if (isDebug(COMPONENT_NFSPROTO)) { char str[LEN_FH_STR]; sprint_fhandle3(str, &(arg->arg_pathconf3.object)); LogDebug(COMPONENT_NFSPROTO, "REQUEST PROCESSING: Calling nfs3_pathconf handle: " "%s", str); } /* to avoid setting it on each error case */ res->res_pathconf3.PATHCONF3res_u.resfail.obj_attributes. attributes_follow = FALSE; /* Convert file handle into a fsal_handle */ entry = nfs3_FhandleToCache(&arg->arg_pathconf3.object, &res->res_pathconf3.status, &rc); if (entry == NULL) { /* Status and rc have been set by nfs3_FhandleToCache */ goto out; } res->res_pathconf3.PATHCONF3res_u.resok.linkmax = exp_hdl->ops->fs_maxlink(exp_hdl); res->res_pathconf3.PATHCONF3res_u.resok.name_max = exp_hdl->ops->fs_maxnamelen(exp_hdl); res->res_pathconf3.PATHCONF3res_u.resok.no_trunc = exp_hdl->ops->fs_supports(exp_hdl, fso_no_trunc); res->res_pathconf3.PATHCONF3res_u.resok.chown_restricted = exp_hdl->ops->fs_supports(exp_hdl, fso_chown_restricted); res->res_pathconf3.PATHCONF3res_u.resok.case_insensitive = exp_hdl->ops->fs_supports(exp_hdl, fso_case_insensitive); res->res_pathconf3.PATHCONF3res_u.resok.case_preserving = exp_hdl->ops->fs_supports(exp_hdl, fso_case_preserving); /* Build post op file attributes */ nfs_SetPostOpAttr(entry, &(res->res_pathconf3.PATHCONF3res_u.resok. obj_attributes)); out: if (entry) cache_inode_put(entry); return rc; } /* nfs3_pathconf */
int nfs3_getattr(nfs_arg_t *arg, nfs_worker_data_t *worker, struct svc_req *req, nfs_res_t *res) { cache_entry_t *entry = NULL; int rc = NFS_REQ_OK; if (isDebug(COMPONENT_NFSPROTO)) { char str[LEN_FH_STR]; nfs_FhandleToStr(req->rq_vers, &(arg->arg_getattr3.object), NULL, str); LogDebug(COMPONENT_NFSPROTO, "REQUEST PROCESSING: Calling nfs3_getattr handle: %s", str); } entry = nfs3_FhandleToCache(&arg->arg_getattr3.object, &res->res_getattr3.status, &rc); if (entry == NULL) { /* Status and rc have been set by nfs3_FhandleToCache */ LogFullDebug(COMPONENT_NFSPROTO, "nfs_Getattr returning %d", rc); goto out; } if (!cache_entry_to_nfs3_Fattr( entry, &res->res_getattr3.GETATTR3res_u.resok.obj_attributes)) { res->res_getattr3.status = nfs3_Errno(CACHE_INODE_INVALID_ARGUMENT); LogFullDebug(COMPONENT_NFSPROTO, "nfs_Getattr set failed status v3"); rc = NFS_REQ_OK; goto out; } res->res_getattr3.status = NFS3_OK; LogFullDebug(COMPONENT_NFSPROTO, "nfs_Getattr succeeded"); rc = NFS_REQ_OK; out: /* return references */ if (entry) cache_inode_put(entry); return rc; }
int nfs4_op_putrootfh(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp) { char __attribute__ ((__unused__)) funcname[] = "nfs4_op_putrootfh"; /* This NFS4 Operation has no argument, it just get then ROOTFH (replace MOUNTPROC3_MNT) */ /* First of all, set the reply to zero to make sure it contains no parasite information */ memset(resp, 0, sizeof(struct nfs_resop4)); resp->resop = NFS4_OP_PUTROOTFH; res_PUTROOTFH4.status = CreateROOTFH4(&(data->rootFH), data); if(res_PUTROOTFH4.status != NFS4_OK) return res_PUTROOTFH4.status; if (data->current_entry) { cache_inode_put(data->current_entry); } /* Fill in compound data */ set_compound_data_for_pseudo(data); /* I copy the root FH to the currentFH */ if(data->currentFH.nfs_fh4_len == 0) { res_PUTROOTFH4.status = nfs4_AllocateFH(&(data->currentFH)); if(res_PUTROOTFH4.status != NFS4_OK) return res_PUTROOTFH4.status; } /* Copy the data from root FH to current FH */ memcpy(data->currentFH.nfs_fh4_val, data->rootFH.nfs_fh4_val, data->rootFH.nfs_fh4_len); data->currentFH.nfs_fh4_len = data->rootFH.nfs_fh4_len; LogHandleNFS4("NFS4 PUTROOTFH ROOT FH: ", &data->rootFH); LogHandleNFS4("NFS4 PUTROOTFH CURRENT FH: ", &data->currentFH); LogFullDebug(COMPONENT_NFS_V4, "NFS4 PUTROOTFH: Ending on status %d", res_PUTROOTFH4.status); return res_PUTROOTFH4.status; } /* nfs4_op_putrootfh */
fsal_status_t dumb_fsal_up_lock_grant(fsal_up_event_data_t * pevdata) { #ifdef _USE_BLOCKING_LOCKS cache_inode_status_t cache_status; cache_entry_t * pentry = NULL; fsal_attrib_list_t attr; LogDebug(COMPONENT_FSAL_UP, "FSAL_UP_DUMB: calling cache_inode_get()"); pentry = cache_inode_get(&pevdata->event_context.fsal_data, &attr, NULL, NULL, &cache_status); if(pentry == NULL) { LogDebug(COMPONENT_FSAL_UP, "FSAL_UP_DUMB: cache inode get failed."); /* Not an error. Expecting some nodes will not have it in cache in * a cluster. */ ReturnCode(ERR_FSAL_NO_ERROR, 0); } LogDebug(COMPONENT_FSAL_UP, "FSAL_UP_DUMB: Lock Grant found entry %p", pentry); grant_blocked_lock_upcall(pentry, pevdata->type.lock_grant.lock_owner, &pevdata->type.lock_grant.lock_param); if(pentry) cache_inode_put(pentry); ReturnCode(ERR_FSAL_NO_ERROR, 0); #else INVALIDATE_STUB; #endif }
int nfs4_op_rename(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp) { char __attribute__ ((__unused__)) funcname[] = "nfs4_op_rename"; cache_entry_t * dst_entry = NULL; cache_entry_t * src_entry = NULL; cache_entry_t * tst_entry_dst = NULL; cache_entry_t * tst_entry_src = NULL; fsal_attrib_list_t attr_dst; fsal_attrib_list_t attr_src; fsal_attrib_list_t attr_tst_dst; fsal_attrib_list_t attr_tst_src; cache_inode_status_t cache_status; fsal_status_t fsal_status; fsal_handle_t * handlenew = NULL; fsal_handle_t * handleold = NULL; fsal_name_t oldname; fsal_name_t newname; resp->resop = NFS4_OP_RENAME; res_RENAME4.status = NFS4_OK; /* Do basic checks on a filehandle */ res_RENAME4.status = nfs4_sanity_check_FH(data, 0LL); if(res_RENAME4.status != NFS4_OK) return res_RENAME4.status; /* Do basic checks on saved filehandle */ /* If there is no FH */ if(nfs4_Is_Fh_Empty(&(data->savedFH))) { res_RENAME4.status = NFS4ERR_NOFILEHANDLE; return res_RENAME4.status; } /* If the filehandle is invalid */ if(nfs4_Is_Fh_Invalid(&(data->savedFH))) { res_RENAME4.status = NFS4ERR_BADHANDLE; return res_RENAME4.status; } /* Tests if the Filehandle is expired (for volatile filehandle) */ if(nfs4_Is_Fh_Expired(&(data->savedFH))) { res_RENAME4.status = NFS4ERR_FHEXPIRED; return res_RENAME4.status; } /* Pseudo Fs is explictely a Read-Only File system */ if(nfs4_Is_Fh_Pseudo(&(data->savedFH))) { res_RENAME4.status = NFS4ERR_ROFS; return res_RENAME4.status; } if (nfs_in_grace()) { res_RENAME4.status = NFS4ERR_GRACE; return res_RENAME4.status; } /* get the names from the RPC input */ cache_status = utf8_to_name(&arg_RENAME4.oldname, &oldname); if(cache_status != CACHE_INODE_SUCCESS) { res_RENAME4.status = nfs4_Errno(cache_status); return res_RENAME4.status; } cache_status = utf8_to_name(&arg_RENAME4.newname, &newname); if(cache_status != CACHE_INODE_SUCCESS) { res_RENAME4.status = nfs4_Errno(cache_status); return res_RENAME4.status; } /* Sanuty check: never rename to '.' or '..' */ if(!FSAL_namecmp(&newname, (fsal_name_t *) & FSAL_DOT) || !FSAL_namecmp(&newname, (fsal_name_t *) & FSAL_DOT_DOT)) { res_RENAME4.status = NFS4ERR_BADNAME; return res_RENAME4.status; } /* Sanuty check: never rename to '.' or '..' */ if(!FSAL_namecmp(&oldname, (fsal_name_t *) & FSAL_DOT) || !FSAL_namecmp(&oldname, (fsal_name_t *) & FSAL_DOT_DOT)) { res_RENAME4.status = NFS4ERR_BADNAME; return res_RENAME4.status; } /* * This operation renames * - the object in directory pointed by savedFH, named arg_RENAME4.oldname * into * - an object in directory pointed by currentFH, named arg_RENAME4.newname * * Because of this, we will use 2 entry and we have verified both currentFH and savedFH */ /* No Cross Device */ if(((file_handle_v4_t *) (data->currentFH.nfs_fh4_val))->exportid != ((file_handle_v4_t *) (data->savedFH.nfs_fh4_val))->exportid) { res_RENAME4.status = NFS4ERR_XDEV; return res_RENAME4.status; } /* destination must be a directory */ dst_entry = data->current_entry; if(data->current_filetype != DIRECTORY) { res_RENAME4.status = NFS4ERR_NOTDIR; return res_RENAME4.status; } /* Convert saved FH into a vnode */ src_entry = data->saved_entry; /* Source must be a directory */ if(data->saved_filetype != DIRECTORY) { res_RENAME4.status = NFS4ERR_NOTDIR; return res_RENAME4.status; } /* Renaming a file to himself is allowed, returns NFS4_OK */ if(src_entry == dst_entry) { if(!FSAL_namecmp(&oldname, &newname)) { res_RENAME4.status = NFS4_OK; return res_RENAME4.status; } } /* For the change_info4, get the 'change' attributes for both directories */ if((cache_status = cache_inode_getattr(src_entry, &attr_src, data->pcontext, &cache_status)) != CACHE_INODE_SUCCESS) { res_RENAME4.status = nfs4_Errno(cache_status); return res_RENAME4.status; } #ifdef BUGAZOMEU /* Ne devrait pas se produire dans le cas de exportid differents */ /* Both object must resides on the same filesystem, return NFS4ERR_XDEV if not */ if(attr_src.va_rdev != attr_dst.va_rdev) { res_RENAME4.status = NFS4ERR_XDEV; return res_RENAME4.status; } #endif /* Lookup oldfile to see if it exists (refcount +1) */ if((tst_entry_src = cache_inode_lookup(src_entry, &oldname, &attr_tst_src, data->pcontext, &cache_status)) == NULL) { res_RENAME4.status = nfs4_Errno(cache_status); goto release; } /* Lookup file with new name to see if it already exists (refcount +1), * I expect to get NO_ERROR or ENOENT, anything else means an error */ tst_entry_dst = cache_inode_lookup(dst_entry, &newname, &attr_tst_dst, data->pcontext, &cache_status); if((cache_status != CACHE_INODE_SUCCESS) && (cache_status != CACHE_INODE_NOT_FOUND)) { /* Unexpected status at this step, exit with an error */ res_RENAME4.status = nfs4_Errno(cache_status); goto release; } if(cache_status == CACHE_INODE_NOT_FOUND) tst_entry_dst = NULL; /* Just to make sure */ /* Renaming a file to one of its own hardlink is allowed, return NFS4_OK */ if(tst_entry_src == tst_entry_dst) { res_RENAME4.status = NFS4_OK; goto release; } /* Renaming dir into existing file should return NFS4ERR_EXIST */ if ((tst_entry_src->type == DIRECTORY) && ((tst_entry_dst != NULL) && (tst_entry_dst->type == REGULAR_FILE))) { res_RENAME4.status = NFS4ERR_EXIST; goto release; } /* Renaming file into existing dir should return NFS4ERR_EXIST */ if(tst_entry_src->type == REGULAR_FILE) { if(tst_entry_dst != NULL) { if(tst_entry_dst->type == DIRECTORY) { res_RENAME4.status = NFS4ERR_EXIST; goto release; } } } /* Renaming dir1 into existing, nonempty dir2 should return NFS4ERR_EXIST * Renaming file into existing, nonempty dir should return NFS4ERR_EXIST */ if(tst_entry_dst != NULL) { if((tst_entry_dst->type == DIRECTORY) && ((tst_entry_src->type == DIRECTORY) || (tst_entry_src->type == REGULAR_FILE))) { if(cache_inode_is_dir_empty_WithLock(tst_entry_dst) == CACHE_INODE_DIR_NOT_EMPTY) { res_RENAME4.status = NFS4ERR_EXIST; goto release; } } } res_RENAME4.RENAME4res_u.resok4.source_cinfo.before = cache_inode_get_changeid4(src_entry); res_RENAME4.RENAME4res_u.resok4.target_cinfo.before = cache_inode_get_changeid4(dst_entry); if(cache_status == CACHE_INODE_SUCCESS) { /* New entry already exists, its attributes are in attr_tst_*, check for old entry to see if types are compatible */ handlenew = &tst_entry_dst->handle; handleold = &tst_entry_src->handle; if(!FSAL_handlecmp(handlenew, handleold, &fsal_status)) { /* For the change_info4, get the 'change' attributes for both directories */ res_RENAME4.RENAME4res_u.resok4.source_cinfo.before = cache_inode_get_changeid4(src_entry); res_RENAME4.RENAME4res_u.resok4.target_cinfo.before = cache_inode_get_changeid4(dst_entry); res_RENAME4.RENAME4res_u.resok4.target_cinfo.atomic = FALSE; res_RENAME4.RENAME4res_u.resok4.source_cinfo.atomic = FALSE; res_RENAME4.status = NFS4_OK; goto release; } else { /* Destination exists and is something different from source */ if(( tst_entry_src->type == REGULAR_FILE && tst_entry_dst->type == REGULAR_FILE ) || ( tst_entry_src->type == DIRECTORY && tst_entry_dst->type == DIRECTORY )) { if(cache_inode_rename(src_entry, &oldname, dst_entry, &newname, &attr_src, &attr_dst, data->pcontext, &cache_status) != CACHE_INODE_SUCCESS) { res_RENAME4.status = nfs4_Errno(cache_status); goto release; } } else { res_RENAME4.status = NFS4ERR_EXIST; goto release; } } } else { /* New entry does not already exist, call cache_entry_rename */ if(cache_inode_rename(src_entry, &oldname, dst_entry, &newname, &attr_src, &attr_dst, data->pcontext, &cache_status) != CACHE_INODE_SUCCESS) { res_RENAME4.status = nfs4_Errno(cache_status); goto release; } } /* If you reach this point, then everything was alright */ /* For the change_info4, get the 'change' attributes for both directories */ res_RENAME4.RENAME4res_u.resok4.source_cinfo.after = cache_inode_get_changeid4(src_entry); res_RENAME4.RENAME4res_u.resok4.target_cinfo.after = cache_inode_get_changeid4(dst_entry); res_RENAME4.RENAME4res_u.resok4.target_cinfo.atomic = FALSE; res_RENAME4.RENAME4res_u.resok4.source_cinfo.atomic = FALSE; res_RENAME4.status = nfs4_Errno(cache_status); release: if (tst_entry_src) (void) cache_inode_put(tst_entry_src); if (tst_entry_dst) (void) cache_inode_put(tst_entry_dst); return (res_RENAME4.status); } /* nfs4_op_rename */
int nfs3_rename(nfs_arg_t *arg, struct svc_req *req, nfs_res_t *res) { const char *entry_name = arg->arg_rename3.from.name; const char *new_entry_name = arg->arg_rename3.to.name; cache_entry_t *parent_entry = NULL; cache_entry_t *new_parent_entry = NULL; cache_inode_status_t cache_status; short to_exportid = 0; short from_exportid = 0; int rc = NFS_REQ_OK; pre_op_attr pre_parent = { .attributes_follow = false }; pre_op_attr pre_new_parent = { .attributes_follow = false }; if (isDebug(COMPONENT_NFSPROTO)) { char strto[LEN_FH_STR], strfrom[LEN_FH_STR]; nfs_FhandleToStr(req->rq_vers, &arg->arg_rename3.from.dir, NULL, strfrom); nfs_FhandleToStr(req->rq_vers, &arg->arg_rename3.to.dir, NULL, strto); LogDebug(COMPONENT_NFSPROTO, "REQUEST PROCESSING: Calling nfs_Rename from handle: %s name %s to handle: %s name: %s", strfrom, entry_name, strto, new_entry_name); } /* to avoid setting it on each error case */ res->res_rename3.RENAME3res_u.resfail.fromdir_wcc.before. attributes_follow = FALSE; res->res_rename3.RENAME3res_u.resfail.fromdir_wcc.after. attributes_follow = FALSE; res->res_rename3.RENAME3res_u.resfail.todir_wcc.before. attributes_follow = FALSE; res->res_rename3.RENAME3res_u.resfail.todir_wcc.after. attributes_follow = FALSE; /* Get the exportids for the two handles. */ to_exportid = nfs3_FhandleToExportId(&(arg->arg_rename3.to.dir)); from_exportid = nfs3_FhandleToExportId(&(arg->arg_rename3.from.dir)); /* Validate the to_exportid */ if (to_exportid < 0 || from_exportid < 0) { LogInfo(COMPONENT_DISPATCH, "NFS%d RENAME Request from client %s has badly formed handle for to dir", req->rq_vers, op_ctx->client ? op_ctx->client->hostaddr_str : "unknown client"); /* Bad handle, report to client */ res->res_rename3.status = NFS3ERR_BADHANDLE; goto out; } /* Both objects have to be in the same filesystem */ if (to_exportid != from_exportid) { res->res_rename3.status = NFS3ERR_XDEV; goto out; } /* Convert fromdir file handle into a cache_entry */ parent_entry = nfs3_FhandleToCache(&arg->arg_rename3.from.dir, &res->res_create3.status, &rc); if (parent_entry == NULL) { /* Status and rc have been set by nfs3_FhandleToCache */ goto out; } nfs_SetPreOpAttr(parent_entry, &pre_parent); /* Convert todir file handle into a cache_entry */ new_parent_entry = nfs3_FhandleToCache(&arg->arg_rename3.to.dir, &res->res_create3.status, &rc); if (new_parent_entry == NULL) { /* Status and rc have been set by nfs3_FhandleToCache */ goto out; } nfs_SetPreOpAttr(new_parent_entry, &pre_new_parent); if (entry_name == NULL || *entry_name == '\0' || new_entry_name == NULL || *new_entry_name == '\0') { cache_status = CACHE_INODE_INVALID_ARGUMENT; goto out_fail; } cache_status = cache_inode_rename(parent_entry, entry_name, new_parent_entry, new_entry_name); if (cache_status != CACHE_INODE_SUCCESS) goto out_fail; res->res_rename3.status = NFS3_OK; nfs_SetWccData(&pre_parent, parent_entry, &res->res_rename3.RENAME3res_u.resok.fromdir_wcc); nfs_SetWccData(&pre_new_parent, new_parent_entry, &res->res_rename3.RENAME3res_u.resok.todir_wcc); rc = NFS_REQ_OK; goto out; out_fail: res->res_rename3.status = nfs3_Errno(cache_status); nfs_SetWccData(&pre_parent, parent_entry, &res->res_rename3.RENAME3res_u.resfail.fromdir_wcc); nfs_SetWccData(&pre_new_parent, new_parent_entry, &res->res_rename3.RENAME3res_u.resfail.todir_wcc); /* If we are here, there was an error */ if (nfs_RetryableError(cache_status)) rc = NFS_REQ_DROP; out: if (parent_entry) cache_inode_put(parent_entry); if (new_parent_entry) cache_inode_put(new_parent_entry); return rc; } /** * @brief Free the result structure allocated for nfs3_rename. * * This function frees the result structure allocated for nfs3_rename. * * @param[in,out] res Result structure * */ void nfs3_rename_free(nfs_res_t *res) { /* Nothing to do here */ }
int nlm_process_parameters(struct svc_req * preq, bool_t exclusive, nlm4_lock * alock, fsal_lock_param_t * plock, cache_entry_t ** ppentry, fsal_op_context_t * pcontext, care_t care, state_nsm_client_t ** ppnsm_client, state_nlm_client_t ** ppnlm_client, state_owner_t ** ppowner, state_block_data_t ** ppblock_data) { cache_inode_fsal_data_t fsal_data; fsal_attrib_list_t attr; cache_inode_status_t cache_status; SVCXPRT *ptr_svc = preq->rq_xprt; int rc; *ppnsm_client = NULL; *ppnlm_client = NULL; *ppowner = NULL; /* Convert file handle into a cache entry */ if(alock->fh.n_len > MAX_NETOBJ_SZ || !nfs3_FhandleToFSAL((nfs_fh3 *) &alock->fh, &fsal_data.fh_desc, pcontext)) { /* handle is not valid */ return NLM4_STALE_FH; } /* Now get the cached inode attributes */ *ppentry = cache_inode_get(&fsal_data, &attr, pcontext, NULL, &cache_status); if(*ppentry == NULL) { /* handle is not valid */ return NLM4_STALE_FH; } *ppnsm_client = get_nsm_client(care, ptr_svc, alock->caller_name); if(*ppnsm_client == NULL) { /* If NSM Client is not found, and we don't care (such as unlock), * just return GRANTED (the unlock must succeed, there can't be * any locks). */ if(care != CARE_NOT) rc = NLM4_DENIED_NOLOCKS; else rc = NLM4_GRANTED; goto out_put; } *ppnlm_client = get_nlm_client(care, ptr_svc, *ppnsm_client, alock->caller_name); if(*ppnlm_client == NULL) { /* If NLM Client is not found, and we don't care (such as unlock), * just return GRANTED (the unlock must succeed, there can't be * any locks). */ dec_nsm_client_ref(*ppnsm_client); if(care != CARE_NOT) rc = NLM4_DENIED_NOLOCKS; else rc = NLM4_GRANTED; goto out_put; } *ppowner = get_nlm_owner(care, *ppnlm_client, &alock->oh, alock->svid); if(*ppowner == NULL) { LogDebug(COMPONENT_NLM, "Could not get NLM Owner"); dec_nsm_client_ref(*ppnsm_client); dec_nlm_client_ref(*ppnlm_client); *ppnlm_client = NULL; /* If owner is not found, and we don't care (such as unlock), * just return GRANTED (the unlock must succeed, there can't be * any locks). */ if(care != CARE_NOT) rc = NLM4_DENIED_NOLOCKS; else rc = NLM4_GRANTED; goto out_put; } if(ppblock_data != NULL) { *ppblock_data = gsh_calloc(1, sizeof(**ppblock_data)); /* Fill in the block data, if we don't get one, we will just proceed * without (which will mean the lock doesn't block. */ if(*ppblock_data != NULL) { if(copy_xprt_addr(&(*ppblock_data)->sbd_block_data.sbd_nlm_block_data.sbd_nlm_hostaddr, ptr_svc) == 0) { LogFullDebug(COMPONENT_NLM, "copy_xprt_addr failed for Program %d, Version %d, Function %d", (int)preq->rq_prog, (int)preq->rq_vers, (int)preq->rq_proc); gsh_free(*ppblock_data); *ppblock_data = NULL; rc = NLM4_FAILED; goto out_put; } (*ppblock_data)->sbd_granted_callback = nlm_granted_callback; (*ppblock_data)->sbd_block_data.sbd_nlm_block_data.sbd_nlm_fh.n_bytes = (*ppblock_data)->sbd_block_data.sbd_nlm_block_data.sbd_nlm_fh_buf; (*ppblock_data)->sbd_block_data.sbd_nlm_block_data.sbd_nlm_fh.n_len = alock->fh.n_len; memcpy((*ppblock_data)->sbd_block_data.sbd_nlm_block_data.sbd_nlm_fh_buf, alock->fh.n_bytes, alock->fh.n_len); /* FSF TODO: Ultimately I think the following will go away, we won't need the context, just the export */ /* Copy credentials from pcontext */ #ifdef _USE_HPSS /** @todo : PhD: Think about removing hpsscred_t from FSAL */ (*ppblock_data)->sbd_credential.user = pcontext->credential.hpss_usercred.Uid ; (*ppblock_data)->sbd_credential.group = pcontext->credential.hpss_usercred.Gid ; #else (*ppblock_data)->sbd_credential = pcontext->credential; /* Copy the alt groups list */ if(pcontext->credential.nbgroups != 0) { (*ppblock_data)->sbd_credential.alt_groups = gsh_malloc(sizeof(gid_t) * pcontext->credential.nbgroups); if((*ppblock_data)->sbd_credential.alt_groups == NULL) { gsh_free(*ppblock_data); *ppblock_data = NULL; rc = NLM4_FAILED; goto out_put; } memcpy((*ppblock_data)->sbd_credential.alt_groups, pcontext->credential.alt_groups, pcontext->credential.nbgroups); } #endif } } /* Fill in plock */ plock->lock_type = exclusive ? FSAL_LOCK_W : FSAL_LOCK_R; plock->lock_start = alock->l_offset; plock->lock_length = alock->l_len; LogFullDebug(COMPONENT_NLM, "Parameters Processed"); return -1; out_put: cache_inode_put(*ppentry); *ppentry = NULL; return rc; }
int nfs_Fsstat(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) { fsal_dynamicfsinfo_t dynamicinfo; cache_inode_status_t cache_status; cache_entry_t *pentry = NULL; fsal_attrib_list_t attr; int rc = NFS_REQ_OK; if(isDebug(COMPONENT_NFSPROTO)) { char str[LEN_FH_STR]; nfs_FhandleToStr(preq->rq_vers, &(parg->arg_statfs2), &(parg->arg_fsstat3.fsroot), NULL, str); LogDebug(COMPONENT_NFSPROTO, "REQUEST PROCESSING: Calling nfs_Fsstat handle: %s", str); } if(preq->rq_vers == NFS_V3) { /* to avoid setting it on each error case */ pres->res_fsstat3.FSSTAT3res_u.resfail.obj_attributes.attributes_follow = FALSE; } /* convert file handle to vnode */ if((pentry = nfs_FhandleToCache(preq->rq_vers, &(parg->arg_statfs2), &(parg->arg_fsstat3.fsroot), NULL, &(pres->res_statfs2.status), &(pres->res_fsstat3.status), NULL, NULL, pcontext, &rc)) == NULL) { /* Stale NFS FH ? */ /* return NFS_REQ_DROP ; */ goto out; } /* Get statistics and convert from cache */ if((cache_status = cache_inode_statfs(pentry, &dynamicinfo, pcontext, &cache_status)) == CACHE_INODE_SUCCESS) { /* This call is costless, the pentry was cached during call to nfs_FhandleToCache */ if((cache_status = cache_inode_getattr(pentry, &attr, pcontext, &cache_status)) == CACHE_INODE_SUCCESS) { LogFullDebug(COMPONENT_NFSPROTO, "nfs_Fsstat --> dynamicinfo.total_bytes = %zu dynamicinfo.free_bytes = %zu dynamicinfo.avail_bytes = %zu", dynamicinfo.total_bytes, dynamicinfo.free_bytes, dynamicinfo.avail_bytes); LogFullDebug(COMPONENT_NFSPROTO, "nfs_Fsstat --> dynamicinfo.total_files = %llu dynamicinfo.free_files = %llu dynamicinfo.avail_files = %llu", dynamicinfo.total_files, dynamicinfo.free_files, dynamicinfo.avail_files); switch (preq->rq_vers) { case NFS_V2: pres->res_statfs2.STATFS2res_u.info.tsize = NFS2_MAXDATA; pres->res_statfs2.STATFS2res_u.info.bsize = DEV_BSIZE; pres->res_statfs2.STATFS2res_u.info.blocks = dynamicinfo.total_bytes / DEV_BSIZE; pres->res_statfs2.STATFS2res_u.info.bfree = dynamicinfo.free_bytes / DEV_BSIZE; pres->res_statfs2.STATFS2res_u.info.bavail = dynamicinfo.avail_bytes / DEV_BSIZE; pres->res_statfs2.status = NFS_OK; break; case NFS_V3: nfs_SetPostOpAttr(pexport, &attr, &(pres->res_fsstat3.FSSTAT3res_u .resok.obj_attributes)); pres->res_fsstat3.FSSTAT3res_u.resok.tbytes = dynamicinfo.total_bytes; pres->res_fsstat3.FSSTAT3res_u.resok.fbytes = dynamicinfo.free_bytes; pres->res_fsstat3.FSSTAT3res_u.resok.abytes = dynamicinfo.avail_bytes; pres->res_fsstat3.FSSTAT3res_u.resok.tfiles = dynamicinfo.total_files; pres->res_fsstat3.FSSTAT3res_u.resok.ffiles = dynamicinfo.free_files; pres->res_fsstat3.FSSTAT3res_u.resok.afiles = dynamicinfo.avail_files; pres->res_fsstat3.FSSTAT3res_u.resok.invarsec = 0; /* volatile FS */ pres->res_fsstat3.status = NFS3_OK; LogFullDebug(COMPONENT_NFSPROTO, "nfs_Fsstat --> tbytes=%llu fbytes=%llu abytes=%llu", pres->res_fsstat3.FSSTAT3res_u.resok.tbytes, pres->res_fsstat3.FSSTAT3res_u.resok.fbytes, pres->res_fsstat3.FSSTAT3res_u.resok.abytes); LogFullDebug(COMPONENT_NFSPROTO, "nfs_Fsstat --> tfiles=%llu fffiles=%llu afiles=%llu", pres->res_fsstat3.FSSTAT3res_u.resok.tfiles, pres->res_fsstat3.FSSTAT3res_u.resok.ffiles, pres->res_fsstat3.FSSTAT3res_u.resok.afiles); break; } rc = NFS_REQ_OK; goto out; } } /* At this point we met an error */ if(nfs_RetryableError(cache_status)) { rc = NFS_REQ_DROP; goto out; } nfs_SetFailedStatus(pcontext, pexport, preq->rq_vers, cache_status, &pres->res_statfs2.status, &pres->res_fsstat3.status, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); rc = NFS_REQ_OK; out: /* return references */ if (pentry) cache_inode_put(pentry); return (rc); } /* nfs_Fsstat */
/** * @brief Implement actual work of removing file * * Actually remove an entry from the directory. Assume that the * directory contents and attributes are locked for writes. The * attribute lock is released unless keep_md_lock is TRUE. * * @param[in] entry Entry for the parent directory to be managed. * @param[in] name Name of the entry that we are looking for in the cache. * @param[in] context FSAL credentials * @param[in] status Returned status * @param[in] flags Flags to control lock retention * * @return CACHE_INODE_SUCCESS if operation is a success * */ cache_inode_status_t cache_inode_remove_impl(cache_entry_t *entry, fsal_name_t *name, fsal_op_context_t *context, cache_inode_status_t *status, uint32_t flags) { cache_entry_t *to_remove_entry = NULL; fsal_status_t fsal_status = {0, 0}; #ifdef _USE_NFS4_ACL fsal_acl_t *saved_acl = NULL; fsal_acl_status_t acl_status = 0; #endif /* _USE_NFS4_ACL */ if(entry->type != DIRECTORY) { *status = CACHE_INODE_BAD_TYPE; goto out; } if (!(flags & CACHE_INODE_FLAG_CONTENT_HAVE)) { pthread_rwlock_rdlock(&entry->content_lock); flags |= CACHE_INODE_FLAG_CONTENT_HAVE; } /* Factor this somewhat. In the case where the directory hasn't been populated, the entry may not exist in the cache and we'd be bringing it in just to dispose of it. */ /* Looks up for the entry to remove */ if ((to_remove_entry = cache_inode_lookup_impl(entry, name, context, status)) == NULL) { goto out; } /* Lock the attributes (so we can decrement the link count) */ pthread_rwlock_wrlock(&to_remove_entry->attr_lock); LogDebug(COMPONENT_CACHE_INODE, "---> Cache_inode_remove : %s", name->name); #ifdef _USE_NFS4_ACL saved_acl = entry->attributes.acl; #endif /* _USE_NFS4_ACL */ fsal_status = FSAL_unlink(&entry->handle, name, context, &entry->attributes); if (FSAL_IS_ERROR(fsal_status)) { *status = cache_inode_error_convert(fsal_status); if (fsal_status.major == ERR_FSAL_STALE) { cache_inode_kill_entry(entry); } goto unlock; } else { #ifdef _USE_NFS4_ACL /* Decrement refcount on saved ACL */ nfs4_acl_release_entry(saved_acl, &acl_status); if (acl_status != NFS_V4_ACL_SUCCESS) { LogCrit(COMPONENT_CACHE_INODE, "Failed to release old acl, status=%d", acl_status); } #endif /* _USE_NFS4_ACL */ } cache_inode_fixup_md(entry); if ((flags & CACHE_INODE_FLAG_ATTR_HAVE) && !(flags & CACHE_INODE_FLAG_ATTR_HOLD)) { pthread_rwlock_unlock(&entry->attr_lock); } /* Remove the entry from parent dir_entries avl */ cache_inode_remove_cached_dirent(entry, name, status); LogFullDebug(COMPONENT_CACHE_INODE, "cache_inode_remove_cached_dirent: status=%d", *status); /* Update the attributes for the removed entry */ if ((to_remove_entry->type != DIRECTORY) && (to_remove_entry->attributes.numlinks > 1)) { if ((*status = cache_inode_refresh_attrs(to_remove_entry, context)) != CACHE_INODE_SUCCESS) { goto unlock; } } else { /* Otherwise our count is zero, or it was an empty directory. */ to_remove_entry->attributes.numlinks = 0; } /* Now, delete "to_remove_entry" from the cache inode and free its associated resources, but only if numlinks == 0 */ if (to_remove_entry->attributes.numlinks == 0) { /* Destroy the entry when everyone's references to it have been relinquished. Most likely now. */ pthread_rwlock_unlock(&to_remove_entry->attr_lock); /* Kill off the sentinel reference (and mark the entry so it doesn't get recycled while a reference exists.) */ cache_inode_lru_kill(to_remove_entry); } else { unlock: pthread_rwlock_unlock(&to_remove_entry->attr_lock); } out: if ((flags & CACHE_INODE_FLAG_CONTENT_HAVE) && !(flags & CACHE_INODE_FLAG_CONTENT_HOLD)) { pthread_rwlock_unlock(&entry->content_lock); } /* This is for the reference taken by lookup */ if (to_remove_entry) { cache_inode_put(to_remove_entry); } return *status; }
int nfs3_access(nfs_arg_t *arg, struct svc_req *req, nfs_res_t *res) { cache_inode_status_t cache_status; cache_entry_t *entry = NULL; int rc = NFS_REQ_OK; if (isDebug(COMPONENT_NFSPROTO)) { char str[LEN_FH_STR]; sprint_fhandle3(str, &(arg->arg_access3.object)); LogDebug(COMPONENT_NFSPROTO, "REQUEST PROCESSING: Calling nfs3_access handle: %s", str); } /* to avoid setting it on each error case */ res->res_access3.ACCESS3res_u.resfail.obj_attributes.attributes_follow = FALSE; /* Convert file handle into a vnode */ entry = nfs3_FhandleToCache(&(arg->arg_access3.object), &(res->res_access3.status), &rc); if (entry == NULL) { /* Status and rc have been set by nfs3_FhandleToCache */ goto out; } /* Perform the 'access' call */ cache_status = nfs_access_op(entry, arg->arg_access3.access, &res->res_access3.ACCESS3res_u.resok.access, NULL); if (cache_status == CACHE_INODE_SUCCESS || cache_status == CACHE_INODE_FSAL_EACCESS) { /* Build Post Op Attributes */ nfs_SetPostOpAttr(entry, &(res->res_access3.ACCESS3res_u.resok. obj_attributes)); res->res_access3.status = NFS3_OK; rc = NFS_REQ_OK; goto out; } /* If we are here, there was an error */ if (nfs_RetryableError(cache_status)) { rc = NFS_REQ_DROP; goto out; } res->res_access3.status = nfs3_Errno(cache_status); nfs_SetPostOpAttr(entry, &(res->res_access3.ACCESS3res_u.resfail. obj_attributes)); out: if (entry) cache_inode_put(entry); return rc; } /* nfs3_access */
int _9p_walk(struct _9p_request_data *req9p, void *worker_data, u32 *plenout, char *preply) { char *cursor = req9p->_9pmsg + _9P_HDR_SIZE + _9P_TYPE_SIZE; unsigned int i = 0; u16 *msgtag = NULL; u32 *fid = NULL; u32 *newfid = NULL; u16 *nwname = NULL; u16 *wnames_len; char *wnames_str; uint64_t fileid; cache_inode_status_t cache_status; cache_entry_t *pentry = NULL; char name[MAXNAMLEN]; u16 *nwqid; struct _9p_fid *pfid = NULL; struct _9p_fid *pnewfid = NULL; /* Now Get data */ _9p_getptr(cursor, msgtag, u16); _9p_getptr(cursor, fid, u32); _9p_getptr(cursor, newfid, u32); _9p_getptr(cursor, nwname, u16); LogDebug(COMPONENT_9P, "TWALK: tag=%u fid=%u newfid=%u nwname=%u", (u32) *msgtag, *fid, *newfid, *nwname); if (*fid >= _9P_FID_PER_CONN) return _9p_rerror(req9p, worker_data, msgtag, ERANGE, plenout, preply); if (*newfid >= _9P_FID_PER_CONN) return _9p_rerror(req9p, worker_data, msgtag, ERANGE, plenout, preply); pfid = req9p->pconn->fids[*fid]; /* Check that it is a valid fid */ if (pfid == NULL || pfid->pentry == NULL) { LogDebug(COMPONENT_9P, "request on invalid fid=%u", *fid); return _9p_rerror(req9p, worker_data, msgtag, EIO, plenout, preply); } op_ctx = &pfid->op_context; pnewfid = gsh_calloc(1, sizeof(struct _9p_fid)); if (pnewfid == NULL) return _9p_rerror(req9p, worker_data, msgtag, ERANGE, plenout, preply); /* Is this a lookup or a fid cloning operation ? */ if (*nwname == 0) { /* Cloning operation */ memcpy((char *)pnewfid, (char *)pfid, sizeof(struct _9p_fid)); /* Set the new fid id */ pnewfid->fid = *newfid; /* This is not a TATTACH fid */ pnewfid->from_attach = false; /* Increments refcount */ (void) cache_inode_lru_ref(pnewfid->pentry, LRU_REQ_STALE_OK); } else { /* the walk is in fact a lookup */ pentry = pfid->pentry; for (i = 0; i < *nwname; i++) { _9p_getstr(cursor, wnames_len, wnames_str); snprintf(name, MAXNAMLEN, "%.*s", *wnames_len, wnames_str); LogDebug(COMPONENT_9P, "TWALK (lookup): tag=%u fid=%u newfid=%u (component %u/%u :%s)", (u32) *msgtag, *fid, *newfid, i + 1, *nwname, name); if (pnewfid->pentry == pentry) pnewfid->pentry = NULL; /* refcount +1 */ cache_status = cache_inode_lookup(pentry, name, &pnewfid->pentry); if (pnewfid->pentry == NULL) { gsh_free(pnewfid); return _9p_rerror(req9p, worker_data, msgtag, _9p_tools_errno(cache_status), plenout, preply); } if (pentry != pfid->pentry) cache_inode_put(pentry); pentry = pnewfid->pentry; } pnewfid->fid = *newfid; pnewfid->op_context = pfid->op_context; pnewfid->ppentry = pfid->pentry; strncpy(pnewfid->name, name, MAXNAMLEN-1); /* gdata ref is not hold : the pfid, which use same gdata */ /* will be clunked after pnewfid */ /* This clunk release the gdata */ pnewfid->gdata = pfid->gdata; /* This is not a TATTACH fid */ pnewfid->from_attach = false; cache_status = cache_inode_fileid(pnewfid->pentry, &fileid); if (cache_status != CACHE_INODE_SUCCESS) { gsh_free(pnewfid); return _9p_rerror(req9p, worker_data, msgtag, _9p_tools_errno(cache_status), plenout, preply); } /* Build the qid */ /* No cache, we want the client to stay synchronous * with the server */ pnewfid->qid.version = 0; pnewfid->qid.path = fileid; pnewfid->specdata.xattr.xattr_id = 0; pnewfid->specdata.xattr.xattr_content = NULL; switch (pnewfid->pentry->type) { case REGULAR_FILE: case CHARACTER_FILE: case BLOCK_FILE: case SOCKET_FILE: case FIFO_FILE: pnewfid->qid.type = _9P_QTFILE; break; case SYMBOLIC_LINK: pnewfid->qid.type = _9P_QTSYMLINK; break; case DIRECTORY: pnewfid->qid.type = _9P_QTDIR; break; default: LogMajor(COMPONENT_9P, "implementation error, you should not see this message !!!!!!"); gsh_free(pnewfid); return _9p_rerror(req9p, worker_data, msgtag, EINVAL, plenout, preply); break; } } /* keep info on new fid */ req9p->pconn->fids[*newfid] = pnewfid; /* As much qid as requested fid */ nwqid = nwname; /* Hold refcount on gdata */ uid2grp_hold_group_data(pnewfid->gdata); /* Build the reply */ _9p_setinitptr(cursor, preply, _9P_RWALK); _9p_setptr(cursor, msgtag, u16); _9p_setptr(cursor, nwqid, u16); for (i = 0; i < *nwqid; i++) { /** @todo: should be different qids * for each directory walked through */ _9p_setqid(cursor, pnewfid->qid); } _9p_setendptr(cursor, preply); _9p_checkbound(cursor, preply, plenout); LogDebug(COMPONENT_9P, "RWALK: tag=%u fid=%u newfid=%u nwqid=%u fileid=%llu pentry=%p refcount=%i", (u32) *msgtag, *fid, *newfid, *nwqid, (unsigned long long)pnewfid->qid.path, pnewfid->pentry, pnewfid->pentry->lru.refcnt); return 1; }
int nfs4_op_restorefh(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp) { char __attribute__ ((__unused__)) funcname[] = "nfs4_op_restorefh"; /* First of all, set the reply to zero to make sure it contains no parasite information */ memset(resp, 0, sizeof(struct nfs_resop4)); resp->resop = NFS4_OP_RESTOREFH; res_RESTOREFH.status = NFS4_OK; /* If there is no currentFH, teh return an error */ if(nfs4_Is_Fh_Empty(&(data->savedFH))) { /* There is no current FH, return NFS4ERR_RESTOREFH (cg RFC3530, page 202) */ res_RESTOREFH.status = NFS4ERR_RESTOREFH; return res_RESTOREFH.status; } /* If the filehandle is invalid */ if(nfs4_Is_Fh_Invalid(&(data->savedFH))) { res_RESTOREFH.status = NFS4ERR_BADHANDLE; return res_RESTOREFH.status; } /* Tests if the Filehandle is expired (for volatile filehandle) */ if(nfs4_Is_Fh_Expired(&(data->savedFH))) { res_RESTOREFH.status = NFS4ERR_FHEXPIRED; return res_RESTOREFH.status; } /* If data->exportp is null, a junction from pseudo fs was traversed, credp and exportp have to be updated */ if(data->pexport == NULL) { res_RESTOREFH.status = nfs4_SetCompoundExport(data); if(res_RESTOREFH.status != NFS4_OK) { LogCrit(COMPONENT_NFS_V4, "Error %d in nfs4_SetCompoundExport", res_RESTOREFH.status); return res_RESTOREFH.status; } } /* Copy the data from current FH to saved FH */ memcpy(data->currentFH.nfs_fh4_val, data->savedFH.nfs_fh4_val, data->savedFH.nfs_fh4_len); data->currentFH.nfs_fh4_len = data->savedFH.nfs_fh4_len; /* If current and saved entry are identical, get no references and make no changes. */ if (data->current_entry == data->saved_entry) { goto out; } if (data->current_entry) { cache_inode_put(data->current_entry); data->current_entry = NULL; } data->current_entry = data->saved_entry; data->current_filetype = data->saved_filetype; /* Take another reference. As of now the filehandle is both saved and current and both must be counted. Protect in case of pseudofs handle. */ if (data->current_entry) { if (cache_inode_lru_ref(data->current_entry, LRU_FLAG_NONE) != CACHE_INODE_SUCCESS) { resp->nfs_resop4_u.opgetfh.status = NFS4ERR_STALE; data->current_entry = NULL; return resp->nfs_resop4_u.opgetfh.status; } } out: if(isFullDebug(COMPONENT_NFS_V4)) { char str[LEN_FH_STR]; sprint_fhandle4(str, &data->currentFH); LogFullDebug(COMPONENT_NFS_V4, "RESTORE FH: Current FH %s", str); } return NFS4_OK; } /* nfs4_op_restorefh */
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 */
static bool populate_dirent(const char *name, void *dir_state, fsal_cookie_t cookie) { struct cache_inode_populate_cb_state *state = (struct cache_inode_populate_cb_state *)dir_state; struct fsal_obj_handle *entry_hdl; cache_inode_dir_entry_t *new_dir_entry = NULL; cache_entry_t *cache_entry = NULL; fsal_status_t fsal_status = { 0, 0 }; struct fsal_obj_handle *dir_hdl = state->directory->obj_handle; fsal_status = dir_hdl->obj_ops.lookup(dir_hdl, name, &entry_hdl); if (FSAL_IS_ERROR(fsal_status)) { *state->status = cache_inode_error_convert(fsal_status); if (*state->status == CACHE_INODE_FSAL_XDEV) { LogInfo(COMPONENT_NFS_READDIR, "Ignoring XDEV entry %s", name); *state->status = CACHE_INODE_SUCCESS; return true; } LogInfo(COMPONENT_CACHE_INODE, "Lookup failed on %s in dir %p with %s", name, dir_hdl, cache_inode_err_str(*state->status)); return !cache_param.retry_readdir; } LogFullDebug(COMPONENT_NFS_READDIR, "Creating entry for %s", name); *state->status = cache_inode_new_entry(entry_hdl, CACHE_INODE_FLAG_NONE, &cache_entry); if (cache_entry == NULL) { *state->status = CACHE_INODE_NOT_FOUND; /* we do not free entry_hdl because it is consumed by cache_inode_new_entry */ LogEvent(COMPONENT_NFS_READDIR, "cache_inode_new_entry failed with %s", cache_inode_err_str(*state->status)); return false; } if (cache_entry->type == DIRECTORY) { /* Insert Parent's key */ cache_inode_key_dup(&cache_entry->object.dir.parent, &state->directory->fh_hk.key); } *state->status = cache_inode_add_cached_dirent(state->directory, name, cache_entry, &new_dir_entry); /* return initial ref */ cache_inode_put(cache_entry); if ((*state->status != CACHE_INODE_SUCCESS) && (*state->status != CACHE_INODE_ENTRY_EXISTS)) { LogEvent(COMPONENT_NFS_READDIR, "cache_inode_add_cached_dirent failed with %s", cache_inode_err_str(*state->status)); return false; } return true; }
int nfs3_fsstat(nfs_arg_t *arg, struct svc_req *req, nfs_res_t *res) { fsal_dynamicfsinfo_t dynamicinfo; cache_inode_status_t cache_status; cache_entry_t *entry = NULL; int rc = NFS_REQ_OK; if (isDebug(COMPONENT_NFSPROTO)) { char str[LEN_FH_STR]; nfs_FhandleToStr(req->rq_vers, &(arg->arg_fsstat3.fsroot), NULL, str); LogDebug(COMPONENT_NFSPROTO, "REQUEST PROCESSING: Calling nfs3_fsstat handle: %s", str); } /* to avoid setting it on each error case */ res->res_fsstat3.FSSTAT3res_u.resfail.obj_attributes.attributes_follow = FALSE; entry = nfs3_FhandleToCache(&arg->arg_fsstat3.fsroot, &res->res_fsstat3.status, &rc); if (entry == NULL) { /* Status and rc have been set by nfs3_FhandleToCache */ goto out; } /* Get statistics and convert from cache */ cache_status = cache_inode_statfs(entry, &dynamicinfo); if (cache_status == CACHE_INODE_SUCCESS) { LogFullDebug(COMPONENT_NFSPROTO, "nfs_Fsstat --> dynamicinfo.total_bytes=%" PRIu64 " dynamicinfo.free_bytes=%" PRIu64 " dynamicinfo.avail_bytes=%" PRIu64, dynamicinfo.total_bytes, dynamicinfo.free_bytes, dynamicinfo.avail_bytes); LogFullDebug(COMPONENT_NFSPROTO, "nfs_Fsstat --> dynamicinfo.total_files=%" PRIu64 " dynamicinfo.free_files=%" PRIu64 " dynamicinfo.avail_files=%" PRIu64, dynamicinfo.total_files, dynamicinfo.free_files, dynamicinfo.avail_files); nfs_SetPostOpAttr(entry, &(res->res_fsstat3.FSSTAT3res_u.resok. obj_attributes)); res->res_fsstat3.FSSTAT3res_u.resok.tbytes = dynamicinfo.total_bytes; res->res_fsstat3.FSSTAT3res_u.resok.fbytes = dynamicinfo.free_bytes; res->res_fsstat3.FSSTAT3res_u.resok.abytes = dynamicinfo.avail_bytes; res->res_fsstat3.FSSTAT3res_u.resok.tfiles = dynamicinfo.total_files; res->res_fsstat3.FSSTAT3res_u.resok.ffiles = dynamicinfo.free_files; res->res_fsstat3.FSSTAT3res_u.resok.afiles = dynamicinfo.avail_files; /* volatile FS */ res->res_fsstat3.FSSTAT3res_u.resok.invarsec = 0; res->res_fsstat3.status = NFS3_OK; LogFullDebug(COMPONENT_NFSPROTO, "nfs_Fsstat --> tbytes=%llu fbytes=%llu abytes=%llu", res->res_fsstat3.FSSTAT3res_u.resok.tbytes, res->res_fsstat3.FSSTAT3res_u.resok.fbytes, res->res_fsstat3.FSSTAT3res_u.resok.abytes); LogFullDebug(COMPONENT_NFSPROTO, "nfs_Fsstat --> tfiles=%llu fffiles=%llu afiles=%llu", res->res_fsstat3.FSSTAT3res_u.resok.tfiles, res->res_fsstat3.FSSTAT3res_u.resok.ffiles, res->res_fsstat3.FSSTAT3res_u.resok.afiles); rc = NFS_REQ_OK; goto out; } /* At this point we met an error */ if (nfs_RetryableError(cache_status)) { rc = NFS_REQ_DROP; goto out; } res->res_fsstat3.status = nfs3_Errno(cache_status); rc = NFS_REQ_OK; out: /* return references */ if (entry) cache_inode_put(entry); return rc; } /* nfs3_fsstat */
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; }
int nfs3_readlink(nfs_arg_t *arg, struct svc_req *req, nfs_res_t *res) { cache_entry_t *entry = NULL; cache_inode_status_t cache_status; struct gsh_buffdesc link_buffer = { .addr = NULL, .len = 0 }; int rc = NFS_REQ_OK; if (isDebug(COMPONENT_NFSPROTO)) { char str[LEN_FH_STR]; nfs_FhandleToStr(req->rq_vers, &(arg->arg_readlink3.symlink), NULL, str); LogDebug(COMPONENT_NFSPROTO, "REQUEST PROCESSING: Calling nfs_Readlink handle: %s", str); } /* to avoid setting it on each error case */ res->res_readlink3.READLINK3res_u.resfail.symlink_attributes. attributes_follow = false; entry = nfs3_FhandleToCache(&arg->arg_readlink3.symlink, &res->res_readlink3.status, &rc); if (entry == NULL) { /* Status and rc have been set by nfs3_FhandleToCache */ goto out; } /* Sanity Check: the entry must be a link */ if (entry->type != SYMBOLIC_LINK) { res->res_readlink3.status = NFS3ERR_INVAL; rc = NFS_REQ_OK; goto out; } cache_status = cache_inode_readlink(entry, &link_buffer); if (cache_status != CACHE_INODE_SUCCESS) { res->res_readlink3.status = nfs3_Errno(cache_status); nfs_SetPostOpAttr(entry, &res->res_readlink3.READLINK3res_u.resfail. symlink_attributes); if (nfs_RetryableError(cache_status)) rc = NFS_REQ_DROP; goto out; } /* Reply to the client */ res->res_readlink3.READLINK3res_u.resok.data = link_buffer.addr; nfs_SetPostOpAttr(entry, &res->res_readlink3.READLINK3res_u. resok.symlink_attributes); res->res_readlink3.status = NFS3_OK; rc = NFS_REQ_OK; out: /* return references */ if (entry) cache_inode_put(entry); return rc; } /* nfs3_readlink */ /** * @brief Free the result structure allocated for nfs3_readlink. * * This function frees the result structure allocated for * nfs3_readlink. * * @param[in,out] res Result structure * */ void nfs3_readlink_free(nfs_res_t *res) { if (res->res_readlink3.status == NFS3_OK) gsh_free(res->res_readlink3.READLINK3res_u.resok.data); }
int nlm4_Share(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) { nlm4_shareargs * arg = &parg->arg_nlm4_share; cache_entry_t * pentry; state_status_t state_status = STATE_SUCCESS; char buffer[MAXNETOBJ_SZ * 2]; state_nsm_client_t * nsm_client; state_nlm_client_t * nlm_client; state_owner_t * nlm_owner; int rc; int grace = nfs_in_grace(); pres->res_nlm4share.sequence = 0; netobj_to_string(&arg->cookie, buffer, 1024); LogDebug(COMPONENT_NLM, "REQUEST PROCESSING: Calling nlm4_Share cookie=%s reclaim=%s", buffer, arg->reclaim ? "yes" : "no"); if(!copy_netobj(&pres->res_nlm4share.cookie, &arg->cookie)) { pres->res_nlm4share.stat = NLM4_FAILED; LogDebug(COMPONENT_NLM, "REQUEST RESULT: nlm4_Share %s", lock_result_str(pres->res_nlm4share.stat)); return NFS_REQ_OK; } /* Allow only reclaim share request during recovery and visa versa. * Note: NLM_SHARE is indicated to be non-monitored, however, it does * have a reclaim flag, so we will honor the reclaim flag if used. */ if((grace && !arg->reclaim) || (!grace && arg->reclaim)) { pres->res_nlm4share.stat = NLM4_DENIED_GRACE_PERIOD; LogDebug(COMPONENT_NLM, "REQUEST RESULT: nlm4_Share %s", lock_result_str(pres->res_nlm4share.stat)); return NFS_REQ_OK; } rc = nlm_process_share_parms(preq, &arg->share, &pentry, pcontext, CARE_NO_MONITOR, &nsm_client, &nlm_client, &nlm_owner); if(rc >= 0) { /* Present the error back to the client */ pres->res_nlm4share.stat = (nlm4_stats)rc; LogDebug(COMPONENT_NLM, "REQUEST RESULT: nlm4_Share %s", lock_result_str(pres->res_nlm4share.stat)); return NFS_REQ_OK; } if(state_nlm_share(pentry, pcontext, pexport, arg->share.access, arg->share.mode, nlm_owner, &state_status) != STATE_SUCCESS) { pres->res_nlm4share.stat = nlm_convert_state_error(state_status); } else { pres->res_nlm4share.stat = NLM4_GRANTED; } /* Release the NLM Client and NLM Owner references we have */ dec_nsm_client_ref(nsm_client); dec_nlm_client_ref(nlm_client); dec_state_owner_ref(nlm_owner); cache_inode_put(pentry); LogDebug(COMPONENT_NLM, "REQUEST RESULT: nlm4_Share %s", lock_result_str(pres->res_nlm4share.stat)); return NFS_REQ_OK; }
int nfs_Symlink(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) { char *str_symlink_name = NULL; fsal_name_t symlink_name; char *str_target_path = NULL; cache_inode_create_arg_t create_arg; fsal_accessmode_t mode = 0777; cache_entry_t *symlink_pentry = NULL; cache_entry_t *parent_pentry; cache_inode_file_type_t parent_filetype; fsal_attrib_list_t parent_attr; fsal_attrib_list_t attr_symlink; fsal_attrib_list_t attributes_symlink; fsal_attrib_list_t attr_parent_after; fsal_attrib_list_t *ppre_attr; cache_inode_status_t cache_status; cache_inode_status_t cache_status_parent; fsal_handle_t *pfsal_handle; int rc = NFS_REQ_OK; #ifdef _USE_QUOTA fsal_status_t fsal_status ; #endif memset(&create_arg, 0, sizeof(create_arg)); if(isDebug(COMPONENT_NFSPROTO)) { char str[LEN_FH_STR]; switch (preq->rq_vers) { case NFS_V2: str_symlink_name = parg->arg_symlink2.from.name; str_target_path = parg->arg_symlink2.to; break; case NFS_V3: str_symlink_name = parg->arg_symlink3.where.name; str_target_path = parg->arg_symlink3.symlink.symlink_data; break; } nfs_FhandleToStr(preq->rq_vers, &(parg->arg_symlink2.from.dir), &(parg->arg_symlink3.where.dir), NULL, str); LogDebug(COMPONENT_NFSPROTO, "REQUEST PROCESSING: Calling nfs_Symlink handle: %s name: %s target: %s", str, str_symlink_name, str_target_path); } if(preq->rq_vers == NFS_V3) { /* to avoid setting it on each error case */ pres->res_symlink3.SYMLINK3res_u.resfail.dir_wcc.before.attributes_follow = FALSE; pres->res_symlink3.SYMLINK3res_u.resfail.dir_wcc.after.attributes_follow = FALSE; ppre_attr = NULL; } /* Convert directory file handle into a vnode */ if((parent_pentry = nfs_FhandleToCache(preq->rq_vers, &(parg->arg_symlink2.from.dir), &(parg->arg_symlink3.where.dir), NULL, &(pres->res_stat2), &(pres->res_symlink3.status), NULL, &parent_attr, pcontext, &rc)) == NULL) { /* Stale NFS FH ? */ goto out;; } /* get directory attributes before action (for V3 reply) */ ppre_attr = &parent_attr; /* Extract the filetype */ parent_filetype = cache_inode_fsal_type_convert(parent_attr.type); /* * Sanity checks: new directory name must be non-null; parent must be * a directory. */ if(parent_filetype != DIRECTORY) { switch (preq->rq_vers) { case NFS_V2: pres->res_stat2 = NFSERR_NOTDIR; break; case NFS_V3: pres->res_symlink3.status = NFS3ERR_NOTDIR; break; } rc = NFS_REQ_OK; goto out; } #ifdef _USE_QUOTA /* if quota support is active, then we should check is the FSAL allows inode creation or not */ fsal_status = FSAL_check_quota( pexport->fullpath, FSAL_QUOTA_INODES, FSAL_OP_CONTEXT_TO_UID( pcontext ) ) ; if( FSAL_IS_ERROR( fsal_status ) ) { switch (preq->rq_vers) { case NFS_V2: pres->res_stat2 = NFSERR_DQUOT ; break; case NFS_V3: pres->res_symlink3.status = NFS3ERR_DQUOT; break; } rc = NFS_REQ_OK; goto out; } #endif /* _USE_QUOTA */ switch (preq->rq_vers) { case NFS_V2: str_symlink_name = parg->arg_symlink2.from.name; str_target_path = parg->arg_symlink2.to; break; case NFS_V3: str_symlink_name = parg->arg_symlink3.where.name; str_target_path = parg->arg_symlink3.symlink.symlink_data; break; } if(str_symlink_name == NULL || *str_symlink_name == '\0'|| str_target_path == NULL || *str_target_path == '\0' || FSAL_IS_ERROR(FSAL_str2name(str_symlink_name, 0, &symlink_name)) || FSAL_IS_ERROR(FSAL_str2path(str_target_path, 0, &create_arg.link_content))) { cache_status = CACHE_INODE_INVALID_ARGUMENT; } else { /* Make the symlink */ if((symlink_pentry = cache_inode_create(parent_pentry, &symlink_name, SYMBOLIC_LINK, mode, &create_arg, &attr_symlink, pcontext, &cache_status)) != NULL) { switch (preq->rq_vers) { case NFS_V2: pres->res_stat2 = NFS_OK; break; case NFS_V3: /* Build file handle */ pfsal_handle = &symlink_pentry->handle; /* Some clients (like the Spec NFS benchmark) set attributes with the NFSPROC3_SYMLINK request */ if(nfs3_Sattr_To_FSALattr(&attributes_symlink, &parg->arg_symlink3.symlink.symlink_attributes) == 0) { pres->res_create3.status = NFS3ERR_INVAL; rc = NFS_REQ_OK; goto out; } /* Mode is managed above (in cache_inode_create), there is no need * to manage it */ if(attributes_symlink.asked_attributes & FSAL_ATTR_MODE) attributes_symlink.asked_attributes &= ~FSAL_ATTR_MODE; /* Some clients (like Solaris 10) try to set the size of the file to 0 * at creation time. The FSAL create empty file, so we ignore this */ if(attributes_symlink.asked_attributes & FSAL_ATTR_SIZE) attributes_symlink.asked_attributes &= ~FSAL_ATTR_SIZE; if(attributes_symlink.asked_attributes & FSAL_ATTR_SPACEUSED) attributes_symlink.asked_attributes &= ~FSAL_ATTR_SPACEUSED; /* If owner or owner_group are set, and the credential was * squashed, then we must squash the set owner and owner_group. */ squash_setattr(&pworker->export_perms, &pworker->user_credentials, &attributes_symlink); /* Are there attributes to be set (additional to the mode) ? */ if(attributes_symlink.asked_attributes != 0ULL && attributes_symlink.asked_attributes != FSAL_ATTR_MODE) { /* A call to cache_inode_setattr is required */ if(cache_inode_setattr(symlink_pentry, &attributes_symlink, pcontext, FALSE, &cache_status) != CACHE_INODE_SUCCESS) { goto out_error; } } if ((pres->res_symlink3.status = (nfs3_AllocateFH(&pres->res_symlink3.SYMLINK3res_u .resok.obj.post_op_fh3_u.handle))) != NFS3_OK) { pres->res_symlink3.status = NFS3ERR_IO; rc = NFS_REQ_OK; goto out; } if(nfs3_FSALToFhandle (&pres->res_symlink3.SYMLINK3res_u.resok.obj.post_op_fh3_u.handle, pfsal_handle, pexport) == 0) { gsh_free(pres->res_symlink3.SYMLINK3res_u.resok.obj. post_op_fh3_u.handle.data.data_val); pres->res_symlink3.status = NFS3ERR_BADHANDLE; rc = NFS_REQ_OK; goto out; } /* The the parent pentry attributes for building Wcc Data */ if(cache_inode_getattr(parent_pentry, &attr_parent_after, pcontext, &cache_status_parent) != CACHE_INODE_SUCCESS) { gsh_free(pres->res_symlink3.SYMLINK3res_u.resok.obj. post_op_fh3_u.handle.data.data_val); pres->res_symlink3.status = NFS3ERR_BADHANDLE; rc = NFS_REQ_OK; goto out; } /* Set Post Op Fh3 structure */ pres->res_symlink3.SYMLINK3res_u.resok.obj.handle_follows = TRUE; /* Build entry attributes */ nfs_SetPostOpAttr(pexport, &attr_symlink, &(pres->res_symlink3.SYMLINK3res_u .resok.obj_attributes)); /* Build Weak Cache Coherency data */ nfs_SetWccData(pexport, ppre_attr, &attr_parent_after, &(pres->res_symlink3.SYMLINK3res_u.resok.dir_wcc)); pres->res_symlink3.status = NFS3_OK; break; } /* switch */ rc = NFS_REQ_OK; goto out; } } out_error: rc = nfs_SetFailedStatus(pexport, preq->rq_vers, cache_status, &pres->res_stat2, &pres->res_symlink3.status, NULL, ppre_attr, &(pres->res_symlink3.SYMLINK3res_u.resfail.dir_wcc), NULL, NULL); out: /* return references */ if (parent_pentry) cache_inode_put(parent_pentry); if (symlink_pentry) cache_inode_put(symlink_pentry); return (rc); } /* nfs_Symlink */
int nfs_Create(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) { char *str_file_name = NULL; fsal_name_t file_name; fsal_accessmode_t mode = 0; cache_entry_t *file_pentry = NULL; cache_entry_t *parent_pentry = NULL; fsal_attrib_list_t parent_attr; fsal_attrib_list_t attr; fsal_attrib_list_t attr_parent_after; fsal_attrib_list_t attr_newfile; fsal_attrib_list_t attributes_create; fsal_attrib_list_t *ppre_attr; cache_inode_status_t cache_status = CACHE_INODE_SUCCESS; cache_inode_status_t cache_status_lookup; cache_inode_file_type_t parent_filetype; int rc = NFS_REQ_OK; #ifdef _USE_QUOTA fsal_status_t fsal_status ; #endif if(isDebug(COMPONENT_NFSPROTO)) { char str[LEN_FH_STR]; switch (preq->rq_vers) { case NFS_V2: str_file_name = parg->arg_create2.where.name; break; case NFS_V3: str_file_name = parg->arg_create3.where.name; break; } nfs_FhandleToStr(preq->rq_vers, &(parg->arg_create2.where.dir), &(parg->arg_create3.where.dir), NULL, str); LogDebug(COMPONENT_NFSPROTO, "REQUEST PROCESSING: Calling nfs_Create handle: %s name: %s", str, str_file_name); } if((preq->rq_vers == NFS_V3) && (nfs3_Is_Fh_Xattr(&(parg->arg_create3.where.dir)))) { rc = nfs3_Create_Xattr(parg, pexport, pcontext, preq, pres); goto out; } if(preq->rq_vers == NFS_V3) { /* to avoid setting it on each error case */ pres->res_create3.CREATE3res_u.resfail.dir_wcc.before.attributes_follow = FALSE; pres->res_create3.CREATE3res_u.resfail.dir_wcc.after.attributes_follow = FALSE; ppre_attr = NULL; } if((parent_pentry = nfs_FhandleToCache(preq->rq_vers, &(parg->arg_create2.where.dir), &(parg->arg_create3.where.dir), NULL, &(pres->res_dirop2.status), &(pres->res_create3.status), NULL, &parent_attr, pcontext, &rc)) == NULL) { /* Stale NFS FH ? */ goto out; } /* get directory attributes before action (for V3 reply) */ ppre_attr = &parent_attr; /* Extract the filetype */ parent_filetype = cache_inode_fsal_type_convert(parent_attr.type); /* * Sanity checks: new file name must be non-null; parent must be a * directory. */ if(parent_filetype != DIRECTORY) { switch (preq->rq_vers) { case NFS_V2: pres->res_dirop2.status = NFSERR_NOTDIR; break; case NFS_V3: pres->res_create3.status = NFS3ERR_NOTDIR; break; } rc = NFS_REQ_OK; goto out; } switch (preq->rq_vers) { case NFS_V2: str_file_name = parg->arg_create2.where.name; if(parg->arg_create2.attributes.mode != (unsigned int)-1) { mode = unix2fsal_mode(parg->arg_create2.attributes.mode); } else { mode = 0; } break; case NFS_V3: str_file_name = parg->arg_create3.where.name; if(parg->arg_create3.how.mode == EXCLUSIVE) { /* * Client has not provided mode information. * If the create works, the client will issue * a separate setattr request to fix up the * file's mode, so pick arbitrary value for now. */ mode = 0; } else if(parg->arg_create3.how.createhow3_u.obj_attributes.mode.set_it == TRUE) mode = unix2fsal_mode(parg->arg_create3.how.createhow3_u.obj_attributes.mode. set_mode3_u.mode); else mode = 0; break; } #ifdef _USE_QUOTA /* if quota support is active, then we should check is the FSAL allows inode creation or not */ fsal_status = FSAL_check_quota( pexport->fullpath, FSAL_QUOTA_INODES, FSAL_OP_CONTEXT_TO_UID( pcontext ) ) ; if( FSAL_IS_ERROR( fsal_status ) ) { switch (preq->rq_vers) { case NFS_V2: pres->res_dirop2.status = NFSERR_DQUOT ; break; case NFS_V3: pres->res_create3.status = NFS3ERR_DQUOT; break; } rc = NFS_REQ_OK ; goto out; } #endif /* _USE_QUOTA */ // if(str_file_name == NULL || strlen(str_file_name) == 0) if(str_file_name == NULL || *str_file_name == '\0' ) { if(preq->rq_vers == NFS_V2) pres->res_dirop2.status = NFSERR_IO; if(preq->rq_vers == NFS_V3) pres->res_create3.status = NFS3ERR_INVAL; } else { if((cache_status = cache_inode_error_convert(FSAL_str2name(str_file_name, FSAL_MAX_NAME_LEN, &file_name))) == CACHE_INODE_SUCCESS) { /* * Lookup file to see if it exists. If so, use it. Otherwise * create a new one. */ file_pentry = cache_inode_lookup(parent_pentry, &file_name, &attr, pcontext, &cache_status_lookup); if((cache_status_lookup == CACHE_INODE_NOT_FOUND) || ((cache_status_lookup == CACHE_INODE_SUCCESS) && (parg->arg_create3.how.mode == UNCHECKED))) { /* Create the file */ if((parg->arg_create3.how.mode == UNCHECKED) && (cache_status_lookup == CACHE_INODE_SUCCESS)) { cache_status = CACHE_INODE_SUCCESS; attr_newfile = attr; } else file_pentry = cache_inode_create(parent_pentry, &file_name, REGULAR_FILE, mode, NULL, &attr_newfile, pcontext, &cache_status); if(file_pentry != NULL) { /* * Look at sattr to see if some attributes are to be set at creation time */ attributes_create.asked_attributes = 0ULL; switch (preq->rq_vers) { case NFS_V2: if(nfs2_Sattr_To_FSALattr(&attributes_create, &parg->arg_create2.attributes) == 0) { pres->res_dirop2.status = NFSERR_IO; rc = NFS_REQ_OK; goto out; break; } break; case NFS_V3: if(nfs3_Sattr_To_FSALattr(&attributes_create, &parg->arg_create3.how.createhow3_u. obj_attributes) == 0) { pres->res_create3.status = NFS3ERR_INVAL; rc = NFS_REQ_OK; goto out; } break; } /* Mode is managed above (in cache_inode_create), there is no need * to manage it */ if(attributes_create.asked_attributes & FSAL_ATTR_MODE) attributes_create.asked_attributes &= ~FSAL_ATTR_MODE; /* Some clients (like Solaris 10) try to set the size of the file to 0 * at creation time. The FSAL create empty file, so we ignore this */ if(attributes_create.asked_attributes & FSAL_ATTR_SIZE) attributes_create.asked_attributes &= ~FSAL_ATTR_SIZE; if(attributes_create.asked_attributes & FSAL_ATTR_SPACEUSED) attributes_create.asked_attributes &= ~FSAL_ATTR_SPACEUSED; /* Are there attributes to be set (additional to the mode) ? */ if(attributes_create.asked_attributes != 0ULL && attributes_create.asked_attributes != FSAL_ATTR_MODE) { /* A call to cache_inode_setattr is required */ if(cache_inode_setattr(file_pentry, &attributes_create, pcontext, &cache_status) != CACHE_INODE_SUCCESS) { /* If we are here, there was an error */ nfs_SetFailedStatus(pcontext, pexport, preq->rq_vers, cache_status, &pres->res_dirop2.status, &pres->res_create3.status, NULL, NULL, parent_pentry, ppre_attr, &(pres->res_create3.CREATE3res_u.resfail. dir_wcc), NULL, NULL, NULL); if(nfs_RetryableError(cache_status)) { rc = NFS_REQ_DROP; goto out; } rc = NFS_REQ_OK; goto out; } /* Get the resulting attributes from the Cache Inode */ if(cache_inode_getattr(file_pentry, &attr_newfile, pcontext, &cache_status) != CACHE_INODE_SUCCESS) { /* If we are here, there was an error */ nfs_SetFailedStatus(pcontext, pexport, preq->rq_vers, cache_status, &pres->res_dirop2.status, &pres->res_create3.status, NULL, NULL, parent_pentry, ppre_attr, &(pres->res_create3.CREATE3res_u.resfail. dir_wcc), NULL, NULL, NULL); if(nfs_RetryableError(cache_status)) { rc = NFS_REQ_DROP; goto out; } rc = NFS_REQ_OK; goto out; } } switch (preq->rq_vers) { case NFS_V2: /* Build file handle */ if(nfs2_FSALToFhandle( &(pres->res_dirop2.DIROP2res_u.diropok.file), &file_pentry->handle, pexport) == 0) pres->res_dirop2.status = NFSERR_IO; else { if(!nfs2_FSALattr_To_Fattr( pexport, &attr_newfile, &(pres->res_dirop2.DIROP2res_u. diropok.attributes))) pres->res_dirop2.status = NFSERR_IO; else pres->res_dirop2.status = NFS_OK; } break; case NFS_V3: /* Build file handle */ pres->res_create3.status = nfs3_AllocateFH(&pres->res_create3.CREATE3res_u .resok.obj.post_op_fh3_u.handle); if (pres->res_create3.status != NFS3_OK) { rc = NFS_REQ_OK; goto out; } /* Set Post Op Fh3 structure */ if(nfs3_FSALToFhandle( &(pres->res_create3.CREATE3res_u.resok .obj.post_op_fh3_u.handle), &file_pentry->handle, pexport) == 0) { gsh_free(pres->res_create3.CREATE3res_u.resok.obj. post_op_fh3_u.handle.data.data_val); pres->res_create3.status = NFS3ERR_BADHANDLE; rc = NFS_REQ_OK; goto out; } /* Set Post Op Fh3 structure */ pres->res_create3.CREATE3res_u.resok.obj.handle_follows = TRUE; /* Get the attributes of the parent after the operation */ attr_parent_after = parent_pentry->attributes; /* Build entry attributes */ nfs_SetPostOpAttr(pexport, &attr_newfile, &(pres->res_create3.CREATE3res_u.resok. obj_attributes)); /* * Build Weak Cache Coherency data */ nfs_SetWccData(pexport, ppre_attr, &attr_parent_after, &(pres->res_create3.CREATE3res_u .resok.dir_wcc)); pres->res_create3.status = NFS3_OK; break; } /* switch */ rc = NFS_REQ_OK; goto out; } } else { if(cache_status_lookup == CACHE_INODE_SUCCESS) { /* Trying to create a file that already exists */ cache_status = CACHE_INODE_ENTRY_EXISTS; switch (preq->rq_vers) { case NFS_V2: pres->res_dirop2.status = NFSERR_EXIST; break; case NFS_V3: pres->res_create3.status = NFS3ERR_EXIST; break; } } else { /* Server fault */ cache_status = cache_status_lookup; switch (preq->rq_vers) { case NFS_V2: pres->res_dirop2.status = NFSERR_IO; break; case NFS_V3: pres->res_create3.status = NFS3ERR_INVAL; break; } } nfs_SetFailedStatus(pcontext, pexport, preq->rq_vers, cache_status, &pres->res_dirop2.status, &pres->res_create3.status, NULL, NULL, parent_pentry, ppre_attr, &(pres->res_create3.CREATE3res_u.resfail.dir_wcc), NULL, NULL, NULL); rc = NFS_REQ_OK; goto out; } /* if( cache_status_lookup == CACHE_INODE_NOT_FOUND ) */ } } /* Set the exit status */ nfs_SetFailedStatus(pcontext, pexport, preq->rq_vers, cache_status, &pres->res_dirop2.status, &pres->res_create3.status, NULL, NULL, parent_pentry, ppre_attr, &(pres->res_create3.CREATE3res_u.resfail.dir_wcc), NULL, NULL, NULL); /* If we are here, there was an error */ if(nfs_RetryableError(cache_status)) { rc = NFS_REQ_DROP; goto out; } rc = NFS_REQ_OK; out: /* return references */ if (file_pentry) cache_inode_put(file_pentry); if (parent_pentry) cache_inode_put(parent_pentry); return (rc); } /* nfs_Create */
int nfs3_rmdir(nfs_arg_t *arg, nfs_worker_data_t *worker, struct svc_req *req, nfs_res_t *res) { cache_entry_t *parent_entry = NULL; cache_entry_t *child_entry = NULL; pre_op_attr pre_parent = { .attributes_follow = false }; cache_inode_status_t cache_status; const char *name = arg->arg_rmdir3.object.name; int rc = NFS_REQ_OK; if (isDebug(COMPONENT_NFSPROTO)) { char str[LEN_FH_STR]; nfs_FhandleToStr(req->rq_vers, &arg->arg_rmdir3.object.dir, NULL, str); LogDebug(COMPONENT_NFSPROTO, "REQUEST PROCESSING: Calling nfs3_rmdir handle: %s " "name: %s", str, name); } /* Convert file handle into a pentry */ /* to avoid setting it on each error case */ res->res_rmdir3.RMDIR3res_u.resfail.dir_wcc.before.attributes_follow = FALSE; res->res_rmdir3.RMDIR3res_u.resfail.dir_wcc.after.attributes_follow = FALSE; parent_entry = nfs3_FhandleToCache(&arg->arg_rmdir3.object.dir, &res->res_rmdir3.status, &rc); if (parent_entry == NULL) { /* Status and rc have been set by nfs3_FhandleToCache */ goto out; } nfs_SetPreOpAttr(parent_entry, &pre_parent); /* Sanity checks: directory name must be non-null; parent * must be a directory. */ if (parent_entry->type != DIRECTORY) { res->res_rmdir3.status = NFS3ERR_NOTDIR; rc = NFS_REQ_OK; goto out; } if ((name == NULL) || (*name == '\0')) { cache_status = CACHE_INODE_INVALID_ARGUMENT; goto out_fail; } /* Lookup to the entry to be removed to check that it is a * directory */ cache_status = cache_inode_lookup(parent_entry, name, &child_entry); if (child_entry != NULL) { /* Sanity check: make sure we are about to remove a * directory */ if (child_entry->type != DIRECTORY) { res->res_rmdir3.status = NFS3ERR_NOTDIR; rc = NFS_REQ_OK; goto out; } } cache_status = cache_inode_remove(parent_entry, name); if (cache_status != CACHE_INODE_SUCCESS) goto out_fail; nfs_SetWccData(&pre_parent, parent_entry, &res->res_rmdir3.RMDIR3res_u.resok.dir_wcc); res->res_rmdir3.status = NFS3_OK; rc = NFS_REQ_OK; goto out; out_fail: res->res_rmdir3.status = nfs3_Errno(cache_status); nfs_SetWccData(&pre_parent, parent_entry, &res->res_rmdir3.RMDIR3res_u.resfail.dir_wcc); /* If we are here, there was an error */ if (nfs_RetryableError(cache_status)) rc = NFS_REQ_DROP; out: /* return references */ if (child_entry) cache_inode_put(child_entry); if (parent_entry) cache_inode_put(parent_entry); return rc; } /* nfs3_rmdir */ /** * @brief Free the result structure allocated for nfs3_rmdir * * This function frees the result structure allocated for nfs3_rmdir. * * @param[in,out] res Result structure * */ void nfs3_rmdir_free(nfs_res_t *res) { return; }
int _9p_symlink(struct _9p_request_data *req9p, void *worker_data, u32 *plenout, char *preply) { char *cursor = req9p->_9pmsg + _9P_HDR_SIZE + _9P_TYPE_SIZE; u16 *msgtag = NULL; u32 *fid = NULL; u16 *name_len = NULL; char *name_str = NULL; u16 *linkcontent_len = NULL; char *linkcontent_str = NULL; u32 *gid = NULL; struct _9p_fid *pfid = NULL; struct _9p_qid qid_symlink; cache_entry_t *pentry_symlink = NULL; char symlink_name[MAXNAMLEN]; uint64_t fileid; cache_inode_status_t cache_status; uint32_t mode = 0777; cache_inode_create_arg_t create_arg; memset(&create_arg, 0, sizeof(create_arg)); /* Get data */ _9p_getptr(cursor, msgtag, u16); _9p_getptr(cursor, fid, u32); _9p_getstr(cursor, name_len, name_str); _9p_getstr(cursor, linkcontent_len, linkcontent_str); _9p_getptr(cursor, gid, u32); LogDebug(COMPONENT_9P, "TSYMLINK: tag=%u fid=%u name=%.*s linkcontent=%.*s gid=%u", (u32) *msgtag, *fid, *name_len, name_str, *linkcontent_len, linkcontent_str, *gid); if (*fid >= _9P_FID_PER_CONN) return _9p_rerror(req9p, worker_data, msgtag, ERANGE, plenout, preply); pfid = req9p->pconn->fids[*fid]; /* Check that it is a valid fid */ if (pfid == NULL || pfid->pentry == NULL) { LogDebug(COMPONENT_9P, "request on invalid fid=%u", *fid); return _9p_rerror(req9p, worker_data, msgtag, EIO, plenout, preply); } if ((pfid->op_context.export_perms->options & EXPORT_OPTION_WRITE_ACCESS) == 0) return _9p_rerror(req9p, worker_data, msgtag, EROFS, plenout, preply); op_ctx = &pfid->op_context; snprintf(symlink_name, MAXNAMLEN, "%.*s", *name_len, name_str); create_arg.link_content = gsh_malloc(MAXPATHLEN); if (create_arg.link_content == NULL) return _9p_rerror(req9p, worker_data, msgtag, EFAULT, plenout, preply); snprintf(create_arg.link_content, MAXPATHLEN, "%.*s", *linkcontent_len, linkcontent_str); /* Let's do the job */ /* BUGAZOMEU: @todo : the gid parameter is not used yet, * flags is not yet used */ cache_status = cache_inode_create(pfid->pentry, symlink_name, SYMBOLIC_LINK, mode, &create_arg, &pentry_symlink); if (create_arg.link_content != NULL) gsh_free(create_arg.link_content); if (pentry_symlink == NULL) { return _9p_rerror(req9p, worker_data, msgtag, _9p_tools_errno(cache_status), plenout, preply); } /* This is not a TATTACH fid */ pfid->from_attach = false; cache_status = cache_inode_fileid(pentry_symlink, &fileid); /* put the entry: * we don't want to remember it even if cache_inode_fileid fails. */ cache_inode_put(pentry_symlink); if (cache_status != CACHE_INODE_SUCCESS) { return _9p_rerror(req9p, worker_data, msgtag, _9p_tools_errno(cache_status), plenout, preply); } /* Build the qid */ qid_symlink.type = _9P_QTSYMLINK; qid_symlink.version = 0; qid_symlink.path = fileid; /* Build the reply */ _9p_setinitptr(cursor, preply, _9P_RSYMLINK); _9p_setptr(cursor, msgtag, u16); _9p_setqid(cursor, qid_symlink); _9p_setendptr(cursor, preply); _9p_checkbound(cursor, preply, plenout); LogDebug(COMPONENT_9P, "RSYMLINK: tag=%u fid=%u name=%.*s qid=(type=%u,version=%u,path=%llu)", (u32) *msgtag, *fid, *name_len, name_str, qid_symlink.type, qid_symlink.version, (unsigned long long)qid_symlink.path); return 1; }
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; }
int nfs_Remove(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 *parent_pentry = NULL; cache_entry_t *pentry_child = NULL; fsal_attrib_list_t pre_parent_attr; fsal_attrib_list_t pentry_child_attr; fsal_attrib_list_t parent_attr; fsal_attrib_list_t *pparent_attr = NULL; cache_inode_file_type_t filetype; cache_inode_file_type_t childtype; cache_inode_status_t cache_status; char *file_name = NULL; fsal_name_t name; int rc = NFS_REQ_OK; if(isDebug(COMPONENT_NFSPROTO)) { char str[LEN_FH_STR]; switch (preq->rq_vers) { case NFS_V2: file_name = parg->arg_remove2.name; break; case NFS_V3: file_name = parg->arg_remove3.object.name; break; } nfs_FhandleToStr(preq->rq_vers, &(parg->arg_create2.where.dir), &(parg->arg_create3.where.dir), NULL, str); LogDebug(COMPONENT_NFSPROTO, "REQUEST PROCESSING: Calling nfs_Remove handle: %s name: %s", str, file_name); } if(preq->rq_vers == NFS_V3) { /* to avoid setting it on each error case */ pres->res_remove3.REMOVE3res_u.resfail.dir_wcc.before.attributes_follow = FALSE; pres->res_remove3.REMOVE3res_u.resfail.dir_wcc.after.attributes_follow = FALSE; pparent_attr = NULL; } /* Convert file handle into a pentry */ if((parent_pentry = nfs_FhandleToCache(preq->rq_vers, &(parg->arg_remove2.dir), &(parg->arg_remove3.object.dir), NULL, &(pres->res_dirop2.status), &(pres->res_remove3.status), NULL, &pre_parent_attr, pcontext, &rc)) == NULL) { /* Stale NFS FH ? */ goto out; } if((preq->rq_vers == NFS_V3) && (nfs3_Is_Fh_Xattr(&(parg->arg_remove3.object.dir)))) { rc = nfs3_Remove_Xattr(parg, pexport, pcontext, preq, pres); goto out; } /* get directory attributes before action (for V3 reply) */ pparent_attr = &pre_parent_attr; /* Extract the filetype */ filetype = cache_inode_fsal_type_convert(pre_parent_attr.type); /* * Sanity checks: new directory name must be non-null; parent must be * a directory. */ if(filetype != DIRECTORY) { switch (preq->rq_vers) { case NFS_V2: pres->res_stat2 = NFSERR_NOTDIR; break; case NFS_V3: pres->res_remove3.status = NFS3ERR_NOTDIR; break; } rc = NFS_REQ_OK; goto out; } switch (preq->rq_vers) { case NFS_V2: file_name = parg->arg_remove2.name; break; case NFS_V3: file_name = parg->arg_remove3.object.name; break; } //if(file_name == NULL || strlen(file_name) == 0) if(file_name == NULL || *file_name == '\0' ) { cache_status = CACHE_INODE_INVALID_ARGUMENT; /* for lack of better... */ } else { if((cache_status = cache_inode_error_convert(FSAL_str2name(file_name, 0, &name))) == CACHE_INODE_SUCCESS) { /* * Lookup to the child entry to check if it is a directory * */ if((pentry_child = cache_inode_lookup(parent_pentry, &name, &pentry_child_attr, pcontext, &cache_status)) != NULL) { /* Extract the filetype */ childtype = cache_inode_fsal_type_convert(pentry_child_attr.type); /* * Sanity check: make sure we are about to remove a directory */ if(childtype == DIRECTORY) { switch (preq->rq_vers) { case NFS_V2: pres->res_stat2 = NFSERR_ISDIR; break; case NFS_V3: pres->res_remove3.status = NFS3ERR_ISDIR; break; } rc = NFS_REQ_OK; goto out; } LogFullDebug(COMPONENT_NFSPROTO, "==== NFS REMOVE ====> Trying to remove file %s", name.name); /* * Remove the entry. */ if(cache_inode_remove(parent_pentry, &name, &parent_attr, pcontext, &cache_status) == CACHE_INODE_SUCCESS) { switch (preq->rq_vers) { case NFS_V2: pres->res_stat2 = NFS_OK; break; case NFS_V3: /* Build Weak Cache Coherency data */ nfs_SetWccData(pexport, pparent_attr, &parent_attr, &(pres->res_remove3.REMOVE3res_u.resok.dir_wcc)); pres->res_remove3.status = NFS3_OK; break; } rc = NFS_REQ_OK; goto out; } } } } /* If we are here, there was an error */ rc = nfs_SetFailedStatus(pexport, preq->rq_vers, cache_status, &pres->res_stat2, &pres->res_remove3.status, NULL, pparent_attr, &(pres->res_remove3.REMOVE3res_u.resfail.dir_wcc), NULL, NULL); out: /* return references */ if (pentry_child) cache_inode_put(pentry_child); if (parent_pentry) cache_inode_put(parent_pentry); return (rc); } /* nfs_Remove */
int nfs_Mkdir(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) { char *str_dir_name = NULL; fsal_accessmode_t mode = 0; cache_entry_t *dir_pentry = NULL; cache_entry_t *parent_pentry = NULL; fsal_attrib_list_t parent_attr; fsal_attrib_list_t attr; fsal_attrib_list_t *ppre_attr; fsal_attrib_list_t attr_parent_after; cache_inode_file_type_t parent_filetype; fsal_handle_t *pfsal_handle; fsal_name_t dir_name; cache_inode_status_t cache_status = CACHE_INODE_SUCCESS; cache_inode_status_t cache_status_lookup; cache_inode_create_arg_t create_arg; int rc = NFS_REQ_OK; #ifdef _USE_QUOTA fsal_status_t fsal_status ; #endif memset(&create_arg, 0, sizeof(create_arg)); if(isDebug(COMPONENT_NFSPROTO)) { char str[LEN_FH_STR]; switch (preq->rq_vers) { case NFS_V2: str_dir_name = parg->arg_mkdir2.where.name; break; case NFS_V3: str_dir_name = parg->arg_mkdir3.where.name; break; } nfs_FhandleToStr(preq->rq_vers, &(parg->arg_mkdir2.where.dir), &(parg->arg_mkdir3.where.dir), NULL, str); LogDebug(COMPONENT_NFSPROTO, "REQUEST PROCESSING: Calling nfs_Mkdir handle: %s name: %s", str, str_dir_name); } if(preq->rq_vers == NFS_V3) { /* to avoid setting it on each error case */ pres->res_mkdir3.MKDIR3res_u.resfail.dir_wcc.before.attributes_follow = FALSE; pres->res_mkdir3.MKDIR3res_u.resfail.dir_wcc.after.attributes_follow = FALSE; ppre_attr = NULL; } if((parent_pentry = nfs_FhandleToCache(preq->rq_vers, &(parg->arg_mkdir2.where.dir), &(parg->arg_mkdir3.where.dir), NULL, &(pres->res_dirop2.status), &(pres->res_mkdir3.status), NULL, &parent_attr, pcontext, &rc)) == NULL) { /* Stale NFS FH ? */ goto out; } /* get directory attributes before action (for V3 reply) */ ppre_attr = &parent_attr; /* Extract the filetype */ parent_filetype = cache_inode_fsal_type_convert(parent_attr.type); /* * Sanity checks: */ if(parent_filetype != DIRECTORY) { switch (preq->rq_vers) { case NFS_V2: pres->res_dirop2.status = NFSERR_NOTDIR; break; case NFS_V3: pres->res_mkdir3.status = NFS3ERR_NOTDIR; break; } rc = NFS_REQ_OK; goto out; } #ifdef _USE_QUOTA /* if quota support is active, then we should check is the FSAL allows inode creation or not */ fsal_status = FSAL_check_quota( pexport->fullpath, FSAL_QUOTA_INODES, FSAL_OP_CONTEXT_TO_UID( pcontext ) ) ; if( FSAL_IS_ERROR( fsal_status ) ) { switch (preq->rq_vers) { case NFS_V2: pres->res_dirop2.status = NFSERR_DQUOT; break; case NFS_V3: pres->res_mkdir3.status = NFS3ERR_DQUOT; break; } rc = NFS_REQ_OK ; goto out; } #endif /* _USE_QUOTA */ switch (preq->rq_vers) { case NFS_V2: str_dir_name = parg->arg_mkdir2.where.name; if(parg->arg_mkdir2.attributes.mode != (unsigned int)-1) { mode = (fsal_accessmode_t) parg->arg_mkdir2.attributes.mode; } else { mode = (fsal_accessmode_t) 0; } break; case NFS_V3: str_dir_name = parg->arg_mkdir3.where.name; if(parg->arg_mkdir3.attributes.mode.set_it == TRUE) mode = (fsal_accessmode_t) parg->arg_mkdir3.attributes.mode.set_mode3_u.mode; else mode = (fsal_accessmode_t) 0; break; } //if(str_dir_name == NULL || strlen(str_dir_name) == 0) if(str_dir_name == NULL || *str_dir_name == '\0' ) { if(preq->rq_vers == NFS_V2) pres->res_dirop2.status = NFSERR_IO; if(preq->rq_vers == NFS_V3) pres->res_mkdir3.status = NFS3ERR_INVAL; } else { /* Make the directory */ if((cache_status = cache_inode_error_convert(FSAL_str2name(str_dir_name, 0, &dir_name))) == CACHE_INODE_SUCCESS) { /* * Lookup file to see if it exists. If so, use it. Otherwise * create a new one. */ dir_pentry = cache_inode_lookup(parent_pentry, &dir_name, &attr, pcontext, &cache_status_lookup); if(cache_status_lookup == CACHE_INODE_NOT_FOUND) { /* The create_arg structure contains the information "newly created directory" * to be passed to cache_inode_new_entry from cache_inode_create */ create_arg.newly_created_dir = TRUE; /* Create the directory */ if((dir_pentry = cache_inode_create(parent_pentry, &dir_name, DIRECTORY, mode, &create_arg, &attr, pcontext, &cache_status)) != NULL) { /* * Get the FSAL handle for this entry */ pfsal_handle = &dir_pentry->handle; if(preq->rq_vers == NFS_V2) { DIROP2resok *d2ok = &pres->res_dirop2.DIROP2res_u.diropok; /* Build file handle */ if(!nfs2_FSALToFhandle(&d2ok->file, pfsal_handle, pexport)) pres->res_dirop2.status = NFSERR_IO; else { /* * Build entry * attributes */ if(nfs2_FSALattr_To_Fattr(pexport, &attr, &d2ok->attributes) == 0) pres->res_dirop2.status = NFSERR_IO; else pres->res_dirop2.status = NFS_OK; } } else { MKDIR3resok *d3ok = &pres->res_mkdir3.MKDIR3res_u.resok; /* Build file handle */ pres->res_mkdir3.status = nfs3_AllocateFH(&d3ok->obj.post_op_fh3_u.handle); if(pres->res_mkdir3.status != NFS3_OK) { rc = NFS_REQ_OK; goto out; } if(nfs3_FSALToFhandle(&d3ok->obj.post_op_fh3_u.handle, pfsal_handle, pexport) == 0) { gsh_free(d3ok->obj.post_op_fh3_u.handle.data.data_val); pres->res_mkdir3.status = NFS3ERR_INVAL; rc = NFS_REQ_OK; goto out; } /* Set Post Op Fh3 structure */ d3ok->obj.handle_follows = TRUE; /* * Build entry attributes */ nfs_SetPostOpAttr(pexport, &attr, &d3ok->obj_attributes); /* Get the attributes of the parent after the operation */ if(cache_inode_getattr(parent_pentry, &attr_parent_after, pcontext, &cache_status) != CACHE_INODE_SUCCESS) { pres->res_mkdir3.status = nfs3_Errno(cache_status); rc = NFS_REQ_OK; goto out; } /* * Build Weak Cache Coherency data */ nfs_SetWccData(pexport, ppre_attr, &attr_parent_after, &d3ok->dir_wcc); pres->res_mkdir3.status = NFS3_OK; } rc = NFS_REQ_OK; goto out; } } /* If( cache_status_lookup == CACHE_INODE_NOT_FOUND ) */ else { switch (preq->rq_vers) { case NFS_V2: if(cache_status_lookup == CACHE_INODE_SUCCESS) pres->res_dirop2.status = NFSERR_EXIST; else pres->res_dirop2.status = NFSERR_IO; break; case NFS_V3: if(cache_status_lookup == CACHE_INODE_SUCCESS) pres->res_mkdir3.status = NFS3ERR_EXIST; else pres->res_mkdir3.status = NFS3ERR_INVAL; nfs_SetWccData(pexport, ppre_attr, NULL, &(pres->res_mkdir3.MKDIR3res_u.resfail.dir_wcc)); break; } rc = NFS_REQ_OK; goto out; } } } /* If we are here, there was an error */ rc = nfs_SetFailedStatus(pexport, preq->rq_vers, cache_status, &pres->res_dirop2.status, &pres->res_mkdir3.status, NULL, ppre_attr, &(pres->res_mkdir3.MKDIR3res_u.resfail.dir_wcc), NULL, NULL); out: /* return references */ if (dir_pentry) cache_inode_put(dir_pentry); if (parent_pentry) cache_inode_put(parent_pentry); return (rc); }
int nlm_process_share_parms(struct svc_req * preq, nlm4_share * share, cache_entry_t ** ppentry, fsal_op_context_t * pcontext, care_t care, state_nsm_client_t ** ppnsm_client, state_nlm_client_t ** ppnlm_client, state_owner_t ** ppowner) { cache_inode_fsal_data_t fsal_data; fsal_attrib_list_t attr; cache_inode_status_t cache_status; SVCXPRT *ptr_svc = preq->rq_xprt; int rc; *ppnsm_client = NULL; *ppnlm_client = NULL; *ppowner = NULL; /* Convert file handle into a cache entry */ if(share->fh.n_len > MAX_NETOBJ_SZ || !nfs3_FhandleToFSAL((nfs_fh3 *) &share->fh, &fsal_data.fh_desc, pcontext)) { /* handle is not valid */ return NLM4_STALE_FH; } /* Now get the cached inode attributes */ *ppentry = cache_inode_get(&fsal_data, &attr, pcontext, NULL, &cache_status); if(*ppentry == NULL) { /* handle is not valid */ return NLM4_STALE_FH; } *ppnsm_client = get_nsm_client(care, ptr_svc, share->caller_name); if(*ppnsm_client == NULL) { /* If NSM Client is not found, and we don't care (for unshare), * just return GRANTED (the unshare must succeed, there can't be * any shares). */ if(care != CARE_NOT) rc = NLM4_DENIED_NOLOCKS; else rc = NLM4_GRANTED; goto out_put; } *ppnlm_client = get_nlm_client(care, ptr_svc, *ppnsm_client, share->caller_name); if(*ppnlm_client == NULL) { /* If NLM Client is not found, and we don't care (such as unlock), * just return GRANTED (the unlock must succeed, there can't be * any locks). */ dec_nsm_client_ref(*ppnsm_client); if(care != CARE_NOT) rc = NLM4_DENIED_NOLOCKS; else rc = NLM4_GRANTED; goto out_put; } *ppowner = get_nlm_owner(care, *ppnlm_client, &share->oh, 0); if(*ppowner == NULL) { LogDebug(COMPONENT_NLM, "Could not get NLM Owner"); dec_nsm_client_ref(*ppnsm_client); dec_nlm_client_ref(*ppnlm_client); *ppnlm_client = NULL; /* If owner is not found, and we don't care (such as unlock), * just return GRANTED (the unlock must succeed, there can't be * any locks). */ if(care != CARE_NOT) rc = NLM4_DENIED_NOLOCKS; else rc = NLM4_GRANTED; goto out_put; } LogFullDebug(COMPONENT_NLM, "Parameters Processed"); return -1; out_put: cache_inode_put(*ppentry); *ppentry = NULL; return rc; }
int nfs3_Mknod(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 *parent_pentry = NULL; fsal_attrib_list_t parent_attr; fsal_attrib_list_t *ppre_attr; fsal_attrib_list_t attr_parent_after; cache_inode_file_type_t parent_filetype; cache_inode_file_type_t nodetype; char *str_file_name = NULL; fsal_name_t file_name; cache_inode_status_t cache_status; cache_inode_status_t cache_status_lookup; fsal_accessmode_t mode = 0; cache_entry_t *node_pentry = NULL; fsal_attrib_list_t attr; cache_inode_create_arg_t create_arg; fsal_handle_t *pfsal_handle; int rc = NFS_REQ_OK; #ifdef _USE_QUOTA fsal_status_t fsal_status ; #endif memset(&create_arg, 0, sizeof(create_arg)); if(isDebug(COMPONENT_NFSPROTO)) { char str[LEN_FH_STR]; sprint_fhandle3(str, &(parg->arg_mknod3.where.dir)); LogDebug(COMPONENT_NFSPROTO, "REQUEST PROCESSING: Calling nfs3_Mknod handle: %s name: %s", str, parg->arg_mknod3.where.name); } /* to avoid setting them on each error case */ pres->res_mknod3.MKNOD3res_u.resfail.dir_wcc.before.attributes_follow = FALSE; pres->res_mknod3.MKNOD3res_u.resfail.dir_wcc.after.attributes_follow = FALSE; ppre_attr = NULL; /* retrieve parent entry */ if((parent_pentry = nfs_FhandleToCache(preq->rq_vers, NULL, &(parg->arg_mknod3.where.dir), NULL, NULL, &(pres->res_mknod3.status), NULL, &parent_attr, pcontext, &rc)) == NULL) { /* Stale NFS FH ? */ return rc; } /* get directory attributes before action (for V3 reply) */ ppre_attr = &parent_attr; /* Extract the filetype */ parent_filetype = cache_inode_fsal_type_convert(parent_attr.type); /* * Sanity checks: new node name must be non-null; parent must be a * directory. */ if(parent_filetype != DIRECTORY) { pres->res_mknod3.status = NFS3ERR_NOTDIR; rc = NFS_REQ_OK; goto out; } str_file_name = parg->arg_mknod3.where.name; switch (parg->arg_mknod3.what.type) { case NF3CHR: case NF3BLK: if(parg->arg_mknod3.what.mknoddata3_u.device.dev_attributes.mode.set_it) mode = (fsal_accessmode_t) parg->arg_mknod3.what.mknoddata3_u.device.dev_attributes. mode.set_mode3_u.mode; else mode = (fsal_accessmode_t) 0; create_arg.dev_spec.major = parg->arg_mknod3.what.mknoddata3_u.device.spec.specdata1; create_arg.dev_spec.minor = parg->arg_mknod3.what.mknoddata3_u.device.spec.specdata2; break; case NF3FIFO: case NF3SOCK: if(parg->arg_mknod3.what.mknoddata3_u.pipe_attributes.mode.set_it) mode = (fsal_accessmode_t) parg->arg_mknod3.what.mknoddata3_u.pipe_attributes.mode. set_mode3_u.mode; else mode = (fsal_accessmode_t) 0; create_arg.dev_spec.major = 0; create_arg.dev_spec.minor = 0; break; default: pres->res_mknod3.status = NFS3ERR_BADTYPE; rc = NFS_REQ_OK; goto out; } switch (parg->arg_mknod3.what.type) { case NF3CHR: nodetype = CHARACTER_FILE; break; case NF3BLK: nodetype = BLOCK_FILE; break; case NF3FIFO: nodetype = FIFO_FILE; break; case NF3SOCK: nodetype = SOCKET_FILE; break; default: pres->res_mknod3.status = NFS3ERR_BADTYPE; rc = NFS_REQ_OK; goto out; } //if(str_file_name == NULL || strlen(str_file_name) == 0) if(str_file_name == NULL || *str_file_name == '\0' ) { pres->res_mknod3.status = NFS3ERR_INVAL; rc = NFS_REQ_OK; goto out; } #ifdef _USE_QUOTA /* if quota support is active, then we should check is the FSAL allows inode creation or not */ fsal_status = FSAL_check_quota( pexport->fullpath, FSAL_QUOTA_INODES, FSAL_OP_CONTEXT_TO_UID( pcontext ) ) ; if( FSAL_IS_ERROR( fsal_status ) ) { pres->res_mknod3.status = NFS3ERR_DQUOT; return NFS_REQ_OK; } #endif /* _USE_QUOTA */ /* convert node name */ if((cache_status = cache_inode_error_convert(FSAL_str2name(str_file_name, 0, &file_name))) == CACHE_INODE_SUCCESS) { /* * Lookup node to see if it exists. If so, use it. Otherwise * create a new one. */ node_pentry = cache_inode_lookup(parent_pentry, &file_name, &attr, pcontext, &cache_status_lookup); if(cache_status_lookup == CACHE_INODE_NOT_FOUND) { /* Create the node */ if((node_pentry = cache_inode_create(parent_pentry, &file_name, nodetype, mode, &create_arg, &attr, pcontext, &cache_status)) != NULL) { MKNOD3resok *rok = &pres->res_mknod3.MKNOD3res_u.resok; /* * Get the FSAL handle for this entry */ pfsal_handle = &node_pentry->handle; /* Build file handle */ pres->res_mknod3.status = nfs3_AllocateFH(&rok->obj.post_op_fh3_u.handle); if(pres->res_mknod3.status != NFS3_OK) return NFS_REQ_OK; if(nfs3_FSALToFhandle(&rok->obj.post_op_fh3_u.handle, pfsal_handle, pexport) == 0) { gsh_free(rok->obj.post_op_fh3_u.handle.data.data_val); pres->res_mknod3.status = NFS3ERR_INVAL; rc = NFS_REQ_OK; goto out; } /* Set Post Op Fh3 structure */ rok->obj.handle_follows = TRUE; /* Build entry attributes */ nfs_SetPostOpAttr(pexport, &attr, &rok->obj_attributes); /* Get the attributes of the parent after the operation */ if(cache_inode_getattr(parent_pentry, &attr_parent_after, pcontext, &cache_status) != CACHE_INODE_SUCCESS) { pres->res_mknod3.status = nfs3_Errno(cache_status); rc = NFS_REQ_OK; goto out; } /* Build Weak Cache Coherency data */ nfs_SetWccData(pexport, ppre_attr, &attr_parent_after, &rok->dir_wcc); pres->res_mknod3.status = NFS3_OK; rc = NFS_REQ_OK; goto out; } /* mknod sucess */ } /* not found */ else { /* object already exists or failure during lookup */ if(cache_status_lookup == CACHE_INODE_SUCCESS) { /* Trying to create an entry that already exists */ pres->res_mknod3.status = NFS3ERR_EXIST; } else { /* Server fault */ pres->res_mknod3.status = NFS3ERR_INVAL; } nfs_SetWccData(pexport, NULL, NULL, &(pres->res_mknod3.MKNOD3res_u.resfail.dir_wcc)); rc = NFS_REQ_OK; goto out; } } /* If we are here, there was an error */ rc = nfs_SetFailedStatus(pexport, preq->rq_vers, cache_status, NULL, &pres->res_mknod3.status, NULL, ppre_attr, &(pres->res_mknod3.MKNOD3res_u.resfail.dir_wcc), NULL, NULL); out: /* return references */ if (parent_pentry) cache_inode_put(parent_pentry); if (node_pentry) cache_inode_put(node_pentry); return (rc); } /* nfs3_Mknod */
/** * @brief Renames an entry * * This function calls the FSAL to rename a file, then mirrors the * operation in the cache. * * @param[in] dir_src The source directory * @param[in] oldname The current name of the file * @param[in] dir_dest The destination directory * @param[in] newname The name to be assigned to the object * * @retval CACHE_INODE_SUCCESS if operation is a success. * @retval CACHE_INODE_NOT_FOUND if source object does not exist * @retval CACHE_INODE_ENTRY_EXISTS on collision. * @retval CACHE_INODE_NOT_A_DIRECTORY if dir_src or dir_dest is not a * directory. * @retval CACHE_INODE_BADNAME if either name is "." or ".." */ cache_inode_status_t cache_inode_rename(cache_entry_t *dir_src, const char *oldname, cache_entry_t *dir_dest, const char *newname) { fsal_status_t fsal_status = { 0, 0 }; cache_entry_t *lookup_src = NULL; cache_entry_t *lookup_dst = NULL; cache_inode_status_t status = CACHE_INODE_SUCCESS; cache_inode_status_t status_ref_dir_src = CACHE_INODE_SUCCESS; cache_inode_status_t status_ref_dir_dst = CACHE_INODE_SUCCESS; cache_inode_status_t status_ref_dst = CACHE_INODE_SUCCESS; if ((dir_src->type != DIRECTORY) || (dir_dest->type != DIRECTORY)) { status = CACHE_INODE_NOT_A_DIRECTORY; goto out; } /* Check for . and .. on oldname and newname. */ if (!strcmp(oldname, ".") || !strcmp(oldname, "..") || !strcmp(newname, ".") || !strcmp(newname, "..")) { status = CACHE_INODE_BADNAME; goto out; } /* Check for object existence in source directory */ status = cache_inode_lookup_impl(dir_src, oldname, &lookup_src); if (lookup_src == NULL) { /* If FSAL FH is stale, then this was managed in * cache_inode_lookup */ if (status != CACHE_INODE_FSAL_ESTALE) status = CACHE_INODE_NOT_FOUND; LogEvent(COMPONENT_CACHE_INODE, "Rename (%p,%s)->(%p,%s) : source doesn't exist", dir_src, oldname, dir_dest, newname); goto out; } /* Do not rename a junction node or an export root. */ if (lookup_src->type == DIRECTORY) { /* Get attr_lock for looking at junction_export */ PTHREAD_RWLOCK_rdlock(&lookup_src->attr_lock); if (lookup_src->object.dir.junction_export != NULL || atomic_fetch_int32_t(&lookup_src->exp_root_refcount) != 0) { /* Trying to rename an export mount point */ LogCrit(COMPONENT_CACHE_INODE, "Attempt to rename export %s", oldname); /* Release attr_lock */ PTHREAD_RWLOCK_unlock(&lookup_src->attr_lock); status = CACHE_INODE_DIR_NOT_EMPTY; goto out; } /* Release attr_lock */ PTHREAD_RWLOCK_unlock(&lookup_src->attr_lock); } /* Check if an object with the new name exists in the destination directory */ status = cache_inode_lookup_impl(dir_dest, newname, &lookup_dst); if (status == CACHE_INODE_SUCCESS) { LogDebug(COMPONENT_CACHE_INODE, "Rename (%p,%s)->(%p,%s) : destination already exists", dir_src, oldname, dir_dest, newname); } if (status == CACHE_INODE_NOT_FOUND) status = CACHE_INODE_SUCCESS; if (status == CACHE_INODE_FSAL_ESTALE) { LogDebug(COMPONENT_CACHE_INODE, "Rename (%p,%s)->(%p,%s) : stale destination", dir_src, oldname, dir_dest, newname); } if (lookup_src == lookup_dst) { /* Nothing to do according to POSIX and NFS3/4 * If from and to both refer to the same file (they might be * hard links of each other), then RENAME should perform no * action and return success */ LogDebug(COMPONENT_CACHE_INODE, "Rename (%p,%s)->(%p,%s) : same file so skipping out", dir_src, oldname, dir_dest, newname); goto out; } /* Perform the rename operation in FSAL before doing anything in the * cache. Indeed, if the FSAL_rename fails unexpectly, the cache would * be inconsistent! * * We do almost no checking before making call because we want to return * error based on the files actually present in the directories, not * what we have in our cache. */ LogFullDebug(COMPONENT_CACHE_INODE, "about to call FSAL rename"); fsal_status = dir_src->obj_handle->ops->rename(dir_src->obj_handle, oldname, dir_dest->obj_handle, newname); LogFullDebug(COMPONENT_CACHE_INODE, "returned from FSAL rename"); status_ref_dir_src = cache_inode_refresh_attrs_locked(dir_src); if (dir_src != dir_dest) status_ref_dir_dst = cache_inode_refresh_attrs_locked(dir_dest); LogFullDebug(COMPONENT_CACHE_INODE, "done refreshing attributes"); if (FSAL_IS_ERROR(fsal_status)) { status = cache_inode_error_convert(fsal_status); LogFullDebug(COMPONENT_CACHE_INODE, "FSAL rename failed with %s", cache_inode_err_str(status)); goto out; } if (lookup_dst) { /* Force a refresh of the overwritten inode */ status_ref_dst = cache_inode_refresh_attrs_locked(lookup_dst); if (status_ref_dst == CACHE_INODE_FSAL_ESTALE) status_ref_dst = CACHE_INODE_SUCCESS; } status = status_ref_dir_src; if (status == CACHE_INODE_SUCCESS) status = status_ref_dir_dst; if (status == CACHE_INODE_SUCCESS) status = status_ref_dst; if (status != CACHE_INODE_SUCCESS) goto out; /* Must take locks on directories now, * because if another thread checks source and destination existence * in the same time, it will try to do the same checks... * and it will have the same conclusion !!! */ src_dest_lock(dir_src, dir_dest); if (lookup_dst) { /* Remove the entry from parent dir_entries avl */ status_ref_dir_dst = cache_inode_remove_cached_dirent(dir_dest, newname); if (status_ref_dir_dst != CACHE_INODE_SUCCESS) { LogDebug(COMPONENT_CACHE_INODE, "remove entry failed with status %s", cache_inode_err_str(status_ref_dir_dst)); cache_inode_invalidate_all_cached_dirent(dir_dest); } } if (dir_src == dir_dest) { /* if the rename operation is made within the same dir, then we * use an optimization: cache_inode_rename_dirent is used * instead of adding/removing dirent. This limits the use of * resource in this case */ LogDebug(COMPONENT_CACHE_INODE, "Rename (%p,%s)->(%p,%s) : source and target " "directory the same", dir_src, oldname, dir_dest, newname); cache_inode_status_t tmp_status = cache_inode_rename_cached_dirent(dir_dest, oldname, newname); if (tmp_status != CACHE_INODE_SUCCESS) { /* We're obviously out of date. Throw out the cached directory */ cache_inode_invalidate_all_cached_dirent(dir_dest); } } else { cache_inode_status_t tmp_status = CACHE_INODE_SUCCESS; LogDebug(COMPONENT_CACHE_INODE, "Rename (%p,%s)->(%p,%s) : moving entry", dir_src, oldname, dir_dest, newname); /* We may have a cache entry for the destination * filename. If we do, we must delete it : it is stale. */ tmp_status = cache_inode_remove_cached_dirent(dir_dest, newname); if (tmp_status != CACHE_INODE_SUCCESS && tmp_status != CACHE_INODE_NOT_FOUND) { LogDebug(COMPONENT_CACHE_INODE, "Remove stale dirent returned %s", cache_inode_err_str(tmp_status)); cache_inode_invalidate_all_cached_dirent(dir_dest); } tmp_status = cache_inode_add_cached_dirent(dir_dest, newname, lookup_src, NULL); if (tmp_status != CACHE_INODE_SUCCESS) { /* We're obviously out of date. Throw out the cached directory */ LogCrit(COMPONENT_CACHE_INODE, "Add dirent returned %s", cache_inode_err_str(tmp_status)); cache_inode_invalidate_all_cached_dirent(dir_dest); } /* Remove the old entry */ tmp_status = cache_inode_remove_cached_dirent(dir_src, oldname); if (tmp_status != CACHE_INODE_SUCCESS && tmp_status != CACHE_INODE_NOT_FOUND) { LogDebug(COMPONENT_CACHE_INODE, "Remove old dirent returned %s", cache_inode_err_str(tmp_status)); cache_inode_invalidate_all_cached_dirent(dir_src); } } /* unlock entries */ src_dest_unlock(dir_src, dir_dest); out: if (lookup_src) cache_inode_put(lookup_src); if (lookup_dst) cache_inode_put(lookup_dst); return status; }
int nfs3_link(nfs_arg_t *arg, nfs_worker_data_t *worker, struct svc_req *req, nfs_res_t *res) { const char *link_name = arg->arg_link3.link.name; cache_entry_t *target_entry = NULL; cache_entry_t *parent_entry = NULL; pre_op_attr pre_parent = { .attributes_follow = false }; cache_inode_status_t cache_status = CACHE_INODE_SUCCESS; short to_exportid = 0; short from_exportid = 0; int rc = NFS_REQ_OK; if (isDebug(COMPONENT_NFSPROTO)) { char strto[LEN_FH_STR], strfrom[LEN_FH_STR]; nfs_FhandleToStr(req->rq_vers, &(arg->arg_link3.file), NULL, strfrom); nfs_FhandleToStr(req->rq_vers, &(arg->arg_link3.link.dir), NULL, strto); LogDebug(COMPONENT_NFSPROTO, "REQUEST PROCESSING: Calling nfs3_link handle: %s to " "handle: %s name: %s", strfrom, strto, link_name); } /* to avoid setting it on each error case */ res->res_link3.LINK3res_u.resfail.file_attributes.attributes_follow = FALSE; res->res_link3.LINK3res_u.resfail.linkdir_wcc.before.attributes_follow = FALSE; res->res_link3.LINK3res_u.resfail.linkdir_wcc.after.attributes_follow = FALSE; /* Get the exportids for the two handles. */ to_exportid = nfs3_FhandleToExportId(&(arg->arg_link3.link.dir)); from_exportid = nfs3_FhandleToExportId(&(arg->arg_link3.file)); /* Validate the to_exportid */ if (to_exportid < 0 || from_exportid < 0) { LogInfo(COMPONENT_DISPATCH, "NFS%d LINK Request from client %s has badly formed handle for link dir", req->rq_vers, op_ctx->client ? op_ctx->client->hostaddr_str : "unknown client"); /* Bad handle, report to client */ res->res_link3.status = NFS3ERR_BADHANDLE; goto out; } /* Both objects have to be in the same filesystem */ if (to_exportid != from_exportid) { res->res_link3.status = NFS3ERR_XDEV; goto out; } /* Get entry for parent directory */ parent_entry = nfs3_FhandleToCache(&arg->arg_link3.link.dir, &res->res_link3.status, &rc); if (parent_entry == NULL) { /* Status and rc have been set by nfs3_FhandleToCache */ goto out; } nfs_SetPreOpAttr(parent_entry, &pre_parent); target_entry = nfs3_FhandleToCache(&arg->arg_link3.file, &res->res_link3.status, &rc); if (target_entry == NULL) { /* Status and rc have been set by nfs3_FhandleToCache */ goto out; } /* Sanity checks: */ if (parent_entry->type != DIRECTORY) { res->res_link3.status = NFS3ERR_NOTDIR; rc = NFS_REQ_OK; goto out; } if (link_name == NULL || *link_name == '\0') res->res_link3.status = NFS3ERR_INVAL; else { /* Both objects have to be in the same filesystem */ if (to_exportid != from_exportid) res->res_link3.status = NFS3ERR_XDEV; else { cache_status = cache_inode_link(target_entry, parent_entry, link_name); if (cache_status == CACHE_INODE_SUCCESS) { nfs_SetPostOpAttr(target_entry, &(res->res_link3.LINK3res_u. resok.file_attributes)); nfs_SetWccData(&pre_parent, parent_entry, &(res->res_link3.LINK3res_u. resok.linkdir_wcc)); res->res_link3.status = NFS3_OK; rc = NFS_REQ_OK; goto out; } } /* else */ } /* If we are here, there was an error */ if (nfs_RetryableError(cache_status)) { rc = NFS_REQ_DROP; goto out; } res->res_link3.status = nfs3_Errno(cache_status); nfs_SetPostOpAttr(target_entry, &(res->res_link3.LINK3res_u.resfail.file_attributes)); nfs_SetWccData(&pre_parent, parent_entry, &res->res_link3.LINK3res_u.resfail.linkdir_wcc); rc = NFS_REQ_OK; out: /* return references */ if (target_entry) cache_inode_put(target_entry); if (parent_entry) cache_inode_put(parent_entry); return rc; } /* nfs3_link */ /** * @brief Free the result structure allocated for nfs3_link * * This function frees the result structure allocated for nfs3_link. * * @param[in,out] resp Result structure * */ void nfs3_link_free(nfs_res_t *resp) { return; }