/* * XDR the MSG_ACCEPTED part of a reply message union */ bool xdr_naccepted_reply(XDR *xdrs, struct accepted_reply *ar) { assert(xdrs != NULL); assert(ar != NULL); /* personalized union, rather than calling xdr_union */ if (!inline_xdr_opaque_auth(xdrs, &(ar->ar_verf))) return (false); if (!inline_xdr_enum(xdrs, (enum_t *) &(ar->ar_stat))) return (false); switch (ar->ar_stat) { case SUCCESS: return ((*(ar->ar_results.proc)) (xdrs, ar->ar_results.where)); case PROG_MISMATCH: if (!inline_xdr_u_int32_t(xdrs, &(ar->ar_vers.low))) return (false); return (inline_xdr_u_int32_t(xdrs, &(ar->ar_vers.high))); case GARBAGE_ARGS: case SYSTEM_ERR: case PROC_UNAVAIL: case PROG_UNAVAIL: break; } return (true); /* true => open ended set of problems */ }
/* * Serializes the "static part" of a call message header. * The fields include: rm_xid, rm_direction, rpcvers, prog, and vers. * The rm_xid is not really static, but the user can easily munge on the fly. */ bool xdr_ncallhdr(XDR *xdrs, struct rpc_msg *cmsg) { assert(xdrs != NULL); assert(cmsg != NULL); cmsg->rm_direction = CALL; cmsg->rm_call.cb_rpcvers = RPC_MSG_VERSION; if ((xdrs->x_op == XDR_ENCODE) && inline_xdr_u_int32_t(xdrs, &(cmsg->rm_xid)) && inline_xdr_enum(xdrs, (enum_t *) &(cmsg->rm_direction)) && inline_xdr_u_int32_t(xdrs, &(cmsg->rm_call.cb_rpcvers)) && inline_xdr_u_int32_t(xdrs, &(cmsg->rm_call.cb_prog))) return (inline_xdr_u_int32_t(xdrs, &(cmsg->rm_call.cb_vers))); return (false); }
/* * XDR the MSG_DENIED part of a reply message union */ bool xdr_nrejected_reply(XDR *xdrs, struct rejected_reply *rr) { assert(xdrs != NULL); assert(rr != NULL); /* personalized union, rather than calling xdr_union */ if (!inline_xdr_enum(xdrs, (enum_t *) &(rr->rj_stat))) return (false); switch (rr->rj_stat) { case RPC_MISMATCH: if (!inline_xdr_u_int32_t(xdrs, &(rr->rj_vers.low))) return (false); return (inline_xdr_u_int32_t(xdrs, &(rr->rj_vers.high))); case AUTH_ERROR: return (inline_xdr_enum(xdrs, (enum_t *) &(rr->rj_why))); } /* NOTREACHED */ assert(0); return (false); }
/* * XDR a reply message */ bool xdr_nreplymsg(XDR *xdrs, struct rpc_msg *rmsg) { assert(xdrs != NULL); assert(rmsg != NULL); if (inline_xdr_u_int32_t(xdrs, &(rmsg->rm_xid)) && inline_xdr_enum(xdrs, (enum_t *) &(rmsg->rm_direction)) && (rmsg->rm_direction == REPLY)) return (inline_xdr_union (xdrs, (enum_t *) &(rmsg->rm_reply.rp_stat), (caddr_t) (void *)&(rmsg->rm_reply.ru), reply_dscrm, NULL_xdrproc_t)); return (false); }
static bool initiate_recall(vinodeno_t vi, bool write, void *opaque) { /* The private 'full' object handle */ struct handle *handle = (struct handle *)opaque; /* Return code from upcall operation */ state_status_t status = STATE_SUCCESS; struct gsh_buffdesc key = { .addr = &handle->vi, .len = sizeof(vinodeno_t) }; struct pnfs_segment segment = { .offset = 0, .length = UINT64_MAX, .io_mode = (write ? LAYOUTIOMODE4_RW : LAYOUTIOMODE4_READ) }; status = handle->up_ops->layoutrecall(&key, LAYOUT4_NFSV4_1_FILES, false, &segment, NULL, NULL); if (status != STATE_SUCCESS) return false; return true; } /** * @brief Describe a Ceph striping pattern * * At present, we support a files based layout only. The CRUSH * striping pattern is a-periodic * * @param[in] export_pub Public export handle * @param[out] da_addr_body Stream we write the result to * @param[in] type Type of layout that gave the device * @param[in] deviceid The device to look up * * @return Valid error codes in RFC 5661, p. 365. */ static nfsstat4 getdeviceinfo(struct fsal_export *export_pub, XDR *da_addr_body, const layouttype4 type, const struct pnfs_deviceid *deviceid) { /* Full 'private' export */ struct export *export = container_of(export_pub, struct export, export); /* The number of Ceph OSDs in the cluster */ unsigned num_osds = ceph_ll_num_osds(export->cmount); /* Minimal information needed to get layout info */ vinodeno_t vinode; /* Structure containing the storage parameters of the file within the Ceph cluster. */ struct ceph_file_layout file_layout; /* Currently, all layouts have the same number of stripes */ uint32_t stripes = BIGGEST_PATTERN; /* Index for iterating over stripes */ size_t stripe = 0; /* Index for iterating over OSDs */ size_t osd = 0; /* NFSv4 status code */ nfsstat4 nfs_status = 0; vinode.ino.val = deviceid->devid; vinode.snapid.val = CEPH_NOSNAP; /* Sanity check on type */ if (type != LAYOUT4_NFSV4_1_FILES) { LogCrit(COMPONENT_PNFS, "Unsupported layout type: %x", type); return NFS4ERR_UNKNOWN_LAYOUTTYPE; } /* Retrieve and calculate storage parameters of layout */ memset(&file_layout, 0, sizeof(struct ceph_file_layout)); if (ceph_ll_file_layout(export->cmount, vinode, &file_layout) != 0) { LogCrit(COMPONENT_PNFS, "Failed to get Ceph layout for inode"); return NFS4ERR_SERVERFAULT; } /* As this is large, we encode as we go rather than building a structure and encoding it all at once. */ /* The first entry in the nfsv4_1_file_ds_addr4 is the array of stripe indices. First we encode the count of stripes. Since our pattern doesn't repeat, we have as many indices as we do stripes. */ if (!inline_xdr_u_int32_t(da_addr_body, &stripes)) { LogCrit(COMPONENT_PNFS, "Failed to encode length of stripe_indices array: %" PRIu32 ".", stripes); return NFS4ERR_SERVERFAULT; } for (stripe = 0; stripe < stripes; stripe++) { uint32_t stripe_osd = stripe_osd = ceph_ll_get_stripe_osd(export->cmount, vinode, stripe, &file_layout); if (stripe_osd < 0) { LogCrit(COMPONENT_PNFS, "Failed to retrieve OSD for stripe %lu of file %" PRIu64 ". Error: %u", stripe, deviceid->devid, -stripe_osd); return NFS4ERR_SERVERFAULT; } if (!inline_xdr_u_int32_t(da_addr_body, &stripe_osd)) { LogCrit(COMPONENT_PNFS, "Failed to encode OSD for stripe %lu.", stripe); return NFS4ERR_SERVERFAULT; } } /* The number of OSDs in our cluster is the length of our array of multipath_lists */ if (!inline_xdr_u_int32_t(da_addr_body, &num_osds)) { LogCrit(COMPONENT_PNFS, "Failed to encode length of multipath_ds_list array: %u", num_osds); return NFS4ERR_SERVERFAULT; } /* Since our index is the OSD number itself, we have only one host per multipath_list. */ for (osd = 0; osd < num_osds; osd++) { fsal_multipath_member_t host; memset(&host, 0, sizeof(fsal_multipath_member_t)); host.proto = 6; if (ceph_ll_osdaddr(export->cmount, osd, &host.addr) < 0) { LogCrit(COMPONENT_PNFS, "Unable to get IP address for OSD %lu.", osd); return NFS4ERR_SERVERFAULT; } host.port = 2049; nfs_status = FSAL_encode_v4_multipath(da_addr_body, 1, &host); if (nfs_status != NFS4_OK) return nfs_status; } return NFS4_OK; } /** * @brief Get list of available devices * * We do not support listing devices and just set EOF without doing * anything. * * @param[in] export_pub Export handle * @param[in] type Type of layout to get devices for * @param[in] cb Function taking device ID halves * @param[in,out] res In/out and output arguments of the function * * @return Valid error codes in RFC 5661, pp. 365-6. */ static nfsstat4 getdevicelist(struct fsal_export *export_pub, layouttype4 type, void *opaque, bool(*cb) (void *opaque, const uint64_t id), struct fsal_getdevicelist_res *res) { res->eof = true; return NFS4_OK; } /** * @brief Get layout types supported by export * * We just return a pointer to the single type and set the count to 1. * * @param[in] export_pub Public export handle * @param[out] count Number of layout types in array * @param[out] types Static array of layout types that must not be * freed or modified and must not be dereferenced * after export reference is relinquished */ static void fs_layouttypes(struct fsal_export *export_pub, int32_t *count, const layouttype4 **types) { static const layouttype4 supported_layout_type = LAYOUT4_NFSV4_1_FILES; *types = &supported_layout_type; *count = 1; } /** * @brief Get layout block size for export * * This function just returns the Ceph default. * * @param[in] export_pub Public export handle * * @return 4 MB. */ static uint32_t fs_layout_blocksize(struct fsal_export *export_pub) { return 0x400000; } /** * @brief Maximum number of segments we will use * * Since current clients only support 1, that's what we'll use. * * @param[in] export_pub Public export handle * * @return 1 */ static uint32_t fs_maximum_segments(struct fsal_export *export_pub) { return 1; } /** * @brief Size of the buffer needed for a loc_body * * Just a handle plus a bit. * * @param[in] export_pub Public export handle * * @return Size of the buffer needed for a loc_body */ static size_t fs_loc_body_size(struct fsal_export *export_pub) { return 0x100; } /** * @brief Size of the buffer needed for a ds_addr * * This one is huge, due to the striping pattern. * * @param[in] export_pub Public export handle * * @return Size of the buffer needed for a ds_addr */ static size_t fs_da_addr_size(struct fsal_export *export_pub) { return 0x1400; } void export_ops_pnfs(struct export_ops *ops) { ops->getdeviceinfo = getdeviceinfo; ops->getdevicelist = getdevicelist; ops->fs_layouttypes = fs_layouttypes; ops->fs_layout_blocksize = fs_layout_blocksize; ops->fs_maximum_segments = fs_maximum_segments; ops->fs_loc_body_size = fs_loc_body_size; ops->fs_da_addr_size = fs_da_addr_size; }
/** * @brief Describes the DS information for the client * * @param[in] export_pub Public export handle * @param[out] da_addr_body Stream we write the result to * @param[in] type Type of layout that gave the device * @param[in] deviceid The device to look up * * @return Valid error codes in RFC 5661, p. 365. */ nfsstat4 getdeviceinfo(struct fsal_module *fsal_hdl, XDR *da_addr_body, const layouttype4 type, const struct pnfs_deviceid *deviceid) { nfsstat4 nfs_status = 0; /* Stores IP address of DS */ fsal_multipath_member_t host; /* Entire file layout will be situated inside ONE DS * And whole file is provided to the DS, so the starting * index for that file is zero */ unsigned num_ds = 1; uint32_t stripes = 1; uint32_t stripe_ind = 0; if (type != LAYOUT4_NFSV4_1_FILES) { LogMajor(COMPONENT_PNFS, "Unsupported layout type: %x", type); return NFS4ERR_UNKNOWN_LAYOUTTYPE; } if (!inline_xdr_u_int32_t(da_addr_body, &stripes)) { LogMajor(COMPONENT_PNFS, "Failed to encode length of stripe_indices array: %" PRIu32 ".", stripes); return NFS4ERR_SERVERFAULT; } if (!inline_xdr_u_int32_t(da_addr_body, &stripe_ind)) { LogMajor(COMPONENT_PNFS, "Failed to encode ds for the stripe: %" PRIu32 ".", stripe_ind); return NFS4ERR_SERVERFAULT; } if (!inline_xdr_u_int32_t(da_addr_body, &num_ds)) { LogMajor(COMPONENT_PNFS, "Failed to encode length of multipath_ds_list array: %u", num_ds); return NFS4ERR_SERVERFAULT; } memset(&host, 0, sizeof(fsal_multipath_member_t)); host.addr = ntohl(deviceid->device_id4); host.port = 2049; host.proto = 6; nfs_status = FSAL_encode_v4_multipath(da_addr_body, 1, &host); if (nfs_status != NFS4_OK) { LogMajor(COMPONENT_PNFS, "Failed to encode data server address"); return nfs_status; } /** @todo: Here information about Data-Server where file resides * is only send from MDS.If that Data-Server is down then * read or write will performed through MDS. * Instead should we send the information about all * the available data-servers, so that these fops will * always performed through Data-Servers. * (Like in replicated volume contains more than ONE DS) */ return NFS4_OK; }