summaryrefslogtreecommitdiffstats
path: root/cpukit/libblock/include/rtems/bdbuf.h
blob: 56dc9b44cb3ee99f8d524fd5d2d8e3f36ec74fe4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
/**
 * @file rtems/bdbuf.h
 *
 * Block Device Buffer Management
 */
 
/*
 * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
 * Author: Victor V. Vengerov <vvv@oktet.ru>
 *
 * Copyright (C) 2008 Chris Johns <chrisj@rtems.org>
 *    Rewritten to remove score mutex access. Fixes many performance
 *    issues.
 *
 * @(#) bdbuf.h,v 1.9 2005/02/02 00:06:18 joel Exp
 */

#ifndef _RTEMS_BDBUF_H
#define _RTEMS_BDBUF_H

#include <rtems.h>
#include <rtems/libio.h>
#include <rtems/chain.h>

#include <rtems/blkdev.h>
#include <rtems/diskdevs.h>

#ifdef __cplusplus
extern "C" {
#endif


/**
 * State of a buffer in the cache.
 */
typedef enum
{
  RTEMS_BDBUF_STATE_EMPTY = 0,            /*< Not in use. */
  RTEMS_BDBUF_STATE_READ_AHEAD = 1,       /*< Holds read ahead data only */
  RTEMS_BDBUF_STATE_CACHED = 2,           /*< In the cache and available */
  RTEMS_BDBUF_STATE_ACCESS = 3,           /*< The user has the buffer */
  RTEMS_BDBUF_STATE_MODIFIED = 4,         /*< In the cache but modified */
  RTEMS_BDBUF_STATE_ACCESS_MODIFIED = 5,  /*< With the user but modified */
  RTEMS_BDBUF_STATE_SYNC = 6,             /*< Requested to be sync'ed */
  RTEMS_BDBUF_STATE_TRANSFER = 7          /*< Being transferred to or from disk */
} rtems_bdbuf_buf_state;

/**
 * To manage buffers we using buffer descriptors (BD). A BD holds a buffer plus
 * a range of other information related to managing the buffer in the cache. To
 * speed-up buffer lookup descriptors are organized in AVL-Tree.  The fields
 * 'dev' and 'block' are search keys.
 */
typedef struct rtems_bdbuf_buffer
{
  rtems_chain_node link;       /* Link in the BD onto a number of lists. */

  struct rtems_bdbuf_avl_node
  {
    signed char                cache;  /*< Cache */
    struct rtems_bdbuf_buffer* left;   /*< Left Child */
    struct rtems_bdbuf_buffer* right;  /*< Right Child */
    signed char                bal;    /*< The balance of the sub-tree */
  } avl;

  dev_t             dev;        /*< device number */
  rtems_blkdev_bnum block;      /*< block number on the device */

  unsigned char*    buffer;     /*< Pointer to the buffer memory area */
  int               error;      /*< If not 0 indicate an error value (errno)
                                 * which can be used by user later */

  volatile rtems_bdbuf_buf_state state;  /*< State of the buffer. */

  volatile uint32_t waiters;    /*< The number of threads waiting on this
                                 * buffer. */
  rtems_bdpool_id pool;         /*< Identifier of buffer pool to which this buffer
                                    belongs */

  volatile uint32_t hold_timer; /*< Timer to indicate how long a buffer
                                 * has been held in the cache modified. */
} rtems_bdbuf_buffer;

/**
 * The groups of the blocks with the same size are collected in a pool. Note
 * that a several of the buffer's groups with the same size can exists.
 */
typedef struct rtems_bdbuf_pool
{
  uint32_t            blksize;           /*< The size of the blocks (in bytes) */
  uint32_t            nblks;             /*< Number of blocks in this pool */

  uint32_t            flags;             /*< Configuration flags */

  rtems_id            lock;              /*< The pool lock. Lock this data and
                                          * all BDs. */
  rtems_id            sync_lock;         /*< Sync calls lock writes. */
  bool                sync_active;       /*< True if a sync is active. */
  rtems_id            sync_requester;    /*< The sync requester. */
  dev_t               sync_device;       /*< The device to sync */

  rtems_bdbuf_buffer* tree;             /*< Buffer descriptor lookup AVL tree
                                         * root */
  rtems_chain_control ready;            /*< Free buffers list (or read-ahead) */
  rtems_chain_control lru;              /*< Last recently used list */
  rtems_chain_control modified;         /*< Modified buffers list */
  rtems_chain_control sync;             /*< Buffers to sync list */

  rtems_id            access;           /*< Obtain if waiting for a buffer in the
                                         * ACCESS state. */
  volatile uint32_t   access_waiters;   /*< Count of access blockers. */
  rtems_id            transfer;         /*< Obtain if waiting for a buffer in the
                                         * TRANSFER state. */
  volatile uint32_t   transfer_waiters; /*< Count of transfer blockers. */
  rtems_id            waiting;          /*< Obtain if waiting for a buffer and the
                                         * none are available. */
  volatile uint32_t   wait_waiters;     /*< Count of waiting blockers. */

  rtems_bdbuf_buffer* bds;              /*< Pointer to table of buffer descriptors
                                         * allocated for this buffer pool. */
  void*               buffers;          /*< The buffer's memory. */
} rtems_bdbuf_pool;

/**
 * Configuration structure describes block configuration (size, amount, memory
 * location) for buffering layer pool.
 */
typedef struct rtems_bdbuf_pool_config {
  int            size;      /*< Size of block */
  int            num;       /*< Number of blocks of appropriate size */
  unsigned char* mem_area;  /*< Pointer to the blocks location or NULL, in this
                             * case memory for blocks will be allocated by
                             * Buffering Layer with the help of RTEMS partition
                             * manager */
} rtems_bdbuf_pool_config;

/**
 * External references provided by the user for each pool in the system.
 */
extern rtems_bdbuf_pool_config rtems_bdbuf_pool_configuration[];
extern int                     rtems_bdbuf_pool_configuration_size;

/**
 * Buffering configuration definition. See confdefs.h for support on using this
 * structure.
 */
typedef struct rtems_bdbuf_config {
  uint32_t            max_read_ahead_blocks; /*< Number of blocks to read ahead. */
  uint32_t            max_write_blocks;      /*< Number of blocks to write at once. */
  rtems_task_priority swapout_priority;      /*< Priority of the swap out task. */
  uint32_t            swapout_period;        /*< Period swapout checks buf timers. */
  uint32_t            swap_block_hold;       /*< Period a buffer is held. */
} rtems_bdbuf_config;

/**
 * External referernce to the configuration. The configuration is provided by
 * the user.
 */
extern rtems_bdbuf_config rtems_bdbuf_configuration;

/**
 * The max_read_ahead_blocks value is altered if there are fewer buffers
 * than this defined max. This stops thrashing in the cache.
 */
#define RTEMS_BDBUF_MAX_READ_AHEAD_BLOCKS_DEFAULT    32
#define RTEMS_BDBUF_MAX_WRITE_BLOCKS_DEFAULT         16
#define RTEMS_BDBUF_SWAPOUT_TASK_PRIORITY_DEFAULT    15
#define RTEMS_BDBUF_SWAPOUT_TASK_SWAP_PERIOD_DEFAULT 250  /* milli-seconds */
#define RTEMS_BDBUF_SWAPOUT_TASK_BLOCK_HOLD_DEFAULT  1000 /* milli-seconds */

/**
 * Prepare buffering layer to work - initialize buffer descritors and (if it is
 * neccessary) buffers. Buffers will be allocated accoriding to the
 * configuration table, each entry describes the size of block and the size of
 * the pool. After initialization all blocks is placed into the ready state.
 * lists.
 *
 * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed
 *         successfully or error code if error is occured)
 */
rtems_status_code
rtems_bdbuf_init (void);

/**
 * Get block buffer for data to be written into. The buffers is set to the
 * access or modifed access state. If the buffer is in the cache and modified
 * the state is access modified else the state is access. This buffer contents
 * are not initialised if the buffer is not already in the cache. If the block
 * is already resident in memory it is returned how-ever if not in memory the
 * buffer is not read from disk. This call is used when writing the whole block
 * on a disk rather than just changing a part of it. If there is no buffers
 * available this call will block. A buffer obtained with this call will not be
 * involved in a transfer request and will not be returned to another user
 * until released. If the buffer is already with a user when this call is made
 * the call is blocked until the buffer is returned. The highest priority
 * waiter will obtain the buffer first.
 *
 * The block number is the linear block number. This is relative to the start
 * of the partition on the media.
 *
 * @param device Device number (constructed of major and minor device number)
 * @param block  Linear media block number
 * @param bd     Reference to the buffer descriptor pointer.
 *
 * @return       RTEMS status code (RTEMS_SUCCESSFUL if operation completed
 *               successfully or error code if error is occured)
 */
rtems_status_code
rtems_bdbuf_get (dev_t device, rtems_blkdev_bnum block, rtems_bdbuf_buffer** bd);

/**
 * Get the block buffer and if not already in the cache read from the disk. If
 * specified block already cached return. The buffer is set to the access or
 * modifed access state. If the buffer is in the cache and modified the state
 * is access modified else the state is access. If block is already being read
 * from disk for being written to disk this call blocks. If the buffer is
 * waiting to be written it is removed from modified queue and returned to the
 * user. If the buffer is not in the cache a new buffer is obtained and the
 * data read from disk. The call may block until these operations complete. A
 * buffer obtained with this call will not be involved in a transfer request
 * and will not be returned to another user until released. If the buffer is
 * already with a user when this call is made the call is blocked until the
 * buffer is returned. The highest priority waiter will obtain the buffer
 * first. 
 *
 * @param device Device number (constructed of major and minor device number)
 * @param block  Linear media block number
 * @param bd     Reference to the buffer descriptor pointer.
 *
 * @return       RTEMS status code (RTEMS_SUCCESSFUL if operation completed
 *               successfully or error code if error is occured)
 */
rtems_status_code
rtems_bdbuf_read (dev_t device, rtems_blkdev_bnum block, rtems_bdbuf_buffer** bd);

/**
 * Release the buffer obtained by a read call back to the cache. If the buffer
 * was obtained by a get call and was not already in the cache the release
 * modified call should be used. A buffer released with this call obtained by a
 * get call may not be in sync with the contents on disk. If the buffer was in
 * the cache and modified before this call it will be returned to the modified
 * queue. The buffers is returned to the end of the LRU list.
 *
 * @param bd Reference to the buffer descriptor.
 *
 * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed
 *         successfully or error code if error is occured)
 */
rtems_status_code
rtems_bdbuf_release (rtems_bdbuf_buffer* bd);

/**
 * Release the buffer allocated with a get or read call placing it on the
 * modidied list.  If the buffer was not released modified before the hold
 * timer is set to the configuration value. If the buffer had been released
 * modified before but not written to disk the hold timer is not updated. The
 * buffer will be written to disk when the hold timer has expired, there are
 * not more buffers available in the cache and a get or read buffer needs one
 * or a sync call has been made. If the buffer is obtained with a get or read
 * before the hold timer has expired the buffer will be returned to the user.
 *
 * @param bd Reference to the buffer descriptor.
 *
 * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed
 *         successfully or error code if error is occured)
 */
rtems_status_code
rtems_bdbuf_release_modified (rtems_bdbuf_buffer* bd);

/**
 * Release the buffer as modified and wait until it has been synchronized with
 * the disk by writing it. This buffer will be the first to be transfer to disk
 * and other buffers may also be written if the maximum number of blocks in a
 * requests allows it.
 *
 * @note This code does not lock the sync mutex and stop additions to the
 *       modified queue.

 * @param bd Reference to the buffer descriptor.
 *
 * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed
 *         successfully or error code if error is occured)
 */
rtems_status_code
rtems_bdbuf_sync (rtems_bdbuf_buffer* bd);

/**
 * Synchronize all modified buffers for this device with the disk and wait
 * until the transfers have completed. The sync mutex for the pool is locked
 * stopping the addition of any further modifed buffers. It is only the
 * currently modified buffers that are written.
 *
 * @note Nesting calls to sync multiple devices attached to a single pool will
 * be handled sequentially. A nested call will be blocked until the first sync
 * request has complete. This is only true for device using the same pool.
 *
 * @param dev Block device number
 *
 * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed
 *         successfully or error code if error is occured)
 */
rtems_status_code
rtems_bdbuf_syncdev (dev_t dev);

/**
 * Find first appropriate buffer pool. This primitive returns the index of
 * first buffer pool which block size is greater than or equal to specified
 * size.
 *
 * @param block_size Requested block size
 * @param pool The pool to use for the requested pool size.
 *
 * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed
 *         successfully or error code if error is occured)
 * @retval RTEMS_INVALID_SIZE The specified block size is invalid (not a power
 *         of 2)
 * @retval RTEMS_NOT_DEFINED The buffer pool for this or greater block size
 *         is not configured.
 */
rtems_status_code
rtems_bdbuf_find_pool (uint32_t block_size, rtems_bdpool_id *pool);

/**
 * Obtain characteristics of buffer pool with specified number.
 *
 * @param pool Buffer pool number
 * @param block_size Block size for which buffer pool is configured returned
 *                   there
 * @param blocks Number of buffers in buffer pool.
 *
 * RETURNS:
 * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed
 *         successfully or error code if error is occured)
 * @retval RTEMS_INVALID_SIZE The appropriate buffer pool is not configured.
 *
 * @note Buffer pools enumerated continuously starting from 0.
 */
rtems_status_code
rtems_bdbuf_get_pool_info (rtems_bdpool_id pool, int *block_size, int *blocks);

#ifdef __cplusplus
}
#endif

#endif