- Main Page
- Related Pages
- Data Structures
- Files

- File List
- Globals

# drivers/block/copy.c

Go to the documentation of this file.

    00001
    00044 #include <debug.h>
    00045 #include <malloc.h>
    00046 #include <string.h>
    00047 #include <block/device.h>
    00048 #include <buffer.h>
    00049 #include <workqueue.h>
    00050 #include <app/workqueue.h>
    00051 #include <app/config_dmapool.h>
    00052 #include <block/copy.h>
    00053
    00054 #define BLOCK_COPY_BUF_SIZE     CONFIG_DMAPOOL_LARGE_OBJ_SIZE
    00055 #define BLOCK_COPY_MAX_BUFFERS  (CONFIG_DMAPOOL_NR_LARGE_OBJS / 2)
    00056
    00057 static void block_copy_read_blocks(void *data);
    00058
    00059 static void block_copy_complete(void *data)
    00060 {
    00061         struct block_copy_request *req = data;
    00062
    00063         if (req->completion_callback)
    00064                 req->completion_callback(req, req->total_blocks_copied,
    00065                                 req->data);
    00066 }
    00067
    00068 static void block_copy_continue(void *data)
    00069 {
    00070         struct block_copy_request *req = data;
    00071
    00072         if (req->progress_callback)
    00073                 req->progress_callback(req, req->total_blocks_copied,
    00074                                 req->data);
    00075
    00076         workqueue_init_item(&req->work,
    00077                         block_copy_read_blocks, req);
    00078         workqueue_add_item(&block_workqueue, &req->work);
    00079 }
    00080
    00081 static void block_copy_write_done(
    00082                 struct block_device *bdev,
    00083                 struct block_request *breq)
    00084 {
    00085         struct block_copy_request *req = breq->context;
    00086         uint32_t blocks_xfered = breq->bytes_xfered / req->block_size;
    00087
    00088         if (breq->status) {
    00089                 dbg_error("block copy: Error during write, status: %d\n",
    00090                                 breq->status);
    00091                 req->status = req->dest_status = breq->status;
    00092                 /* Schedule the completion callback to be executed */
    00093                 workqueue_init_item(&req->work,
    00094                                 block_copy_complete, req);
    00095                 workqueue_add_item(&block_workqueue, &req->work);
    00096                 return;
    00097         } else {
    00098                 dbg_verbose("block copy: Write completed: %zu blocks "
    00099                                 "written\n", breq->bytes_xfered);
    00100         }
    00101
    00102         slist_move_to_tail(&req->buffer_list, &breq->buf_list);
    00103         req->total_blocks_copied += blocks_xfered;
    00104
    00105         if (req->total_blocks_copied < req->length)
    00106                 workqueue_init_item(&req->work, block_copy_continue, req);
    00107         else
    00108                 workqueue_init_item(&req->work, block_copy_complete, req);
    00109
    00110         workqueue_add_item(&block_workqueue, &req->work);
    00111 }
    00112
    00113 static void block_copy_write_blocks(void *data)
    00114 {
    00115         struct block_copy_request *req = data;
    00116
    00117         block_prepare_req(req->target, req->write_req,
    00118                         req->target_start + req->total_blocks_copied,
    00119                         req->blocks_allocated, BLK_OP_WRITE);
    00120         slist_move_to_tail(&req->write_req->buf_list,
    00121                         &req->read_req->buf_list);
    00122         block_submit_req(req->target, req->write_req);
    00123 }
    00124
    00125 static void block_copy_read_done(
    00126                 struct block_device *bdev,
    00127                 struct block_request *breq)
    00128 {
    00129         struct block_copy_request *req = breq->context;
    00130
    00131         if (breq->status) {
    00132                 dbg_error("block copy: Error during read, status: %d\n",
    00133                                 breq->status);
    00134
    00135                 req->status = req->source_status = breq->status;
    00136
    00137                 /* Schedule the completion callback to be executed */
    00138                 workqueue_init_item(&req->work,
    00139                                 block_copy_complete, req);
    00140         } else {
    00141                 dbg_verbose("block copy: Read completed: %zu bytes read\n",
    00142                                 breq->bytes_xfered);
    00143                 workqueue_init_item(&req->work, block_copy_write_blocks, req);
    00144         }
    00145
    00146         workqueue_add_item(&block_workqueue, &req->work);
    00147 }
    00148
    00149 static void block_copy_read_blocks(void *data)
    00150 {
    00151         struct block_copy_request *req = data;
    00152         struct buffer *buf;
    00153         struct slist *buffer_list = &req->buffer_list;
    00154         uint32_t blocks_remaining = req->length - req->total_blocks_copied;
    00155         uint32_t excess_blocks;
    00156
    00157         if (req->total_blocks_copied > 0) {
    00158                 /* Free excess buffers */
    00159                 while (req->blocks_allocated - req->blocks_pr_buf
    00160                                 >= blocks_remaining) {
    00161                         buf = slist_pop_head(buffer_list,
    00162                                         struct buffer, node);
    00163                         buffer_dma_free(buf, BLOCK_COPY_BUF_SIZE);
    00164                         req->blocks_allocated -= req->blocks_pr_buf;
    00165                 }
    00166
    00167                 /* If our buffers still are to big after removing the
    00168                  * excess, we need to resize one of them to fit our data */
    00169                 if (req->blocks_allocated > blocks_remaining) {
    00170                         excess_blocks = req->blocks_allocated
    00171                                 - blocks_remaining;
    00172                         buf = slist_peek_tail(buffer_list,
    00173                                         struct buffer, node);
    00174                         buffer_resize(buf, BLOCK_COPY_BUF_SIZE
    00175                                         - req->block_size * excess_blocks);
    00176                         req->blocks_allocated = blocks_remaining;
    00177                 }
    00178         }
    00179
    00180         block_prepare_req(req->source, req->read_req,
    00181                         req->source_start + req->total_blocks_copied,
    00182                         req->blocks_allocated, BLK_OP_READ);
    00183         slist_move_to_tail(&req->read_req->buf_list, buffer_list);
    00184
    00185         block_submit_req(req->source, req->read_req);
    00186 }
    00187
    00201 struct block_copy_request *block_copy_alloc(
    00202                 uint32_t nr_blocks,
    00203                 uint32_t block_size,
    00204                 void *data)
    00205 {
    00206         struct block_copy_request *request;
    00207         uint32_t alloc_size;
    00208         struct buffer *buf;
    00209         unsigned int i;
    00210
    00211         assert(nr_blocks > 0);
    00212
    00213         if (BLOCK_COPY_BUF_SIZE < block_size)
    00214                 return NULL;
    00215         if (BLOCK_COPY_BUF_SIZE % block_size)
    00216                 return NULL;
    00217
    00218         request = malloc(sizeof(struct block_copy_request));
    00219         if (!request)
    00220                 return NULL;
    00221
    00222         memset(request, 0, sizeof(struct block_copy_request));
    00223
    00224         request->block_size = block_size;
    00225         request->blocks_pr_buf = BLOCK_COPY_BUF_SIZE / block_size;
    00226
    00227         request->data = data;
    00228         request->length = nr_blocks;
    00229         slist_init(&request->buffer_list);
    00230
    00231         for (i = 0; i < BLOCK_COPY_MAX_BUFFERS; i++) {
    00232                 uint32_t blocks_remaining;
    00233
    00234                 /* We only allocate from the large object pool and resize
    00235                  * the last buffer to match the size of our data */
    00236                 buf = buffer_dma_alloc(BLOCK_COPY_BUF_SIZE);
    00237                 if (!buf)
    00238                         break;
    00239
    00240                 slist_insert_tail(&request->buffer_list, &buf->node);
    00241                 blocks_remaining = request->length - request->blocks_allocated;
    00242                 alloc_size = request->blocks_pr_buf;
    00243                 request->blocks_allocated += alloc_size;
    00244
    00245                 if (alloc_size >= blocks_remaining) {
    00246                         if (alloc_size > blocks_remaining) {
    00247                                 request->blocks_allocated
    00248                                         -= alloc_size - blocks_remaining;
    00249                                 alloc_size = blocks_remaining;
    00250                                 buffer_resize(buf, alloc_size * block_size);
    00251                         }
    00252                         break;
    00253                 }
    00254         }
    00255
    00256         if (request->blocks_allocated == 0) {
    00257                 /* Give up if we could not allocate any buffers */
    00258                 free(request);
    00259                 return NULL;
    00260         }
    00261
    00262         return request;
    00263 }
    00264
    00273 void block_copy_free(struct block_copy_request *request)
    00274 {
    00275         struct buffer *buf;
    00276
    00277         while (!slist_is_empty(&request->buffer_list)) {
    00278                 buf = slist_pop_head(&request->buffer_list,
    00279                                 struct buffer, node);
    00280                 /* All our buffers are allocated from the large object
    00281                  * pool, even those that are smaller */
    00282                 buffer_dma_free(buf, BLOCK_COPY_BUF_SIZE);
    00283         }
    00284
    00285         if (request->read_req)
    00286                 block_free_request(request->source, request->read_req);
    00287         if (request->write_req)
    00288                 block_free_request(request->target, request->write_req);
    00289
    00290         free(request);
    00291 }
    00292
    00304 int block_copy_set_source(
    00305                 struct block_copy_request *req,
    00306                 struct block_device *dev,
    00307                 block_addr_t lba)
    00308 {
    00309         assert(req);
    00310         assert(dev);
    00311
    00312         if (req->block_size != dev->block_size)
    00313                 return -BLOCK_COPY_BLOCK_SIZE_MISMATCH;
    00314
    00315         req->source = dev;
    00316         req->source_start = lba;
    00317         req->read_req = block_alloc_request(dev);
    00318
    00319         if (!req->read_req)
    00320                 return -BLOCK_COPY_NOMEM;
    00321
    00322         req->read_req->req_done = block_copy_read_done;
    00323         req->read_req->context = req;
    00324         return 0;
    00325 }
    00326
    00338 int block_copy_set_dest(
    00339                 struct block_copy_request *req,
    00340                 struct block_device *dev,
    00341                 block_addr_t lba)
    00342 {
    00343         assert(req);
    00344         assert(dev);
    00345
    00346         if (req->block_size != dev->block_size)
    00347                 return -BLOCK_COPY_BLOCK_SIZE_MISMATCH;
    00348
    00349         req->target = dev;
    00350         req->target_start = lba;
    00351         req->write_req = block_alloc_request(dev);
    00352
    00353         if (!req->write_req)
    00354                 return -BLOCK_COPY_NOMEM;
    00355
    00356         req->write_req->req_done = block_copy_write_done;
    00357         req->write_req->context = req;
    00358         return 0;
    00359 }
    00360
    00371 void block_copy_set_completion_callback(
    00372                 struct block_copy_request *req,
    00373                 void (*callback)
    00374                         (struct block_copy_request *, uint32_t, void *))
    00375 {
    00376         assert(req);
    00377         req->completion_callback = callback;
    00378 }
    00379
    00390 void block_copy_set_progress_callback(
    00391                 struct block_copy_request *req,
    00392                 void (*callback)
    00393                         (struct block_copy_request *, uint32_t, void *))
    00394 {
    00395         assert(req);
    00396         req->progress_callback = callback;
    00397 }
    00398
    00408 void block_copy_submit(struct block_copy_request *req)
    00409 {
    00410         assert(req);
    00411         assert(req->source);
    00412         assert(req->target);
    00413         assert(req->read_req);
    00414         assert(req->write_req);
    00415
    00416         req->total_blocks_copied = 0;
    00417
    00418         block_copy_read_blocks(req);
    00419 }