/** * @brief Return true if create verifier matches * * This function returns true if the create verifier matches * * @param[in] entry Entry to be managed. * @param[in] req_ctx Request context(user creds, client address etc) * @param[in] verf_hi High long of verifier * @param[in] verf_lo Low long of verifier * * @return Errors from cache_inode_lock_trust_attributes. * */ bool cache_inode_create_verify(cache_entry_t *entry, const struct req_op_context *req_ctx, uint32_t verf_hi, uint32_t verf_lo) { /* True if the verifier matches */ bool verified = false; /* Lock (and refresh if necessary) the attributes, copy them out, and unlock. */ if (cache_inode_lock_trust_attrs(entry, req_ctx, false) == CACHE_INODE_SUCCESS) { if (FSAL_TEST_MASK(entry->obj_handle->attributes.mask, ATTR_ATIME) && FSAL_TEST_MASK(entry->obj_handle->attributes.mask, ATTR_MTIME) && entry->obj_handle->attributes.atime.tv_sec == verf_hi && entry->obj_handle->attributes.mtime.tv_sec == verf_lo) { verified = true; } PTHREAD_RWLOCK_unlock(&entry->attr_lock); } return verified; }
void fsal_interval_proxy_fsalattr2bitmap4(fsal_attrib_list_t * pfsalattr, bitmap4 * pbitmap) { uint32_t tmpattrlist[100]; uint32_t attrlen = 0; if(FSAL_TEST_MASK(pfsalattr->asked_attributes, FSAL_ATTR_SIZE)) tmpattrlist[attrlen++] = FATTR4_SIZE; if(FSAL_TEST_MASK(pfsalattr->asked_attributes, FSAL_ATTR_MODE)) tmpattrlist[attrlen++] = FATTR4_MODE; if(FSAL_TEST_MASK(pfsalattr->asked_attributes, FSAL_ATTR_OWNER)) tmpattrlist[attrlen++] = FATTR4_OWNER; if(FSAL_TEST_MASK(pfsalattr->asked_attributes, FSAL_ATTR_GROUP)) tmpattrlist[attrlen++] = FATTR4_OWNER_GROUP; if(FSAL_TEST_MASK(pfsalattr->asked_attributes, FSAL_ATTR_ATIME)) tmpattrlist[attrlen++] = FATTR4_TIME_ACCESS_SET; if(FSAL_TEST_MASK(pfsalattr->asked_attributes, FSAL_ATTR_ATIME_SERVER)) tmpattrlist[attrlen++] = FATTR4_TIME_ACCESS_SET; if(FSAL_TEST_MASK(pfsalattr->asked_attributes, FSAL_ATTR_MTIME)) tmpattrlist[attrlen++] = FATTR4_TIME_MODIFY_SET; if(FSAL_TEST_MASK(pfsalattr->asked_attributes, FSAL_ATTR_MTIME_SERVER)) tmpattrlist[attrlen++] = FATTR4_TIME_MODIFY_SET; if(FSAL_TEST_MASK(pfsalattr->asked_attributes, FSAL_ATTR_CTIME)) tmpattrlist[attrlen++] = FATTR4_TIME_METADATA; nfs4_list_to_bitmap4(pbitmap, attrlen, tmpattrlist); } /* fsal_interval_proxy_fsalattr2bitmap4 */
/** * hpssHandle2fsalAttributes: * Fills an FSAL attributes structure with the info * provided (only) by the hpss handle of an object. * * \param p_hpsshandle_in (input): * Pointer to the HPSS NS object handle. * \param p_fsalattr_out (input/output): * Pointer to the FSAL attributes. * As input, it defines the attributes that the caller * wants to retrieve (by positioning flags into this structure) * and the output is built considering this input * (it fills the structure according to the flags it contains). * * \return Major error codes: * - ERR_FSAL_NO_ERROR: no error. * - ERR_FSAL_FAULT: NULL pointer passed as input parameter. * - ERR_FSAL_ATTRNOTSUPP: One of the asked attributes is not supported. * - ERR_FSAL_SERVERFAULT: Unexpected error. */ fsal_status_t hpssHandle2fsalAttributes(ns_ObjHandle_t * p_hpsshandle_in, fsal_attrib_list_t * p_fsalattr_out) { fsal_attrib_mask_t avail_attr, unavail_attr; /* sanity check */ if(!p_hpsshandle_in || !p_fsalattr_out) ReturnCode(ERR_FSAL_FAULT, 0); /* check that asked attributes are available */ avail_attr = (FSAL_ATTR_SUPPATTR | FSAL_ATTR_TYPE | FSAL_ATTR_FILEID); unavail_attr = (p_fsalattr_out->asked_attributes) & (~avail_attr); if(unavail_attr) { LogFullDebug(COMPONENT_FSAL, "Attributes not available: %#llX", unavail_attr); ReturnCode(ERR_FSAL_ATTRNOTSUPP, 0); } /* Fills the output struct */ if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_SUPPATTR)) { p_fsalattr_out->supported_attributes = global_fs_info.supported_attrs; } if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_TYPE)) { p_fsalattr_out->type = hpss2fsal_type(p_hpsshandle_in->Type); } if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_FILEID)) { p_fsalattr_out->fileid = (fsal_u64_t) hpss_GetObjId(p_hpsshandle_in); } /* everything has been copied ! */ ReturnCode(ERR_FSAL_NO_ERROR, 0); }
fsal_status_t XFSFSAL_merge_attrs(fsal_attrib_list_t * pinit_attr, fsal_attrib_list_t * pnew_attr, fsal_attrib_list_t * presult_attr) { if(pinit_attr == NULL || pnew_attr == NULL || presult_attr == NULL) Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_merge_attrs); /* The basis for the result attr is the fist argument */ *presult_attr = *pinit_attr; /* Now deal with the attributes to be merged in this set of attributes */ if(FSAL_TEST_MASK(pnew_attr->asked_attributes, FSAL_ATTR_MODE)) presult_attr->mode = pnew_attr->mode; if(FSAL_TEST_MASK(pnew_attr->asked_attributes, FSAL_ATTR_OWNER)) presult_attr->owner = pnew_attr->owner; if(FSAL_TEST_MASK(pnew_attr->asked_attributes, FSAL_ATTR_GROUP)) presult_attr->group = pnew_attr->group; if(FSAL_TEST_MASK(pnew_attr->asked_attributes, FSAL_ATTR_SIZE)) presult_attr->filesize = pnew_attr->filesize; if(FSAL_TEST_MASK(pnew_attr->asked_attributes, FSAL_ATTR_SPACEUSED)) presult_attr->spaceused = pnew_attr->spaceused; if(FSAL_TEST_MASK(pnew_attr->asked_attributes, FSAL_ATTR_ATIME)) { presult_attr->atime.seconds = pnew_attr->atime.seconds; presult_attr->atime.nseconds = pnew_attr->atime.nseconds; } if(FSAL_TEST_MASK(pnew_attr->asked_attributes, FSAL_ATTR_MTIME)) { presult_attr->mtime.seconds = pnew_attr->mtime.seconds; presult_attr->mtime.nseconds = pnew_attr->mtime.nseconds; } /* Do not forget the ctime */ FSAL_SET_MASK(presult_attr->asked_attributes, FSAL_ATTR_CTIME); presult_attr->ctime.seconds = pnew_attr->ctime.seconds; presult_attr->ctime.nseconds = pnew_attr->ctime.nseconds; /* Regular exit */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_merge_attrs); } /* FSAL_merge_attrs */
/* Same function as posixstat64_2_fsal_attributes. When NFS4 ACL support * is enabled, this will replace posixstat64_2_fsal_attributes. */ fsal_status_t ptfsal_xstat_2_fsal_attributes(ptfsal_xstat_t * p_buffxstat, fsal_attrib_list_t * p_fsalattr_out) { fsal_attrib_mask_t supp_attr, unsupp_attr; struct stat64 *p_buffstat; /* sanity checks */ if(!p_buffxstat || !p_fsalattr_out) ReturnCode(ERR_FSAL_FAULT, 0); /* check that asked attributes are supported */ supp_attr = global_fs_info.supported_attrs; unsupp_attr = (p_fsalattr_out->asked_attributes) & (~supp_attr); if(unsupp_attr) { LogFullDebug(COMPONENT_FSAL, "Unsupported attributes: %#llX", unsupp_attr); ReturnCode(ERR_FSAL_ATTRNOTSUPP, 0); } p_buffstat = &p_buffxstat->buffstat; /* Initialize ACL regardless of whether ACL was asked or not. * This is needed to make sure ACL attribute is initialized. */ p_fsalattr_out->acl = NULL; /* Fills the output struct */ if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_SUPPATTR)) { p_fsalattr_out->supported_attributes = supp_attr; LogFullDebug(COMPONENT_FSAL, "supported_attributes = %llu", p_fsalattr_out->supported_attributes); } if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_TYPE)) { p_fsalattr_out->type = posix2fsal_type(p_buffstat->st_mode); LogFullDebug(COMPONENT_FSAL, "type = 0x%x", p_fsalattr_out->type); } if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_SIZE)) { p_fsalattr_out->filesize = p_buffstat->st_size; LogFullDebug(COMPONENT_FSAL, "filesize = %lu", p_fsalattr_out->filesize); } if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_FSID)) { p_fsalattr_out->fsid = posix2fsal_fsid(p_buffstat->st_dev); LogFullDebug(COMPONENT_FSAL, "fsid major = %llu, minor = %llu", p_fsalattr_out->fsid.major, p_fsalattr_out->fsid.minor); } if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_ACL)) { #ifndef _USE_NFS4_ACL p_fsalattr_out->acl = NULL; #else if((p_buffxstat->attr_valid & XATTR_ACL) == 0) { /* ACL is invalid. */ p_fsalattr_out->acl = NULL; } else { /* ACL is valid, so try to convert fsal acl. */ if(ptfs_acl_2_fsal_acl(p_fsalattr_out, (gpfs_acl_t *)p_buffxstat->buffacl) != ERR_FSAL_NO_ERROR) p_fsalattr_out->acl = NULL; } #endif /* _USE_NFS4_ACL */ LogFullDebug(COMPONENT_FSAL, "acl = %p", p_fsalattr_out->acl); } if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_FILEID)) { p_fsalattr_out->fileid = (fsal_u64_t) (p_buffstat->st_ino); LogFullDebug(COMPONENT_FSAL, "fileid = %llu", p_fsalattr_out->fileid); } if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_MODE)) { p_fsalattr_out->mode = unix2fsal_mode(p_buffstat->st_mode); LogFullDebug(COMPONENT_FSAL, "mode = %llu", (long long unsigned int) p_fsalattr_out->mode); } if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_NUMLINKS)) { p_fsalattr_out->numlinks = p_buffstat->st_nlink; LogFullDebug(COMPONENT_FSAL, "numlinks = %lu", p_fsalattr_out->numlinks); } if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_OWNER)) { p_fsalattr_out->owner = p_buffstat->st_uid; LogFullDebug(COMPONENT_FSAL, "owner = %u", p_fsalattr_out->owner); } if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_GROUP)) { p_fsalattr_out->group = p_buffstat->st_gid; LogFullDebug(COMPONENT_FSAL, "group = %u", p_fsalattr_out->group); } if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_ATIME)) { p_fsalattr_out->atime = posix2fsal_time(p_buffstat->st_atime, p_buffstat->st_atim.tv_nsec); LogFullDebug(COMPONENT_FSAL, "atime = %u", p_fsalattr_out->atime.seconds); } if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_CTIME)) { p_fsalattr_out->ctime = posix2fsal_time(p_buffstat->st_ctime, p_buffstat->st_ctim.tv_nsec); LogFullDebug(COMPONENT_FSAL, "ctime = %u", p_fsalattr_out->ctime.seconds); } if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_MTIME)) { p_fsalattr_out->mtime = posix2fsal_time(p_buffstat->st_mtime, p_buffstat->st_mtim.tv_nsec); LogFullDebug(COMPONENT_FSAL, "mtime = %u", p_fsalattr_out->mtime.seconds); } if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_CHGTIME)) { p_fsalattr_out->chgtime = posix2fsal_time(MAX_2(p_buffstat->st_mtime, p_buffstat->st_ctime), 0); p_fsalattr_out->change = (uint64_t) p_fsalattr_out->chgtime.seconds ; LogFullDebug(COMPONENT_FSAL, "chgtime = %u", p_fsalattr_out->chgtime.seconds); } if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_SPACEUSED)) { p_fsalattr_out->spaceused = p_buffstat->st_blocks * S_BLKSIZE; LogFullDebug(COMPONENT_FSAL, "spaceused = %lu", p_fsalattr_out->spaceused); } if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_RAWDEV)) { p_fsalattr_out->rawdev = posix2fsal_devt(p_buffstat->st_rdev); LogFullDebug(COMPONENT_FSAL, "rawdev major = %u, minor = %u", (unsigned int) p_fsalattr_out->rawdev.major, (unsigned int) p_fsalattr_out->rawdev.minor); } /* everything has been copied ! */ ReturnCode(ERR_FSAL_NO_ERROR, 0); }
/** * @brief convert GPFS xstat to FSAl attributes * * @param gpfs_buf Reference to GPFS stat buffer * @param fsal_attr Reference to attribute list * @param use_acl Bool whether ACL are used * @return FSAL status * * Same function as posixstat64_2_fsal_attributes. When NFS4 ACL support * is enabled, this will replace posixstat64_2_fsal_attributes. */ fsal_status_t gpfsfsal_xstat_2_fsal_attributes(gpfsfsal_xstat_t *gpfs_buf, struct attrlist *fsal_attr, bool use_acl) { struct stat *p_buffstat; /* sanity checks */ if (!gpfs_buf || !fsal_attr) return fsalstat(ERR_FSAL_FAULT, 0); p_buffstat = &gpfs_buf->buffstat; LogDebug(COMPONENT_FSAL, "inode %ld", p_buffstat->st_ino); /* Fills the output struct */ if (FSAL_TEST_MASK(fsal_attr->mask, ATTR_TYPE)) { fsal_attr->type = posix2fsal_type(p_buffstat->st_mode); LogFullDebug(COMPONENT_FSAL, "type = 0x%x", fsal_attr->type); } if (FSAL_TEST_MASK(fsal_attr->mask, ATTR_SIZE)) { fsal_attr->filesize = p_buffstat->st_size; LogFullDebug(COMPONENT_FSAL, "filesize = %llu", (unsigned long long)fsal_attr->filesize); } if (FSAL_TEST_MASK(fsal_attr->mask, ATTR_FSID)) { fsal_attr->fsid = gpfs_buf->fsal_fsid; LogFullDebug(COMPONENT_FSAL, "fsid=0x%016"PRIx64".0x%016"PRIx64, fsal_attr->fsid.major, fsal_attr->fsid.minor); } if (FSAL_TEST_MASK(fsal_attr->mask, ATTR_ACL)) { if (fsal_attr->acl != NULL) { /* We should never be passed attributes that have an * ACL attached, but just in case some future code * path changes that assumption, let's not release the * old ACL properly. */ int acl_status; acl_status = nfs4_acl_release_entry(fsal_attr->acl); if (acl_status != NFS_V4_ACL_SUCCESS) LogCrit(COMPONENT_FSAL, "Failed to release old acl, status=%d", acl_status); fsal_attr->acl = NULL; } if (use_acl && gpfs_buf->attr_valid & XATTR_ACL) { /* ACL is valid, so try to convert fsal acl. */ gpfs_acl_2_fsal_acl(fsal_attr, (gpfs_acl_t *) gpfs_buf->buffacl); } LogFullDebug(COMPONENT_FSAL, "acl = %p", fsal_attr->acl); } if (FSAL_TEST_MASK(fsal_attr->mask, ATTR_FILEID)) { fsal_attr->fileid = (uint64_t) (p_buffstat->st_ino); LogFullDebug(COMPONENT_FSAL, "fileid = %" PRIu64, fsal_attr->fileid); } if (FSAL_TEST_MASK(fsal_attr->mask, ATTR_MODE)) { fsal_attr->mode = unix2fsal_mode(p_buffstat->st_mode); LogFullDebug(COMPONENT_FSAL, "mode = %"PRIu32, fsal_attr->mode); } if (FSAL_TEST_MASK(fsal_attr->mask, ATTR_NUMLINKS)) { fsal_attr->numlinks = p_buffstat->st_nlink; LogFullDebug(COMPONENT_FSAL, "numlinks = %u", fsal_attr->numlinks); } if (FSAL_TEST_MASK(fsal_attr->mask, ATTR_OWNER)) { fsal_attr->owner = p_buffstat->st_uid; LogFullDebug(COMPONENT_FSAL, "owner = %" PRIu64, fsal_attr->owner); } if (FSAL_TEST_MASK(fsal_attr->mask, ATTR_GROUP)) { fsal_attr->group = p_buffstat->st_gid; LogFullDebug(COMPONENT_FSAL, "group = %" PRIu64, fsal_attr->group); } if (FSAL_TEST_MASK(fsal_attr->mask, ATTR_ATIME)) { fsal_attr->atime = posix2fsal_time(p_buffstat->st_atime, p_buffstat->st_atim.tv_nsec); LogFullDebug(COMPONENT_FSAL, "atime = %lu", fsal_attr->atime.tv_sec); } if (FSAL_TEST_MASK(fsal_attr->mask, ATTR_CTIME)) { fsal_attr->ctime = posix2fsal_time(p_buffstat->st_ctime, p_buffstat->st_ctim.tv_nsec); LogFullDebug(COMPONENT_FSAL, "ctime = %lu", fsal_attr->ctime.tv_sec); } if (FSAL_TEST_MASK(fsal_attr->mask, ATTR_MTIME)) { fsal_attr->mtime = posix2fsal_time(p_buffstat->st_mtime, p_buffstat->st_mtim.tv_nsec); LogFullDebug(COMPONENT_FSAL, "mtime = %lu", fsal_attr->mtime.tv_sec); } if (FSAL_TEST_MASK(fsal_attr->mask, ATTR_CHGTIME)) { if (p_buffstat->st_mtime == p_buffstat->st_ctime) { if (p_buffstat->st_mtim.tv_nsec > p_buffstat->st_ctim.tv_nsec) fsal_attr->chgtime = posix2fsal_time(p_buffstat->st_mtime, p_buffstat->st_mtim. tv_nsec); else fsal_attr->chgtime = posix2fsal_time(p_buffstat->st_ctime, p_buffstat->st_ctim. tv_nsec); } else if (p_buffstat->st_mtime > p_buffstat->st_ctime) { fsal_attr->chgtime = posix2fsal_time(p_buffstat->st_mtime, p_buffstat->st_mtim.tv_nsec); } else { fsal_attr->chgtime = posix2fsal_time(p_buffstat->st_ctime, p_buffstat->st_ctim.tv_nsec); } fsal_attr->change = (uint64_t) fsal_attr->chgtime.tv_sec + (uint64_t) fsal_attr->chgtime.tv_nsec; LogFullDebug(COMPONENT_FSAL, "chgtime = %lu", fsal_attr->chgtime.tv_sec); } if (FSAL_TEST_MASK(fsal_attr->mask, ATTR_SPACEUSED)) { fsal_attr->spaceused = p_buffstat->st_blocks * S_BLKSIZE; LogFullDebug(COMPONENT_FSAL, "spaceused = %llu", (unsigned long long)fsal_attr->spaceused); } if (FSAL_TEST_MASK(fsal_attr->mask, ATTR_RAWDEV)) { fsal_attr->rawdev = posix2fsal_devt(p_buffstat->st_rdev); LogFullDebug(COMPONENT_FSAL, "rawdev major = %u, minor = %u", (unsigned int)fsal_attr->rawdev.major, (unsigned int)fsal_attr->rawdev.minor); } /* everything has been copied ! */ return fsalstat(ERR_FSAL_NO_ERROR, 0); }
/** * @brief Set the attributes for a file. * * This function sets the attributes of a file, both in the cache and * in the underlying filesystem. * * @param[in] entry Entry whose attributes are to be set * @param[in,out] attr Attributes to set/result of set * * @retval CACHE_INODE_SUCCESS if operation is a success */ cache_inode_status_t cache_inode_setattr(cache_entry_t *entry, struct attrlist *attr, bool is_open_write) { struct fsal_obj_handle *obj_handle = entry->obj_handle; fsal_status_t fsal_status = { 0, 0 }; fsal_acl_t *saved_acl = NULL; fsal_acl_status_t acl_status = 0; cache_inode_status_t status = CACHE_INODE_SUCCESS; uint64_t before; /* True if we have taken the content lock on 'entry' */ bool content_locked = false; if ((attr->mask & (ATTR_SIZE | ATTR4_SPACE_RESERVED)) && (entry->type != REGULAR_FILE)) { LogWarn(COMPONENT_CACHE_INODE, "Attempt to truncate non-regular file: type=%d", entry->type); status = CACHE_INODE_BAD_TYPE; } /* Is it allowed to change times ? */ if (!op_ctx->fsal_export->ops->fs_supports(op_ctx->fsal_export, fso_cansettime) && (FSAL_TEST_MASK (attr->mask, (ATTR_ATIME | ATTR_CREATION | ATTR_CTIME | ATTR_MTIME)))) { status = CACHE_INODE_INVALID_ARGUMENT; goto out; } /* Get wrlock on attr_lock and verify attrs */ status = cache_inode_lock_trust_attrs(entry, true); if (status != CACHE_INODE_SUCCESS) return status; /* Do permission checks */ status = cache_inode_check_setattr_perms(entry, attr, is_open_write); if (status != CACHE_INODE_SUCCESS) goto unlock; if (attr->mask & (ATTR_SIZE | ATTR4_SPACE_RESERVED)) { PTHREAD_RWLOCK_wrlock(&entry->content_lock); content_locked = true; } saved_acl = obj_handle->attributes.acl; before = obj_handle->attributes.change; fsal_status = obj_handle->ops->setattrs(obj_handle, attr); if (FSAL_IS_ERROR(fsal_status)) { status = cache_inode_error_convert(fsal_status); if (fsal_status.major == ERR_FSAL_STALE) { LogEvent(COMPONENT_CACHE_INODE, "FSAL returned STALE from truncate"); cache_inode_kill_entry(entry); } goto unlock; } fsal_status = obj_handle->ops->getattrs(obj_handle); *attr = obj_handle->attributes; if (FSAL_IS_ERROR(fsal_status)) { status = cache_inode_error_convert(fsal_status); if (fsal_status.major == ERR_FSAL_STALE) { LogEvent(COMPONENT_CACHE_INODE, "FSAL returned STALE from setattrs"); cache_inode_kill_entry(entry); } goto unlock; } if (before == obj_handle->attributes.change) obj_handle->attributes.change++; /* Decrement refcount on saved ACL */ nfs4_acl_release_entry(saved_acl, &acl_status); if (acl_status != NFS_V4_ACL_SUCCESS) LogCrit(COMPONENT_CACHE_INODE, "Failed to release old acl, status=%d", acl_status); cache_inode_fixup_md(entry); /* Copy the complete set of new attributes out. */ *attr = entry->obj_handle->attributes; status = CACHE_INODE_SUCCESS; unlock: if (content_locked) PTHREAD_RWLOCK_unlock(&entry->content_lock); PTHREAD_RWLOCK_unlock(&entry->attr_lock); out: return status; }
/* Same function as posixstat64_2_fsal_attributes. When NFS4 ACL support * is enabled, this will replace posixstat64_2_fsal_attributes. */ fsal_status_t gpfsfsal_xstat_2_fsal_attributes(gpfsfsal_xstat_t *p_buffxstat, struct attrlist *p_fsalattr_out, bool use_acl) { struct stat *p_buffstat; /* sanity checks */ if (!p_buffxstat || !p_fsalattr_out) return fsalstat(ERR_FSAL_FAULT, 0); p_buffstat = &p_buffxstat->buffstat; LogDebug(COMPONENT_FSAL, "inode %ld", p_buffstat->st_ino); /* Fills the output struct */ if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_TYPE)) { p_fsalattr_out->type = posix2fsal_type(p_buffstat->st_mode); LogFullDebug(COMPONENT_FSAL, "type = 0x%x", p_fsalattr_out->type); } if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_SIZE)) { p_fsalattr_out->filesize = p_buffstat->st_size; LogFullDebug(COMPONENT_FSAL, "filesize = %llu", (unsigned long long)p_fsalattr_out->filesize); } if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_FSID)) { p_fsalattr_out->fsid = p_buffxstat->fsal_fsid; LogFullDebug(COMPONENT_FSAL, "fsid=0x%016"PRIx64".0x%016"PRIx64, p_fsalattr_out->fsid.major, p_fsalattr_out->fsid.minor); } if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_ACL)) { p_fsalattr_out->acl = NULL; if (use_acl && p_buffxstat->attr_valid & XATTR_ACL) { /* ACL is valid, so try to convert fsal acl. */ gpfs_acl_2_fsal_acl(p_fsalattr_out, (gpfs_acl_t *) p_buffxstat-> buffacl); } LogFullDebug(COMPONENT_FSAL, "acl = %p", p_fsalattr_out->acl); } if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_FILEID)) { p_fsalattr_out->fileid = (uint64_t) (p_buffstat->st_ino); LogFullDebug(COMPONENT_FSAL, "fileid = %lu", p_fsalattr_out->fileid); } if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_MODE)) { p_fsalattr_out->mode = unix2fsal_mode(p_buffstat->st_mode); LogFullDebug(COMPONENT_FSAL, "mode = %"PRIu32, p_fsalattr_out->mode); } if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_NUMLINKS)) { p_fsalattr_out->numlinks = p_buffstat->st_nlink; LogFullDebug(COMPONENT_FSAL, "numlinks = %u", p_fsalattr_out->numlinks); } if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_OWNER)) { p_fsalattr_out->owner = p_buffstat->st_uid; LogFullDebug(COMPONENT_FSAL, "owner = %lu", p_fsalattr_out->owner); } if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_GROUP)) { p_fsalattr_out->group = p_buffstat->st_gid; LogFullDebug(COMPONENT_FSAL, "group = %lu", p_fsalattr_out->group); } if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_ATIME)) { p_fsalattr_out->atime = posix2fsal_time(p_buffstat->st_atime, p_buffstat->st_atim.tv_nsec); LogFullDebug(COMPONENT_FSAL, "atime = %lu", p_fsalattr_out->atime.tv_sec); } if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_CTIME)) { p_fsalattr_out->ctime = posix2fsal_time(p_buffstat->st_ctime, p_buffstat->st_ctim.tv_nsec); LogFullDebug(COMPONENT_FSAL, "ctime = %lu", p_fsalattr_out->ctime.tv_sec); } if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_MTIME)) { p_fsalattr_out->mtime = posix2fsal_time(p_buffstat->st_mtime, p_buffstat->st_mtim.tv_nsec); LogFullDebug(COMPONENT_FSAL, "mtime = %lu", p_fsalattr_out->mtime.tv_sec); } if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_CHGTIME)) { if (p_buffstat->st_mtime == p_buffstat->st_ctime) { if (p_buffstat->st_mtim.tv_nsec > p_buffstat->st_ctim.tv_nsec) p_fsalattr_out->chgtime = posix2fsal_time(p_buffstat->st_mtime, p_buffstat->st_mtim. tv_nsec); else p_fsalattr_out->chgtime = posix2fsal_time(p_buffstat->st_ctime, p_buffstat->st_ctim. tv_nsec); } else if (p_buffstat->st_mtime > p_buffstat->st_ctime) { p_fsalattr_out->chgtime = posix2fsal_time(p_buffstat->st_mtime, p_buffstat->st_mtim.tv_nsec); } else { p_fsalattr_out->chgtime = posix2fsal_time(p_buffstat->st_ctime, p_buffstat->st_ctim.tv_nsec); } p_fsalattr_out->change = (uint64_t) p_fsalattr_out->chgtime.tv_sec + (uint64_t) p_fsalattr_out->chgtime.tv_nsec; LogFullDebug(COMPONENT_FSAL, "chgtime = %lu", p_fsalattr_out->chgtime.tv_sec); } if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_SPACEUSED)) { p_fsalattr_out->spaceused = p_buffstat->st_blocks * S_BLKSIZE; LogFullDebug(COMPONENT_FSAL, "spaceused = %llu", (unsigned long long)p_fsalattr_out->spaceused); } if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_RAWDEV)) { p_fsalattr_out->rawdev = posix2fsal_devt(p_buffstat->st_rdev); LogFullDebug(COMPONENT_FSAL, "rawdev major = %u, minor = %u", (unsigned int)p_fsalattr_out->rawdev.major, (unsigned int)p_fsalattr_out->rawdev.minor); } /* everything has been copied ! */ return fsalstat(ERR_FSAL_NO_ERROR, 0); }
fsal_status_t posix2fsal_attributes(struct stat * p_buffstat, fsal_attrib_list_t * p_fsalattr_out) { fsal_attrib_mask_t supp_attr, unsupp_attr; /* sanity checks */ if(!p_buffstat || !p_fsalattr_out) ReturnCode(ERR_FSAL_FAULT, 0); /* check that asked attributes are supported */ supp_attr = global_fs_info.supported_attrs; unsupp_attr = (p_fsalattr_out->asked_attributes) & (~supp_attr); if(unsupp_attr) { LogFullDebug(COMPONENT_FSAL, "Unsupported attributes: %#llX", unsupp_attr); ReturnCode(ERR_FSAL_ATTRNOTSUPP, 0); } /* Initialize ACL regardless of whether ACL was asked or not. * This is needed to make sure ACL attribute is initialized. */ p_fsalattr_out->acl = NULL; /* Fills the output struct */ if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_SUPPATTR)) { p_fsalattr_out->supported_attributes = supp_attr; } if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_TYPE)) { p_fsalattr_out->type = posix2fsal_type(p_buffstat->st_mode); } if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_SIZE)) { p_fsalattr_out->filesize = p_buffstat->st_size; } if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_FSID)) { p_fsalattr_out->fsid = posix2fsal_fsid(p_buffstat->st_dev); } if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_ACL)) { p_fsalattr_out->acl = NULL; } if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_FILEID)) { p_fsalattr_out->fileid = (fsal_u64_t) (p_buffstat->st_ino); } if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_MODE)) { p_fsalattr_out->mode = unix2fsal_mode(p_buffstat->st_mode); } if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_NUMLINKS)) { p_fsalattr_out->numlinks = p_buffstat->st_nlink; } if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_OWNER)) { p_fsalattr_out->owner = p_buffstat->st_uid; } if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_GROUP)) { p_fsalattr_out->group = p_buffstat->st_gid; } if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_ATIME)) { p_fsalattr_out->atime = posix2fsal_time(p_buffstat->st_atime); } if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_CTIME)) { p_fsalattr_out->ctime = posix2fsal_time(p_buffstat->st_ctime); } if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_MTIME)) { p_fsalattr_out->mtime = posix2fsal_time(p_buffstat->st_mtime); } if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_CHGTIME)) { p_fsalattr_out->chgtime = posix2fsal_time(MAX_2(p_buffstat->st_mtime, p_buffstat->st_ctime)); p_fsalattr_out->change = (uint64_t) p_fsalattr_out->chgtime.seconds ; } if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_SPACEUSED)) { p_fsalattr_out->spaceused = p_buffstat->st_blocks * S_BLKSIZE; } if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_RAWDEV)) { p_fsalattr_out->rawdev = posix2fsal_devt(p_buffstat->st_rdev); /* XXX: convert ? */ } /* mounted_on_fileid : if ( FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_MOUNTFILEID )){ p_fsalattr_out->mounted_on_fileid = hpss2fsal_64( p_hpss_attr_in->FilesetRootId ); } */ /* everything has been copied ! */ ReturnCode(ERR_FSAL_NO_ERROR, 0); }
/* convert ghostfs attributes to FSAL attributes */ int ghost2fsal_attrs(fsal_attrib_list_t * p_fsal_attrs, GHOSTFS_Attrs_t * p_ghost_attrs) { /* Fills the output struct */ if(FSAL_TEST_MASK(p_fsal_attrs->asked_attributes, FSAL_ATTR_SUPPATTR)) { p_fsal_attrs->supported_attributes = GHOSTFS_SUPPORTED_ATTRIBUTES; } if(FSAL_TEST_MASK(p_fsal_attrs->asked_attributes, FSAL_ATTR_TYPE)) { p_fsal_attrs->type = ghost2fsal_type(p_ghost_attrs->type); } if(FSAL_TEST_MASK(p_fsal_attrs->asked_attributes, FSAL_ATTR_SIZE)) { p_fsal_attrs->filesize = p_ghost_attrs->size; } if(FSAL_TEST_MASK(p_fsal_attrs->asked_attributes, FSAL_ATTR_FSID)) { /* constant FSID for ghostFS */ p_fsal_attrs->fsid.major = 1; p_fsal_attrs->fsid.minor = 1; } if(FSAL_TEST_MASK(p_fsal_attrs->asked_attributes, FSAL_ATTR_FILEID)) { p_fsal_attrs->fileid = (unsigned int)p_ghost_attrs->inode; } if(FSAL_TEST_MASK(p_fsal_attrs->asked_attributes, FSAL_ATTR_MODE)) { p_fsal_attrs->mode = ghost2fsal_mode(p_ghost_attrs->mode); } if(FSAL_TEST_MASK(p_fsal_attrs->asked_attributes, FSAL_ATTR_NUMLINKS)) { p_fsal_attrs->numlinks = p_ghost_attrs->linkcount; } if(FSAL_TEST_MASK(p_fsal_attrs->asked_attributes, FSAL_ATTR_OWNER)) { p_fsal_attrs->owner = (fsal_uid_t) p_ghost_attrs->uid; } if(FSAL_TEST_MASK(p_fsal_attrs->asked_attributes, FSAL_ATTR_GROUP)) { p_fsal_attrs->group = (fsal_gid_t) p_ghost_attrs->gid; } if(FSAL_TEST_MASK(p_fsal_attrs->asked_attributes, FSAL_ATTR_ATIME)) { p_fsal_attrs->atime.seconds = p_ghost_attrs->atime; p_fsal_attrs->atime.nseconds = 0; } if(FSAL_TEST_MASK(p_fsal_attrs->asked_attributes, FSAL_ATTR_CTIME)) { p_fsal_attrs->ctime.seconds = p_ghost_attrs->ctime; p_fsal_attrs->ctime.nseconds = 0; } if(FSAL_TEST_MASK(p_fsal_attrs->asked_attributes, FSAL_ATTR_MTIME)) { p_fsal_attrs->mtime.seconds = p_ghost_attrs->mtime; p_fsal_attrs->mtime.nseconds = 0; } if(FSAL_TEST_MASK(p_fsal_attrs->asked_attributes, FSAL_ATTR_CREATION)) { p_fsal_attrs->creation.seconds = p_ghost_attrs->creationTime; p_fsal_attrs->creation.nseconds = 0; } if(FSAL_TEST_MASK(p_fsal_attrs->asked_attributes, FSAL_ATTR_SPACEUSED)) { p_fsal_attrs->spaceused = p_ghost_attrs->size; } if(FSAL_TEST_MASK(p_fsal_attrs->asked_attributes, FSAL_ATTR_CHGTIME)) { p_fsal_attrs->chgtime.seconds = p_ghost_attrs->ctime; p_fsal_attrs->chgtime.nseconds = 0; p_fsal_attrs->change = (uint64_t) p_fsal_attrs->chgtime.seconds; } return 0; }
/** * GPFSFSAL_setattrs: * Set attributes for the object specified by its filehandle. * * \param filehandle (input): * The handle of the object to get parameters. * \param cred (input): * Authentication context for the operation (user,...). * \param attrib_set (mandatory input): * The attributes to be set for the object. * It defines the attributes that the caller * wants to set and their values. * \param object_attributes (optionnal input/output): * The post operation attributes for the object. * As input, it defines the attributes that the caller * wants to retrieve (by positioning flags into this structure) * and the output is built considering this input * (it fills the structure according to the flags it contains). * May be NULL. * * \return Major error codes : * - ERR_FSAL_NO_ERROR (no error) * - Another error code if an error occured. */ fsal_status_t GPFSFSAL_setattrs(fsal_handle_t * p_filehandle, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_attrib_list_t * p_attrib_set, /* IN */ fsal_attrib_list_t * p_object_attributes /* [ IN/OUT ] */ ) { unsigned int i; fsal_status_t status; /* Buffer that will be passed to gpfs_ganesha API. */ gpfsfsal_xstat_t buffxstat; /* Indicate if stat or acl or both should be changed. */ int attr_valid = 0; /* Indiate which attribute in stat should be changed. */ int attr_changed = 0; fsal_accessflags_t access_mask = 0; fsal_attrib_list_t wanted_attrs, current_attrs; /* sanity checks. * note : object_attributes is optional. */ if(!p_filehandle || !p_context || !p_attrib_set) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_setattrs); /* local copy of attributes */ wanted_attrs = *p_attrib_set; /* It does not make sense to setattr on a symlink */ /* if(p_filehandle->type == DT_LNK) return fsal_internal_setattrs_symlink(p_filehandle, p_context, p_attrib_set, p_object_attributes); */ /* First, check that FSAL attributes changes are allowed. */ /* Is it allowed to change times ? */ if(!global_fs_info.cansettime) { if(wanted_attrs.asked_attributes & (FSAL_ATTR_ATIME | FSAL_ATTR_CREATION | FSAL_ATTR_CTIME | FSAL_ATTR_MTIME)) { /* handled as an unsettable attribute. */ Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_setattrs); } } /* apply umask, if mode attribute is to be changed */ if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_MODE)) { wanted_attrs.mode &= (~global_fs_info.umask); } /* get current attributes */ current_attrs.asked_attributes = GPFS_SUPPORTED_ATTRIBUTES; status = GPFSFSAL_getattrs(p_filehandle, p_context, ¤t_attrs); if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_object_attributes->asked_attributes); FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); ReturnStatus(status, INDEX_FSAL_setattrs); } /*********** * CHMOD * ***********/ if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_MODE)) { /* The POSIX chmod call don't affect the symlink object, but * the entry it points to. So we must ignore it. */ if(current_attrs.type != FSAL_TYPE_LNK) { #ifdef _USE_NFS4_ACL if(current_attrs.acl) { /* Check permission using ACL. */ access_mask = FSAL_MODE_MASK_SET(0) | /* Dummy. */ FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_ATTR); status = fsal_internal_testAccess(p_context, access_mask, NULL, ¤t_attrs); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_setattrs); } else { #endif /* For modifying mode, user must be root or the owner */ if((p_context->credential.user != 0) && (p_context->credential.user != current_attrs.owner)) { LogFullDebug(COMPONENT_FSAL, "Permission denied for CHMOD opeartion: current owner=%d, credential=%d", current_attrs.owner, p_context->credential.user); Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs); } #ifdef _USE_NFS4_ACL } #endif attr_valid |= XATTR_STAT; attr_changed |= XATTR_MODE; /* Fill wanted mode. */ buffxstat.buffstat.st_mode = fsal2unix_mode(wanted_attrs.mode); LogDebug(COMPONENT_FSAL, "current mode = %o, new mode = %o", fsal2unix_mode(current_attrs.mode), buffxstat.buffstat.st_mode); } } /*********** * CHOWN * ***********/ /* Only root can change uid and A normal user must be in the group he wants to set */ if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_OWNER)) { #ifdef _USE_NFS4_ACL if(current_attrs.acl) { /* Check permission using ACL. */ access_mask = FSAL_MODE_MASK_SET(0) | /* Dummy. */ FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_OWNER); status = fsal_internal_testAccess(p_context, access_mask, NULL, ¤t_attrs); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_setattrs); } else { #endif /* For modifying owner, user must be root or current owner==wanted==client */ if((p_context->credential.user != 0) && ((p_context->credential.user != current_attrs.owner) || (p_context->credential.user != wanted_attrs.owner))) { LogFullDebug(COMPONENT_FSAL, "Permission denied for CHOWN opeartion: current owner=%d, credential=%d, new owner=%d", current_attrs.owner, p_context->credential.user, wanted_attrs.owner); Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs); } #ifdef _USE_NFS4_ACL } #endif } if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_GROUP)) { #ifdef _USE_NFS4_ACL if(current_attrs.acl) { /* Check permission using ACL. */ access_mask = FSAL_MODE_MASK_SET(0) | /* Dummy. */ FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_OWNER); status = fsal_internal_testAccess(p_context, access_mask, NULL, ¤t_attrs); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_setattrs); } else { #endif /* For modifying group, user must be root or current owner */ if((p_context->credential.user != 0) && (p_context->credential.user != current_attrs.owner)) { Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs); } int in_grp = 0; /* set in_grp */ if(p_context->credential.group == wanted_attrs.group) in_grp = 1; else for(i = 0; i < p_context->credential.nbgroups; i++) { if((in_grp = (wanted_attrs.group == p_context->credential.alt_groups[i]))) break; } /* it must also be in target group */ if(p_context->credential.user != 0 && !in_grp) { LogFullDebug(COMPONENT_FSAL, "Permission denied for CHOWN operation: current group=%d, credential=%d, new group=%d", current_attrs.group, p_context->credential.group, wanted_attrs.group); Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs); } #ifdef _USE_NFS4_ACL } #endif } if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_OWNER | FSAL_ATTR_GROUP)) { /* LogFullDebug(COMPONENT_FSAL, "Performing chown(%s, %d,%d)", fsalpath.path, FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_OWNER) ? (int)wanted_attrs.owner : -1, FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_GROUP) ? (int)wanted_attrs.group : -1);*/ attr_valid |= XATTR_STAT; attr_changed |= FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_OWNER) ? XATTR_UID : XATTR_GID; /* Fill wanted owner. */ if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_OWNER)) { buffxstat.buffstat.st_uid = (int)wanted_attrs.owner; LogDebug(COMPONENT_FSAL, "current uid = %d, new uid = %d", current_attrs.owner, buffxstat.buffstat.st_uid); } /* Fill wanted group. */ if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_GROUP)) { buffxstat.buffstat.st_gid = (int)wanted_attrs.group; LogDebug(COMPONENT_FSAL, "current gid = %d, new gid = %d", current_attrs.group, buffxstat.buffstat.st_gid); } } /*********** * UTIME * ***********/ /* user must be the owner or have read access to modify 'atime' */ access_mask = FSAL_MODE_MASK_SET(FSAL_R_OK) | FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_ATTR); if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_ATIME) && (p_context->credential.user != 0) && (p_context->credential.user != current_attrs.owner) && ((status = fsal_internal_testAccess(p_context, access_mask, NULL, ¤t_attrs)).major != ERR_FSAL_NO_ERROR)) { ReturnStatus(status, INDEX_FSAL_setattrs); } /* user must be the owner or have write access to modify 'mtime' */ access_mask = FSAL_MODE_MASK_SET(FSAL_W_OK) | FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_ATTR); if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_MTIME) && (p_context->credential.user != 0) && (p_context->credential.user != current_attrs.owner) && ((status = fsal_internal_testAccess(p_context, access_mask, NULL, ¤t_attrs)).major != ERR_FSAL_NO_ERROR)) { ReturnStatus(status, INDEX_FSAL_setattrs); } if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_ATIME | FSAL_ATTR_MTIME)) { attr_valid |= XATTR_STAT; /* Fill wanted atime. */ if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_ATIME)) { attr_changed |= XATTR_ATIME; buffxstat.buffstat.st_atime = (time_t) wanted_attrs.atime.seconds; LogDebug(COMPONENT_FSAL, "current atime = %lu, new atime = %lu", (unsigned long)current_attrs.atime.seconds, (unsigned long)buffxstat.buffstat.st_atime); } /* Fill wanted mtime. */ if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_MTIME)) { attr_changed |= XATTR_CTIME; buffxstat.buffstat.st_mtime = (time_t) wanted_attrs.mtime.seconds; LogDebug(COMPONENT_FSAL, "current mtime = %lu, new mtime = %lu", (unsigned long)current_attrs.mtime.seconds, (unsigned long)buffxstat.buffstat.st_mtime); } } #ifdef _USE_NFS4_ACL /*********** * ACL * ***********/ if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_ACL)) { /* Check permission to set ACL. */ access_mask = FSAL_MODE_MASK_SET(0) | /* Dummy */ FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_ACL); status = fsal_internal_testAccess(p_context, access_mask, NULL, ¤t_attrs); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_setattrs); if(wanted_attrs.acl) { attr_valid |= XATTR_ACL; LogDebug(COMPONENT_FSAL, "setattr acl = %p", wanted_attrs.acl); /* Convert FSAL ACL to GPFS NFS4 ACL and fill the buffer. */ status = fsal_acl_2_gpfs_acl(wanted_attrs.acl, &buffxstat); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_setattrs); } else { LogCrit(COMPONENT_FSAL, "setattr acl is NULL"); Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_setattrs); } } #endif /* _USE_NFS4_ACL */ /* If there is any change in stat or acl or both, send it down to file system. */ if((attr_valid == XATTR_STAT && attr_changed !=0) || attr_valid == XATTR_ACL) { status = fsal_set_xstat_by_handle(p_context, p_filehandle, attr_valid, attr_changed, &buffxstat); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_setattrs); } /* Optionaly fills output attributes. */ if(p_object_attributes) { status = GPFSFSAL_getattrs(p_filehandle, p_context, p_object_attributes); /* on error, we set a special bit in the mask. */ if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_object_attributes->asked_attributes); FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_setattrs); }
fsal_status_t posixstat64_2_fsal_attributes(struct stat *p_buffstat, struct attrlist *p_fsalattr_out) { /* sanity checks */ if (!p_buffstat || !p_fsalattr_out) return fsalstat(ERR_FSAL_FAULT, 0); /* Initialize ACL regardless of whether ACL was asked or not. * This is needed to make sure ACL attribute is initialized. */ p_fsalattr_out->acl = NULL; /* Fills the output struct */ if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_TYPE)) p_fsalattr_out->type = posix2fsal_type(p_buffstat->st_mode); if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_SIZE)) p_fsalattr_out->filesize = p_buffstat->st_size; if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_FSID)) p_fsalattr_out->fsid = posix2fsal_fsid(p_buffstat->st_dev); if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_ACL)) p_fsalattr_out->acl = NULL; if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_FILEID)) p_fsalattr_out->fileid = (uint64_t) (p_buffstat->st_ino); if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_MODE)) p_fsalattr_out->mode = unix2fsal_mode(p_buffstat->st_mode); if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_NUMLINKS)) p_fsalattr_out->numlinks = p_buffstat->st_nlink; if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_OWNER)) p_fsalattr_out->owner = p_buffstat->st_uid; if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_GROUP)) p_fsalattr_out->group = p_buffstat->st_gid; if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_ATIME)) { p_fsalattr_out->atime = posix2fsal_time(p_buffstat->st_atime, p_buffstat->st_atim.tv_nsec); } if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_CTIME)) { p_fsalattr_out->ctime = posix2fsal_time(p_buffstat->st_ctime, p_buffstat->st_ctim.tv_nsec); } if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_MTIME)) { p_fsalattr_out->mtime = posix2fsal_time(p_buffstat->st_mtime, p_buffstat->st_mtim.tv_nsec); } if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_CHGTIME)) { p_fsalattr_out->chgtime = posix2fsal_time(MAX (p_buffstat->st_mtime, p_buffstat->st_ctime), 0); p_fsalattr_out->change = (uint64_t) p_fsalattr_out->chgtime.tv_sec; } if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_SPACEUSED)) p_fsalattr_out->spaceused = p_buffstat->st_blocks * S_BLKSIZE; if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_RAWDEV)) p_fsalattr_out->rawdev = posix2fsal_devt(p_buffstat->st_rdev); /* everything has been copied ! */ return fsalstat(ERR_FSAL_NO_ERROR, 0); }
/** * * @brief Checks permissions on an entry for setattrs * * This function acquires the attribute lock on the supplied cache * entry then checks if the supplied credentials are sufficient to * perform the required setattrs. * * @param[in] entry The object to be checked * @param[in] attr Attributes to set/result of set * * @return CACHE_INODE_SUCCESS if operation is a success */ cache_inode_status_t cache_inode_check_setattr_perms(cache_entry_t *entry, struct attrlist *attr, bool is_open_write) { cache_inode_status_t status = CACHE_INODE_SUCCESS; fsal_accessflags_t access_check = 0; bool not_owner; char *note = ""; const struct user_cred *creds = op_ctx->creds; if (isDebug(COMPONENT_CACHE_INODE) || isDebug(COMPONENT_NFS_V4_ACL)) { char *setattr_size = ""; char *setattr_owner = ""; char *setattr_owner_group = ""; char *setattr_mode = ""; char *setattr_acl = ""; char *setattr_mtime = ""; char *setattr_atime = ""; if (FSAL_TEST_MASK(attr->mask, ATTR_SIZE)) setattr_size = " SIZE"; if (FSAL_TEST_MASK(attr->mask, ATTR_OWNER)) setattr_owner = " OWNER"; if (FSAL_TEST_MASK(attr->mask, ATTR_GROUP)) setattr_owner_group = " GROUP"; if (FSAL_TEST_MASK(attr->mask, ATTR_MODE)) setattr_mode = " MODE"; if (FSAL_TEST_MASK(attr->mask, ATTR_ACL)) setattr_acl = " ACL"; if (FSAL_TEST_MASK(attr->mask, ATTR_ATIME)) setattr_atime = " ATIME"; else if (FSAL_TEST_MASK(attr->mask, ATTR_ATIME_SERVER)) setattr_atime = " ATIME_SERVER"; if (FSAL_TEST_MASK(attr->mask, ATTR_MTIME)) setattr_mtime = " MTIME"; else if (FSAL_TEST_MASK(attr->mask, ATTR_MTIME_SERVER)) setattr_mtime = " MTIME_SERVER"; LogDebugCIA(COMPONENT_CACHE_INODE, COMPONENT_NFS_V4_ACL, "SETATTR %s%s%s%s%s%s%s", setattr_size, setattr_owner, setattr_owner_group, setattr_mode, setattr_acl, setattr_mtime, setattr_atime); } /* Shortcut, if current user is root, then we can just bail out with * success. */ if (creds->caller_uid == 0) { note = " (Ok for root user)"; goto out; } not_owner = (creds->caller_uid != entry->obj_handle->attributes.owner); /* Only ownership change need to be checked for owner */ if (FSAL_TEST_MASK(attr->mask, ATTR_OWNER)) { /* non-root is only allowed to "take ownership of file" */ if (attr->owner != creds->caller_uid) { status = CACHE_INODE_FSAL_EPERM; note = " (new OWNER was not user)"; goto out; } /* Owner of file will always be able to "change" the owner to * himself. */ if (not_owner) { access_check |= FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_OWNER); LogDebugCIA(COMPONENT_CACHE_INODE, COMPONENT_NFS_V4_ACL, "Change OWNER requires FSAL_ACE_PERM_WRITE_OWNER"); } } if (FSAL_TEST_MASK(attr->mask, ATTR_GROUP)) { /* non-root is only allowed to change group_owner to a group * user is a member of. */ int not_in_group = not_in_group_list(attr->group); if (not_in_group) { status = CACHE_INODE_FSAL_EPERM; note = " (user is not member of new GROUP)"; goto out; } /* Owner is always allowed to change the group_owner of a file * to a group they are a member of. */ if (not_owner) { access_check |= FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_OWNER); LogDebugCIA(COMPONENT_CACHE_INODE, COMPONENT_NFS_V4_ACL, "Change GROUP requires FSAL_ACE_PERM_WRITE_OWNER"); } } /* Any attribute after this is always changeable by the owner. * And the above attributes have already been validated as a valid * change for the file owner to make. Note that the owner may be * setting ATTR_OWNER but at this point it MUST be to himself, and * thus is no-op and does not need FSAL_ACE_PERM_WRITE_OWNER. */ if (!not_owner) { note = " (Ok for owner)"; goto out; } if (FSAL_TEST_MASK(attr->mask, ATTR_MODE) || FSAL_TEST_MASK(attr->mask, ATTR_ACL)) { /* Changing mode or ACL requires ACE4_WRITE_ACL */ access_check |= FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_ACL); LogDebugCIA(COMPONENT_CACHE_INODE, COMPONENT_NFS_V4_ACL, "Change MODE or ACL requires FSAL_ACE_PERM_WRITE_ACL"); } if (FSAL_TEST_MASK(attr->mask, ATTR_SIZE) && !is_open_write) { /* Changing size requires owner or write permission */ /** @todo: does FSAL_ACE_PERM_APPEND_DATA allow enlarging the file? */ access_check |= FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_DATA); LogDebugCIA(COMPONENT_CACHE_INODE, COMPONENT_NFS_V4_ACL, "Change SIZE requires FSAL_ACE_PERM_WRITE_DATA"); } /* Check if just setting atime and mtime to "now" */ if ((FSAL_TEST_MASK(attr->mask, ATTR_MTIME_SERVER) || FSAL_TEST_MASK(attr->mask, ATTR_ATIME_SERVER)) && !FSAL_TEST_MASK(attr->mask, ATTR_MTIME) && !FSAL_TEST_MASK(attr->mask, ATTR_ATIME)) { /* If either atime and/or mtime are set to "now" then need only * have write permission. * * Technically, client should not send atime updates, but if * they really do, we'll let them to make the perm check a bit * simpler. */ access_check |= FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_DATA); LogDebugCIA(COMPONENT_CACHE_INODE, COMPONENT_NFS_V4_ACL, "Change ATIME and MTIME to NOW requires FSAL_ACE_PERM_WRITE_DATA"); } else if (FSAL_TEST_MASK(attr->mask, ATTR_MTIME_SERVER) || FSAL_TEST_MASK(attr->mask, ATTR_ATIME_SERVER) || FSAL_TEST_MASK(attr->mask, ATTR_MTIME) || FSAL_TEST_MASK(attr->mask, ATTR_ATIME)) { /* Any other changes to atime or mtime require owner, root, or * ACES4_WRITE_ATTRIBUTES. * * NOTE: we explicity do NOT check for update of atime only to * "now". Section 10.6 of both RFC 3530 and RFC 5661 document * the reasons clients should not do atime updates. */ access_check |= FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_ATTR); LogDebugCIA(COMPONENT_CACHE_INODE, COMPONENT_NFS_V4_ACL, "Change ATIME and/or MTIME requires FSAL_ACE_PERM_WRITE_ATTR"); } if (isDebug(COMPONENT_CACHE_INODE) || isDebug(COMPONENT_NFS_V4_ACL)) { char *need_write_owner = ""; char *need_write_acl = ""; char *need_write_data = ""; char *need_write_attr = ""; if (access_check & FSAL_ACE_PERM_WRITE_OWNER) need_write_owner = " WRITE_OWNER"; if (access_check & FSAL_ACE_PERM_WRITE_ACL) need_write_acl = " WRITE_ACL"; if (access_check & FSAL_ACE_PERM_WRITE_DATA) need_write_data = " WRITE_DATA"; if (access_check & FSAL_ACE_PERM_WRITE_ATTR) need_write_attr = " WRITE_ATTR"; LogDebugCIA(COMPONENT_CACHE_INODE, COMPONENT_NFS_V4_ACL, "Requires %s%s%s%s", need_write_owner, need_write_acl, need_write_data, need_write_attr); } if (entry->obj_handle->attributes.acl) { status = cache_inode_access_no_mutex(entry, access_check); note = " (checked ACL)"; goto out; } if (access_check != FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_DATA)) { /* Without an ACL, this user is not allowed some operation */ status = CACHE_INODE_FSAL_EPERM; note = " (no ACL to check)"; goto out; } status = cache_inode_access_no_mutex(entry, FSAL_W_OK); note = " (checked mode)"; out: LogDebugCIA(COMPONENT_CACHE_INODE, COMPONENT_NFS_V4_ACL, "Access check returned %s%s", cache_inode_err_str(status), note); return status; }
/** * @brief Set the attributes for a file. * * This function sets the attributes of a file, both in the cache and * in the underlying filesystem. * * @param[in] entry Entry whose attributes are to be set * @param[in,out] attr Attributes to set/result of set * * @retval CACHE_INODE_SUCCESS if operation is a success */ cache_inode_status_t cache_inode_setattr(cache_entry_t *entry, struct attrlist *attr, bool is_open_write) { struct fsal_obj_handle *obj_handle = entry->obj_handle; fsal_status_t fsal_status = { 0, 0 }; fsal_acl_t *saved_acl = NULL; fsal_acl_status_t acl_status = 0; cache_inode_status_t status = CACHE_INODE_SUCCESS; uint64_t before; const struct user_cred *creds = op_ctx->creds; /* True if we have taken the content lock on 'entry' */ bool content_locked = false; if ((attr->mask & (ATTR_SIZE | ATTR4_SPACE_RESERVED)) && (entry->type != REGULAR_FILE)) { LogWarn(COMPONENT_CACHE_INODE, "Attempt to truncate non-regular file: type=%d", entry->type); status = CACHE_INODE_BAD_TYPE; goto out; } /* Is it allowed to change times ? */ if (!op_ctx->fsal_export->exp_ops.fs_supports(op_ctx->fsal_export, fso_cansettime) && (FSAL_TEST_MASK (attr->mask, (ATTR_ATIME | ATTR_CREATION | ATTR_CTIME | ATTR_MTIME)))) { status = CACHE_INODE_INVALID_ARGUMENT; goto out; } /* Get wrlock on attr_lock and verify attrs */ status = cache_inode_lock_trust_attrs(entry, true); if (status != CACHE_INODE_SUCCESS) return status; /* Do permission checks */ status = cache_inode_check_setattr_perms(entry, attr, is_open_write); if (status != CACHE_INODE_SUCCESS) goto unlock; if (attr->mask & (ATTR_SIZE | ATTR4_SPACE_RESERVED)) { PTHREAD_RWLOCK_wrlock(&entry->content_lock); content_locked = true; } /* Test for the following condition from chown(2): * * When the owner or group of an executable file are changed by an * unprivileged user the S_ISUID and S_ISGID mode bits are cleared. * POSIX does not specify whether this also should happen when * root does the chown(); the Linux behavior depends on the kernel * version. In case of a non-group-executable file (i.e., one for * which the S_IXGRP bit is not set) the S_ISGID bit indicates * mandatory locking, and is not cleared by a chown(). * */ if (creds->caller_uid != 0 && (FSAL_TEST_MASK(attr->mask, ATTR_OWNER) || FSAL_TEST_MASK(attr->mask, ATTR_GROUP)) && ((entry->obj_handle->attrs->mode & (S_IXOTH | S_IXUSR | S_IXGRP)) != 0) && ((entry->obj_handle->attrs->mode & (S_ISUID | S_ISGID)) != 0)) { /* Non-priviledged user changing ownership on an executable * file with S_ISUID or S_ISGID bit set, need to be cleared. */ if (!FSAL_TEST_MASK(attr->mask, ATTR_MODE)) { /* Mode wasn't being set, so set it now, start with * the current attributes. */ attr->mode = entry->obj_handle->attrs->mode; FSAL_SET_MASK(attr->mask, ATTR_MODE); } /* Don't clear S_ISGID if the file isn't group executable. * In that case, S_ISGID indicates mandatory locking and * is not cleared by chown. */ if ((entry->obj_handle->attrs->mode & S_IXGRP) != 0) attr->mode &= ~S_ISGID; /* Clear S_ISUID. */ attr->mode &= ~S_ISUID; } /* Test for the following condition from chmod(2): * * If the calling process is not privileged (Linux: does not have * the CAP_FSETID capability), and the group of the file does not * match the effective group ID of the process or one of its * supplementary group IDs, the S_ISGID bit will be turned off, * but this will not cause an error to be returned. * * We test the actual mode being set before testing for group * membership since that is a bit more expensive. */ if (creds->caller_uid != 0 && FSAL_TEST_MASK(attr->mask, ATTR_MODE) && (attr->mode & S_ISGID) != 0 && not_in_group_list(entry->obj_handle->attrs->group)) { /* Clear S_ISGID */ attr->mode &= ~S_ISGID; } saved_acl = entry->obj_handle->attrs->acl; before = entry->obj_handle->attrs->change; fsal_status = obj_handle->obj_ops.setattrs(obj_handle, attr); if (FSAL_IS_ERROR(fsal_status)) { status = cache_inode_error_convert(fsal_status); if (fsal_status.major == ERR_FSAL_STALE) { LogEvent(COMPONENT_CACHE_INODE, "FSAL returned STALE from setattrs"); cache_inode_kill_entry(entry); } goto unlock; } fsal_status = obj_handle->obj_ops.getattrs(obj_handle); *attr = *entry->obj_handle->attrs; if (FSAL_IS_ERROR(fsal_status)) { status = cache_inode_error_convert(fsal_status); if (fsal_status.major == ERR_FSAL_STALE) { LogEvent(COMPONENT_CACHE_INODE, "FSAL returned STALE from getattrs"); cache_inode_kill_entry(entry); } goto unlock; } if (before == entry->obj_handle->attrs->change) entry->obj_handle->attrs->change++; /* Decrement refcount on saved ACL */ nfs4_acl_release_entry(saved_acl, &acl_status); if (acl_status != NFS_V4_ACL_SUCCESS) LogCrit(COMPONENT_CACHE_INODE, "Failed to release old acl, status=%d", acl_status); cache_inode_fixup_md(entry); /* Copy the complete set of new attributes out. */ *attr = *entry->obj_handle->attrs; status = CACHE_INODE_SUCCESS; unlock: if (content_locked) PTHREAD_RWLOCK_unlock(&entry->content_lock); PTHREAD_RWLOCK_unlock(&entry->attr_lock); out: return status; }
/** * * cache_inode_get: Gets an entry by using its fsdata as a key and caches it if needed. * * Gets an entry by using its fsdata as a key and caches it if needed. * ASSUMPTION: DIR_CONT entries are always garbabbaged before their related DIR_BEGINNG * * @param fsdata [IN] file system data * @param pattr [OUT] pointer to the attributes for the result. * @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. * * @return the pointer to the entry is successfull, NULL otherwise. * */ cache_entry_t *cache_inode_get(cache_inode_fsal_data_t * pfsdata, fsal_attrib_list_t * pattr, hash_table_t * ht, cache_inode_client_t * pclient, fsal_op_context_t * pcontext, cache_inode_status_t * pstatus) { hash_buffer_t key, value; cache_entry_t *pentry = NULL; fsal_status_t fsal_status; cache_inode_create_arg_t create_arg; cache_inode_file_type_t type; int hrc = 0; fsal_attrib_list_t fsal_attributes; cache_inode_fsal_data_t *ppoolfsdata = NULL; /* Set the return default to CACHE_INODE_SUCCESS */ *pstatus = CACHE_INODE_SUCCESS; /* stats */ pclient->stat.nb_call_total += 1; pclient->stat.func_stats.nb_call[CACHE_INODE_GET] += 1; /* Turn the input to a hash key */ if(cache_inode_fsaldata_2_key(&key, pfsdata, pclient)) { *pstatus = CACHE_INODE_UNAPPROPRIATED_KEY; /* stats */ pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_GET] += 1; ppoolfsdata = (cache_inode_fsal_data_t *) key.pdata; RELEASE_PREALLOC(ppoolfsdata, pclient->pool_key, next_alloc); return NULL; } switch (hrc = HashTable_Get(ht, &key, &value)) { case HASHTABLE_SUCCESS: /* Entry exists in the cache and was found */ pentry = (cache_entry_t *) value.pdata; /* return attributes additionally */ cache_inode_get_attributes(pentry, pattr); break; case HASHTABLE_ERROR_NO_SUCH_KEY: /* Cache miss, allocate a new entry */ /* If we ask for a dir cont (in this case pfsdata.cookie != FSAL_DIR_BEGINNING, we have * a client who performs a readdir in the middle of a directory, when the direcctories * have been garbbage. we must search for the DIR_BEGIN related to this DIR_CONT */ if(pfsdata->cookie != DIR_START) { /* added for sanity check */ LogDebug(COMPONENT_CACHE_INODE_GC, "=======> Pb cache_inode_get: line %u pfsdata->cookie != DIR_START (=%u) on object whose type is %u", __LINE__, pfsdata->cookie, cache_inode_fsal_type_convert(fsal_attributes.type)); pfsdata->cookie = DIR_START; /* Free this key */ cache_inode_release_fsaldata_key(&key, pclient); /* redo the call */ return cache_inode_get(pfsdata, pattr, ht, pclient, pcontext, pstatus); } /* First, call FSAL to know what the object is */ fsal_attributes.asked_attributes = pclient->attrmask; fsal_status = FSAL_getattrs(&pfsdata->handle, pcontext, &fsal_attributes); if(FSAL_IS_ERROR(fsal_status)) { *pstatus = cache_inode_error_convert(fsal_status); LogDebug(COMPONENT_CACHE_INODE_GC, "cache_inode_get: line %u cache_inode_status=%u fsal_status=%u,%u ", __LINE__, *pstatus, fsal_status.major, fsal_status.minor); if(fsal_status.major == ERR_FSAL_STALE) { char handle_str[256]; snprintHandle(handle_str, 256, &pfsdata->handle); LogEvent(COMPONENT_CACHE_INODE_GC,"cache_inode_get: Stale FSAL File Handle %s", handle_str); *pstatus = CACHE_INODE_FSAL_ESTALE; } /* stats */ pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_GET] += 1; /* Free this key */ cache_inode_release_fsaldata_key(&key, pclient); return NULL; } /* The type has to be set in the attributes */ if(!FSAL_TEST_MASK(fsal_attributes.supported_attributes, FSAL_ATTR_TYPE)) { *pstatus = CACHE_INODE_FSAL_ERROR; /* stats */ pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_GET] += 1; /* Free this key */ cache_inode_release_fsaldata_key(&key, pclient); return NULL; } /* Get the cache_inode file type */ type = cache_inode_fsal_type_convert(fsal_attributes.type); if(type == SYMBOLIC_LINK) { FSAL_CLEAR_MASK(fsal_attributes.asked_attributes); FSAL_SET_MASK(fsal_attributes.asked_attributes, pclient->attrmask); fsal_status = FSAL_readlink(&pfsdata->handle, pcontext, &create_arg.link_content, &fsal_attributes); if(FSAL_IS_ERROR(fsal_status)) { *pstatus = cache_inode_error_convert(fsal_status); /* stats */ pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_GET] += 1; /* Free this key */ cache_inode_release_fsaldata_key(&key, pclient); if(fsal_status.major == ERR_FSAL_STALE) { cache_inode_status_t kill_status; LogDebug(COMPONENT_CACHE_INODE_GC, "cache_inode_get: Stale FSAL File Handle detected for pentry = %p", pentry); if(cache_inode_kill_entry(pentry, ht, pclient, &kill_status) != CACHE_INODE_SUCCESS) LogCrit(COMPONENT_CACHE_INODE_GC,"cache_inode_get: Could not kill entry %p, status = %u", pentry, kill_status); *pstatus = CACHE_INODE_FSAL_ESTALE; } return NULL; } } /* Add the entry to the cache */ if((pentry = cache_inode_new_entry(pfsdata, &fsal_attributes, type, &create_arg, NULL, /* never used to add a new DIR_CONTINUE within the scope of this function */ ht, pclient, pcontext, FALSE, /* This is a population, not a creation */ pstatus)) == NULL) { /* stats */ pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_GET] += 1; /* Free this key */ cache_inode_release_fsaldata_key(&key, pclient); return NULL; } /* Set the returned attributes */ *pattr = fsal_attributes; /* Now, exit the switch/case and returns */ break; default: /* This should not happened */ *pstatus = CACHE_INODE_INVALID_ARGUMENT; /* stats */ pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_GET] += 1; /* Free this key */ cache_inode_release_fsaldata_key(&key, pclient); return NULL; break; } *pstatus = CACHE_INODE_SUCCESS; /* valid the found entry, if this is not feasable, returns nothing to the client */ P_w(&pentry->lock); if((*pstatus = cache_inode_valid(pentry, CACHE_INODE_OP_GET, pclient)) != CACHE_INODE_SUCCESS) { V_w(&pentry->lock); pentry = NULL; } V_w(&pentry->lock); /* stats */ pclient->stat.func_stats.nb_success[CACHE_INODE_GET] += 1; /* Free this key */ cache_inode_release_fsaldata_key(&key, pclient); return pentry; } /* cache_inode_get */
/** * * cache_inode_getattr: Gets the attributes for a cached entry. * * Gets the attributes for a cached entry. The FSAL attributes are kept in a structure when the entry * is added to the cache. * * @param pentry [IN] entry to be managed. * @param pattr [OUT] pointer to the results * @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. * * @return CACHE_INODE_SUCCESS if operation is a success \n * @return CACHE_INODE_LRU_ERROR if allocation error occured when validating the entry * */ cache_inode_status_t cache_inode_getattr(cache_entry_t * pentry, fsal_attrib_list_t * pattr, hash_table_t * ht, /* Unused, kept for protototype's homogeneity */ cache_inode_client_t * pclient, fsal_op_context_t * pcontext, cache_inode_status_t * pstatus) { cache_inode_status_t status; fsal_handle_t *pfsal_handle = NULL; fsal_status_t fsal_status; /* sanity check */ if(pentry == NULL || pattr == NULL || ht == NULL || pclient == NULL || pcontext == NULL) { *pstatus = CACHE_INODE_INVALID_ARGUMENT; LogDebug(COMPONENT_CACHE_INODE, "cache_inode_getattr: returning CACHE_INODE_INVALID_ARGUMENT because of bad arg"); return *pstatus; } /* Set the return default to CACHE_INODE_SUCCESS */ *pstatus = CACHE_INODE_SUCCESS; /* stats */ pclient->stat.nb_call_total += 1; inc_func_call(pclient, CACHE_INODE_GETATTR); /* Lock the entry */ P_w(&pentry->lock); status = cache_inode_renew_entry(pentry, pattr, ht, pclient, pcontext, pstatus); if(status != CACHE_INODE_SUCCESS) { V_w(&pentry->lock); inc_func_err_retryable(pclient, CACHE_INODE_GETATTR); LogFullDebug(COMPONENT_CACHE_INODE, "cache_inode_getattr: returning %d(%s) from cache_inode_renew_entry", *pstatus, cache_inode_err_str(*pstatus)); return *pstatus; } /* RW Lock goes for writer to reader */ rw_lock_downgrade(&pentry->lock); cache_inode_get_attributes(pentry, pattr); if(FSAL_TEST_MASK(pattr->asked_attributes, FSAL_ATTR_RDATTR_ERR)) { switch (pentry->internal_md.type) { case REGULAR_FILE: pfsal_handle = &pentry->object.file.handle; break; case SYMBOLIC_LINK: assert(pentry->object.symlink); pfsal_handle = &pentry->object.symlink->handle; break; case DIRECTORY: pfsal_handle = &pentry->object.dir.handle; break; case SOCKET_FILE: case FIFO_FILE: case BLOCK_FILE: case CHARACTER_FILE: pfsal_handle = &pentry->object.special_obj.handle; break; case FS_JUNCTION: case UNASSIGNED: case RECYCLED: *pstatus = CACHE_INODE_INVALID_ARGUMENT; LogFullDebug(COMPONENT_CACHE_INODE, "cache_inode_getattr: returning %d(%s) from cache_inode_renew_entry - unexpected md_type", *pstatus, cache_inode_err_str(*pstatus)); return *pstatus; } /* * An error occured when trying to get * the attributes, they have to be renewed */ #ifdef _USE_MFSL fsal_status = FSAL_getattrs_descriptor(&(cache_inode_fd(pentry)->fsal_file), pfsal_handle, pcontext, pattr); #else fsal_status = FSAL_getattrs_descriptor(cache_inode_fd(pentry), pfsal_handle, pcontext, pattr); #endif if(FSAL_IS_ERROR(fsal_status)) { *pstatus = cache_inode_error_convert(fsal_status); V_r(&pentry->lock); if(fsal_status.major == ERR_FSAL_STALE) { cache_inode_status_t kill_status; LogEvent(COMPONENT_CACHE_INODE, "cache_inode_getattr: Stale FSAL File Handle detected for pentry = %p", pentry); /* Locked flag is set to true to show entry has a read lock */ cache_inode_kill_entry( pentry, WT_LOCK, ht, pclient, &kill_status); if(kill_status != CACHE_INODE_SUCCESS) LogCrit(COMPONENT_CACHE_INODE, "cache_inode_getattr: Could not kill entry %p, status = %u", pentry, kill_status); *pstatus = CACHE_INODE_FSAL_ESTALE; } /* stat */ inc_func_err_unrecover(pclient, CACHE_INODE_GETATTR); LogDebug(COMPONENT_CACHE_INODE, "cache_inode_getattr: returning %d(%s) from FSAL_getattrs_descriptor", *pstatus, cache_inode_err_str(*pstatus)); return *pstatus; } /* Set the new attributes */ cache_inode_set_attributes(pentry, pattr); } *pstatus = cache_inode_valid(pentry, CACHE_INODE_OP_GET, pclient); V_r(&pentry->lock); /* stat */ if(*pstatus != CACHE_INODE_SUCCESS) inc_func_err_retryable(pclient, CACHE_INODE_GETATTR); else inc_func_success(pclient, CACHE_INODE_GETATTR); #ifdef _USE_NFS4_ACL if(isDebug(COMPONENT_NFS_V4_ACL)) { LogDebug(COMPONENT_CACHE_INODE, "cache_inode_getattr: pentry = %p, acl = %p", pentry, pattr->acl); if(pattr->acl) { fsal_ace_t *pace; for(pace = pattr->acl->aces; pace < pattr->acl->aces + pattr->acl->naces; pace++) { LogDebug(COMPONENT_CACHE_INODE, "cache_inode_getattr: 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)); } } } #endif /* _USE_NFS4_ACL */ LogFullDebug(COMPONENT_CACHE_INODE, "cache_inode_getattr: returning %d(%s) from cache_inode_valid", *pstatus, cache_inode_err_str(*pstatus)); return *pstatus; }
/** * VFSFSAL_setattrs: * Set attributes for the object specified by its filehandle. * * \param filehandle (input): * The handle of the object to get parameters. * \param cred (input): * Authentication context for the operation (user,...). * \param attrib_set (mandatory input): * The attributes to be set for the object. * It defines the attributes that the caller * wants to set and their values. * \param object_attributes (optionnal input/output): * The post operation attributes for the object. * As input, it defines the attributes that the caller * wants to retrieve (by positioning flags into this structure) * and the output is built considering this input * (it fills the structure according to the flags it contains). * May be NULL. * * \return Major error codes : * - ERR_FSAL_NO_ERROR (no error) * - Another error code if an error occured. */ fsal_status_t VFSFSAL_setattrs(fsal_handle_t * p_filehandle, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_attrib_list_t * p_attrib_set, /* IN */ fsal_attrib_list_t * p_object_attributes /* [ IN/OUT ] */ ) { vfsfsal_op_context_t * vfs_context = (vfsfsal_op_context_t *) p_context; int rc, errsv; unsigned int i; fsal_status_t status; fsal_attrib_list_t attrs; int fd; struct stat buffstat; /* sanity checks. * note : object_attributes is optional. */ if(!p_filehandle || !p_context || !p_attrib_set) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_setattrs); /* local copy of attributes */ attrs = *p_attrib_set; /* It does not make sense to setattr on a symlink */ /* if(p_filehandle->type == DT_LNK) return fsal_internal_setattrs_symlink(p_filehandle, p_context, p_attrib_set, p_object_attributes); */ /* First, check that FSAL attributes changes are allowed. */ /* Is it allowed to change times ? */ if(!global_fs_info.cansettime) { if(attrs.asked_attributes & (FSAL_ATTR_ATIME | FSAL_ATTR_CREATION | FSAL_ATTR_CTIME | FSAL_ATTR_MTIME)) { /* handled as an unsettable attribute. */ Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_setattrs); } } /* apply umask, if mode attribute is to be changed */ if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MODE)) { attrs.mode &= (~global_fs_info.umask); } TakeTokenFSCall(); status = fsal_internal_handle2fd(p_context, p_filehandle, &fd, O_RDONLY); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) { /* Symbolic link are handled here, they are to be opened as O_PATH */ if( status.minor == ELOOP ) { if(p_object_attributes) { status = VFSFSAL_getattrs(p_filehandle, p_context, p_object_attributes); /* on error, we set a special bit in the mask. */ if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_object_attributes->asked_attributes); FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_setattrs); } ReturnStatus( status, INDEX_FSAL_setattrs); } /* get current attributes */ TakeTokenFSCall(); rc = fstat(fd, &buffstat); errsv = errno; ReleaseTokenFSCall(); if(rc != 0) { close(fd); if(errsv == ENOENT) Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_setattrs); else Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_setattrs); } /*********** * CHMOD * ***********/ if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MODE)) { /* The POSIX chmod call don't affect the symlink object, but * the entry it points to. So we must ignore it. */ if(!S_ISLNK(buffstat.st_mode)) { /* For modifying mode, user must be root or the owner */ if((vfs_context->credential.user != 0) && (vfs_context->credential.user != buffstat.st_uid)) { LogFullDebug(COMPONENT_FSAL, "Permission denied for CHMOD opeartion: current owner=%d, credential=%d", buffstat.st_uid, vfs_context->credential.user); close(fd); Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs); } TakeTokenFSCall(); rc = fchmod(fd, fsal2unix_mode(attrs.mode)); errsv = errno; ReleaseTokenFSCall(); if(rc) { close(fd); Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_setattrs); } } } /*********** * CHOWN * ***********/ /* Only root can change uid and A normal user must be in the group he wants to set */ if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_OWNER)) { /* For modifying owner, user must be root or current owner==wanted==client */ if((vfs_context->credential.user != 0) && ((vfs_context->credential.user != buffstat.st_uid) || (vfs_context->credential.user != attrs.owner))) { LogFullDebug(COMPONENT_FSAL, "Permission denied for CHOWN opeartion: current owner=%d, credential=%d, new owner=%d", buffstat.st_uid, vfs_context->credential.user, attrs.owner); close(fd); Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs); } } if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_GROUP)) { /* For modifying group, user must be root or current owner */ if((vfs_context->credential.user != 0) && (vfs_context->credential.user != buffstat.st_uid)) { close(fd); Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs); } int in_grp = 0; /* set in_grp */ if(vfs_context->credential.group == attrs.group) in_grp = 1; else for(i = 0; i < vfs_context->credential.nbgroups; i++) { if((in_grp = (attrs.group == vfs_context->credential.alt_groups[i]))) break; } /* it must also be in target group */ if(vfs_context->credential.user != 0 && !in_grp) { LogFullDebug(COMPONENT_FSAL, "Permission denied for CHOWN operation: current group=%d, credential=%d, new group=%d", buffstat.st_gid, vfs_context->credential.group, attrs.group); close(fd); Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs); } } if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_OWNER | FSAL_ATTR_GROUP)) { /* LogFullDebug(COMPONENT_FSAL, "Performing chown(%s, %d,%d)", fsalpath.path, FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_OWNER) ? (int)attrs.owner : -1, FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_GROUP) ? (int)attrs.group : -1);*/ TakeTokenFSCall(); rc = fchown(fd, FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_OWNER) ? (int)attrs.owner : -1, FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_GROUP) ? (int)attrs.group : -1); ReleaseTokenFSCall(); if(rc) { close(fd); Return(posix2fsal_error(errno), errno, INDEX_FSAL_setattrs); } } /*********** * UTIME * ***********/ /* user must be the owner or have read access to modify 'atime' */ if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_ATIME) && (vfs_context->credential.user != 0) && (vfs_context->credential.user != buffstat.st_uid) && ((status = fsal_check_access(p_context, FSAL_R_OK, &buffstat, NULL)).major != ERR_FSAL_NO_ERROR)) { close(fd); ReturnStatus(status, INDEX_FSAL_setattrs); } /* user must be the owner or have write access to modify 'mtime' */ if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MTIME) && (vfs_context->credential.user != 0) && (vfs_context->credential.user != buffstat.st_uid) && ((status = fsal_check_access(p_context, FSAL_W_OK, &buffstat, NULL)).major != ERR_FSAL_NO_ERROR)) { close(fd); ReturnStatus(status, INDEX_FSAL_setattrs); } if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_ATIME | FSAL_ATTR_MTIME)) { struct timeval timebuf[2]; /* Atime */ timebuf[0].tv_sec = (FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_ATIME) ? (time_t) attrs. atime.seconds : buffstat.st_atime); timebuf[0].tv_usec = 0; /* Mtime */ timebuf[1].tv_sec = (FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MTIME) ? (time_t) attrs. mtime.seconds : buffstat.st_mtime); timebuf[1].tv_usec = 0; TakeTokenFSCall(); rc = futimes(fd, timebuf); errsv = errno; ReleaseTokenFSCall(); if(rc) { close(fd); Return(posix2fsal_error(errno), errno, INDEX_FSAL_setattrs); } } /* Optionaly fills output attributes. */ if(p_object_attributes) { status = VFSFSAL_getattrs(p_filehandle, p_context, p_object_attributes); /* on error, we set a special bit in the mask. */ if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_object_attributes->asked_attributes); FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } close(fd); Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_setattrs); }
fsal_status_t CEPHFSAL_setattrs(fsal_handle_t * exthandle, fsal_op_context_t * extcontext, fsal_attrib_list_t * attrib_set, fsal_attrib_list_t * object_attributes) { cephfsal_handle_t* filehandle = (cephfsal_handle_t*) exthandle; cephfsal_op_context_t* context = (cephfsal_op_context_t*) extcontext; struct stat st; fsal_attrib_list_t attrs; int rc, mask=0; int uid = FSAL_OP_CONTEXT_TO_UID(context); int gid = FSAL_OP_CONTEXT_TO_GID(context); /* sanity checks. * note : object_attributes is optional. */ if(!filehandle || !context || !attrib_set) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_setattrs); /* local copy of attributes */ attrs = *attrib_set; /* First, check that FSAL attributes changes are allowed. */ /* Is it allowed to change times ? */ if(!global_fs_info.cansettime) { if(attrs.asked_attributes & (FSAL_ATTR_ATIME | FSAL_ATTR_CREATION | FSAL_ATTR_CTIME | FSAL_ATTR_MTIME)) { /* handled as an unsettable attribute. */ Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_setattrs); } } /* apply umask, if mode attribute is to be changed */ if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MODE)) { attrs.mode &= (~global_fs_info.umask); } /* Build flags and struct stat */ if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MODE)) { mask |= CEPH_SETATTR_MODE; st.st_mode = fsal2unix_mode(attrs.mode); } if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_OWNER)) { mask |= CEPH_SETATTR_UID; st.st_uid = attrs.owner; } if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_GROUP)) { mask |= CEPH_SETATTR_UID; st.st_gid = attrs.group; } if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_ATIME)) { mask |= CEPH_SETATTR_ATIME; st.st_atime = attrs.atime.seconds; } if (FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MTIME)) { mask |= CEPH_SETATTR_MTIME; st.st_mtime = attrs.mtime.seconds; } if (FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_CTIME)) { mask |= CEPH_SETATTR_CTIME; st.st_ctime = attrs.ctime.seconds; } TakeTokenFSCall(); rc = ceph_ll_setattr(context->export_context->cmount, VINODE(filehandle), &st, mask, uid, gid); ReleaseTokenFSCall(); if (rc < 0) Return(posix2fsal_error(rc), 0, INDEX_FSAL_getattrs); if(object_attributes) { fsal_status_t status; status = CEPHFSAL_getattrs(exthandle, extcontext, object_attributes); /* on error, we set a special bit in the mask. */ if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(object_attributes->asked_attributes); FSAL_SET_MASK(object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_setattrs); }
void printmask(fsal_attrib_mask_t mask) { if(FSAL_TEST_MASK(mask, FSAL_ATTR_SUPPATTR)) LogTest("FSAL_ATTR_SUPPATTR"); if(FSAL_TEST_MASK(mask, FSAL_ATTR_TYPE)) LogTest("FSAL_ATTR_TYPE"); if(FSAL_TEST_MASK(mask, FSAL_ATTR_SIZE)) LogTest("FSAL_ATTR_SIZE"); if(FSAL_TEST_MASK(mask, FSAL_ATTR_FSID)) LogTest("FSAL_ATTR_FSID"); if(FSAL_TEST_MASK(mask, FSAL_ATTR_ACL)) LogTest("FSAL_ATTR_ACL "); if(FSAL_TEST_MASK(mask, FSAL_ATTR_FILEID)) LogTest("FSAL_ATTR_FILEID"); if(FSAL_TEST_MASK(mask, FSAL_ATTR_MODE)) LogTest("FSAL_ATTR_MODE"); if(FSAL_TEST_MASK(mask, FSAL_ATTR_NUMLINKS)) LogTest("FSAL_ATTR_NUMLINKS"); if(FSAL_TEST_MASK(mask, FSAL_ATTR_OWNER)) LogTest("FSAL_ATTR_OWNER"); if(FSAL_TEST_MASK(mask, FSAL_ATTR_GROUP)) LogTest("FSAL_ATTR_GROUP"); if(FSAL_TEST_MASK(mask, FSAL_ATTR_RAWDEV)) LogTest("FSAL_ATTR_RAWDEV"); if(FSAL_TEST_MASK(mask, FSAL_ATTR_ATIME)) LogTest("FSAL_ATTR_ATIME"); if(FSAL_TEST_MASK(mask, FSAL_ATTR_CREATION)) LogTest("FSAL_ATTR_CREATION"); if(FSAL_TEST_MASK(mask, FSAL_ATTR_CTIME)) LogTest("FSAL_ATTR_CTIME"); if(FSAL_TEST_MASK(mask, FSAL_ATTR_CHGTIME)) LogTest("FSAL_ATTR_CHGTIME"); if(FSAL_TEST_MASK(mask, FSAL_ATTR_MTIME)) LogTest("FSAL_ATTR_MTIME"); if(FSAL_TEST_MASK(mask, FSAL_ATTR_SPACEUSED)) LogTest("FSAL_ATTR_SPACEUSED"); if(FSAL_TEST_MASK(mask, FSAL_ATTR_MOUNTFILEID)) LogTest("FSAL_ATTR_MOUNTFILEID"); }
/** * FSAL_test_setattr_access_default : * test if a client identified by cred can access setattr on the object * knowing its attributes and parent's attributes. * The following fields of the object_attributes structures MUST be filled : * acls (if supported), mode, owner, group. * This doesn't make any call to the filesystem, * as a result, this doesn't ensure that the file exists, nor that * the permissions given as parameters are the actual file permissions : * this must be ensured by the cache_inode layer, using FSAL_getattrs, * for example. * * \param cred (in zfsfsal_cred_t *) user's identifier. * \param candidate_attributes the attributes we want to set on the object * \param object_attributes (in fsal_attrib_list_t *) the cached attributes * for the object. * * \return Major error codes : * - ERR_FSAL_NO_ERROR (no error) * - ERR_FSAL_ACCESS (Permission denied) * - ERR_FSAL_FAULT (null pointer parameter) * - ERR_FSAL_INVAL (missing attributes : mode, group, user,...) * - ERR_FSAL_SERVERFAULT (unexpected error) */ fsal_status_t FSAL_setattr_access_default(fsal_op_context_t * p_context, /* IN */ fsal_attrib_list_t * candidate_attributes, /* IN */ fsal_attrib_list_t * object_attributes /* IN */ ) { fsal_status_t fsal_status; int in_grp; int i; fsal_count_t nb_alt_groups; gid_t * alt_groups; in_grp = 0; /* * CHMOD * */ /* We just ignore symlinks. */ if(FSAL_TEST_MASK(candidate_attributes->asked_attributes, FSAL_ATTR_MODE) && (object_attributes->type != FSAL_TYPE_LNK)) { /* User must be root or owner of the file */ if( (FSAL_OP_CONTEXT_TO_UID(p_context) != 0) && (FSAL_OP_CONTEXT_TO_UID(p_context) =! object_attributes->owner) ) Return(ERR_FSAL_ACCESS, 0, INDEX_FSAL_setattr_access); } /* * CHOWN * */ if(FSAL_TEST_MASK(candidate_attributes->asked_attributes, FSAL_ATTR_OWNER)) { /* User must be root or (be the owner and the user he wants to set) */ if( (FSAL_OP_CONTEXT_TO_UID(p_context) != 0) && ( ( FSAL_OP_CONTEXT_TO_UID(p_context) != object_attributes->owner ) || ( FSAL_OP_CONTEXT_TO_UID(p_context) != candidate_attributes->owner ) ) ) Return(ERR_FSAL_ACCESS, 0, INDEX_FSAL_setattr_access); } if(FSAL_TEST_MASK(candidate_attributes->asked_attributes, FSAL_ATTR_GROUP)) { /* User must ( be root or owner ) */ if( (FSAL_OP_CONTEXT_TO_UID(p_context) != 0) && (FSAL_OP_CONTEXT_TO_UID(p_context) != object_attributes->owner) ) Return(ERR_FSAL_ACCESS, 0, INDEX_FSAL_setattr_access); /* He must also be in the group he wants to set */ in_grp = ( FSAL_OP_CONTEXT_TO_GID(p_context) == candidate_attributes->group ); if(!in_grp && FSAL_OP_CONTEXT_TO_ALT_GROUPS(p_context) != NULL) { nb_alt_groups = FSAL_OP_CONTEXT_TO_NBGROUPS(p_context); alt_groups = FSAL_OP_CONTEXT_TO_ALT_GROUPS(p_context); /* Test user's alt groups */ for(i = 0; i < nb_alt_groups; i++) { in_grp = (alt_groups[i] == object_attributes->group); if(in_grp) break; } } if(!in_grp) Return(ERR_FSAL_ACCESS, 0, INDEX_FSAL_setattr_access); } /* * UTIME * */ /* Is it allowed to change time? */ if(FSAL_TEST_MASK(candidate_attributes->asked_attributes, FSAL_ATTR_ATIME | FSAL_ATTR_CREATION | FSAL_ATTR_CTIME | FSAL_ATTR_MTIME) && !global_fs_info.cansettime) Return(ERR_FSAL_ACCESS, 0, INDEX_FSAL_setattr_access); /* Atime: user must be owner or be root or have read access */ if( FSAL_TEST_MASK(candidate_attributes->asked_attributes, FSAL_ATTR_ATIME) && (FSAL_OP_CONTEXT_TO_UID(p_context) != 0) && (FSAL_OP_CONTEXT_TO_UID(p_context) != object_attributes->owner)) { fsal_status = FSAL_test_access_default(p_context, FSAL_R_OK, object_attributes); if(FSAL_IS_ERROR(fsal_status)) Return(ERR_FSAL_ACCESS, 0, INDEX_FSAL_setattr_access); } /* Mtime: user must be owner or be root or have write access */ if( FSAL_TEST_MASK(candidate_attributes->asked_attributes, FSAL_ATTR_MTIME) && (FSAL_OP_CONTEXT_TO_UID(p_context) != 0) && (FSAL_OP_CONTEXT_TO_UID(p_context) != object_attributes->owner)) { fsal_status = FSAL_test_access_default(p_context, FSAL_W_OK, object_attributes); if(FSAL_IS_ERROR(fsal_status)) Return(ERR_FSAL_ACCESS, 0, INDEX_FSAL_setattr_access); } /* If this point is reached, then access is granted. */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_setattr_access); } /* FSAL_test_setattr_access */
void printattributes(fsal_attrib_list_t attrs) { if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_RDATTR_ERR)) LogTest("FSAL_ATTR_RDATTR_ERR"); if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_TYPE)) LogTest("Type : %s", strtype(attrs.type)); if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_SIZE)) LogTest("Size : %llu", attrs.filesize); if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_FSID)) LogTest("fsId : %llu.%llu", attrs.fsid.major, attrs.fsid.minor); if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_ACL)) LogTest("ACL List ..."); if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_FILEID)) LogTest("FileId : %llu", attrs.fileid); if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MODE)) LogTest("Mode : %#o", attrs.mode); if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_NUMLINKS)) LogTest("Numlinks : %u", (unsigned int)attrs.numlinks); if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_OWNER)) LogTest("uid : %d", attrs.owner); if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_GROUP)) LogTest("gid : %d", attrs.group); if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_RAWDEV)) LogTest("Rawdev ..."); if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_ATIME)) LogTest("atime : %s", ctime((time_t *) & attrs.atime.seconds)); if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_CREATION)) LogTest("creation time : %s", ctime((time_t *) & attrs.creation.seconds)); if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_CTIME)) LogTest("ctime : %s", ctime((time_t *) & attrs.ctime.seconds)); if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MTIME)) LogTest("mtime : %s", ctime((time_t *) & attrs.mtime.seconds)); if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_CHGTIME)) LogTest("chgtime : %s", ctime((time_t *) & attrs.chgtime.seconds)); if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_SPACEUSED)) LogTest("spaceused : %llu", attrs.spaceused); if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MOUNTFILEID)) LogTest("mounted_on_fileid : %llu", attrs.mounted_on_fileid); }
fsal_status_t posix2fsal_attributes(struct stat * p_buffstat, struct attrlist * p_fsalattr_out) { /* sanity checks */ if(!p_buffstat || !p_fsalattr_out) return fsalstat(ERR_FSAL_FAULT, 0); /* Initialize ACL regardless of whether ACL was asked or not. * This is needed to make sure ACL attribute is initialized. */ p_fsalattr_out->acl = NULL; /* Fills the output struct */ if(FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_TYPE)) { p_fsalattr_out->type = posix2fsal_type(p_buffstat->st_mode); } if(FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_SIZE)) { p_fsalattr_out->filesize = p_buffstat->st_size; } if(FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_FSID)) { p_fsalattr_out->fsid = posix2fsal_fsid(p_buffstat->st_dev); } if(FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_ACL)) { p_fsalattr_out->acl = NULL; } if(FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_FILEID)) { p_fsalattr_out->fileid = (uint64_t) (p_buffstat->st_ino); } if(FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_MODE)) { p_fsalattr_out->mode = unix2fsal_mode(p_buffstat->st_mode); } if(FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_NUMLINKS)) { p_fsalattr_out->numlinks = p_buffstat->st_nlink; } if(FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_OWNER)) { p_fsalattr_out->owner = p_buffstat->st_uid; } if(FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_GROUP)) { p_fsalattr_out->group = p_buffstat->st_gid; } if(FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_ATIME)) { p_fsalattr_out->atime = p_buffstat->st_atim; } if(FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_CTIME)) { p_fsalattr_out->ctime = p_buffstat->st_ctim; } if(FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_MTIME)) { p_fsalattr_out->mtime = p_buffstat->st_mtim; } if(FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_CHGTIME)) { p_fsalattr_out->chgtime = (gsh_time_cmp(&p_buffstat->st_mtim, &p_buffstat->st_ctim) > 0) ? p_buffstat->st_mtim : p_buffstat->st_ctim; /* XXX */ p_fsalattr_out->change = p_fsalattr_out->chgtime.tv_sec + p_fsalattr_out->chgtime.tv_nsec; } if(FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_SPACEUSED)) { p_fsalattr_out->spaceused = p_buffstat->st_blocks * S_BLKSIZE; } if(FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_RAWDEV)) { p_fsalattr_out->rawdev = posix2fsal_devt(p_buffstat->st_rdev); /* XXX: convert ? */ } /* mounted_on_fileid : if ( FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_MOUNTFILEID )){ p_fsalattr_out->mounted_on_fileid = hpss2fsal_64( p_hpss_attr_in->FilesetRootId ); } */ /* everything has been copied ! */ return fsalstat(ERR_FSAL_NO_ERROR, 0); }
/** * @brief Set attributes on an object * * This function sets attributes on an object. Which attributes are * set is determined by attrib_set->mask. The FSAL must manage bypass * or not of share reservations, and a state may be passed. * * @param[in] obj_hdl File on which to operate * @param[in] state state_t to use for this operation * @param[in] attrib_set Attributes to set * * @return FSAL status. */ fsal_status_t vfs_setattr2(struct fsal_obj_handle *obj_hdl, bool bypass, struct state_t *state, struct attrlist *attrib_set) { struct vfs_fsal_obj_handle *myself; fsal_status_t status = {0, 0}; int retval = 0; fsal_openflags_t openflags = FSAL_O_ANY; bool has_lock = false; bool need_fsync = false; bool closefd = false; int my_fd; const char *func; /* apply umask, if mode attribute is to be changed */ if (FSAL_TEST_MASK(attrib_set->mask, ATTR_MODE)) attrib_set->mode &= ~op_ctx->fsal_export->exp_ops.fs_umask(op_ctx->fsal_export); myself = container_of(obj_hdl, struct vfs_fsal_obj_handle, obj_handle); if (obj_hdl->fsal != obj_hdl->fs->fsal) { LogDebug(COMPONENT_FSAL, "FSAL %s operation for handle belonging to FSAL %s, return EXDEV", obj_hdl->fsal->name, obj_hdl->fs->fsal != NULL ? obj_hdl->fs->fsal->name : "(none)"); return fsalstat(posix2fsal_error(EXDEV), EXDEV); } #ifdef ENABLE_VFS_DEBUG_ACL #ifdef ENABLE_RFC_ACL if (FSAL_TEST_MASK(attrib_set->mask, ATTR_MODE) && !FSAL_TEST_MASK(attrib_set->mask, ATTR_ACL)) { /* Set ACL from MODE */ struct attrlist attrs; fsal_prepare_attrs(&attrs, ATTR_ACL); status = obj_hdl->obj_ops.getattrs(obj_hdl, &attrs); if (FSAL_IS_ERROR(status)) return status; status = fsal_mode_to_acl(attrib_set, attrs.acl); /* Done with the attrs */ fsal_release_attrs(&attrs); } else { /* If ATTR_ACL is set, mode needs to be adjusted no matter what. * See 7530 s 6.4.1.3 */ if (!FSAL_TEST_MASK(attrib_set->mask, ATTR_MODE)) attrib_set->mode = myself->mode; status = fsal_acl_to_mode(attrib_set); } if (FSAL_IS_ERROR(status)) return status; #endif /* ENABLE_RFC_ACL */ #endif /* This is yet another "you can't get there from here". If this object * is a socket (AF_UNIX), an fd on the socket s useless _period_. * If it is for a symlink, without O_PATH, you will get an ELOOP error * and (f)chmod doesn't work for a symlink anyway - not that it matters * because access checking is not done on the symlink but the final * target. * AF_UNIX sockets are also ozone material. If the socket is already * active listeners et al, you can manipulate the mode etc. If it is * just sitting there as in you made it with a mknod. * (one of those leaky abstractions...) * or the listener forgot to unlink it, it is lame duck. */ /* Test if size is being set, make sure file is regular and if so, * require a read/write file descriptor. */ if (FSAL_TEST_MASK(attrib_set->mask, ATTR_SIZE)) { if (obj_hdl->type != REGULAR_FILE) { LogFullDebug(COMPONENT_FSAL, "Setting size on non-regular file"); return fsalstat(ERR_FSAL_INVAL, EINVAL); } openflags = FSAL_O_RDWR; } /* Get a usable file descriptor. Share conflict is only possible if * size is being set. */ status = find_fd(&my_fd, obj_hdl, bypass, state, openflags, &has_lock, &need_fsync, &closefd, false); if (FSAL_IS_ERROR(status)) { if (obj_hdl->type == SYMBOLIC_LINK && status.major == ERR_FSAL_PERM) { /* You cannot open_by_handle (XFS) a symlink and it * throws an EPERM error for it. open_by_handle_at * does not throw that error for symlinks so we play a * game here. Since there is not much we can do with * symlinks anyway, say that we did it * but don't actually do anything. * If you *really* want to tweek things * like owners, get a modern linux kernel... */ status = fsalstat(ERR_FSAL_NO_ERROR, 0); } LogFullDebug(COMPONENT_FSAL, "find_fd status=%s", fsal_err_txt(status)); goto out; } /** TRUNCATE **/ if (FSAL_TEST_MASK(attrib_set->mask, ATTR_SIZE)) { retval = ftruncate(my_fd, attrib_set->filesize); if (retval != 0) { /** @todo FSF: is this still necessary? * * XXX ESXi volume creation pattern reliably * reached this point in the past, however now that we * only use the already open file descriptor if it is * open read/write, this may no longer fail. * If there is some other error from ftruncate, then * we will needlessly retry, but without more detail * of the original failure, we can't be sure. * Fortunately permission checking is done by * Ganesha before calling here, so we won't get an * EACCES since this call is done as root. We could * get EFBIG, EPERM, or EINVAL. */ /** @todo FSF: re-open if we really still need this */ retval = ftruncate(my_fd, attrib_set->filesize); if (retval != 0) { func = "truncate"; goto fileerr; } } } /** CHMOD **/ if (FSAL_TEST_MASK(attrib_set->mask, ATTR_MODE)) { /* The POSIX chmod call doesn't affect the symlink object, but * the entry it points to. So we must ignore it. */ if (obj_hdl->type != SYMBOLIC_LINK) { if (vfs_unopenable_type(obj_hdl->type)) retval = fchmodat( my_fd, myself->u.unopenable.name, fsal2unix_mode(attrib_set->mode), 0); else retval = fchmod( my_fd, fsal2unix_mode(attrib_set->mode)); if (retval != 0) { func = "chmod"; goto fileerr; } } } /** CHOWN **/ if (FSAL_TEST_MASK(attrib_set->mask, ATTR_OWNER | ATTR_GROUP)) { uid_t user = FSAL_TEST_MASK(attrib_set->mask, ATTR_OWNER) ? (int)attrib_set->owner : -1; gid_t group = FSAL_TEST_MASK(attrib_set->mask, ATTR_GROUP) ? (int)attrib_set->group : -1; if (vfs_unopenable_type(obj_hdl->type)) retval = fchownat(my_fd, myself->u.unopenable.name, user, group, AT_SYMLINK_NOFOLLOW); else if (obj_hdl->type == SYMBOLIC_LINK) retval = fchownat(my_fd, "", user, group, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH); else retval = fchown(my_fd, user, group); if (retval) { func = "chown"; goto fileerr; } } /** UTIME **/ if (FSAL_TEST_MASK(attrib_set->mask, ATTRS_SET_TIME)) { struct timespec timebuf[2]; if (obj_hdl->type == SYMBOLIC_LINK) goto out; /* Setting time on symlinks is illegal */ /* Atime */ if (FSAL_TEST_MASK(attrib_set->mask, ATTR_ATIME_SERVER)) { timebuf[0].tv_sec = 0; timebuf[0].tv_nsec = UTIME_NOW; } else if (FSAL_TEST_MASK(attrib_set->mask, ATTR_ATIME)) { timebuf[0] = attrib_set->atime; } else { timebuf[0].tv_sec = 0; timebuf[0].tv_nsec = UTIME_OMIT; } /* Mtime */ if (FSAL_TEST_MASK(attrib_set->mask, ATTR_MTIME_SERVER)) { timebuf[1].tv_sec = 0; timebuf[1].tv_nsec = UTIME_NOW; } else if (FSAL_TEST_MASK(attrib_set->mask, ATTR_MTIME)) { timebuf[1] = attrib_set->mtime; } else { timebuf[1].tv_sec = 0; timebuf[1].tv_nsec = UTIME_OMIT; } if (vfs_unopenable_type(obj_hdl->type)) retval = vfs_utimesat(my_fd, myself->u.unopenable.name, timebuf, AT_SYMLINK_NOFOLLOW); else retval = vfs_utimes(my_fd, timebuf); if (retval != 0) { func = "utimes"; goto fileerr; } } /** SUBFSAL **/ if (myself->sub_ops && myself->sub_ops->setattrs) { status = myself->sub_ops->setattrs( myself, my_fd, attrib_set->mask, attrib_set); if (FSAL_IS_ERROR(status)) goto out; } errno = 0; fileerr: retval = errno; if (retval != 0) { LogDebug(COMPONENT_FSAL, "%s returned %s", func, strerror(retval)); } status = fsalstat(posix2fsal_error(retval), retval); out: if (closefd) close(my_fd); if (has_lock) PTHREAD_RWLOCK_unlock(&obj_hdl->lock); return status; }
/** * * @brief Gets an entry by using its fsdata as a key and caches it if needed. * * Gets an entry by using its fsdata as a key and caches it if needed. * * If a cache entry is returned, its refcount is incremented by one. * * It turns out we do need cache_inode_get_located functionality for * cases like lookupp on an entry returning itself when it isn't a * root. Therefore, if the 'associated' parameter is equal to the got * cache entry, a reference count is incremented but the structure * pointed to by attr is NOT filled in. * * @param[in] fsdata File system data * @param[out] attr The attributes of the got entry * @param[in] context FSAL credentials * @param[in] associated Entry that may be equal to the got entry * @param[out] status Returned status * * @return If successful, the pointer to the entry; NULL otherwise * */ cache_entry_t * cache_inode_get(cache_inode_fsal_data_t *fsdata, fsal_attrib_list_t *attr, fsal_op_context_t *context, cache_entry_t *associated, cache_inode_status_t *status) { hash_buffer_t key, value; cache_entry_t *entry = NULL; fsal_status_t fsal_status = {0, 0}; cache_inode_create_arg_t create_arg = { .newly_created_dir = FALSE }; cache_inode_file_type_t type = UNASSIGNED; hash_error_t hrc = 0; fsal_attrib_list_t fsal_attributes; fsal_handle_t *file_handle; struct hash_latch latch; /* Set the return default to CACHE_INODE_SUCCESS */ *status = CACHE_INODE_SUCCESS; /* Turn the input to a hash key on our own. */ key.pdata = fsdata->fh_desc.start; key.len = fsdata->fh_desc.len; hrc = HashTable_GetLatch(fh_to_cache_entry_ht, &key, &value, FALSE, &latch); if ((hrc != HASHTABLE_SUCCESS) && (hrc != HASHTABLE_ERROR_NO_SUCH_KEY)) { /* This should not happened */ *status = CACHE_INODE_HASH_TABLE_ERROR; LogCrit(COMPONENT_CACHE_INODE, "Hash access failed with code %d" " - this should not have happened", hrc); return NULL; } if (hrc == HASHTABLE_SUCCESS) { /* Entry exists in the cache and was found */ entry = value.pdata; /* take an extra reference within the critical section */ if (cache_inode_lru_ref(entry, LRU_REQ_INITIAL) != CACHE_INODE_SUCCESS) { /* Dead entry. Treat like a lookup failure. */ entry = NULL; } else { if (entry == associated) { /* Take a quick exit so we don't invert lock ordering. */ HashTable_ReleaseLatched(fh_to_cache_entry_ht, &latch); return entry; } } } HashTable_ReleaseLatched(fh_to_cache_entry_ht, &latch); if (!context) { /* Upcalls have no access to fsal_op_context_t, so just return the entry without revalidating it or creating a new one. */ if (entry == NULL) { *status = CACHE_INODE_NOT_FOUND; } return entry; } if (!entry) { /* Cache miss, allocate a new entry */ file_handle = (fsal_handle_t *) fsdata->fh_desc.start; /* First, call FSAL to know what the object is */ fsal_attributes.asked_attributes = cache_inode_params.attrmask; fsal_status = FSAL_getattrs(file_handle, context, &fsal_attributes); if (FSAL_IS_ERROR(fsal_status)) { *status = cache_inode_error_convert(fsal_status); LogDebug(COMPONENT_CACHE_INODE, "cache_inode_get: cache_inode_status=%u " "fsal_status=%u,%u ", *status, fsal_status.major, fsal_status.minor); return NULL; } /* The type has to be set in the attributes */ if (!FSAL_TEST_MASK(fsal_attributes.supported_attributes, FSAL_ATTR_TYPE)) { *status = CACHE_INODE_FSAL_ERROR; return NULL; } /* Get the cache_inode file type */ type = cache_inode_fsal_type_convert(fsal_attributes.type); if (type == SYMBOLIC_LINK) { fsal_attributes.asked_attributes = cache_inode_params.attrmask; fsal_status = FSAL_readlink(file_handle, context, &create_arg.link_content, &fsal_attributes); if (FSAL_IS_ERROR(fsal_status)) { *status = cache_inode_error_convert(fsal_status); return NULL; } } if ((entry = cache_inode_new_entry(fsdata, &fsal_attributes, type, &create_arg, status)) == NULL) { return NULL; } } *status = CACHE_INODE_SUCCESS; /* This is the replacement for cache_inode_renew_entry. Rather than calling that function at the start of every cache_inode call with the inode locked, we call cache_inode_check trust to perform 'heavyweight' (timed expiration of cached attributes, getattr-based directory trust) checks the first time after getting an inode. It does all of the checks read-locked and only acquires a write lock if there's something requiring a change. There is a second light-weight check done before use of cached data that checks whether the bits saying that inode attributes or inode content are trustworthy have been cleared by, for example, FSAL_CB. To summarize, the current implementation is that policy-based trust of validity is checked once per logical series of operations at cache_inode_get, and asynchronous trust is checked with use (when the attributes are locked for reading, for example.) */ if ((*status = cache_inode_check_trust(entry, context)) != CACHE_INODE_SUCCESS) { goto out_put; } /* Set the returned attributes */ *status = cache_inode_lock_trust_attrs(entry, context); /* cache_inode_lock_trust_attrs may fail, in that case, the attributes are wrong and pthread_rwlock_unlock can't be called again */ if(*status != CACHE_INODE_SUCCESS) { goto out_put; } *attr = entry->attributes; pthread_rwlock_unlock(&entry->attr_lock); return entry; out_put: cache_inode_put(entry); entry = NULL; return entry; } /* cache_inode_get */
fsal_errors_t nfs_access_op(struct fsal_obj_handle *obj, uint32_t requested_access, uint32_t *granted_access, uint32_t *supported_access) { fsal_status_t fsal_status; fsal_accessflags_t access_mask; fsal_accessflags_t access_allowed; fsal_accessflags_t access_denied; uint32_t granted_mask = requested_access; access_mask = 0; *granted_access = 0; LogDebugAlt(COMPONENT_NFSPROTO, COMPONENT_NFS_V4_ACL, "Requested ACCESS=%s,%s,%s,%s,%s,%s", FSAL_TEST_MASK(requested_access, ACCESS3_READ) ? "READ" : "-", FSAL_TEST_MASK(requested_access, ACCESS3_LOOKUP) ? "LOOKUP" : "-", FSAL_TEST_MASK(requested_access, ACCESS3_MODIFY) ? "MODIFY" : "-", FSAL_TEST_MASK(requested_access, ACCESS3_EXTEND) ? "EXTEND" : "-", FSAL_TEST_MASK(requested_access, ACCESS3_DELETE) ? "DELETE" : "-", FSAL_TEST_MASK(requested_access, ACCESS3_EXECUTE) ? "EXECUTE" : "-"); /* Set mode for read. * NOTE: FSAL_ACE_PERM_LIST_DIR and FSAL_ACE_PERM_READ_DATA have * the same bit value so we don't bother looking at file type. */ if (requested_access & ACCESS3_READ) access_mask |= FSAL_R_OK | FSAL_ACE_PERM_READ_DATA; if (requested_access & ACCESS3_LOOKUP) { if (obj->type == DIRECTORY) access_mask |= FSAL_X_OK | FSAL_ACE_PERM_EXECUTE; else granted_mask &= ~ACCESS3_LOOKUP; } if (requested_access & ACCESS3_MODIFY) { if (obj->type == DIRECTORY) access_mask |= FSAL_W_OK | FSAL_ACE_PERM_DELETE_CHILD; else access_mask |= FSAL_W_OK | FSAL_ACE_PERM_WRITE_DATA; } if (requested_access & ACCESS3_EXTEND) { if (obj->type == DIRECTORY) access_mask |= FSAL_W_OK | FSAL_ACE_PERM_ADD_FILE | FSAL_ACE_PERM_ADD_SUBDIRECTORY; else access_mask |= FSAL_W_OK | FSAL_ACE_PERM_APPEND_DATA; } if (requested_access & ACCESS3_DELETE) { if (obj->type == DIRECTORY) access_mask |= FSAL_W_OK | FSAL_ACE_PERM_DELETE_CHILD; else granted_mask &= ~ACCESS3_DELETE; } if (requested_access & ACCESS3_EXECUTE) { if (obj->type != DIRECTORY) access_mask |= FSAL_X_OK | FSAL_ACE_PERM_EXECUTE; else granted_mask &= ~ACCESS3_EXECUTE; } if (access_mask != 0) access_mask |= FSAL_MODE_MASK_FLAG | FSAL_ACE4_MASK_FLAG | FSAL_ACE4_PERM_CONTINUE; LogDebugAlt(COMPONENT_NFSPROTO, COMPONENT_NFS_V4_ACL, "access_mask = mode(%c%c%c) ACL(%s,%s,%s,%s,%s)", FSAL_TEST_MASK(access_mask, FSAL_R_OK) ? 'r' : '-', FSAL_TEST_MASK(access_mask, FSAL_W_OK) ? 'w' : '-', FSAL_TEST_MASK(access_mask, FSAL_X_OK) ? 'x' : '-', FSAL_TEST_MASK(access_mask, FSAL_ACE_PERM_READ_DATA) ? obj->type == DIRECTORY ? "list_dir" : "read_data" : "-", FSAL_TEST_MASK(access_mask, FSAL_ACE_PERM_WRITE_DATA) ? obj->type == DIRECTORY ? "add_file" : "write_data" : "-", FSAL_TEST_MASK(access_mask, FSAL_ACE_PERM_EXECUTE) ? "execute" : "-", FSAL_TEST_MASK(access_mask, FSAL_ACE_PERM_ADD_SUBDIRECTORY) ? "add_subdirectory" : "-", FSAL_TEST_MASK(access_mask, FSAL_ACE_PERM_DELETE_CHILD) ? "delete_child" : "-"); fsal_status = obj->obj_ops.test_access(obj, access_mask, &access_allowed, &access_denied, false); if (fsal_status.major == ERR_FSAL_NO_ERROR || fsal_status.major == ERR_FSAL_ACCESS) { /* Define granted access based on granted mode bits. */ if (access_allowed & FSAL_R_OK) *granted_access |= ACCESS3_READ; if (access_allowed & FSAL_W_OK) *granted_access |= ACCESS3_MODIFY | ACCESS3_EXTEND | ACCESS3_DELETE; if (access_allowed & FSAL_X_OK) *granted_access |= ACCESS3_LOOKUP | ACCESS3_EXECUTE; /* Define granted access based on granted ACL bits. */ if (access_allowed & FSAL_ACE_PERM_READ_DATA) *granted_access |= ACCESS3_READ; if (obj->type == DIRECTORY) { if (access_allowed & FSAL_ACE_PERM_DELETE_CHILD) *granted_access |= ACCESS3_MODIFY | ACCESS3_DELETE; if (access_allowed & FSAL_ACE_PERM_ADD_FILE) *granted_access |= ACCESS3_EXTEND; if (access_allowed & FSAL_ACE_PERM_ADD_SUBDIRECTORY) *granted_access |= ACCESS3_EXTEND; } else { if (access_allowed & FSAL_ACE_PERM_WRITE_DATA) *granted_access |= ACCESS3_MODIFY; if (access_allowed & FSAL_ACE_PERM_APPEND_DATA) *granted_access |= ACCESS3_EXTEND; } if (access_allowed & FSAL_ACE_PERM_EXECUTE) *granted_access |= ACCESS3_LOOKUP | ACCESS3_EXECUTE; /* Don't allow any bits that weren't set on request or * allowed by the file type. */ *granted_access &= granted_mask; if (supported_access != NULL) *supported_access = granted_mask; LogDebugAlt(COMPONENT_NFSPROTO, COMPONENT_NFS_V4_ACL, "Supported ACCESS=%s,%s,%s,%s,%s,%s", FSAL_TEST_MASK(granted_mask, ACCESS3_READ) ? "READ" : "-", FSAL_TEST_MASK(granted_mask, ACCESS3_LOOKUP) ? "LOOKUP" : "-", FSAL_TEST_MASK(granted_mask, ACCESS3_MODIFY) ? "MODIFY" : "-", FSAL_TEST_MASK(granted_mask, ACCESS3_EXTEND) ? "EXTEND" : "-", FSAL_TEST_MASK(granted_mask, ACCESS3_DELETE) ? "DELETE" : "-", FSAL_TEST_MASK(granted_mask, ACCESS3_EXECUTE) ? "EXECUTE" : "-"); LogDebugAlt(COMPONENT_NFSPROTO, COMPONENT_NFS_V4_ACL, "Granted ACCESS=%s,%s,%s,%s,%s,%s", FSAL_TEST_MASK(*granted_access, ACCESS3_READ) ? "READ" : "-", FSAL_TEST_MASK(*granted_access, ACCESS3_LOOKUP) ? "LOOKUP" : "-", FSAL_TEST_MASK(*granted_access, ACCESS3_MODIFY) ? "MODIFY" : "-", FSAL_TEST_MASK(*granted_access, ACCESS3_EXTEND) ? "EXTEND" : "-", FSAL_TEST_MASK(*granted_access, ACCESS3_DELETE) ? "DELETE" : "-", FSAL_TEST_MASK(*granted_access, ACCESS3_EXECUTE) ? "EXECUTE" : "-"); } return fsal_status.major; }
static void open4_ex(OPEN4args *arg, compound_data_t *data, OPEN4res *res_OPEN4, nfs_client_id_t *clientid, state_owner_t *owner, state_t **file_state, bool *new_state) { /* Parent directory in which to open the file. */ struct fsal_obj_handle *parent = NULL; /* The entry we associated with the desired file before open. */ struct fsal_obj_handle *file_obj = NULL; /* Indicator that file_obj came from lookup. */ bool looked_up_file_obj = false; /* The in_obj to pass to fsal_open2. */ struct fsal_obj_handle *in_obj = NULL; /* The entry open associated with the file. */ struct fsal_obj_handle *out_obj = NULL; fsal_openflags_t openflags = 0; fsal_openflags_t old_openflags = 0; enum fsal_create_mode createmode = FSAL_NO_CREATE; /* The filename to create */ char *filename = NULL; /* The supplied calim type */ open_claim_type4 claim = arg->claim.claim; fsal_verifier_t verifier; struct attrlist sattr; /* Status for fsal calls */ fsal_status_t status = {0, 0}; /* The open state for the file */ bool state_lock_held = false; /* Make sure the attributes are initialized */ memset(&sattr, 0, sizeof(sattr)); /* Make sure... */ *file_state = NULL; *new_state = false; /* Pre-process the claim type */ switch (claim) { case CLAIM_NULL: /* Check parent */ parent = data->current_obj; in_obj = parent; /* Parent must be a directory */ if (parent->type != DIRECTORY) { if (parent->type == SYMBOLIC_LINK) { res_OPEN4->status = NFS4ERR_SYMLINK; goto out; } else { res_OPEN4->status = NFS4ERR_NOTDIR; goto out; } } /* Validate and convert the utf8 filename */ res_OPEN4->status = nfs4_utf8string2dynamic(&arg->claim.open_claim4_u.file, UTF8_SCAN_ALL, &filename); if (res_OPEN4->status != NFS4_OK) goto out; /* Set the createmode if appropriate) */ if (arg->openhow.opentype == OPEN4_CREATE) { open4_ex_create_args(arg, data, res_OPEN4, verifier, &createmode, &sattr); if (res_OPEN4->status != NFS4_OK) goto out; } status = fsal_lookup(parent, filename, &file_obj, NULL); if (!FSAL_IS_ERROR(status)) { /* Check create situations. */ if (arg->openhow.opentype == OPEN4_CREATE) { if (createmode >= FSAL_EXCLUSIVE) { /* Could be a replay, need to continue. */ LogFullDebug(COMPONENT_STATE, "EXCLUSIVE open with existing file %s", filename); } else if (createmode == FSAL_GUARDED) { /* This will be a failure no matter' * what. */ looked_up_file_obj = true; res_OPEN4->status = NFS4ERR_EXIST; goto out; } else { /* FSAL_UNCHECKED, may be a truncate * and we need to pass in the case * of fsal_reopen2 case. */ if (FSAL_TEST_MASK(sattr.valid_mask, ATTR_SIZE) && sattr.filesize == 0) { LogFullDebug(COMPONENT_STATE, "Truncate"); openflags |= FSAL_O_TRUNC; } } } /* We found the file by lookup, discard the filename * and remember that we found the entry by lookup. */ looked_up_file_obj = true; gsh_free(filename); filename = NULL; } else if (status.major != ERR_FSAL_NOENT || arg->openhow.opentype != OPEN4_CREATE) { /* A real error occurred */ res_OPEN4->status = nfs4_Errno_status(status); goto out; } break; /* Both of these just use the current filehandle. */ case CLAIM_PREVIOUS: owner->so_owner.so_nfs4_owner.so_confirmed = true; if (!nfs4_check_deleg_reclaim(clientid, &data->currentFH)) { /* It must have been revoked. Can't reclaim.*/ LogInfo(COMPONENT_NFS_V4, "Can't reclaim delegation"); res_OPEN4->status = NFS4ERR_RECLAIM_BAD; goto out; } openflags |= FSAL_O_RECLAIM; file_obj = data->current_obj; break; case CLAIM_FH: file_obj = data->current_obj; break; case CLAIM_DELEGATE_PREV: /* FIXME: Remove this when we have full support * for CLAIM_DELEGATE_PREV and delegpurge operations */ res_OPEN4->status = NFS4ERR_NOTSUPP; goto out; case CLAIM_DELEGATE_CUR: res_OPEN4->status = open4_claim_deleg(arg, data); if (res_OPEN4->status != NFS4_OK) goto out; openflags |= FSAL_O_RECLAIM; file_obj = data->current_obj; break; default: LogFatal(COMPONENT_STATE, "Programming error. Invalid claim after check."); } if ((arg->share_access & OPEN4_SHARE_ACCESS_READ) != 0) openflags |= FSAL_O_READ; if ((arg->share_access & OPEN4_SHARE_ACCESS_WRITE) != 0) openflags |= FSAL_O_WRITE; if ((arg->share_deny & OPEN4_SHARE_DENY_READ) != 0) openflags |= FSAL_O_DENY_READ; if ((arg->share_deny & OPEN4_SHARE_DENY_WRITE) != 0) openflags |= FSAL_O_DENY_WRITE_MAND; /* Check if file_obj a REGULAR_FILE */ if (file_obj != NULL && file_obj->type != REGULAR_FILE) { LogDebug(COMPONENT_NFS_V4, "Wrong file type expected REGULAR_FILE actual %s", object_file_type_to_str(file_obj->type)); if (file_obj->type == DIRECTORY) { res_OPEN4->status = NFS4ERR_ISDIR; } else { /* All special nodes must return NFS4ERR_SYMLINK for * proper client behavior per this linux-nfs post: * http://marc.info/?l=linux-nfs&m=131342421825436&w=2 */ res_OPEN4->status = NFS4ERR_SYMLINK; } goto out; } if (file_obj != NULL) { /* Go ahead and take the state lock now. */ PTHREAD_RWLOCK_wrlock(&file_obj->state_hdl->state_lock); state_lock_held = true; in_obj = file_obj; /* Check if any existing delegations conflict with this open. * Delegation recalls will be scheduled if there is a conflict. */ if (state_deleg_conflict(file_obj, (arg->share_access & OPEN4_SHARE_ACCESS_WRITE) != 0)) { res_OPEN4->status = NFS4ERR_DELAY; goto out; } /* Check if there is already a state for this entry and owner. */ *file_state = nfs4_State_Get_Obj(file_obj, owner); if (isFullDebug(COMPONENT_STATE) && *file_state != NULL) { char str[LOG_BUFF_LEN] = "\0"; struct display_buffer dspbuf = {sizeof(str), str, str}; display_stateid(&dspbuf, *file_state); LogFullDebug(COMPONENT_STATE, "Found existing state %s", str); } /* Check if open from another export */ if (*file_state != NULL && !state_same_export(*file_state, op_ctx->ctx_export)) { LogEvent(COMPONENT_STATE, "Lock Owner Export Conflict, Lock held for export %" PRIu16" request for export %"PRIu16, state_export_id(*file_state), op_ctx->ctx_export->export_id); res_OPEN4->status = NFS4ERR_INVAL; goto out; } } /* If that did not succeed, allocate a state from the FSAL. */ if (*file_state == NULL) { *file_state = op_ctx->fsal_export->exp_ops.alloc_state( op_ctx->fsal_export, STATE_TYPE_SHARE, NULL); /* Remember we allocated a new state */ *new_state = true; /* We are ready to perform the open (with possible create). * in_obj has been set to the file itself or the parent. * filename is NULL if in_obj is the file itself. * * Permission check has been done on directory if appropriate, * otherwise fsal_open2 will do a directory permission * check. * * fsal_open2 handles the permission check on the file * itself and also handles all the share reservation stuff. * * fsal_open2 returns with a ref on out_obj, which should be * passed to the state. */ LogFullDebug(COMPONENT_STATE, "Calling open2 for %s", filename); status = fsal_open2(in_obj, *file_state, openflags, createmode, filename, &sattr, verifier, &out_obj, NULL); if (FSAL_IS_ERROR(status)) { res_OPEN4->status = nfs4_Errno_status(status); goto out; } } else if (createmode >= FSAL_EXCLUSIVE) { /* We have an EXCLUSIVE create with an existing * state. We still need to verify it, but no need * to call reopen2. */ LogFullDebug(COMPONENT_STATE, "Calling verify2 "); status = fsal_verify2(file_obj, verifier); if (FSAL_IS_ERROR(status)) { res_OPEN4->status = nfs4_Errno_status(status); goto out; } /* We need an extra reference below. */ file_obj->obj_ops->get_ref(file_obj); } else { old_openflags = file_obj->obj_ops->status2(file_obj, *file_state); /* Open upgrade */ LogFullDebug(COMPONENT_STATE, "Calling reopen2"); status = fsal_reopen2(file_obj, *file_state, openflags | old_openflags, false); if (FSAL_IS_ERROR(status)) { res_OPEN4->status = nfs4_Errno_status(status); goto out; } /* We need an extra reference below. */ file_obj->obj_ops->get_ref(file_obj); } if (file_obj == NULL) { /* We have a new cache inode entry, take the state lock. */ file_obj = out_obj; PTHREAD_RWLOCK_wrlock(&file_obj->state_hdl->state_lock); state_lock_held = true; } /* Now the state_lock is held for sure and we have an extra LRU * reference to file_obj, which is the opened file. */ if (*new_state) { /* The state data to be added */ union state_data candidate_data; /* Tracking data for the open state */ struct state_refer refer, *p_refer = NULL; state_status_t state_status; candidate_data.share.share_access = arg->share_access & OPEN4_SHARE_ACCESS_BOTH; candidate_data.share.share_deny = arg->share_deny; candidate_data.share.share_access_prev = (1 << candidate_data.share.share_access); candidate_data.share.share_deny_prev = (1 << candidate_data.share.share_deny); LogFullDebug(COMPONENT_STATE, "Creating new state access=%x deny=%x access_prev=%x deny_prev=%x", candidate_data.share.share_access, candidate_data.share.share_deny, candidate_data.share.share_access_prev, candidate_data.share.share_deny_prev); /* Record the sequence info */ if (data->minorversion > 0) { memcpy(refer.session, data->session->session_id, sizeof(sessionid4)); refer.sequence = data->sequence; refer.slot = data->slot; p_refer = &refer; } /* We need to register this state now. */ state_status = state_add_impl(file_obj, STATE_TYPE_SHARE, &candidate_data, owner, file_state, p_refer); if (state_status != STATE_SUCCESS) { /* state_add_impl failure closed and freed state. * file_state will also be NULL at this point. Also * release the ref on file_obj, since the state add * failed. */ file_obj->obj_ops->put_ref(file_obj); res_OPEN4->status = nfs4_Errno_state(state_status); *new_state = false; goto out; } glist_init(&(*file_state)->state_data.share.share_lockstates); } res_OPEN4->status = open4_create_fh(data, file_obj, true); if (res_OPEN4->status != NFS4_OK) { if (*new_state) { /* state_del_locked will close the file. */ state_del_locked(*file_state); *file_state = NULL; *new_state = false; } else { /*Do an open downgrade to the old open flags */ status = file_obj->obj_ops->reopen2(file_obj, *file_state, old_openflags); if (FSAL_IS_ERROR(status)) { LogCrit(COMPONENT_NFS_V4, "Failed to allocate handle, reopen2 failed with %s", fsal_err_txt(status)); } /* Need to release the state_lock before the put_ref * call. */ PTHREAD_RWLOCK_unlock(&file_obj->state_hdl->state_lock); state_lock_held = false; /* Release the extra LRU reference on file_obj. */ file_obj->obj_ops->put_ref(file_obj); goto out; } } /* Since open4_create_fh succeeded the LRU reference to file_obj was * consumed by data->current_obj. */ if (!(*new_state)) { LogFullDebug(COMPONENT_STATE, "Open upgrade old access=%x deny=%x access_prev=%x deny_prev=%x", (*file_state)->state_data.share.share_access, (*file_state)->state_data.share.share_deny, (*file_state)->state_data.share.share_access_prev, (*file_state)->state_data.share.share_deny_prev); LogFullDebug(COMPONENT_STATE, "Open upgrade to access=%x deny=%x", arg->share_access, arg->share_deny); /* Update share_access and share_deny */ (*file_state)->state_data.share.share_access |= arg->share_access & OPEN4_SHARE_ACCESS_BOTH; (*file_state)->state_data.share.share_deny |= arg->share_deny; /* Update share_access_prev and share_deny_prev */ (*file_state)->state_data.share.share_access_prev |= (1 << (arg->share_access & OPEN4_SHARE_ACCESS_BOTH)); (*file_state)->state_data.share.share_deny_prev |= (1 << arg->share_deny); LogFullDebug(COMPONENT_STATE, "Open upgrade new access=%x deny=%x access_prev=%x deny_prev=%x", (*file_state)->state_data.share.share_access, (*file_state)->state_data.share.share_deny, (*file_state)->state_data.share.share_access_prev, (*file_state)->state_data.share.share_deny_prev); } do_delegation(arg, res_OPEN4, data, owner, *file_state, clientid); out: /* Release the attributes (may release an inherited ACL) */ fsal_release_attrs(&sattr); if (state_lock_held) PTHREAD_RWLOCK_unlock(&file_obj->state_hdl->state_lock); if (filename) gsh_free(filename); if (res_OPEN4->status != NFS4_OK) { /* Cleanup state on error */ if (*new_state) (*file_state) ->state_exp->exp_ops.free_state( (*file_state)->state_exp, *file_state); else if (*file_state != NULL) dec_state_t_ref(*file_state); *file_state = NULL; } if (looked_up_file_obj) { /* We got file_obj via lookup, we need to unref it. */ file_obj->obj_ops->put_ref(file_obj); } }
int nfs4_op_setattr(struct nfs_argop4 *op, compound_data_t *data, struct nfs_resop4 *resp) { SETATTR4args * const arg_SETATTR4 = &op->nfs_argop4_u.opsetattr; SETATTR4res * const res_SETATTR4 = &resp->nfs_resop4_u.opsetattr; struct attrlist sattr; cache_inode_status_t cache_status = CACHE_INODE_SUCCESS; const char *tag = "SETATTR"; state_t *state_found = NULL; state_t *state_open = NULL; cache_entry_t *entry = NULL; bool anonymous_started = false; resp->resop = NFS4_OP_SETATTR; res_SETATTR4->status = NFS4_OK; /* Do basic checks on a filehandle */ res_SETATTR4->status = nfs4_sanity_check_FH(data, NO_FILE_TYPE, false); if (res_SETATTR4->status != NFS4_OK) return res_SETATTR4->status; /* Don't allow attribute change while we are in grace period. * Required for delegation reclaims and may be needed for other * reclaimable states as well. */ if (nfs_in_grace()) { res_SETATTR4->status = NFS4ERR_GRACE; return res_SETATTR4->status; } /* Get only attributes that are allowed to be read */ if (!nfs4_Fattr_Check_Access (&arg_SETATTR4->obj_attributes, FATTR4_ATTR_WRITE)) { res_SETATTR4->status = NFS4ERR_INVAL; return res_SETATTR4->status; } /* Ask only for supported attributes */ if (!nfs4_Fattr_Supported(&arg_SETATTR4->obj_attributes)) { res_SETATTR4->status = NFS4ERR_ATTRNOTSUPP; return res_SETATTR4->status; } /* Convert the fattr4 in the request to a fsal sattr structure */ res_SETATTR4->status = nfs4_Fattr_To_FSAL_attr(&sattr, &arg_SETATTR4->obj_attributes, data); if (res_SETATTR4->status != NFS4_OK) return res_SETATTR4->status; /* Trunc may change Xtime so we have to start with trunc and * finish by the mtime and atime */ if ((FSAL_TEST_MASK(sattr.mask, ATTR_SIZE)) || (FSAL_TEST_MASK(sattr.mask, ATTR4_SPACE_RESERVED))) { /* Setting the size of a directory is prohibited */ if (data->current_filetype == DIRECTORY) { res_SETATTR4->status = NFS4ERR_ISDIR; return res_SETATTR4->status; } /* Object should be a file */ if (data->current_entry->type != REGULAR_FILE) { res_SETATTR4->status = NFS4ERR_INVAL; return res_SETATTR4->status; } entry = data->current_entry; /* Check stateid correctness and get pointer to state */ res_SETATTR4->status = nfs4_Check_Stateid(&arg_SETATTR4->stateid, data->current_entry, &state_found, data, STATEID_SPECIAL_ANY, 0, false, tag); if (res_SETATTR4->status != NFS4_OK) return res_SETATTR4->status; /* NB: After this point, if state_found == NULL, then * the stateid is all-0 or all-1 */ if (state_found != NULL) { switch (state_found->state_type) { case STATE_TYPE_SHARE: state_open = state_found; /* Note this causes an extra refcount, but it * simplifies logic below. */ inc_state_t_ref(state_open); break; case STATE_TYPE_LOCK: state_open = state_found->state_data.lock.openstate; inc_state_t_ref(state_open); break; case STATE_TYPE_DELEG: state_open = NULL; break; default: res_SETATTR4->status = NFS4ERR_BAD_STATEID; return res_SETATTR4->status; } /* This is a size operation, this means that * the file MUST have been opened for writing */ if (state_open != NULL && (state_open->state_data.share.share_access & OPEN4_SHARE_ACCESS_WRITE) == 0) { /* Bad open mode, return NFS4ERR_OPENMODE */ res_SETATTR4->status = NFS4ERR_OPENMODE; return res_SETATTR4->status; } } else { /* Special stateid, no open state, check to * see if any share conflicts */ state_open = NULL; /* Special stateid, no open state, check to see if * any share conflicts The stateid is all-0 or all-1 */ res_SETATTR4->status = nfs4_Errno_state( state_share_anonymous_io_start( entry, OPEN4_SHARE_ACCESS_WRITE, SHARE_BYPASS_NONE)); if (res_SETATTR4->status != NFS4_OK) return res_SETATTR4->status; anonymous_started = true; } } const time_t S_NSECS = 1000000000UL; /* Set the atime and mtime (ctime is not setable) */ /* A carry into seconds considered invalid */ if (sattr.atime.tv_nsec >= S_NSECS) { res_SETATTR4->status = NFS4ERR_INVAL; goto done; } if (sattr.mtime.tv_nsec >= S_NSECS) { res_SETATTR4->status = NFS4ERR_INVAL; goto done; } /* If owner or owner_group are set, and the credential was * squashed, then we must squash the set owner and owner_group. */ squash_setattr(&sattr); /* If a SETATTR comes with an open stateid, and size is being * set, then the open MUST be for write (checked above), so * is_open_write is simple at this stage, it's just a check that * we have an open owner. */ cache_status = cache_inode_setattr(data->current_entry, &sattr, state_open != NULL); if (cache_status != CACHE_INODE_SUCCESS) { res_SETATTR4->status = nfs4_Errno(cache_status); goto done; } /* Set the replyed structure */ res_SETATTR4->attrsset = arg_SETATTR4->obj_attributes.attrmask; /* Exit with no error */ res_SETATTR4->status = NFS4_OK; done: if (anonymous_started) state_share_anonymous_io_done(entry, OPEN4_SHARE_ACCESS_WRITE); if (state_found != NULL) dec_state_t_ref(state_found); if (state_open != NULL) dec_state_t_ref(state_open); return res_SETATTR4->status; } /* nfs4_op_setattr */
static fsal_status_t setattrs(struct fsal_obj_handle *obj_hdl, const struct req_op_context *opctx, struct attrlist *attrs) { int rc = 0; fsal_status_t status = { ERR_FSAL_NO_ERROR, 0 }; struct stat sb; int mask = 0; struct glusterfs_export *glfs_export = container_of(obj_hdl->export, struct glusterfs_export, export); struct glusterfs_handle *objhandle = container_of(obj_hdl, struct glusterfs_handle, handle); #ifdef GLTIMING struct timespec s_time, e_time; now(&s_time); #endif memset(&sb, 0, sizeof(struct stat)); if (FSAL_TEST_MASK(attrs->mask, ATTR_SIZE)) { rc = glfs_h_truncate(glfs_export->gl_fs, objhandle->glhandle, attrs->filesize); if (rc != 0) { status = gluster2fsal_error(errno); goto out; } } if (FSAL_TEST_MASK(attrs->mask, ATTR_MODE)) { mask |= GLAPI_SET_ATTR_MODE; sb.st_mode = fsal2unix_mode(attrs->mode); } if (FSAL_TEST_MASK(attrs->mask, ATTR_OWNER)) { mask |= GLAPI_SET_ATTR_UID; sb.st_uid = attrs->owner; } if (FSAL_TEST_MASK(attrs->mask, ATTR_GROUP)) { mask |= GLAPI_SET_ATTR_GID; sb.st_gid = attrs->group; } if (FSAL_TEST_MASK(attrs->mask, ATTR_ATIME)) { mask |= GLAPI_SET_ATTR_ATIME; sb.st_atim = attrs->atime; } if (FSAL_TEST_MASK(attrs->mask, ATTR_ATIME_SERVER)) { mask |= GLAPI_SET_ATTR_ATIME; struct timespec timestamp; rc = clock_gettime(CLOCK_REALTIME, ×tamp); if (rc != 0) { status = gluster2fsal_error(errno); goto out; } sb.st_atim = timestamp; } if (FSAL_TEST_MASK(attrs->mask, ATTR_MTIME)) { mask |= GLAPI_SET_ATTR_MTIME; sb.st_mtim = attrs->mtime; } if (FSAL_TEST_MASK(attrs->mask, ATTR_MTIME_SERVER)) { mask |= GLAPI_SET_ATTR_MTIME; struct timespec timestamp; rc = clock_gettime(CLOCK_REALTIME, ×tamp); if (rc != 0) { status = gluster2fsal_error(rc); goto out; } sb.st_mtim = timestamp; } rc = glfs_h_setattrs(glfs_export->gl_fs, objhandle->glhandle, &sb, mask); if (rc != 0) { status = gluster2fsal_error(errno); goto out; } out: #ifdef GLTIMING now(&e_time); latency_update(&s_time, &e_time, lat_setattrs); #endif return status; }
static void open4_ex_create_args(OPEN4args *arg, compound_data_t *data, OPEN4res *res_OPEN4, void *verifier, enum fsal_create_mode *createmode, struct attrlist *sattr) { createhow4 *createhow = &arg->openhow.openflag4_u.how; fattr4 *arg_attrs = NULL; *createmode = nfs4_createmode_to_fsal(createhow->mode); if (createhow->mode == EXCLUSIVE4_1) { memcpy(verifier, createhow->createhow4_u.ch_createboth.cva_verf, sizeof(fsal_verifier_t)); } else if (createhow->mode == EXCLUSIVE4) { memcpy(verifier, createhow->createhow4_u.createverf, sizeof(fsal_verifier_t)); } /* Select the correct attributes */ if (createhow->mode == GUARDED4 || createhow->mode == UNCHECKED4) arg_attrs = &createhow->createhow4_u.createattrs; else if (createhow->mode == EXCLUSIVE4_1) arg_attrs = &createhow->createhow4_u.ch_createboth.cva_attrs; if (arg_attrs != NULL) { /* Check if asked attributes are correct */ if (!nfs4_Fattr_Supported(arg_attrs)) { res_OPEN4->status = NFS4ERR_ATTRNOTSUPP; return; } if (!nfs4_Fattr_Check_Access(arg_attrs, FATTR4_ATTR_WRITE)) { res_OPEN4->status = NFS4ERR_INVAL; return; } /* Convert the attributes */ if (arg_attrs->attrmask.bitmap4_len != 0) { /* Convert fattr4 so nfs4_sattr */ res_OPEN4->status = nfs4_Fattr_To_FSAL_attr(sattr, arg_attrs, data); if (res_OPEN4->status != NFS4_OK) return; } if (createhow->mode == EXCLUSIVE4_1) { /** @todo FSF: this needs to be corrected in case FSAL * uses different attributes for the * verifier. */ /* Check that we aren't trying to set the verifier * attributes. */ if (FSAL_TEST_MASK(sattr->valid_mask, ATTR_ATIME) || FSAL_TEST_MASK(sattr->valid_mask, ATTR_MTIME)) { res_OPEN4->status = NFS4ERR_INVAL; return; } } /* If owner or owner_group are set, and the credential was * squashed, then we must squash the set owner and owner_group. */ squash_setattr(sattr); } if (!(sattr->valid_mask & ATTR_MODE)) { /* Make sure mode is set, even for exclusive create. */ sattr->mode = 0600; sattr->valid_mask |= ATTR_MODE; } }
fsal_status_t FSAL_setattrs(fsal_handle_t * filehandle, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_attrib_list_t * attrib_set, /* IN */ fsal_attrib_list_t * object_attributes /* [ IN/OUT ] */ ) { GHOSTFS_setattr_mask_t set_mask = 0; GHOSTFS_Attrs_t ghost_attrs; int rc; memset(&ghost_attrs, 0, sizeof(GHOSTFS_Attrs_t)); /* For logging */ SetFuncID(INDEX_FSAL_setattrs); #define SETTABLE_ATTRIBUTES ( FSAL_ATTR_SIZE |\ FSAL_ATTR_MODE |\ FSAL_ATTR_OWNER |\ FSAL_ATTR_GROUP |\ FSAL_ATTR_ATIME |\ FSAL_ATTR_MTIME ) /* sanity checks. * note : object_attributes is optional. */ if(!filehandle || !p_context || !attrib_set) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_setattrs); /* first convert attributes and mask */ if(FSAL_TEST_MASK(attrib_set->asked_attributes, FSAL_ATTR_SIZE)) { set_mask |= SETATTR_SIZE; ghost_attrs.size = attrib_set->filesize; } if(FSAL_TEST_MASK(attrib_set->asked_attributes, FSAL_ATTR_MODE)) { set_mask |= SETATTR_MODE; ghost_attrs.mode = fsal2ghost_mode(attrib_set->mode); } /* ghostfs does not check chown restrictions, * so we check this for it. */ if(FSAL_TEST_MASK(attrib_set->asked_attributes, FSAL_ATTR_OWNER)) { if(p_context->credential.user != 0) Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs); set_mask |= SETATTR_UID; ghost_attrs.uid = attrib_set->owner; } if(FSAL_TEST_MASK(attrib_set->asked_attributes, FSAL_ATTR_GROUP)) { if(p_context->credential.user != 0) Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs); set_mask |= SETATTR_GID; ghost_attrs.gid = attrib_set->group; } if(FSAL_TEST_MASK(attrib_set->asked_attributes, FSAL_ATTR_ATIME)) { set_mask |= SETATTR_ATIME; ghost_attrs.atime = attrib_set->atime.seconds; } if(FSAL_TEST_MASK(attrib_set->asked_attributes, FSAL_ATTR_MTIME)) { set_mask |= SETATTR_MTIME; ghost_attrs.mtime = attrib_set->mtime.seconds; } if(attrib_set->asked_attributes & ~SETTABLE_ATTRIBUTES) { LogFullDebug(COMPONENT_FSAL, "FSAL: To be set %llX, Settable %llX", (unsigned long long)object_attributes->asked_attributes, (unsigned long long)SETTABLE_ATTRIBUTES); Return(ERR_FSAL_ATTRNOTSUPP, 0, INDEX_FSAL_setattrs); } /* appel a setattr */ rc = GHOSTFS_SetAttrs((GHOSTFS_handle_t) (*filehandle), set_mask, ghost_attrs); if(rc) Return(ghost2fsal_error(rc), rc, INDEX_FSAL_setattrs); if(object_attributes) { fsal_status_t status = FSAL_getattrs(filehandle, p_context, object_attributes); /* on error, we set a special bit in the mask. */ if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(object_attributes->asked_attributes); FSAL_SET_MASK(object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_setattrs); }