| 1 | /*************************************************************************** |
|---|
| 2 | * Copyright (c) 2007-2010, Broadcom Corporation |
|---|
| 3 | * All Rights Reserved |
|---|
| 4 | * Confidential Property of Broadcom Corporation |
|---|
| 5 | * |
|---|
| 6 | * THIS SOFTWARE MAY ONLY BE USED SUBJECT TO AN EXECUTED SOFTWARE LICENSE |
|---|
| 7 | * AGREEMENT BETWEEN THE USER AND BROADCOM. YOU HAVE NO RIGHT TO USE OR |
|---|
| 8 | * EXPLOIT THIS MATERIAL EXCEPT SUBJECT TO THE TERMS OF SUCH AN AGREEMENT. |
|---|
| 9 | * |
|---|
| 10 | * $brcm_Workfile: bfile_buffered.c $ |
|---|
| 11 | * $brcm_Revision: 2 $ |
|---|
| 12 | * $brcm_Date: 1/14/10 1:03p $ |
|---|
| 13 | * |
|---|
| 14 | * Module Description: |
|---|
| 15 | * |
|---|
| 16 | * Block based cached file I/O |
|---|
| 17 | * |
|---|
| 18 | * Revision History: |
|---|
| 19 | * |
|---|
| 20 | * $brcm_Log: /BSEAV/lib/bfile/bfile_buffered.c $ |
|---|
| 21 | * |
|---|
| 22 | * 2 1/14/10 1:03p vsilyaev |
|---|
| 23 | * SW3548-2711: Fixed memory overrun |
|---|
| 24 | * |
|---|
| 25 | * 1 9/18/08 3:25p vsilyaev |
|---|
| 26 | * PR 47105: Layered buffer cache that provides cached interface for any |
|---|
| 27 | * file descriptor |
|---|
| 28 | * |
|---|
| 29 | *******************************************************************************/ |
|---|
| 30 | |
|---|
| 31 | #include "bstd.h" |
|---|
| 32 | #include "bfile_buffered.h" |
|---|
| 33 | #include "bkni.h" |
|---|
| 34 | |
|---|
| 35 | |
|---|
| 36 | BDBG_MODULE(bfile_buffered); |
|---|
| 37 | |
|---|
| 38 | BDBG_OBJECT_ID(bfile_buffered); |
|---|
| 39 | |
|---|
| 40 | struct bfile_buffered_proxy { |
|---|
| 41 | struct bfile_io_read file; /* shall be the first member */ |
|---|
| 42 | bfile_buffered_t parent; |
|---|
| 43 | }; |
|---|
| 44 | |
|---|
| 45 | struct bfile_buffered { |
|---|
| 46 | struct bfile_io_read file; /* shall be the first member */ |
|---|
| 47 | BDBG_OBJECT(bfile_buffered) |
|---|
| 48 | bfile_io_read_t fd; |
|---|
| 49 | off_t pos; |
|---|
| 50 | bfile_buffer_t buffer; |
|---|
| 51 | bfile_buffered_cfg cfg; |
|---|
| 52 | struct bfile_buffered_proxy proxy_fd; |
|---|
| 53 | uint8_t buf[1]; /* variable size buffer */ |
|---|
| 54 | }; |
|---|
| 55 | |
|---|
| 56 | |
|---|
| 57 | void |
|---|
| 58 | bfile_buffered_default_cfg(bfile_buffered_cfg *cfg) |
|---|
| 59 | { |
|---|
| 60 | BDBG_ASSERT(cfg); |
|---|
| 61 | cfg->nsegs = 8; |
|---|
| 62 | cfg->buf_len = cfg->nsegs * (BIO_BLOCK_SIZE*4); |
|---|
| 63 | return; |
|---|
| 64 | } |
|---|
| 65 | |
|---|
| 66 | static ssize_t |
|---|
| 67 | b_file_buffered_proxy_read(bfile_io_read_t fd, void *buf, size_t length) |
|---|
| 68 | { |
|---|
| 69 | bfile_buffered_t file= ((struct bfile_buffered_proxy *)fd)->parent; |
|---|
| 70 | BDBG_OBJECT_ASSERT(file, bfile_buffered); |
|---|
| 71 | if(file->fd) { |
|---|
| 72 | return file->fd->read(file->fd, buf, length); |
|---|
| 73 | } |
|---|
| 74 | return -1; |
|---|
| 75 | } |
|---|
| 76 | |
|---|
| 77 | static off_t |
|---|
| 78 | b_file_buffered_proxy_seek(bfile_io_read_t fd, off_t offset, int whence) |
|---|
| 79 | { |
|---|
| 80 | bfile_buffered_t file= ((struct bfile_buffered_proxy *)fd)->parent; |
|---|
| 81 | BDBG_OBJECT_ASSERT(file, bfile_buffered); |
|---|
| 82 | if(file->fd) { |
|---|
| 83 | return file->fd->seek(file->fd, offset, whence); |
|---|
| 84 | } |
|---|
| 85 | return -1; |
|---|
| 86 | } |
|---|
| 87 | |
|---|
| 88 | static int |
|---|
| 89 | b_file_buffered_proxy_bounds(bfile_io_read_t fd, off_t *first, off_t *last) |
|---|
| 90 | { |
|---|
| 91 | bfile_buffered_t file= ((struct bfile_buffered_proxy *)fd)->parent; |
|---|
| 92 | BDBG_OBJECT_ASSERT(file, bfile_buffered); |
|---|
| 93 | if(file->fd) { |
|---|
| 94 | return file->fd->bounds(file->fd, first, last); |
|---|
| 95 | } |
|---|
| 96 | *first = *last = 0; |
|---|
| 97 | return -1; |
|---|
| 98 | } |
|---|
| 99 | |
|---|
| 100 | static const struct bfile_io_read b_file_buffered_proxy_ops = { |
|---|
| 101 | b_file_buffered_proxy_read, |
|---|
| 102 | b_file_buffered_proxy_seek, |
|---|
| 103 | b_file_buffered_proxy_bounds, |
|---|
| 104 | BIO_DEFAULT_PRIORITY |
|---|
| 105 | }; |
|---|
| 106 | |
|---|
| 107 | static ssize_t |
|---|
| 108 | b_file_buffered_read(bfile_io_read_t fd, void *buf, size_t length) |
|---|
| 109 | { |
|---|
| 110 | bfile_buffered_t file=(void *)fd; |
|---|
| 111 | BDBG_OBJECT_ASSERT(file, bfile_buffered); |
|---|
| 112 | if(file->fd) { |
|---|
| 113 | bfile_buffer_result result; |
|---|
| 114 | batom_t data = bfile_buffer_read(file->buffer, file->pos, length, &result); |
|---|
| 115 | if(data) { |
|---|
| 116 | size_t len; |
|---|
| 117 | batom_cursor cursor; |
|---|
| 118 | |
|---|
| 119 | batom_cursor_from_atom(&cursor, data); |
|---|
| 120 | len = batom_cursor_copy(&cursor, buf, length); |
|---|
| 121 | file->pos += len; |
|---|
| 122 | batom_release(data); |
|---|
| 123 | return (ssize_t) len; |
|---|
| 124 | } |
|---|
| 125 | } |
|---|
| 126 | return -1; |
|---|
| 127 | } |
|---|
| 128 | |
|---|
| 129 | static off_t |
|---|
| 130 | b_file_buffered_seek(bfile_io_read_t fd, off_t offset, int whence) |
|---|
| 131 | { |
|---|
| 132 | bfile_buffered_t file=(void *)fd; |
|---|
| 133 | BDBG_OBJECT_ASSERT(file, bfile_buffered); |
|---|
| 134 | if(file->fd) { |
|---|
| 135 | off_t first, last; |
|---|
| 136 | int rc; |
|---|
| 137 | |
|---|
| 138 | switch(whence) { |
|---|
| 139 | case SEEK_CUR: |
|---|
| 140 | case SEEK_END: |
|---|
| 141 | rc = file->fd->bounds(file->fd, &first, &last); |
|---|
| 142 | if(rc<0) { goto error;} |
|---|
| 143 | if(whence==SEEK_END) { |
|---|
| 144 | offset = last + offset; |
|---|
| 145 | } else { |
|---|
| 146 | offset = file->pos + offset; |
|---|
| 147 | } |
|---|
| 148 | if(offset<first) { |
|---|
| 149 | offset = first; |
|---|
| 150 | } else if (offset>last) { |
|---|
| 151 | offset = last; |
|---|
| 152 | } |
|---|
| 153 | /* keep going */ |
|---|
| 154 | case SEEK_SET: |
|---|
| 155 | default: |
|---|
| 156 | file->pos = offset; |
|---|
| 157 | break; |
|---|
| 158 | } |
|---|
| 159 | return offset; |
|---|
| 160 | } |
|---|
| 161 | error: |
|---|
| 162 | return -1; |
|---|
| 163 | } |
|---|
| 164 | |
|---|
| 165 | static int |
|---|
| 166 | b_file_buffered_bounds(bfile_io_read_t fd, off_t *first, off_t *last) |
|---|
| 167 | { |
|---|
| 168 | bfile_buffered_t file=(void *)fd; |
|---|
| 169 | BDBG_OBJECT_ASSERT(file, bfile_buffered); |
|---|
| 170 | if(file->fd) { |
|---|
| 171 | return file->fd->bounds(file->fd, first, last); |
|---|
| 172 | } |
|---|
| 173 | *first = *last = 0; |
|---|
| 174 | return -1; |
|---|
| 175 | } |
|---|
| 176 | |
|---|
| 177 | static const struct bfile_io_read b_file_buffered_ops = { |
|---|
| 178 | b_file_buffered_read, |
|---|
| 179 | b_file_buffered_seek, |
|---|
| 180 | b_file_buffered_bounds, |
|---|
| 181 | BIO_DEFAULT_PRIORITY |
|---|
| 182 | }; |
|---|
| 183 | |
|---|
| 184 | |
|---|
| 185 | bfile_buffered_t |
|---|
| 186 | bfile_buffered_create(batom_factory_t factory, bfile_buffered_cfg *cfg) |
|---|
| 187 | { |
|---|
| 188 | bfile_buffered_t file; |
|---|
| 189 | bfile_buffer_cfg buffer_cfg; |
|---|
| 190 | BERR_Code rc; |
|---|
| 191 | |
|---|
| 192 | BDBG_ASSERT(factory); |
|---|
| 193 | BDBG_ASSERT(cfg); |
|---|
| 194 | |
|---|
| 195 | file = BKNI_Malloc(sizeof(*file)+cfg->buf_len); |
|---|
| 196 | if(!file) {rc=BERR_TRACE(BERR_OUT_OF_SYSTEM_MEMORY);goto err_alloc;} |
|---|
| 197 | BDBG_OBJECT_INIT(file, bfile_buffered); |
|---|
| 198 | file->cfg = *cfg; |
|---|
| 199 | file->fd = NULL; |
|---|
| 200 | file->pos = 0; |
|---|
| 201 | file->proxy_fd.parent = file; |
|---|
| 202 | file->proxy_fd.file = b_file_buffered_proxy_ops; |
|---|
| 203 | file->file = b_file_buffered_ops; |
|---|
| 204 | |
|---|
| 205 | bfile_buffer_default_cfg(&buffer_cfg); |
|---|
| 206 | buffer_cfg.nsegs = cfg->nsegs; |
|---|
| 207 | buffer_cfg.buf_len = cfg->buf_len; |
|---|
| 208 | buffer_cfg.buf = &file->buf; |
|---|
| 209 | buffer_cfg.fd = &file->proxy_fd.file; |
|---|
| 210 | file->buffer = bfile_buffer_create(factory, &buffer_cfg); |
|---|
| 211 | if(!file->buffer) {rc=BERR_TRACE(BERR_OUT_OF_SYSTEM_MEMORY);goto err_buffer;} |
|---|
| 212 | |
|---|
| 213 | return file; |
|---|
| 214 | err_buffer: |
|---|
| 215 | BKNI_Free(file); |
|---|
| 216 | err_alloc: |
|---|
| 217 | return NULL; |
|---|
| 218 | } |
|---|
| 219 | |
|---|
| 220 | void |
|---|
| 221 | bfile_buffered_destroy(bfile_buffered_t file) |
|---|
| 222 | { |
|---|
| 223 | BDBG_OBJECT_ASSERT(file, bfile_buffered); |
|---|
| 224 | |
|---|
| 225 | bfile_buffer_destroy(file->buffer); |
|---|
| 226 | BDBG_OBJECT_DESTROY(file, bfile_buffered); |
|---|
| 227 | BKNI_Free(file); |
|---|
| 228 | return; |
|---|
| 229 | } |
|---|
| 230 | |
|---|
| 231 | |
|---|
| 232 | bfile_io_read_t |
|---|
| 233 | bfile_buffered_attach(bfile_buffered_t file, bfile_io_read_t fd) |
|---|
| 234 | { |
|---|
| 235 | BDBG_OBJECT_ASSERT(file, bfile_buffered); |
|---|
| 236 | BDBG_ASSERT(fd); |
|---|
| 237 | |
|---|
| 238 | if(file->fd) { |
|---|
| 239 | BDBG_ERR(("bfile_buffered_attach: %#lx already attached file %#lx", (unsigned long)file, (unsigned long)fd)); |
|---|
| 240 | } |
|---|
| 241 | |
|---|
| 242 | file->pos = 0; |
|---|
| 243 | file->fd = fd; |
|---|
| 244 | return &file->file; |
|---|
| 245 | } |
|---|
| 246 | |
|---|
| 247 | void |
|---|
| 248 | bfile_buffered_detach(bfile_buffered_t file) |
|---|
| 249 | { |
|---|
| 250 | BDBG_OBJECT_ASSERT(file, bfile_buffered); |
|---|
| 251 | if(!file->fd) { |
|---|
| 252 | BDBG_ERR(("bfile_buffered_detach: %#lx no attached file", (unsigned long)file)); |
|---|
| 253 | } |
|---|
| 254 | bfile_buffer_clear(file->buffer); |
|---|
| 255 | file->fd = NULL; |
|---|
| 256 | file->pos = 0; |
|---|
| 257 | return; |
|---|
| 258 | } |
|---|
| 259 | |
|---|
| 260 | |
|---|
| 261 | bfile_buffer_t |
|---|
| 262 | bfile_buffered_get_buffer(bfile_buffered_t file) |
|---|
| 263 | { |
|---|
| 264 | BDBG_OBJECT_ASSERT(file, bfile_buffered); |
|---|
| 265 | return file->buffer; |
|---|
| 266 | } |
|---|