/* Covert GPFS NFS4 ACLs to FSAL ACLs, and set the ACL * pointer of attribute. */ static int gpfs_acl_2_fsal_acl(struct attrlist *p_object_attributes, gpfs_acl_t *p_gpfsacl) { fsal_acl_status_t status; fsal_acl_data_t acldata; fsal_ace_t *pace; fsal_acl_t *pacl; gpfs_ace_v4_t *pace_gpfs; /* sanity checks */ if (!p_object_attributes || !p_gpfsacl) return ERR_FSAL_FAULT; /* Create fsal acl data. */ acldata.naces = p_gpfsacl->acl_nace; acldata.aces = (fsal_ace_t *) nfs4_ace_alloc(acldata.naces); /* Fill fsal acl data from gpfs acl. */ for (pace = acldata.aces, pace_gpfs = p_gpfsacl->ace_v4; pace < acldata.aces + acldata.naces; pace++, pace_gpfs++) { pace->type = pace_gpfs->aceType; pace->flag = pace_gpfs->aceFlags; pace->iflag = pace_gpfs->aceIFlags; pace->perm = pace_gpfs->aceMask; if (IS_FSAL_ACE_SPECIAL_ID(*pace)) { /* Record special user. */ pace->who.uid = pace_gpfs->aceWho; } else { if (IS_FSAL_ACE_GROUP_ID(*pace)) pace->who.gid = pace_gpfs->aceWho; else /* Record user. */ pace->who.uid = pace_gpfs->aceWho; } LogMidDebug(COMPONENT_FSAL, "gpfs_acl_2_fsal_acl: fsal ace: type = 0x%x, flag = 0x%x, perm = 0x%x, special = %d, %s = 0x%x", pace->type, pace->flag, pace->perm, IS_FSAL_ACE_SPECIAL_ID(*pace), GET_FSAL_ACE_WHO_TYPE(*pace), GET_FSAL_ACE_WHO(*pace)); } /* Create a new hash table entry for fsal acl. */ pacl = nfs4_acl_new_entry(&acldata, &status); LogMidDebug(COMPONENT_FSAL, "fsal acl = %p, fsal_acl_status = %u", pacl, status); if (pacl == NULL) { LogCrit(COMPONENT_FSAL, "gpfs_acl_2_fsal_acl: failed to create a new acl entry"); return ERR_FSAL_FAULT; } /* Add fsal acl to attribute. */ p_object_attributes->acl = pacl; return ERR_FSAL_NO_ERROR; }
bool vfs_valid_handle(struct gsh_buffdesc *desc) { xfs_handle_t *hdl = (xfs_handle_t *) desc->addr; bool fsid_type_ok = false; if ((desc->addr == NULL) || (desc->len != sizeof(xfs_handle_t))) return false; if (isMidDebug(COMPONENT_FSAL)) { char buf[256]; struct display_buffer dspbuf = {sizeof(buf), buf, buf}; display_printf(&dspbuf, "Handle len %d: " " fsid=0x%016"PRIx32".0x%016"PRIx32 " fid_len=%"PRIu16 " fid_pad=%"PRIu16 " fid_gen=%"PRIu32 " fid_ino=%"PRIu64, (int) desc->len, hdl->ha_fsid.val[0], hdl->ha_fsid.val[1], hdl->ha_fid.fid_len, hdl->ha_fid.fid_pad, hdl->ha_fid.fid_gen, hdl->ha_fid.fid_ino); LogMidDebug(COMPONENT_FSAL, "%s", buf); } if (hdl->ha_fid.fid_pad != 0) { switch ((enum fsid_type) (hdl->ha_fid.fid_pad - 1)) { case FSID_NO_TYPE: case FSID_ONE_UINT64: case FSID_MAJOR_64: case FSID_TWO_UINT64: case FSID_TWO_UINT32: case FSID_DEVICE: fsid_type_ok = true; break; } if (!fsid_type_ok) { LogDebug(COMPONENT_FSAL, "FSID Type %02"PRIu16" invalid", hdl->ha_fid.fid_pad - 1); return false; } if (hdl->ha_fid.fid_gen != 0) return false; } return hdl->ha_fid.fid_len == (sizeof(xfs_handle_t) - sizeof(xfs_fsid_t) - sizeof(hdl->ha_fid.fid_len)); }
/** * @brief Decide if a delegation should be granted based on heuristics. * * Decide if a delegation should be granted based on heuristics. * Note: Whether the export supports delegations should be checked before * calling this function. * The open_state->state_type will decide whether we attempt to get a READ or * WRITE delegation. * * @param[in] entry Inode entry the delegation will be on. * @param[in] client Client that would own the delegation. * @param[in] open_state The open state for the inode to be delegated. */ bool should_we_grant_deleg(cache_entry_t *entry, nfs_client_id_t *client, state_t *open_state) { /* specific file, all clients, stats */ struct file_deleg_heuristics *file_stats = &entry->object.file.deleg_heuristics; /* specific client, all files stats */ struct client_deleg_heuristics *cl_stats = &client->deleg_heuristics; /* specific client, specific file stats */ float ACCEPTABLE_FAILS = 0.1; /* 10% */ float ACCEPTABLE_OPEN_FREQUENCY = .01; /* per second */ time_t spread; LogDebug(COMPONENT_STATE, "Checking if we should grant delegation."); if (open_state->state_type != STATE_TYPE_SHARE) { LogDebug(COMPONENT_STATE, "expects a SHARE open state and no other."); return false; } /* Check if this file is opened too frequently to delegate. */ spread = time(NULL) - file_stats->first_open; if (spread != 0 && (file_stats->num_opens / spread) > ACCEPTABLE_OPEN_FREQUENCY) { LogDebug(COMPONENT_STATE, "This file is opened too frequently to delegate."); return false; } /* Check if open state and requested delegation agree. */ if (file_stats->curr_delegations > 0) { if (file_stats->deleg_type == OPEN_DELEGATE_READ && open_state->state_data.share.share_access & OPEN4_SHARE_ACCESS_WRITE) { LogMidDebug(COMPONENT_STATE, "READ delegate requested, but file is opened for WRITE."); return false; } if (file_stats->deleg_type == OPEN_DELEGATE_WRITE && !(open_state->state_data.share.share_access & OPEN4_SHARE_ACCESS_WRITE)) { LogMidDebug(COMPONENT_STATE, "WRITE delegate requested, but file is not opened for WRITE."); } } /* Check if this is a misbehaving or unreliable client */ if (cl_stats->tot_recalls > 0 && ((1.0 - (cl_stats->failed_recalls / cl_stats->tot_recalls)) > ACCEPTABLE_FAILS)) { LogDebug(COMPONENT_STATE, "Client is %.0f unreliable during recalls. Allowed failure rate is %.0f. Denying delegation.", 1.0 - (cl_stats->failed_recalls / cl_stats->tot_recalls), ACCEPTABLE_FAILS); return false; } /* minimum average milliseconds that delegations should be held on a file. if less, then this is not a good file for delegations. */ #define MIN_AVG_HOLD 1500 if (file_stats->avg_hold < MIN_AVG_HOLD && file_stats->avg_hold != 0) { LogDebug(COMPONENT_STATE, "Average length of delegation (%lld) is less than minimum avg (%lld). Denying delegation.", (long long) file_stats->avg_hold, (long long) MIN_AVG_HOLD); return false; } LogDebug(COMPONENT_STATE, "Let's delegate!!"); return true; }
cache_inode_status_t cache_inode_rdwr(cache_entry_t * pentry, cache_inode_io_direction_t read_or_write, fsal_seek_t * seek_descriptor, fsal_size_t buffer_size, fsal_size_t * pio_size, fsal_attrib_list_t * pfsal_attr, caddr_t buffer, fsal_boolean_t * p_fsal_eof, hash_table_t * ht, cache_inode_client_t * pclient, fsal_op_context_t * pcontext, uint64_t stable, cache_inode_status_t * pstatus) { int statindex = 0; cache_content_io_direction_t io_direction; cache_content_status_t cache_content_status; fsal_status_t fsal_status; fsal_openflags_t openflags; fsal_size_t io_size; fsal_attrib_list_t post_write_attr; fsal_status_t fsal_status_getattr; struct stat buffstat; /* Set the return default to CACHE_INODE_SUCCESS */ *pstatus = CACHE_INODE_SUCCESS; /* For now, only FSAL_SEEK_SET is supported */ if(seek_descriptor->whence != FSAL_SEEK_SET) { LogCrit(COMPONENT_CACHE_INODE, "Implementation trouble: seek_descriptor was not a 'FSAL_SEEK_SET' cursor"); *pstatus = CACHE_INODE_INVALID_ARGUMENT; return *pstatus; } io_size = buffer_size; LogDebug(COMPONENT_CACHE_INODE, "cache_inode_rdwr: INODE : IO Size = %llu fdsize =%zu seeksize=%zu", buffer_size, sizeof(fsal_file_t), sizeof(fsal_seek_t)); /* stat */ pclient->stat.nb_call_total += 1; if(read_or_write == CACHE_INODE_READ) { statindex = CACHE_INODE_READ_DATA; io_direction = CACHE_CONTENT_READ; openflags = FSAL_O_RDONLY; pclient->stat.func_stats.nb_call[CACHE_INODE_READ_DATA] += 1; } else { statindex = CACHE_INODE_WRITE_DATA; io_direction = CACHE_CONTENT_WRITE; openflags = FSAL_O_WRONLY; pclient->stat.func_stats.nb_call[CACHE_INODE_WRITE_DATA] += 1; } P_w(&pentry->lock); /* IO are done only on REGULAR_FILEs */ if(pentry->internal_md.type != REGULAR_FILE) { *pstatus = CACHE_INODE_BAD_TYPE; V_w(&pentry->lock); /* stats */ pclient->stat.func_stats.nb_err_unrecover[statindex] += 1; return *pstatus; } /* Non absolute address within the file are not supported (we act only like pread/pwrite) */ if(seek_descriptor->whence != FSAL_SEEK_SET) { *pstatus = CACHE_INODE_INVALID_ARGUMENT; V_w(&pentry->lock); /* stats */ pclient->stat.func_stats.nb_err_unrecover[statindex] += 1; return *pstatus; } /* Do we use stable or unstable storage ? */ if(stable == FSAL_UNSAFE_WRITE_TO_GANESHA_BUFFER) { /* Data will be stored in memory and not flush to FSAL */ /* If the unstable_data buffer allocated ? */ if(pentry->object.file.unstable_data.buffer == NULL) { if((pentry->object.file.unstable_data.buffer = Mem_Alloc_Label(CACHE_INODE_UNSTABLE_BUFFERSIZE, "Cache_Inode Unstable Buffer")) == NULL) { *pstatus = CACHE_INODE_MALLOC_ERROR; V_w(&pentry->lock); /* stats */ pclient->stat.func_stats.nb_err_unrecover[statindex] += 1; return *pstatus; } pentry->object.file.unstable_data.offset = seek_descriptor->offset; pentry->object.file.unstable_data.length = buffer_size; memcpy(pentry->object.file.unstable_data.buffer, buffer, buffer_size); /* Set mtime and ctime */ cache_inode_set_time_current( &pentry->attributes.mtime ) ; /* BUGAZOMEU : write operation must NOT modify file's ctime */ pentry->attributes.ctime = pentry->attributes.mtime; *pio_size = buffer_size; } /* if( pentry->object.file.unstable_data.buffer == NULL ) */ else { if((pentry->object.file.unstable_data.offset < seek_descriptor->offset) && (buffer_size + seek_descriptor->offset < CACHE_INODE_UNSTABLE_BUFFERSIZE)) { pentry->object.file.unstable_data.length = buffer_size + seek_descriptor->offset; memcpy((char *)(pentry->object.file.unstable_data.buffer + seek_descriptor->offset), buffer, buffer_size); /* Set mtime and ctime */ cache_inode_set_time_current( &pentry->attributes.mtime ) ; /* BUGAZOMEU : write operation must NOT modify file's ctime */ pentry->attributes.ctime = pentry->attributes.mtime; *pio_size = buffer_size; } else { /* Go back to regular situation */ stable = FSAL_SAFE_WRITE_TO_FS; } } } /* if( stable == FALSE ) */ if(stable == FSAL_SAFE_WRITE_TO_FS || stable == FSAL_UNSAFE_WRITE_TO_FS_BUFFER) { /* Calls file content cache to operate on the cache */ if(pentry->object.file.pentry_content != NULL) { /* Entry is data cached */ cache_content_rdwr(pentry->object.file.pentry_content, io_direction, seek_descriptor, &io_size, pio_size, buffer, p_fsal_eof, &buffstat, (cache_content_client_t *) pclient->pcontent_client, pcontext, &cache_content_status); /* If the entry under resync */ if(cache_content_status == CACHE_CONTENT_LOCAL_CACHE_NOT_FOUND) { /* Data cache gc has removed this entry */ if(cache_content_new_entry(pentry, NULL, (cache_content_client_t *)pclient->pcontent_client, RENEW_ENTRY, pcontext, &cache_content_status) == NULL) { /* Entry could not be recoverd, cache_content_status contains an error, let it be managed by the next block */ LogCrit(COMPONENT_CACHE_INODE, "Read/Write Operation through cache failed with status %d (renew process failed)", cache_content_status); /* Will go to the end of the function on the error clause with cache_content_status describing the error */ } else { /* Entry was successfully renewed */ LogInfo(COMPONENT_CACHE_INODE, "----> File Content Entry %p was successfully renewed", pentry); /* Try to access the content of the file again */ cache_content_rdwr(pentry->object.file.pentry_content, io_direction, seek_descriptor, &io_size, pio_size, buffer, p_fsal_eof, &buffstat, (cache_content_client_t *) pclient->pcontent_client, pcontext, &cache_content_status); /* No management of cache_content_status in case of failure, this will be done * within the next block */ } } if(cache_content_status != CACHE_CONTENT_SUCCESS) { *pstatus = cache_content_error_convert(cache_content_status); V_w(&pentry->lock); LogCrit(COMPONENT_CACHE_INODE, "Read/Write Operation through cache failed with status %d", cache_content_status); /* stats */ pclient->stat.func_stats.nb_err_unrecover[statindex] += 1; return *pstatus; } LogFullDebug(COMPONENT_CACHE_INODE, "cache_inode_rdwr: inode/dc: io_size=%llu, pio_size=%llu, eof=%d, seek=%d.%"PRIu64, io_size, *pio_size, *p_fsal_eof, seek_descriptor->whence, seek_descriptor->offset); LogMidDebug(COMPONENT_CACHE_INODE, "cache_inode_rdwr: INODE AFTER : IO Size = %llu %llu", io_size, *pio_size); /* Use information from the buffstat to update the file metadata */ pentry->attributes.filesize = buffstat.st_size; pentry->attributes.spaceused = buffstat.st_blksize * buffstat.st_blocks; } else { /* No data cache entry, we operated directly on FSAL */ pentry->attributes.asked_attributes = pclient->attrmask; /* We need to open if we don't have a cached * descriptor or our open flags differs. */ if(cache_inode_open(pentry, pclient, openflags, pcontext, pstatus) != CACHE_INODE_SUCCESS) { V_w(&pentry->lock); /* stats */ pclient->stat.func_stats.nb_err_unrecover[statindex] += 1; return *pstatus; } /* Call FSAL_read or FSAL_write */ if(read_or_write == CACHE_INODE_READ) { #ifdef _USE_MFSL fsal_status = MFSL_read(&(pentry->object.file.open_fd.mfsl_fd), seek_descriptor, io_size, buffer, pio_size, p_fsal_eof, &pclient->mfsl_context, NULL); #else fsal_status = FSAL_read(&(pentry->object.file.open_fd.fd), seek_descriptor, io_size, buffer, pio_size, p_fsal_eof); #endif } else { #ifdef _USE_MFSL fsal_status = MFSL_write(&(pentry->object.file.open_fd.mfsl_fd), seek_descriptor, io_size, buffer, pio_size, &pclient->mfsl_context, NULL); #else fsal_status = FSAL_write(&(pentry->object.file.open_fd.fd), seek_descriptor, io_size, buffer, pio_size); #endif #if 0 /* Alright, the unstable write is complete. Now if it was supposed to be a stable write * we can sync to the hard drive. */ if(stable == FSAL_SAFE_WRITE_TO_FS) { #ifdef _USE_MFSL fsal_status = MFSL_commit(&(pentry->object.file.open_fd.mfsl_fd), NULL); #else fsal_status = FSAL_commit(&(pentry->object.file.open_fd.fd)); #endif #endif } LogFullDebug(COMPONENT_FSAL, "cache_inode_rdwr: FSAL IO operation returned %d, asked_size=%llu, effective_size=%llu", fsal_status.major, (unsigned long long)io_size, (unsigned long long)*pio_size); if(FSAL_IS_ERROR(fsal_status)) { if(fsal_status.major == ERR_FSAL_DELAY) LogEvent(COMPONENT_CACHE_INODE, "cache_inode_rdwr: FSAL_write returned EBUSY"); else LogDebug(COMPONENT_CACHE_INODE, "cache_inode_rdwr: fsal_status.major = %d", fsal_status.major); if((fsal_status.major != ERR_FSAL_NOT_OPENED) && (pentry->object.file.open_fd.fileno != 0)) { LogDebug(COMPONENT_CACHE_INODE, "cache_inode_rdwr: CLOSING pentry %p: fd=%d", pentry, pentry->object.file.open_fd.fileno); #ifdef _USE_MFSL MFSL_close(&(pentry->object.file.open_fd.mfsl_fd), &pclient->mfsl_context, NULL); #else FSAL_close(&(pentry->object.file.open_fd.fd)); #endif *pstatus = cache_inode_error_convert(fsal_status); } else { /* the fd has been close by another thread. * return CACHE_INODE_FSAL_DELAY so the client will * retry with a new fd. */ *pstatus = CACHE_INODE_FSAL_DELAY; } pentry->object.file.open_fd.last_op = 0; pentry->object.file.open_fd.fileno = 0; V_w(&pentry->lock); /* stats */ pclient->stat.func_stats.nb_err_unrecover[statindex] += 1; return *pstatus; } LogFullDebug(COMPONENT_CACHE_INODE, "cache_inode_rdwr: inode/direct: io_size=%llu, pio_size=%llu, eof=%d, seek=%d.%"PRIu64, io_size, *pio_size, *p_fsal_eof, seek_descriptor->whence, seek_descriptor->offset); if(cache_inode_close(pentry, pclient, pstatus) != CACHE_INODE_SUCCESS) { LogEvent(COMPONENT_CACHE_INODE, "cache_inode_rdwr: cache_inode_close = %d", *pstatus); V_w(&pentry->lock); /* stats */ pclient->stat.func_stats.nb_err_unrecover[statindex] += 1; return *pstatus; } if(read_or_write == CACHE_INODE_WRITE) { /* Do a getattr in order to have update information on filesize * This query is done directly on FSAL (object is not data cached), and result * will be propagated to cache Inode */ /* WARNING: This operation is to be done AFTER FSAL_close (some FSAL, like POSIX, * may not flush data until the file is closed */ /*post_write_attr.asked_attributes = pclient->attrmask ; */ post_write_attr.asked_attributes = FSAL_ATTR_SIZE | FSAL_ATTR_SPACEUSED; fsal_status_getattr = FSAL_getattrs(&(pentry->handle), pcontext, &post_write_attr); /* if failed, the next block will handle the error */ if(FSAL_IS_ERROR(fsal_status_getattr)) fsal_status = fsal_status_getattr; else { /* Update Cache Inode attributes */ pentry->attributes.filesize = post_write_attr.filesize; pentry->attributes.spaceused = post_write_attr.spaceused; } } } /* IO was successfull (through cache content or not), we manually update the times in the attributes */ switch (read_or_write) { case CACHE_INODE_READ: /* Set the atime */ cache_inode_set_time_current( & pentry->attributes.atime ) ; break; case CACHE_INODE_WRITE: /* Set mtime and ctime */ cache_inode_set_time_current( & pentry->attributes.mtime ) ; /* BUGAZOMEU : write operation must NOT modify file's ctime */ pentry->attributes.ctime = pentry->attributes.mtime; break; } } /* if(stable == TRUE ) */ /* Return attributes to caller */ if(pfsal_attr != NULL) *pfsal_attr = pentry->attributes; *pstatus = CACHE_INODE_SUCCESS; /* stat */ if(read_or_write == CACHE_INODE_READ) { *pstatus = cache_inode_valid(pentry, CACHE_INODE_OP_GET, pclient); if(*pstatus != CACHE_INODE_SUCCESS) pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_READ] += 1; else pclient->stat.func_stats.nb_success[CACHE_INODE_READ] += 1; } else { *pstatus = cache_inode_valid(pentry, CACHE_INODE_OP_SET, pclient); if(*pstatus != CACHE_INODE_SUCCESS) pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_WRITE] += 1; else pclient->stat.func_stats.nb_success[CACHE_INODE_WRITE] += 1; } V_w(&pentry->lock); return *pstatus; } /* cache_inode_rdwr */
/* Covert FSAL ACLs to GPFS NFS4 ACLs. */ fsal_status_t fsal_acl_2_gpfs_acl(struct fsal_obj_handle *dir_hdl, fsal_acl_t *p_fsalacl, gpfsfsal_xstat_t *p_buffxstat) { int i; fsal_ace_t *pace; gpfs_acl_t *p_gpfsacl; p_gpfsacl = (gpfs_acl_t *) p_buffxstat->buffacl; p_gpfsacl->acl_level = 0; p_gpfsacl->acl_version = GPFS_ACL_VERSION_NFS4; p_gpfsacl->acl_type = GPFS_ACL_TYPE_NFS4; p_gpfsacl->acl_nace = p_fsalacl->naces; p_gpfsacl->acl_len = ((int)(signed long)&(((gpfs_acl_t *) 0)->ace_v1)) + p_gpfsacl->acl_nace * sizeof(gpfs_ace_v4_t); for (pace = p_fsalacl->aces, i = 0; pace < p_fsalacl->aces + p_fsalacl->naces; pace++, i++) { p_gpfsacl->ace_v4[i].aceType = pace->type; p_gpfsacl->ace_v4[i].aceFlags = pace->flag; p_gpfsacl->ace_v4[i].aceIFlags = pace->iflag; p_gpfsacl->ace_v4[i].aceMask = pace->perm; if (IS_FSAL_ACE_SPECIAL_ID(*pace)) p_gpfsacl->ace_v4[i].aceWho = pace->who.uid; else { if (IS_FSAL_ACE_GROUP_ID(*pace)) p_gpfsacl->ace_v4[i].aceWho = pace->who.gid; else p_gpfsacl->ace_v4[i].aceWho = pace->who.uid; } LogMidDebug(COMPONENT_FSAL, "fsal_acl_2_gpfs_acl: gpfs ace: type = 0x%x, flag = 0x%x, perm = 0x%x, special = %d, %s = 0x%x", p_gpfsacl->ace_v4[i].aceType, p_gpfsacl->ace_v4[i].aceFlags, p_gpfsacl->ace_v4[i].aceMask, (p_gpfsacl->ace_v4[i]. aceIFlags & FSAL_ACE_IFLAG_SPECIAL_ID) ? 1 : 0, (p_gpfsacl->ace_v4[i]. aceFlags & FSAL_ACE_FLAG_GROUP_ID) ? "gid" : "uid", p_gpfsacl->ace_v4[i].aceWho); /* It is invalid to set inherit flags on non dir objects */ if (dir_hdl->type != DIRECTORY && (p_gpfsacl->ace_v4[i].aceFlags & FSAL_ACE_FLAG_INHERIT) != 0) { LogMidDebug(COMPONENT_FSAL, "attempt to set inherit flag to non dir object"); return fsalstat(ERR_FSAL_INVAL, 0); } /* It is invalid to set inherit only with * out an actual inherit flag */ if ((p_gpfsacl->ace_v4[i].aceFlags & FSAL_ACE_FLAG_INHERIT) == FSAL_ACE_FLAG_INHERIT_ONLY) { LogMidDebug(COMPONENT_FSAL, "attempt to set inherit only without an inherit flag"); return fsalstat(ERR_FSAL_INVAL, 0); } } return fsalstat(ERR_FSAL_NO_ERROR, 0); }
/** * @brief Get numeric credentials from request * * @todo This MUST be refactored to not use TI-RPC private structures. * Instead, export appropriate functions from lib(n)tirpc. * * fills out creds in op_ctx * * @param[in] req Incoming request. * * @return NFS4_OK if successful, NFS4ERR_ACCESS otherwise. * */ nfsstat4 nfs_req_creds(struct svc_req *req) { unsigned int i; const char *auth_label = "UNKNOWN"; gid_t **garray_copy = &op_ctx->caller_garray_copy; #ifdef _HAVE_GSSAPI struct svc_rpc_gss_data *gd = NULL; char principal[MAXNAMLEN + 1]; #endif /* Make sure we clear out all the cred_flags except CREDS_LOADED and * CREDS_ANON. */ op_ctx->cred_flags &= CREDS_LOADED | CREDS_ANON; switch (req->rq_cred.oa_flavor) { case AUTH_NONE: /* Nothing to be done here... */ op_ctx->cred_flags |= CREDS_LOADED | CREDS_ANON; auth_label = "AUTH_NONE"; break; case AUTH_SYS: if ((op_ctx->cred_flags & CREDS_LOADED) == 0) { struct authunix_parms *creds = NULL; /* We map the rq_cred to Authunix_parms */ creds = (struct authunix_parms *) req->rq_clntcred; op_ctx->original_creds.caller_uid = creds->aup_uid; op_ctx->original_creds.caller_gid = creds->aup_gid; op_ctx->original_creds.caller_glen = creds->aup_len; op_ctx->original_creds.caller_garray = creds->aup_gids; op_ctx->cred_flags |= CREDS_LOADED; } /* Copy original_creds creds */ *op_ctx->creds = op_ctx->original_creds; /* Do we trust AUTH_SYS creds for groups or not ? */ if ((op_ctx->export_perms->options & EXPORT_OPTION_MANAGE_GIDS) != 0) { op_ctx->cred_flags |= MANAGED_GIDS; garray_copy = &op_ctx->managed_garray_copy; } auth_label = "AUTH_SYS"; break; #ifdef _HAVE_GSSAPI case RPCSEC_GSS: if ((op_ctx->cred_flags & CREDS_LOADED) == 0) { /* Get the gss data to process them */ gd = SVCAUTH_PRIVATE(req->rq_auth); memcpy(principal, gd->cname.value, gd->cname.length); principal[gd->cname.length] = 0; LogMidDebug(COMPONENT_DISPATCH, "Mapping RPCSEC_GSS principal %s to uid/gid", principal); /* Convert to uid */ #if _MSPAC_SUPPORT if (!principal2uid(principal, &op_ctx->original_creds.caller_uid, &op_ctx->original_creds.caller_gid, gd)) { #else if (!principal2uid(principal, &op_ctx->original_creds.caller_uid, &op_ctx->original_creds.caller_gid) ) { #endif LogWarn(COMPONENT_IDMAPPER, "Could not map principal %s to uid", principal); /* For compatibility with Linux knfsd, we set * the uid/gid to anonymous when a name->uid * mapping can't be found. */ op_ctx->cred_flags |= CREDS_ANON | CREDS_LOADED; auth_label = "RPCSEC_GSS (no mapping)"; break; } op_ctx->cred_flags |= CREDS_LOADED; } auth_label = "RPCSEC_GSS"; op_ctx->cred_flags |= MANAGED_GIDS; garray_copy = &op_ctx->managed_garray_copy; break; #endif /* _USE_GSSRPC */ default: LogMidDebug(COMPONENT_DISPATCH, "FAILURE: Request xid=%u, has unsupported authentication %d", req->rq_xid, req->rq_cred.oa_flavor); /* Reject the request for weak authentication and * return to worker */ return NFS4ERR_ACCESS; break; } /****************************************************************/ /* Now check for anon creds or id squashing */ /****************************************************************/ if ((op_ctx->cred_flags & CREDS_ANON) != 0 || ((op_ctx->export_perms->options & EXPORT_OPTION_ALL_ANONYMOUS) != 0) || ((op_ctx->export_perms->options & EXPORT_OPTION_ROOT) == 0 && op_ctx->original_creds.caller_uid == 0)) { op_ctx->creds->caller_uid = op_ctx->export_perms->anonymous_uid; op_ctx->creds->caller_gid = op_ctx->export_perms->anonymous_gid; op_ctx->creds->caller_glen = 0; LogMidDebugAlt(COMPONENT_DISPATCH, COMPONENT_EXPORT, "%s creds squashed to uid=%u, gid=%u", auth_label, op_ctx->creds->caller_uid, op_ctx->creds->caller_gid); op_ctx->cred_flags |= UID_SQUASHED | GID_SQUASHED; return NFS4_OK; } /* Now we will use the original_creds uid from original credential */ op_ctx->creds->caller_uid = op_ctx->original_creds.caller_uid; /****************************************************************/ /* Now sqush group or use original_creds gid */ /****************************************************************/ if ((op_ctx->export_perms->options & EXPORT_OPTION_ROOT) == 0 && op_ctx->original_creds.caller_gid == 0) { /* Squash gid */ op_ctx->creds->caller_gid = op_ctx->export_perms->anonymous_gid; op_ctx->cred_flags |= GID_SQUASHED; } else { /* Use original_creds gid */ op_ctx->creds->caller_gid = op_ctx->original_creds.caller_gid; } /****************************************************************/ /* Check if we have manage_gids. */ /****************************************************************/ if ((op_ctx->cred_flags & MANAGED_GIDS) != 0) { /* Fetch the group data if required */ if (op_ctx->caller_gdata == NULL && !uid2grp(op_ctx->original_creds.caller_uid, &op_ctx->caller_gdata)) { /** @todo: do we really want to bail here? */ LogCrit(COMPONENT_DISPATCH, "Attempt to fetch managed_gids failed"); return NFS4ERR_ACCESS; } op_ctx->creds->caller_glen = op_ctx->caller_gdata->nbgroups; op_ctx->creds->caller_garray = op_ctx->caller_gdata->groups; } else { /* Use the original_creds group list */ op_ctx->creds->caller_glen = op_ctx->original_creds.caller_glen; op_ctx->creds->caller_garray = op_ctx->original_creds.caller_garray; } /****************************************************************/ /* Check the garray for gid 0 to squash */ /****************************************************************/ /* If no root squashing in caller_garray, return now */ if ((op_ctx->export_perms->options & EXPORT_OPTION_ROOT) != 0 || op_ctx->creds->caller_glen == 0) goto out; for (i = 0; i < op_ctx->creds->caller_glen; i++) { if (op_ctx->creds->caller_garray[i] == 0) { /* Meed to make a copy, or use the old copy */ if ((*garray_copy) == NULL) { /* Make a copy of the active garray */ (*garray_copy) = gsh_malloc(op_ctx->creds->caller_glen * sizeof(gid_t)); memcpy((*garray_copy), op_ctx->creds->caller_garray, op_ctx->creds->caller_glen * sizeof(gid_t)); } /* Now squash the root id. Since the original copy is * always the same, any root ids in it were still in * the same place, so even if using a copy that had a * different anonymous_gid, we're fine. */ (*garray_copy)[i] = op_ctx->export_perms->anonymous_gid; /* Indicate we squashed the caller_garray */ op_ctx->cred_flags |= GARRAY_SQUASHED; } } /* If we squashed the caller_garray, use the squashed copy */ if ((op_ctx->cred_flags & GARRAY_SQUASHED) != 0) op_ctx->creds->caller_garray = *garray_copy; out: LogMidDebugAlt(COMPONENT_DISPATCH, COMPONENT_EXPORT, "%s creds mapped to uid=%u, gid=%u%s, glen=%d%s", auth_label, op_ctx->creds->caller_uid, op_ctx->creds->caller_gid, (op_ctx->cred_flags & GID_SQUASHED) != 0 ? " (squashed)" : "", op_ctx->creds->caller_glen, (op_ctx->cred_flags & MANAGED_GIDS) != 0 ? ((op_ctx->cred_flags & GARRAY_SQUASHED) != 0 ? " (managed and squashed)" : " (managed)") : ((op_ctx->cred_flags & GARRAY_SQUASHED) != 0 ? " (squashed)" : "")); return NFS4_OK; } /** * @brief Initialize request context and credentials. * */ void init_credentials(void) { memset(op_ctx->creds, 0, sizeof(*op_ctx->creds)); memset(&op_ctx->original_creds, 0, sizeof(op_ctx->original_creds)); op_ctx->creds->caller_uid = op_ctx->export_perms->anonymous_uid; op_ctx->creds->caller_gid = op_ctx->export_perms->anonymous_gid; op_ctx->caller_gdata = NULL; op_ctx->caller_garray_copy = NULL; op_ctx->managed_garray_copy = NULL; op_ctx->cred_flags = 0; }
/** * * cache_inode_lookup_sw: looks up for a name in a directory indicated by a * cached entry. * * Looks up for a name in a directory indicated by a cached entry. The directory * should have been cached before. * * @param pentry_parent [IN] entry for the parent directory to be managed. * @param name [IN] name of the entry that we are looking for in the * cache. * @param pattr [OUT] attributes for the entry that we have found. * @param ht [IN] hash table used for the cache, unused in this * call. * @param pclient [INOUT] ressource allocated by the client for the nfs * management. * @param pcontext [IN] FSAL credentials * @param pstatus [OUT] returned status. * @param use_mutex [IN] if TRUE, mutex management is done, not if equal * to FALSE. * * @return CACHE_INODE_SUCCESS if operation is a success \n * @return CACHE_INODE_LRU_ERROR if allocation error occured when validating the * entry * */ cache_entry_t *cache_inode_lookup_sw(cache_entry_t * pentry_parent, fsal_name_t * pname, cache_inode_policy_t policy, fsal_attrib_list_t * pattr, hash_table_t * ht, cache_inode_client_t * pclient, fsal_op_context_t * pcontext, cache_inode_status_t * pstatus, int use_mutex) { cache_inode_dir_entry_t dirent_key[1], *dirent; struct avltree_node *dirent_node; cache_inode_dir_entry_t *new_dir_entry; cache_entry_t *pentry = NULL; fsal_status_t fsal_status; #ifdef _USE_MFSL mfsl_object_t object_handle; #else fsal_handle_t object_handle; #endif fsal_handle_t dir_handle; fsal_attrib_list_t object_attributes; cache_inode_create_arg_t create_arg; cache_inode_file_type_t type; cache_inode_status_t cache_status; cache_inode_fsal_data_t new_entry_fsdata; fsal_accessflags_t access_mask = 0; memset(&create_arg, 0, sizeof(create_arg)); memset( (char *)&new_entry_fsdata, 0, sizeof( new_entry_fsdata ) ) ; /* Set the return default to CACHE_INODE_SUCCESS */ *pstatus = CACHE_INODE_SUCCESS; /* stats */ (pclient->stat.nb_call_total)++; (pclient->stat.func_stats.nb_call[CACHE_INODE_LOOKUP])++; /* We should not renew entries when !use_mutex (because unless we * make the flag explicit (shared vs. exclusive), we don't know * whether a mutating operation is safe--and, the caller should have * already renewed the entry */ if(use_mutex == TRUE) { P_w(&pentry_parent->lock); cache_status = cache_inode_renew_entry(pentry_parent, pattr, ht, pclient, pcontext, pstatus); if(cache_status != CACHE_INODE_SUCCESS) { V_w(&pentry_parent->lock); inc_func_err_retryable(pclient, CACHE_INODE_GETATTR); LogDebug(COMPONENT_CACHE_INODE, "cache_inode_lookup: returning %d(%s) from cache_inode_renew_entry", *pstatus, cache_inode_err_str(*pstatus)); return NULL; } /* RW Lock goes for writer to reader */ rw_lock_downgrade(&pentry_parent->lock); } if(pentry_parent->internal_md.type != DIRECTORY) { /* Parent is no directory base, return NULL */ *pstatus = CACHE_INODE_NOT_A_DIRECTORY; /* stats */ (pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_LOOKUP])++; if(use_mutex == TRUE) V_r(&pentry_parent->lock); return NULL; } /* if name is ".", use the input value */ if(!FSAL_namecmp(pname, (fsal_name_t *) & FSAL_DOT)) { pentry = pentry_parent; } else if(!FSAL_namecmp(pname, (fsal_name_t *) & FSAL_DOT_DOT)) { /* Directory do only have exactly one parent. This a limitation in all FS, * which implies that hard link are forbidden on directories (so that * they exists only in one dir). Because of this, the parent list is * always limited to one element for a dir. Clients SHOULD never * 'lookup( .. )' in something that is no dir. */ pentry = cache_inode_lookupp_no_mutex(pentry_parent, ht, pclient, pcontext, pstatus); } else { /* This is a "regular lookup" (not on "." or "..") */ /* Check is user (as specified by the credentials) is authorized to * lookup the directory or not */ access_mask = FSAL_MODE_MASK_SET(FSAL_X_OK) | FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_LIST_DIR); if(cache_inode_access_no_mutex(pentry_parent, access_mask, ht, pclient, pcontext, pstatus) != CACHE_INODE_SUCCESS) { if(use_mutex == TRUE) V_r(&pentry_parent->lock); (pclient->stat.func_stats.nb_err_retryable[CACHE_INODE_GETATTR])++; return NULL; } /* We first try avltree_lookup by name. If that fails, we dispatch to * the fsal. */ FSAL_namecpy(&dirent_key->name, pname); dirent_node = avltree_lookup(&dirent_key->node_n, &pentry_parent->object.dir.dentries); if (dirent_node) { dirent = avltree_container_of(dirent_node, cache_inode_dir_entry_t, node_n); pentry = dirent->pentry; } if(pentry == NULL) { LogDebug(COMPONENT_CACHE_INODE, "Cache Miss detected"); dir_handle = pentry_parent->handle; object_attributes.asked_attributes = pclient->attrmask; #ifdef _USE_MFSL #ifdef _USE_MFSL_ASYNC if(!mfsl_async_is_object_asynchronous(&pentry_parent->mobject)) { /* If the parent is asynchronous, rely on the content of the cache * inode parent entry. * * /!\ If the fs behind the FSAL is touched in a non-nfs way, * there will be huge incoherencies. */ #endif /* _USE_MFSL_ASYNC */ fsal_status = MFSL_lookup(&pentry_parent->mobject, pname, pcontext, &pclient->mfsl_context, &object_handle, &object_attributes, NULL); #ifdef _USE_MFSL_ASYNC } else { LogMidDebug(COMPONENT_CACHE_INODE, "cache_inode_lookup chose to bypass FSAL and trusted his cache for name=%s", pname->name); fsal_status.major = ERR_FSAL_NOENT; fsal_status.minor = ENOENT; } #endif /* _USE_MFSL_ASYNC */ #else fsal_status = FSAL_lookup(&dir_handle, pname, pcontext, &object_handle, &object_attributes); #endif /* _USE_MFSL */ if(FSAL_IS_ERROR(fsal_status)) { *pstatus = cache_inode_error_convert(fsal_status); if(use_mutex == TRUE) V_r(&pentry_parent->lock); /* Stale File Handle to be detected and managed */ if(fsal_status.major == ERR_FSAL_STALE) { cache_inode_status_t kill_status; LogEvent(COMPONENT_CACHE_INODE, "cache_inode_lookup: Stale FSAL File Handle detected for pentry = %p, fsal_status=(%u,%u)", pentry_parent, fsal_status.major, fsal_status.minor); if(cache_inode_kill_entry(pentry_parent, NO_LOCK, ht, pclient, &kill_status) != CACHE_INODE_SUCCESS) LogCrit(COMPONENT_CACHE_INODE, "cache_inode_pentry_parent: Could not kill entry %p, status = %u", pentry_parent, kill_status); *pstatus = CACHE_INODE_FSAL_ESTALE; } /* stats */ (pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_LOOKUP])++; return NULL; } type = cache_inode_fsal_type_convert(object_attributes.type); /* If entry is a symlink, this value for be cached */ if(type == SYMBOLIC_LINK) { if( CACHE_INODE_KEEP_CONTENT( policy ) ) #ifdef _USE_MFSL { fsal_status = MFSL_readlink(&object_handle, pcontext, &pclient->mfsl_context, &create_arg.link_content, &object_attributes, NULL); } #else { fsal_status = FSAL_readlink(&object_handle, pcontext, &create_arg.link_content, &object_attributes); } else { fsal_status.major = ERR_FSAL_NO_ERROR ; fsal_status.minor = 0 ; } #endif if(FSAL_IS_ERROR(fsal_status)) { *pstatus = cache_inode_error_convert(fsal_status); if(use_mutex == TRUE) V_r(&pentry_parent->lock); /* Stale File Handle to be detected and managed */ if(fsal_status.major == ERR_FSAL_STALE) { cache_inode_status_t kill_status; LogEvent(COMPONENT_CACHE_INODE, "cache_inode_lookup: Stale FSAL File Handle detected for pentry = %p, fsal_status=(%u,%u)", pentry_parent, fsal_status.major, fsal_status.minor); if(cache_inode_kill_entry(pentry_parent, NO_LOCK, ht, pclient, &kill_status) != CACHE_INODE_SUCCESS) LogCrit(COMPONENT_CACHE_INODE, "cache_inode_pentry_parent: Could not kill entry %p, status = %u", pentry_parent, kill_status); *pstatus = CACHE_INODE_FSAL_ESTALE; } /* stats */ (pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_LOOKUP])++; return NULL; } } /* Allocation of a new entry in the cache */ #ifdef _USE_MFSL new_entry_fsdata.handle = object_handle.handle; #else new_entry_fsdata.handle = object_handle; #endif new_entry_fsdata.cookie = 0; if((pentry = cache_inode_new_entry( &new_entry_fsdata, &object_attributes, type, policy, &create_arg, NULL, ht, pclient, pcontext, FALSE, /* This is a population and not a creation */ pstatus ) ) == NULL ) { if(use_mutex == TRUE) V_r(&pentry_parent->lock); /* stats */ (pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_LOOKUP])++; return NULL; } /* Entry was found in the FSAL, add this entry to the parent * directory */ cache_status = cache_inode_add_cached_dirent(pentry_parent, pname, pentry, ht, &new_dir_entry, pclient, pcontext, pstatus); if(cache_status != CACHE_INODE_SUCCESS && cache_status != CACHE_INODE_ENTRY_EXISTS) { if(use_mutex == TRUE) V_r(&pentry_parent->lock); /* stats */ (pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_LOOKUP])++; return NULL; } } /* cached lookup fail (try fsal) */
static bool pseudo_node(char *token, void *arg) { struct node_state *state = (struct node_state *)arg; pseudofs_entry_t *node = NULL; pseudofs_entry_t *new_node = NULL; struct gsh_buffdesc key; char fullpseudopath[MAXPATHLEN + 2]; int j = 0; state->retval = 0; /* start off with no errors */ LogFullDebug(COMPONENT_NFS_V4_PSEUDO, "token %s", token); for (node = state->this_node->sons; node != NULL; node = node->next) { /* Looking for a matching entry */ if (!strcmp(node->name, token)) { /* matched entry is new parent node */ state->this_node = node; return true; } j++; } /* not found so create a new entry */ if (gPseudoFs.last_pseudo_id == (MAX_PSEUDO_ENTRY - 1)) { LogMajor(COMPONENT_NFS_V4_PSEUDO, "Too many nodes in Export_Id %d Path=\"%s\" Pseudo=\"%s\"", state->entry->id, state->entry->fullpath, state->entry->pseudopath); state->retval = ENOMEM; return false; } new_node = gsh_calloc(1, sizeof(pseudofs_entry_t)); if (new_node == NULL) { LogMajor(COMPONENT_NFS_V4_PSEUDO, "Insufficient memory to create pseudo fs node"); state->retval = ENOMEM; return false; } strcpy(new_node->name, token); gPseudoFs.last_pseudo_id++; /** @todo: need to fix this ... */ fullpath(fullpseudopath, new_node, state->this_node, MAXPATHLEN); key = create_pseudo_handle_key(fullpseudopath, (ushort) strlen(fullpseudopath)); new_node->fsopaque = (uint8_t *) key.addr; new_node->pseudo_id = *(uint64_t *) new_node->fsopaque; gPseudoFs.reverse_tab[gPseudoFs.last_pseudo_id] = new_node; new_node->last = new_node; if (isMidDebug(COMPONENT_NFS_V4_PSEUDO)) { char str[256]; sprint_mem(str, new_node->fsopaque, V4_FH_OPAQUE_SIZE); LogMidDebug(COMPONENT_NFS_V4_PSEUDO, "Built pseudofs entry " "index:%u name:%s path:%s handle:%s", gPseudoFs.last_pseudo_id, new_node->name, fullpseudopath, str); } /* Step into the new entry and attach it to the tree */ if (state->this_node->sons == NULL) { state->this_node->sons = new_node; } else { state->this_node->sons->last->next = new_node; state->this_node->sons->last = new_node; } new_node->parent = state->this_node; state->this_node = new_node; return true; }
/** * @brief Up Thread * * @param Arg reference to void * */ void *GPFSFSAL_UP_Thread(void *Arg) { struct gpfs_filesystem *gpfs_fs = Arg; struct fsal_up_vector *event_func; char thr_name[16]; int rc = 0; struct pnfs_deviceid devid; struct stat buf; struct glock fl; struct callback_arg callback; struct gpfs_file_handle handle; int reason = 0; int flags = 0; unsigned int *fhP; int retry = 0; struct gsh_buffdesc key; uint32_t expire_time_attr = 0; uint32_t upflags; int errsv = 0; fsal_status_t fsal_status = {0,}; #ifdef _VALGRIND_MEMCHECK memset(&handle, 0, sizeof(handle)); memset(&buf, 0, sizeof(buf)); memset(&fl, 0, sizeof(fl)); memset(&devid, 0, sizeof(devid)); #endif snprintf(thr_name, sizeof(thr_name), "fsal_up_%"PRIu64".%"PRIu64, gpfs_fs->fs->dev.major, gpfs_fs->fs->dev.minor); SetNameFunction(thr_name); LogFullDebug(COMPONENT_FSAL_UP, "Initializing FSAL Callback context for %d.", gpfs_fs->root_fd); /* wait for nfs init completion to get general_fridge * initialized which is needed for processing some upcall events */ nfs_init_wait(); /* Start querying for events and processing. */ while (1) { LogFullDebug(COMPONENT_FSAL_UP, "Requesting event from FSAL Callback interface for %d.", gpfs_fs->root_fd); handle.handle_size = GPFS_MAX_FH_SIZE; handle.handle_key_size = OPENHANDLE_KEY_LEN; handle.handle_version = OPENHANDLE_VERSION; callback.interface_version = GPFS_INTERFACE_VERSION + GPFS_INTERFACE_SUB_VER; callback.mountdirfd = gpfs_fs->root_fd; callback.handle = &handle; callback.reason = &reason; callback.flags = &flags; callback.buf = &buf; callback.fl = &fl; callback.dev_id = &devid; callback.expire_attr = &expire_time_attr; rc = gpfs_ganesha(OPENHANDLE_INODE_UPDATE, &callback); errsv = errno; if (rc != 0) { rc = -(rc); if (rc > GPFS_INTERFACE_VERSION) { LogFatal(COMPONENT_FSAL_UP, "Ganesha version %d mismatch GPFS version %d.", callback.interface_version, rc); return NULL; } if (errsv == EINTR) continue; LogCrit(COMPONENT_FSAL_UP, "OPENHANDLE_INODE_UPDATE failed for %d. rc %d, errno %d (%s) reason %d", gpfs_fs->root_fd, rc, errsv, strerror(errsv), reason); /* @todo 1000 retry logic will go away once the * OPENHANDLE_INODE_UPDATE ioctl separates EINTR * and EUNATCH. */ if (errsv == EUNATCH && ++retry > 1000) LogFatal(COMPONENT_FSAL_UP, "GPFS file system %d has gone away.", gpfs_fs->root_fd); continue; } retry = 0; /* flags is int, but only the least significant 2 bytes * are valid. We are getting random bits into the upper * 2 bytes! Workaround this until the kernel module * gets fixed. */ flags = flags & 0xffff; LogDebug(COMPONENT_FSAL_UP, "inode update: rc %d reason %d update ino %" PRId64 " flags:%x", rc, reason, callback.buf->st_ino, flags); LogFullDebug(COMPONENT_FSAL_UP, "inode update: flags:%x callback.handle:%p handle size = %u handle_type:%d handle_version:%d key_size = %u handle_fsid=%X.%X f_handle:%p expire: %d", *callback.flags, callback.handle, callback.handle->handle_size, callback.handle->handle_type, callback.handle->handle_version, callback.handle->handle_key_size, callback.handle->handle_fsid[0], callback.handle->handle_fsid[1], callback.handle->f_handle, expire_time_attr); callback.handle->handle_version = OPENHANDLE_VERSION; fhP = (int *)&(callback.handle->f_handle[0]); LogFullDebug(COMPONENT_FSAL_UP, " inode update: handle %08x %08x %08x %08x %08x %08x %08x", fhP[0], fhP[1], fhP[2], fhP[3], fhP[4], fhP[5], fhP[6]); /* Here is where we decide what type of event this is * ... open,close,read,...,invalidate? */ key.addr = &handle; key.len = handle.handle_key_size; LogDebug(COMPONENT_FSAL_UP, "Received event to process for %d", gpfs_fs->root_fd); /* We need valid up_vector while processing some of the * events below. Setup up vector and hold the mutex while * processing the event for the entire duration. */ PTHREAD_MUTEX_lock(&gpfs_fs->upvector_mutex); if (!setup_up_vector(gpfs_fs)) { PTHREAD_MUTEX_unlock(&gpfs_fs->upvector_mutex); return NULL; } event_func = gpfs_fs->up_vector; switch (reason) { case INODE_LOCK_GRANTED: /* Lock Event */ case INODE_LOCK_AGAIN: /* Lock Event */ { LogMidDebug(COMPONENT_FSAL_UP, "%s: owner %p pid %d type %d start %lld len %lld", reason == INODE_LOCK_GRANTED ? "inode lock granted" : "inode lock again", fl.lock_owner, fl.flock.l_pid, fl.flock.l_type, (long long)fl.flock.l_start, (long long)fl.flock.l_len); fsal_lock_param_t lockdesc = { .lock_sle_type = FSAL_POSIX_LOCK, .lock_type = fl.flock.l_type, .lock_start = fl.flock.l_start, .lock_length = fl.flock.l_len }; if (reason == INODE_LOCK_AGAIN) fsal_status = up_async_lock_avail( general_fridge, event_func, &key, fl.lock_owner, &lockdesc, NULL, NULL); else fsal_status = up_async_lock_grant( general_fridge, event_func, &key, fl.lock_owner, &lockdesc, NULL, NULL); } break; case BREAK_DELEGATION: /* Delegation Event */ LogDebug(COMPONENT_FSAL_UP, "delegation recall: flags:%x ino %" PRId64, flags, callback.buf->st_ino); fsal_status = up_async_delegrecall(general_fridge, event_func, &key, NULL, NULL); break; case LAYOUT_FILE_RECALL: /* Layout file recall Event */ { struct pnfs_segment segment = { .offset = 0, .length = UINT64_MAX, .io_mode = LAYOUTIOMODE4_ANY }; LogDebug(COMPONENT_FSAL_UP, "layout file recall: flags:%x ino %" PRId64, flags, callback.buf->st_ino); fsal_status = up_async_layoutrecall( general_fridge, event_func, &key, LAYOUT4_NFSV4_1_FILES, false, &segment, NULL, NULL, NULL, NULL); } break; case LAYOUT_RECALL_ANY: /* Recall all layouts Event */ LogDebug(COMPONENT_FSAL_UP, "layout recall any: flags:%x ino %" PRId64, flags, callback.buf->st_ino); /** * @todo This functionality needs to be implemented as a * bulk FSID CB_LAYOUTRECALL. RECALL_ANY isn't suitable * since it can't be restricted to just one FSAL. Also * an FSID LAYOUTRECALL lets you have multiplke * filesystems exported from one FSAL and not yank layouts * on all of them when you only need to recall them for one. */ break; case LAYOUT_NOTIFY_DEVICEID: /* Device update Event */ LogDebug(COMPONENT_FSAL_UP, "layout dev update: flags:%x ino %" PRId64 " seq %d fd %d fsid 0x%" PRIx64, flags, callback.buf->st_ino, devid.device_id2, devid.device_id4, devid.devid); memset(&devid, 0, sizeof(devid)); devid.fsal_id = FSAL_ID_GPFS; fsal_status = up_async_notify_device(general_fridge, event_func, NOTIFY_DEVICEID4_DELETE_MASK, LAYOUT4_NFSV4_1_FILES, &devid, true, NULL, NULL); break; case INODE_UPDATE: /* Update Event */ { struct attrlist attr; LogMidDebug(COMPONENT_FSAL_UP, "inode update: flags:%x update ino %" PRId64 " n_link:%d", flags, callback.buf->st_ino, (int)callback.buf->st_nlink); /** @todo: This notification is completely * asynchronous. If we happen to change some * of the attributes later, we end up over * writing those with these possibly stale * values as we don't know when we get to * update with these up call values. We should * probably use time stamp or let the up call * always provide UP_TIMES flag in which case * we can compare the current ctime vs up call * provided ctime before updating the * attributes. * * For now, we think size attribute is more * important than others, so invalidate the * attributes and let ganesha fetch attributes * as needed if this update includes a size * change. We are careless for other attribute * changes, and we may end up with stale values * until this gets fixed! */ if (flags & (UP_SIZE | UP_SIZE_BIG)) { fsal_status = event_func->invalidate( event_func, &key, FSAL_UP_INVALIDATE_CACHE); break; } /* Check for accepted flags, any other changes just invalidate. */ if (flags & ~(UP_SIZE | UP_NLINK | UP_MODE | UP_OWN | UP_TIMES | UP_ATIME | UP_SIZE_BIG)) { fsal_status = event_func->invalidate( event_func, &key, FSAL_UP_INVALIDATE_CACHE); } else { /* buf may not have all attributes set. * Set the mask to what is changed */ attr.valid_mask = 0; attr.acl = NULL; upflags = 0; if (flags & UP_SIZE) attr.valid_mask |= ATTR_CHGTIME | ATTR_CHANGE | ATTR_SIZE | ATTR_SPACEUSED; if (flags & UP_SIZE_BIG) { attr.valid_mask |= ATTR_CHGTIME | ATTR_CHANGE | ATTR_SIZE | ATTR_SPACEUSED; upflags |= fsal_up_update_filesize_inc | fsal_up_update_spaceused_inc; } if (flags & UP_MODE) attr.valid_mask |= ATTR_CHGTIME | ATTR_CHANGE | ATTR_MODE; if (flags & UP_OWN) attr.valid_mask |= ATTR_CHGTIME | ATTR_CHANGE | ATTR_OWNER | ATTR_GROUP | ATTR_MODE; if (flags & UP_TIMES) attr.valid_mask |= ATTR_CHGTIME | ATTR_CHANGE | ATTR_ATIME | ATTR_CTIME | ATTR_MTIME; if (flags & UP_ATIME) attr.valid_mask |= ATTR_CHGTIME | ATTR_CHANGE | ATTR_ATIME; if (flags & UP_NLINK) attr.valid_mask |= ATTR_NUMLINKS; attr.request_mask = attr.valid_mask; attr.expire_time_attr = expire_time_attr; posix2fsal_attributes(&buf, &attr); fsal_status = event_func->update( event_func, &key, &attr, upflags); if ((flags & UP_NLINK) && (attr.numlinks == 0)) { upflags = fsal_up_nlink; attr.valid_mask = 0; attr.request_mask = 0; fsal_status = up_async_update (general_fridge, event_func, &key, &attr, upflags, NULL, NULL); } } } break; case THREAD_STOP: /* We wanted to terminate this thread */ LogDebug(COMPONENT_FSAL_UP, "Terminating the GPFS up call thread for %d", gpfs_fs->root_fd); PTHREAD_MUTEX_unlock(&gpfs_fs->upvector_mutex); return NULL; case INODE_INVALIDATE: LogMidDebug(COMPONENT_FSAL_UP, "inode invalidate: flags:%x update ino %" PRId64, flags, callback.buf->st_ino); upflags = FSAL_UP_INVALIDATE_CACHE; fsal_status = event_func->invalidate_close( event_func, &key, upflags); break; case THREAD_PAUSE: /* File system image is probably going away, but * we don't need to do anything here as we * eventually get other errors that stop this * thread. */ PTHREAD_MUTEX_unlock(&gpfs_fs->upvector_mutex); continue; /* get next event */ default: PTHREAD_MUTEX_unlock(&gpfs_fs->upvector_mutex); LogWarn(COMPONENT_FSAL_UP, "Unknown event: %d", reason); continue; } PTHREAD_MUTEX_unlock(&gpfs_fs->upvector_mutex); if (FSAL_IS_ERROR(fsal_status) && fsal_status.major != ERR_FSAL_NOENT) { LogWarn(COMPONENT_FSAL_UP, "Event %d could not be processed for fd %d rc %s", reason, gpfs_fs->root_fd, fsal_err_txt(fsal_status)); } } return NULL; } /* GPFSFSAL_UP_Thread */
int nfs4_op_putrootfh(struct nfs_argop4 *op, compound_data_t *data, struct nfs_resop4 *resp) { fsal_status_t status = {0, 0}; struct fsal_obj_handle *file_obj; PUTROOTFH4res * const res_PUTROOTFH4 = &resp->nfs_resop4_u.opputrootfh; /* 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; /* Release any old export reference */ if (op_ctx->ctx_export != NULL) put_gsh_export(op_ctx->ctx_export); op_ctx->ctx_export = NULL; op_ctx->fsal_export = NULL; /* Clear out current entry for now */ set_current_entry(data, NULL); /* Get the root export of the Pseudo FS */ op_ctx->ctx_export = get_gsh_export_by_pseudo("/", true); if (op_ctx->ctx_export == NULL) { LogCrit(COMPONENT_EXPORT, "Could not get export for Pseudo Root"); res_PUTROOTFH4->status = NFS4ERR_NOENT; return res_PUTROOTFH4->status; } op_ctx->fsal_export = op_ctx->ctx_export->fsal_export; /* Build credentials */ res_PUTROOTFH4->status = nfs4_export_check_access(data->req); /* Test for access error (export should not be visible). */ if (res_PUTROOTFH4->status == NFS4ERR_ACCESS) { /* Client has no access at all */ LogDebug(COMPONENT_EXPORT, "Client doesn't have access to Pseudo Root"); return res_PUTROOTFH4->status; } if (res_PUTROOTFH4->status != NFS4_OK) { LogMajor(COMPONENT_EXPORT, "Failed to get FSAL credentials Pseudo Root"); return res_PUTROOTFH4->status; } /* Get the Pesudo Root inode of the mounted on export */ status = nfs_export_get_root_entry(op_ctx->ctx_export, &file_obj); if (FSAL_IS_ERROR(status)) { LogCrit(COMPONENT_EXPORT, "Could not get root inode for Pseudo Root"); res_PUTROOTFH4->status = nfs4_Errno_status(status); return res_PUTROOTFH4->status; } LogMidDebug(COMPONENT_EXPORT, "Root node %p", data->current_obj); set_current_entry(data, file_obj); /* Put our ref */ file_obj->obj_ops.put_ref(file_obj); /* Convert it to a file handle */ if (!nfs4_FSALToFhandle(data->currentFH.nfs_fh4_val == NULL, &data->currentFH, data->current_obj, op_ctx->ctx_export)) { LogCrit(COMPONENT_EXPORT, "Could not get handle for Pseudo Root"); res_PUTROOTFH4->status = NFS4ERR_SERVERFAULT; return res_PUTROOTFH4->status; } LogHandleNFS4("NFS4 PUTROOTFH CURRENT FH: ", &data->currentFH); res_PUTROOTFH4->status = NFS4_OK; return res_PUTROOTFH4->status; } /* nfs4_op_putrootfh */