mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-29 20:30:35 +00:00
![Chuck Lever](/assets/img/avatar_default.png)
This simple data structure binds the location of each data payload inside of an RPC message to the chunk that will be used to push it to or pull it from the client. There are several benefits to this small additional overhead: * It enables support for more than one chunk in incoming Read and Write lists. * It translates the version-specific on-the-wire format into a generic in-memory structure, enabling support for multiple versions of the RPC/RDMA transport protocol. * It enables the server to re-organize a chunk list if it needs to adjust where Read chunk data lands in server memory without altering the contents of the XDR-encoded Receive buffer. Construction of these lists is done while sanity checking each incoming RPC/RDMA header. Subsequent patches will make use of the generated data structures. Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
128 lines
3.1 KiB
C
128 lines
3.1 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* Copyright (c) 2020, Oracle and/or its affiliates
|
|
*/
|
|
|
|
#ifndef SVC_RDMA_PCL_H
|
|
#define SVC_RDMA_PCL_H
|
|
|
|
#include <linux/list.h>
|
|
|
|
struct svc_rdma_segment {
|
|
u32 rs_handle;
|
|
u32 rs_length;
|
|
u64 rs_offset;
|
|
};
|
|
|
|
struct svc_rdma_chunk {
|
|
struct list_head ch_list;
|
|
|
|
u32 ch_position;
|
|
u32 ch_length;
|
|
u32 ch_payload_length;
|
|
|
|
u32 ch_segcount;
|
|
struct svc_rdma_segment ch_segments[];
|
|
};
|
|
|
|
struct svc_rdma_pcl {
|
|
unsigned int cl_count;
|
|
struct list_head cl_chunks;
|
|
};
|
|
|
|
/**
|
|
* pcl_init - Initialize a parsed chunk list
|
|
* @pcl: parsed chunk list to initialize
|
|
*
|
|
*/
|
|
static inline void pcl_init(struct svc_rdma_pcl *pcl)
|
|
{
|
|
INIT_LIST_HEAD(&pcl->cl_chunks);
|
|
}
|
|
|
|
/**
|
|
* pcl_is_empty - Return true if parsed chunk list is empty
|
|
* @pcl: parsed chunk list
|
|
*
|
|
*/
|
|
static inline bool pcl_is_empty(const struct svc_rdma_pcl *pcl)
|
|
{
|
|
return list_empty(&pcl->cl_chunks);
|
|
}
|
|
|
|
/**
|
|
* pcl_first_chunk - Return first chunk in a parsed chunk list
|
|
* @pcl: parsed chunk list
|
|
*
|
|
* Returns the first chunk in the list, or NULL if the list is empty.
|
|
*/
|
|
static inline struct svc_rdma_chunk *
|
|
pcl_first_chunk(const struct svc_rdma_pcl *pcl)
|
|
{
|
|
if (pcl_is_empty(pcl))
|
|
return NULL;
|
|
return list_first_entry(&pcl->cl_chunks, struct svc_rdma_chunk,
|
|
ch_list);
|
|
}
|
|
|
|
/**
|
|
* pcl_next_chunk - Return next chunk in a parsed chunk list
|
|
* @pcl: a parsed chunk list
|
|
* @chunk: chunk in @pcl
|
|
*
|
|
* Returns the next chunk in the list, or NULL if @chunk is already last.
|
|
*/
|
|
static inline struct svc_rdma_chunk *
|
|
pcl_next_chunk(const struct svc_rdma_pcl *pcl, struct svc_rdma_chunk *chunk)
|
|
{
|
|
if (list_is_last(&chunk->ch_list, &pcl->cl_chunks))
|
|
return NULL;
|
|
return list_next_entry(chunk, ch_list);
|
|
}
|
|
|
|
/**
|
|
* pcl_for_each_chunk - Iterate over chunks in a parsed chunk list
|
|
* @pos: the loop cursor
|
|
* @pcl: a parsed chunk list
|
|
*/
|
|
#define pcl_for_each_chunk(pos, pcl) \
|
|
for (pos = list_first_entry(&(pcl)->cl_chunks, struct svc_rdma_chunk, ch_list); \
|
|
&pos->ch_list != &(pcl)->cl_chunks; \
|
|
pos = list_next_entry(pos, ch_list))
|
|
|
|
/**
|
|
* pcl_for_each_segment - Iterate over segments in a parsed chunk
|
|
* @pos: the loop cursor
|
|
* @chunk: a parsed chunk
|
|
*/
|
|
#define pcl_for_each_segment(pos, chunk) \
|
|
for (pos = &(chunk)->ch_segments[0]; \
|
|
pos <= &(chunk)->ch_segments[(chunk)->ch_segcount - 1]; \
|
|
pos++)
|
|
|
|
/**
|
|
* pcl_chunk_end_offset - Return offset of byte range following @chunk
|
|
* @chunk: chunk in @pcl
|
|
*
|
|
* Returns starting offset of the region just after @chunk
|
|
*/
|
|
static inline unsigned int
|
|
pcl_chunk_end_offset(const struct svc_rdma_chunk *chunk)
|
|
{
|
|
return xdr_align_size(chunk->ch_position + chunk->ch_payload_length);
|
|
}
|
|
|
|
struct svc_rdma_recv_ctxt;
|
|
|
|
extern void pcl_free(struct svc_rdma_pcl *pcl);
|
|
extern bool pcl_alloc_call(struct svc_rdma_recv_ctxt *rctxt, __be32 *p);
|
|
extern bool pcl_alloc_read(struct svc_rdma_recv_ctxt *rctxt, __be32 *p);
|
|
extern bool pcl_alloc_write(struct svc_rdma_recv_ctxt *rctxt,
|
|
struct svc_rdma_pcl *pcl, __be32 *p);
|
|
extern int pcl_process_nonpayloads(const struct svc_rdma_pcl *pcl,
|
|
const struct xdr_buf *xdr,
|
|
int (*actor)(const struct xdr_buf *,
|
|
void *),
|
|
void *data);
|
|
|
|
#endif /* SVC_RDMA_PCL_H */
|