source: gpfs_3.1_ker2.6.20/lpp/mmfs/src/ibm-kxi/cxiIOBuffer.h @ 223

Last change on this file since 223 was 16, checked in by rock, 17 years ago
File size: 15.2 KB
Line 
1/***************************************************************************
2 *
3 * Copyright (C) 2001 International Business Machines
4 * All rights reserved.
5 *
6 * This file is part of the GPFS mmfslinux kernel module.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 *  1. Redistributions of source code must retain the above copyright notice,
13 *     this list of conditions and the following disclaimer.
14 *  2. Redistributions in binary form must reproduce the above copyright
15 *     notice, this list of conditions and the following disclaimer in the
16 *     documentation and/or other materials provided with the distribution.
17 *  3. The name of the author may not be used to endorse or promote products
18 *     derived from this software without specific prior written
19 *     permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
30 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 *************************************************************************** */
33/* @(#)12       1.27  src/avs/fs/mmfs/ts/kernext/ibm-kxi/cxiIOBuffer.h, mmfs, avs_rgpfs24, rgpfs240610b 5/4/04 10:12:05 */
34/*
35 * Abstraction of an I/O buffer
36 *   struct cxiIOBuffer_t
37 *   InitIOBuffer
38 *   GetDaemonIOBufferEndAddr
39 *
40 * Support for buffers that are not contiguous in memory
41 *   struct cxiDiscontiguousDirectoryBuffer_t
42 *   InitDiscontiguousBuffer
43 *   OffsetToPtr
44 *   MapContiguousBuffer
45 */
46
47#ifndef _h_cxiIOBuffer
48#define _h_cxiIOBuffer
49
50#include <cxiTypes.h>
51/* Use logging definitions for non portability layer */
52#if !defined(GPFS_GPL)
53#include <Logger.h>
54#endif /* !GPFS_GPL */
55
56
57/* Abstraction of an I/O buffer.  I/O buffers are contiguous in virtual
58   memory from the point of view of the GPFS daemon.  The view of the buffer
59   from kernel code is platform-dependent.
60
61   The first operation that must be performed on an I/O buffer must be to
62   attach it to kernel memory.  Once this is done, the buffer may be
63   accessed indirectly by transferring data between it and buffers in user
64   or kernel space.  The buffer may also be mapped so that normal loads and
65   stores from the kernel may access the data in the buffer.  In general,
66   such a mapping will not be contiguous in the address space of the kernel,
67   so the code that accesses the contents of the buffer must be aware of
68   page boundaries.  Once all direct and indirect accesses to the buffer are
69   complete, it must be detached from kernel memory. */
70
71/* Forward declarations */
72
73/* Kernel data structure associated with an I/O buffer */
74struct cxiKernelIOBufferDesc_t;
75
76/* Result of making a read-only copy of a portion of an I/O buffer */
77struct cxiContiguousBuffer_t;
78
79/* Result of mapping a buffer too large to be mapped contiguously */
80struct cxiDiscontiguousDirectoryBuffer_t;
81
82/* Handle that describes a cxiIOBuffer_t that has been attached */
83struct cxiIOBufferAttachment_t;
84
85struct cxiIOBuffer_t;
86
87/* Include platform-specific definitions and possibly define
88 * __CXI_BUFFERS_ARE_CONTIGUOUS to affect the definition of
89 * cxiDiscontiguousDirectoryBuffer_t below.
90 */
91#include <cxiIOBuffer-plat.h>
92
93#include <cxiLinkList.h>
94
95#define BUDDY_NONE  0
96#define BUDDY_FIRST 1
97#define BUDDY_LAST  255  /* unsigned char max */
98
99#ifndef __cplusplus
100/* forward declaration in C for Linux portability layer */
101typedef struct Buffer Buffer;
102typedef Buffer *BufferXPtr;
103#endif
104
105struct cxiMemoryDesc_t
106{
107  unsigned char  vindex;    /* index in shared seg memMapping array */
108  unsigned char  buddyNum;  /* buddies that can be rejoined share a number */
109  unsigned short klength;   /* length of area in kilobytes */
110  unsigned int   offset;    /* offset within the segment */
111
112  /* If C++ would allow me to make a union between inactive and bufP
113   * these could be coalesced to make the structure smaller.
114   * (something on the inactive list shouldn't have a buffer)
115   */
116  BufferXPtr bufP;          /* pointer to owning buffer */
117
118  /* list of descriptors on inactive list */
119  DLink_t inactive;       
120
121  /* circular doubly linked list of memory siblings */
122  DLink_t sibling;
123};
124
125typedef struct cxiMemoryDesc_t cxiMemoryDesc_t;
126
127#ifdef GPFS_GPL
128/* handle a few shared cxi structures (for swizzling) */
129typedef cxiMemoryDesc_t *cxiMemoryDesc_tXPtr;
130#endif
131
132static inline void 
133InitMemoryDesc(struct cxiMemoryDesc_t *mdP)
134{
135  mdP->vindex = 0;
136  mdP->buddyNum = BUDDY_NONE;
137  mdP->klength = 0;
138  mdP->offset = 0;
139  mdP->bufP = NULL;
140  DLinkInit(&mdP->inactive);
141  DLinkInit(&mdP->sibling);
142}
143
144/* I/O buffer description
145
146   On AIX, an I/O buffer in the virtual address space of the daemon must
147   be pinned before it can be used for I/O, and must be mapped before
148   accessing its contents.  On AIX, the kernel mapping will be contiguous,
149   although not necessarily at the same addresses as used by the daemon.
150
151   On Linux, an I/O buffer in the virtual address space of the daemon must
152   be pinned before it can be used for I/O, and must be mapped before
153   accessing its contents.  On Linux, pages of the buffer will in general
154   not be contiguous in kernel virtual memory.  The cxiK... routines
155   just call into the kernel (kx...), which then calls the corresponding
156   routines on cxiKernelIOBufferDesc_t's (Kibd...). */
157struct cxiIOBuffer_t
158{
159  /* Length of buffer in bytes */
160  int ioBufLen;
161
162  /* Number of users that are currently using this buffer and require it
163     to be pinned in memory.  A value of 0 means the buffer is not pinned. */
164  int pinCount;
165
166  /* Pointer to beginning of contiguous buffer in daemon virtual address
167     space */
168  char* daemonBufP; 
169
170  /* Pointer to kernel data structure associated with this I/O buffer */
171  struct cxiKernelIOBufferDesc_t* kernelIOBufferDescP;
172
173  /* A chain of possibly multiple memory descriptors */
174  cxiMemoryDesc_tXPtr descP;
175};
176
177static inline char *
178OffsetToDataPtr(const struct cxiIOBuffer_t *iobP, int offset, int length)
179{
180  return iobP->daemonBufP + offset;
181}
182
183/* Clear all fields of an cxiIOBuffer_t to default values */
184static inline void InitIOBuffer(struct cxiIOBuffer_t* iobP)
185{ 
186  iobP->ioBufLen = -1; 
187  iobP->pinCount = 0;
188  iobP->daemonBufP = NULL; 
189  iobP->kernelIOBufferDescP = NULL; 
190  iobP->descP = NULL;
191}
192
193/* Return true if the fields describing the IOBuffer are self-consistent. */
194static inline Boolean IOBufferIsConsistent(struct cxiIOBuffer_t* iobP)
195  { return IOBUFFER_IS_CONSISTENT(iobP); };
196
197/* Return the daemon address of the first byte beyond the end of the
198   I/O buffer */
199static inline char* GetDaemonIOBufferEndAddr(struct cxiIOBuffer_t* iobP)
200  { return iobP->daemonBufP + iobP->ioBufLen; };
201
202#if 0
203  /* Pin all the pages of a buffer.  If the buffer is already pinned, just
204     increment its pin count.  Returns EOK if successful, other error codes
205     if unsuccessful. */
206  int pin();
207
208  /* Decrement the pin count on the buffer.  If the count reaches zero,
209     unpin the pages of the buffer. */
210  void unpin();
211#endif
212
213/* Attach an I/O buffer to the kernel's virtual address space.  The
214   cxiIOBufferAttachment_t returned in *attachP must be used as a parameter
215   of most of the other operations on cxiIOBuffer_t's. */
216EXTERNC void cxiAttachIOBuffer(struct cxiIOBuffer_t* iobP,
217                               struct cxiIOBufferAttachment_t* attachP);
218
219/* Detach a buffer from the kernel's virtual address space. */
220EXTERNC void cxiDetachIOBuffer(struct cxiIOBuffer_t* iobP,
221                               struct cxiIOBufferAttachment_t* attachP);
222
223/* Transfer len bytes beginning at offset bufOffset within I/O buffer *iobP
224   to or from a user buffer.  The direction of the transfer is given with
225   respect to the I/O buffer.  Returns EOK if successful, other error
226   codes if unsuccessful. */
227EXTERNC int cxiUXfer(struct cxiIOBuffer_t* iobP, Boolean toIOBuffer,
228                     const struct cxiIOBufferAttachment_t* attachP,
229                     void* vkopP, int bufOffset, int len,
230                     struct cxiUio_t* uioP);
231#define CXI_XFER_TO_IOBUFFER true
232#define CXI_XFER_FROM_IOBUFFER false
233
234/* Perform cross-memory transfer of len bytes from user memory in current
235   task to memory in specified address space.  If toXmem is true then
236   copy is from userAddrP to udataP/xmemP, otherwise the opposite. */
237EXTERNC int cxiXmemXfer(char *userAddrP, int len, char *udataP,
238                        cxiXmem_t *xmemP, Boolean toXmem);
239
240/* Transfer len bytes beginning at offset bufOffset within I/O buffer *iobP
241   to or from a contiguous kernel buffer.  The direction of the transfer
242   is given with respect to the I/O buffer.  Returns EOK if successful,
243   other error codes if unsuccessful. */
244EXTERNC int cxiKXfer(struct cxiIOBuffer_t* iobP, Boolean toIOBuffer,
245                     const struct cxiIOBufferAttachment_t* attachP,
246                     int bufOffset, int len, char* kBufP);
247
248/* Set len bytes beginning at offset bufOffset within I/O buffer *iobP
249   to zero.  Returns EOK if successful, other error codes if unsuccessful. */
250EXTERNC int cxiKZero(struct cxiIOBuffer_t* iobP,
251                     const struct cxiIOBufferAttachment_t* attachP,
252                     int bufOffset, int len);
253
254/* Map an I/O buffer so it can be read and written from kernel code
255   running in the context of a user thread.  Depending on the platform,
256   the addresses at which the I/O buffer gets mapped may not be
257   contiguous.  The details of how the buffer got mapped are handled by
258   the cxiDiscontiguousDirectoryBuffer_t object that is filled in by this
259   call.  On some platforms, mapping buffers using this call consumes
260   scarce resources, so all cxiMapDiscontiguousRW calls should be promptly
261   matched by unmapDiscontiguousRW calls as soon as the operation that
262   required access to the I/O buffer completes.  Returns EOK if
263   successful, other error codes if unsuccessful. */
264EXTERNC int cxiMapDiscontiguousRW(struct cxiIOBuffer_t* iobP,
265                                  const struct cxiIOBufferAttachment_t* attachP,
266                                  struct cxiDiscontiguousDirectoryBuffer_t* discontigP);
267
268/* Unmap an I/O buffer previously mapped */
269EXTERNC void cxiUnmapDiscontiguousRW(struct cxiIOBuffer_t* iobP,
270                                     struct cxiDiscontiguousDirectoryBuffer_t* discontigP);
271
272/* Return an address in kernel memory that holds a contigous read-only
273   copy of a portion of an I/O buffer.  If possible, this will be a
274   mapping of the I/O buffer.  If necessary, this routine will allocate a
275   new block of kernel memory and copy the requested data to it.  The
276   returned cxiContiguousBuffer_t encapsulates what method was used, so
277   that unmapContiguousRO can release whatever resources were obtained by
278   this call.  Returns EOK if successful, other error codes if
279   unsuccessful. */
280EXTERNC int cxiMapContiguousRO(struct cxiIOBuffer_t* iobP,
281                               const struct cxiIOBufferAttachment_t* attachP,
282                               int bufOffset, int len,
283                               const char** contigBasePP,
284                               struct cxiContiguousBuffer_t* contigP);
285
286/* Release a mapping or copy obtained with cxiMapContiguousRO */
287EXTERNC void cxiUnmapContiguousRO(struct cxiIOBuffer_t* iobP,
288                                  struct cxiContiguousBuffer_t* contigP);
289
290
291/* Maximum size of a directory block.  Must be a multiple of PAGE_SIZE. */
292#define MAX_DIRBLOCK_SIZE (32*1024)
293
294
295/* The size of the cxiDiscontiguousDirectoryBuffer_t object may be different
296   depending on whether or not _KERNEL is defined, so do not define
297   cxiDiscontiguousDirectoryBuffer_t if this code will be compiled once and
298   used in both places. */
299#ifndef USED_IN_DAEMON_AND_KERNEL
300
301
302/* Page size controlling alignment and unit of relocation for discontiguous
303   buffers (must be equal to operating system page size) */
304#define DISCONTIG_PAGE_SIZE PAGE_SIZE
305
306/* Description of a buffer that is not necessarily contiguous in memory.
307   All buffers managed through this type must begin on page boundaries. */
308struct cxiDiscontiguousDirectoryBuffer_t
309{
310  /* Number of valid bytes in the buffer.  A value of -1 indicates that the
311     buffer is not mapped and should not be accessed. */
312  int mappedLen;
313
314#ifdef __CXI_BUFFERS_ARE_CONTIGUOUS
315  /* Pointer to the contiguous buffer */
316  char* dataP;
317#else
318  /* Number of paes in a maximum size directory block */
319#define MAX_PAGES_PER_DIRBLOCK (MAX_DIRBLOCK_SIZE/DISCONTIG_PAGE_SIZE)
320
321  /* Array of pointers to the pages that contain the buffer.  This array
322     contains the addresses at which the pages of the buffer can be accessed
323     by the thread that called cxiMapDiscontiguousRW. */
324  char* userPagePointerArray[MAX_PAGES_PER_DIRBLOCK];
325
326  /* Array of pointers to OS-specific data structures needed to unmap each
327     of the pages given by the array of pointers above. */
328  void* osPagePointerArray[MAX_PAGES_PER_DIRBLOCK];
329#endif  /* __CXI_BUFFERS_ARE_CONTIGUOUS */
330};
331
332
333/* Initialize a cxiDiscontiguousDirectoryBuffer_t */
334static inline void 
335InitDiscontiguousBuffer(struct cxiDiscontiguousDirectoryBuffer_t* ddbP)
336{
337  /* Indicate buffer is invalid */
338  ddbP->mappedLen = -1;
339};
340
341
342/* Convert an offset into a logical buffer into a pointer to the byte
343   at that offset.  The caller is assumed to know the length of the
344   object beginning at the returned pointer, and is not supposed to access
345   beyond the end of the page in which the pointer points */
346static inline char* 
347OffsetToPtr(const struct cxiDiscontiguousDirectoryBuffer_t* ddbP, int offset)
348{
349  char* pageStartP;
350
351  DBGASSERT(offset >= 0);
352  DBGASSERT(offset < ddbP->mappedLen);
353#ifdef __CXI_BUFFERS_ARE_CONTIGUOUS
354  return ddbP->dataP+offset;
355#else
356  pageStartP = ddbP->userPagePointerArray[offset/DISCONTIG_PAGE_SIZE];
357  return pageStartP + offset%DISCONTIG_PAGE_SIZE;
358#endif  /* __CXI_BUFFERS_ARE_CONTIGUOUS */
359};
360
361
362/* Given a contiguous buffer, set up a mapping as if it was discontiguous */
363static inline void 
364MapContiguousBuffer(char* bufP, int len,
365                    struct cxiDiscontiguousDirectoryBuffer_t* ddbP)
366{
367  int i;
368
369
370  ddbP->mappedLen = len;
371#ifdef __CXI_BUFFERS_ARE_CONTIGUOUS
372  ddbP->dataP = bufP;
373#else
374  /* Either we should start on a page boundary or our total buffer
375   * should fit within the same page.
376   */
377  DBGASSERT(((UIntPtr)bufP & (DISCONTIG_PAGE_SIZE-1)) == 0 ||
378            ((UIntPtr)bufP & ~(DISCONTIG_PAGE_SIZE-1)) ==
379            ((UIntPtr)(bufP + len - 1) & ~(DISCONTIG_PAGE_SIZE-1)));
380  DBGASSERT(len <= MAX_PAGES_PER_DIRBLOCK*DISCONTIG_PAGE_SIZE);
381  for (i=0 ; len>0 ; i++, bufP+=DISCONTIG_PAGE_SIZE, len-=DISCONTIG_PAGE_SIZE)
382  {
383    ddbP->userPagePointerArray[i] = bufP;
384    ddbP->osPagePointerArray[i] = NULL;
385  }
386#endif  /* __CXI_BUFFERS_ARE_CONTIGUOUS */
387};
388
389#endif  /* USED_IN_DAEMON_AND_KERNEL */
390
391#endif  /* _h_cxiIOBuffer */
Note: See TracBrowser for help on using the repository browser.