| 1 | /*************************************************************************** |
|---|
| 2 | * (c)2005-2011 Broadcom Corporation |
|---|
| 3 | * |
|---|
| 4 | * This program is the proprietary software of Broadcom Corporation and/or its licensors, |
|---|
| 5 | * and may only be used, duplicated, modified or distributed pursuant to the terms and |
|---|
| 6 | * conditions of a separate, written license agreement executed between you and Broadcom |
|---|
| 7 | * (an "Authorized License"). Except as set forth in an Authorized License, Broadcom grants |
|---|
| 8 | * no license (express or implied), right to use, or waiver of any kind with respect to the |
|---|
| 9 | * Software, and Broadcom expressly reserves all rights in and to the Software and all |
|---|
| 10 | * intellectual property rights therein. IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU |
|---|
| 11 | * HAVE NO RIGHT TO USE THIS SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY |
|---|
| 12 | * NOTIFY BROADCOM AND DISCONTINUE ALL USE OF THE SOFTWARE. |
|---|
| 13 | * |
|---|
| 14 | * Except as expressly set forth in the Authorized License, |
|---|
| 15 | * |
|---|
| 16 | * 1. This program, including its structure, sequence and organization, constitutes the valuable trade |
|---|
| 17 | * secrets of Broadcom, and you shall use all reasonable efforts to protect the confidentiality thereof, |
|---|
| 18 | * and to use this information only in connection with your use of Broadcom integrated circuit products. |
|---|
| 19 | * |
|---|
| 20 | * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" |
|---|
| 21 | * AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES, REPRESENTATIONS OR |
|---|
| 22 | * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO |
|---|
| 23 | * THE SOFTWARE. BROADCOM SPECIFICALLY DISCLAIMS ANY AND ALL IMPLIED WARRANTIES |
|---|
| 24 | * OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, |
|---|
| 25 | * LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION |
|---|
| 26 | * OR CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT OF |
|---|
| 27 | * USE OR PERFORMANCE OF THE SOFTWARE. |
|---|
| 28 | * |
|---|
| 29 | * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR ITS |
|---|
| 30 | * LICENSORS BE LIABLE FOR (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR |
|---|
| 31 | * EXEMPLARY DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO YOUR |
|---|
| 32 | * USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM HAS BEEN ADVISED OF |
|---|
| 33 | * THE POSSIBILITY OF SUCH DAMAGES; OR (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT |
|---|
| 34 | * ACTUALLY PAID FOR THE SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE |
|---|
| 35 | * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF ESSENTIAL PURPOSE OF |
|---|
| 36 | * ANY LIMITED REMEDY. |
|---|
| 37 | * |
|---|
| 38 | * $brcm_Workfile: nexus_file_fifo_chunk.c $ |
|---|
| 39 | * $brcm_Revision: 7 $ |
|---|
| 40 | * $brcm_Date: 10/12/11 7:56a $ |
|---|
| 41 | * |
|---|
| 42 | * Module Description: |
|---|
| 43 | * |
|---|
| 44 | * Revision History: |
|---|
| 45 | * |
|---|
| 46 | * $brcm_Log: /nexus/modules/file/src/nexus_file_fifo_chunk.c $ |
|---|
| 47 | * |
|---|
| 48 | * 7 10/12/11 7:56a dlwin |
|---|
| 49 | * SW7231-352: Added code to silence Coverity 32988 issue. |
|---|
| 50 | * |
|---|
| 51 | * 6 8/31/11 2:07p vsilyaev |
|---|
| 52 | * SW7231-351: Fixed typo |
|---|
| 53 | * |
|---|
| 54 | * 5 8/29/11 2:47p vsilyaev |
|---|
| 55 | * SW7231-351: Fixed typo |
|---|
| 56 | * |
|---|
| 57 | * 4 8/15/11 3:47p mphillip |
|---|
| 58 | * SW7335-1249: Added option to periodically write metadata into a disk |
|---|
| 59 | * file |
|---|
| 60 | * |
|---|
| 61 | * 3 2/25/11 12:47p erickson |
|---|
| 62 | * SW7125-818: use BNAV_GetEntrySize |
|---|
| 63 | * |
|---|
| 64 | * 2 5/11/10 11:17a jtna |
|---|
| 65 | * SW7405-4313: Coverity Defect ID:21991 FORWARD_NULL |
|---|
| 66 | * |
|---|
| 67 | * 1 4/22/10 6:57p mphillip |
|---|
| 68 | * SW7405-4251: Merge chunked PVR support from branch to main |
|---|
| 69 | * |
|---|
| 70 | * SW7405-3587/4 4/22/10 12:01p mphillip |
|---|
| 71 | * SW7405-4251: Update chunked PVR after API review, prepare for merge to |
|---|
| 72 | * main. |
|---|
| 73 | * |
|---|
| 74 | * SW7405-3587/3 4/15/10 11:31a mphillip |
|---|
| 75 | * SW7405-3587: Update with header changes |
|---|
| 76 | * |
|---|
| 77 | * SW7405-3587/2 2/22/10 5:23p mphillip |
|---|
| 78 | * SW7405-3587: Properly reference sub-chunk files |
|---|
| 79 | * |
|---|
| 80 | * SW7405-3587/1 2/4/10 10:21a mphillip |
|---|
| 81 | * SW7405-3587: Chunked fifo |
|---|
| 82 | * |
|---|
| 83 | ***************************************************************************/ |
|---|
| 84 | #include "nexus_file_module.h" |
|---|
| 85 | #include "bstd.h" |
|---|
| 86 | #include "bkni.h" |
|---|
| 87 | #include "bkni_multi.h" |
|---|
| 88 | #include "blst_queue.h" |
|---|
| 89 | #include "bcmplayer.h" |
|---|
| 90 | #include "bcmindexer.h" |
|---|
| 91 | #include "bfile_io.h" |
|---|
| 92 | #include "nexus_file_pvr.h" |
|---|
| 93 | #include "nexus_file_types.h" |
|---|
| 94 | #include "nexus_file_posix.h" |
|---|
| 95 | |
|---|
| 96 | #include "unistd.h" |
|---|
| 97 | |
|---|
| 98 | BDBG_MODULE(fileio_fifo_chunk); |
|---|
| 99 | |
|---|
| 100 | |
|---|
| 101 | |
|---|
| 102 | struct bpvrfifo_entry { |
|---|
| 103 | off_t size; /* size of the entry */ |
|---|
| 104 | off_t voff; /* file 'virtual' offset */ |
|---|
| 105 | off_t doff; /* disk 'physical' offset */ |
|---|
| 106 | unsigned no; /* chunk no */ |
|---|
| 107 | }; |
|---|
| 108 | |
|---|
| 109 | struct bpvrfifo_signature { |
|---|
| 110 | char signature[16]; |
|---|
| 111 | }; |
|---|
| 112 | |
|---|
| 113 | static const struct bpvrfifo_signature bpvrfifo_signature = |
|---|
| 114 | { |
|---|
| 115 | "bpvrFiFo 0.3" |
|---|
| 116 | }; |
|---|
| 117 | static void bfile_fifo_write_snapshot_locked(struct NEXUS_ChunkedFifoRecord *file); |
|---|
| 118 | |
|---|
| 119 | #define TEMPLATE_SIZE 128 |
|---|
| 120 | #define FILE_NAME_SIZE 2048 |
|---|
| 121 | |
|---|
| 122 | #define BFIFO_N_ENTRYS 512 |
|---|
| 123 | #define BFIFO_INVALID_CHUNK ((unsigned)(-1)) |
|---|
| 124 | struct bpvrfifo_header { |
|---|
| 125 | /* we use dual lock scheme, lock is acquired every time when header table is accessed, and busy flag is set wherever there is an active transaction, in this manner we allow simultaneous read and write transactions, and effectively serialize trim with both read and write */ |
|---|
| 126 | BKNI_MutexHandle lock; |
|---|
| 127 | unsigned busy; /* busy counter, if busy > 0 then there is an active write or read, and trim has to fail */ |
|---|
| 128 | unsigned prev_trim; /* previously trimmed value */ |
|---|
| 129 | unsigned trim_gap; /* Gap between real start of file and next trim point */ |
|---|
| 130 | bool chunked; |
|---|
| 131 | bool active; |
|---|
| 132 | unsigned trim_count; |
|---|
| 133 | union { |
|---|
| 134 | struct { |
|---|
| 135 | struct bpvrfifo_signature signature; |
|---|
| 136 | struct bpvrfifo_entry entrys[BFIFO_N_ENTRYS+1]; |
|---|
| 137 | enum { |
|---|
| 138 | bpvrfifo_type_master=0, /* master (record file) */ |
|---|
| 139 | bpvrfifo_type_snapshot=1, /* read only snapshot file) */ |
|---|
| 140 | bpvrfifo_type_zombie=2, /* deleted master file, with active snapshots */ |
|---|
| 141 | bpvrfifo_type_unit=3 /* single, not chunked, file */ |
|---|
| 142 | } type; /* type of file */ |
|---|
| 143 | union { |
|---|
| 144 | struct { |
|---|
| 145 | unsigned chunk_no[BFIFO_N_ENTRYS]; |
|---|
| 146 | uint16_t chunk_ref_cnt[BFIFO_N_ENTRYS]; |
|---|
| 147 | char chunkTemplate[TEMPLATE_SIZE]; /* template for the chunk name */ |
|---|
| 148 | } master; |
|---|
| 149 | struct { |
|---|
| 150 | char chunkTemplate[TEMPLATE_SIZE]; /* template for the chunk name */ |
|---|
| 151 | char master_file[FILE_NAME_SIZE]; /* name of the master file (only used for delete operations) */ |
|---|
| 152 | } snapshot; |
|---|
| 153 | } meta; |
|---|
| 154 | } h; |
|---|
| 155 | uint8_t buf[24*1024]; /* for performance reasons header shall be multiplier of the FS block size */ |
|---|
| 156 | } data; /* this is persistent portion of index (e.g. part that is saved on the disk */ |
|---|
| 157 | }; |
|---|
| 158 | #define B_ENTRY(f,i) (&(f)->header->data.h.entrys[(i)]) |
|---|
| 159 | #define b_lock(x) BKNI_AcquireMutex(x->header->lock) |
|---|
| 160 | #define b_unlock(x) BKNI_ReleaseMutex(x->header->lock) |
|---|
| 161 | |
|---|
| 162 | struct bfile_io_write_fifo { |
|---|
| 163 | struct bfile_io_write self; |
|---|
| 164 | const struct bpvrfifo_entry *entry_cache; /* cached value of file entry */ |
|---|
| 165 | struct bfile_io_write_posix data; |
|---|
| 166 | struct bfile_io_write_posix chunk_data; /* data chunk */ |
|---|
| 167 | unsigned chunk_data_no; |
|---|
| 168 | struct bpvrfifo_header *header; |
|---|
| 169 | struct bpvrfifo_header _header; |
|---|
| 170 | off_t offset; /* current virtual offset, also known as a file size */ |
|---|
| 171 | off_t size; /* size of the file on a disk */ |
|---|
| 172 | off_t start; /* offset, where writeable area begins */ |
|---|
| 173 | unsigned ref_cnt; /* number of references, including itself */ |
|---|
| 174 | unsigned next_chunk; |
|---|
| 175 | char chunk_name[FILE_NAME_SIZE]; |
|---|
| 176 | struct bfile_io_write_posix data_; /* placeholder */ |
|---|
| 177 | struct bfile_io_write_posix chunk_data_; |
|---|
| 178 | bool direct; |
|---|
| 179 | char file_name[FILE_NAME_SIZE]; |
|---|
| 180 | struct bfile_io_write_fifo *meta; /* file to save meta data */ |
|---|
| 181 | off_t meta_offset; |
|---|
| 182 | off_t meta_size; |
|---|
| 183 | struct NEXUS_ChunkedFifoRecord *writeSnapshotFile; |
|---|
| 184 | }; |
|---|
| 185 | |
|---|
| 186 | struct bfile_io_read_fifo { |
|---|
| 187 | struct bfile_io_read self; |
|---|
| 188 | struct bfile_io_read_posix data; |
|---|
| 189 | struct bfile_io_read_posix chunk_data; /* data chunk */ |
|---|
| 190 | unsigned chunk_data_no; |
|---|
| 191 | struct bpvrfifo_entry *entry_cache; /* cached value of file entry */ |
|---|
| 192 | unsigned trim_count; |
|---|
| 193 | struct bpvrfifo_header *header; |
|---|
| 194 | off_t cur_pos; /* current virtual offset */ |
|---|
| 195 | struct bfile_io_write_fifo *writer; |
|---|
| 196 | char chunk_name[FILE_NAME_SIZE]; |
|---|
| 197 | struct bfile_io_read_posix data_; /* placeholder */ |
|---|
| 198 | struct bfile_io_read_posix chunk_data_; /* placeholder */ |
|---|
| 199 | bool direct; |
|---|
| 200 | char file_name[FILE_NAME_SIZE]; |
|---|
| 201 | const char *chunkTemplate; |
|---|
| 202 | char master_name[FILE_NAME_SIZE]; |
|---|
| 203 | struct bfile_io_read_fifo *meta; /* file to save meta data */ |
|---|
| 204 | off_t meta_offset; |
|---|
| 205 | }; |
|---|
| 206 | |
|---|
| 207 | #define B_ENTRY_CLEAR(entry) do{ (entry)->no=BFIFO_INVALID_CHUNK;(entry)->doff=-1;(entry)->voff=0;(entry)->size=0;}while(0) |
|---|
| 208 | #define B_ENTRY_IS_EMPTY(entry) ((entry)->no==BFIFO_INVALID_CHUNK) |
|---|
| 209 | |
|---|
| 210 | #if 0 |
|---|
| 211 | #define BDBG_MSG_IO(i, x) BDBG_INSTANCE_MSG(i, x) |
|---|
| 212 | #else |
|---|
| 213 | #define BDBG_MSG_IO(i, x) |
|---|
| 214 | #endif |
|---|
| 215 | |
|---|
| 216 | #if 0 |
|---|
| 217 | #define B_DUMP_ENTRY(file, i) BDBG_MSG_IO(file, ("%#x:%u %lld %lld %u", file, i, B_ENTRY(file,i)->voff, B_ENTRY(file,i)->doff, (unsigned)B_ENTRY(file,i)->size)) |
|---|
| 218 | #else |
|---|
| 219 | #define B_DUMP_ENTRY(file, i) |
|---|
| 220 | #endif |
|---|
| 221 | |
|---|
| 222 | #if 0 |
|---|
| 223 | #define B_DUMP_ENTRYS(file) do{unsigned i;for(i=0;i<BFIFO_N_ENTRYS;i++) {B_DUMP_ENTRY(file,i);if(B_ENTRY_IS_EMPTY(B_ENTRY(file,i))) {break;}}}while(0) |
|---|
| 224 | #else |
|---|
| 225 | #define B_DUMP_ENTRYS(file) |
|---|
| 226 | #endif |
|---|
| 227 | |
|---|
| 228 | #ifdef DIRECT_IO_SUPPORT |
|---|
| 229 | /* we need to maintain data file aligned by 4096 (for DIRECT I/O) and 188 aligned to keep it valid transport packet */ |
|---|
| 230 | /* it rounds in 192K */ |
|---|
| 231 | #define B_DATA_ALIGN ((188/4)*4096) |
|---|
| 232 | #else |
|---|
| 233 | #define B_DATA_ALIGN (188) |
|---|
| 234 | #endif |
|---|
| 235 | |
|---|
| 236 | static const char b_file_chunkTemplate[]="%s_%d%03d"; |
|---|
| 237 | |
|---|
| 238 | void NEXUS_ChunkedFifoRecord_GetDefaultSettings( |
|---|
| 239 | NEXUS_ChunkedFifoRecordSettings *pSettings /* [out] */ |
|---|
| 240 | ) |
|---|
| 241 | { |
|---|
| 242 | BKNI_Memset(pSettings, 0, sizeof(NEXUS_ChunkedFifoRecordSettings)); |
|---|
| 243 | pSettings->interval = 30; |
|---|
| 244 | pSettings->data.soft = 512*1024*1024; |
|---|
| 245 | pSettings->data.hard = 1024*1024*1024; |
|---|
| 246 | pSettings->data.soft -= pSettings->data.soft % B_DATA_ALIGN; |
|---|
| 247 | pSettings->data.hard -= pSettings->data.hard % B_DATA_ALIGN; |
|---|
| 248 | pSettings->index.soft = 4*1024*1024; |
|---|
| 249 | pSettings->index.hard = 8*1024*1024; |
|---|
| 250 | BKNI_Snprintf(pSettings->chunkTemplate,TEMPLATE_SIZE,"%s",b_file_chunkTemplate); |
|---|
| 251 | } |
|---|
| 252 | |
|---|
| 253 | static ssize_t |
|---|
| 254 | b_read(struct bfile_io_read_posix *fd, void *buf, size_t count) |
|---|
| 255 | { |
|---|
| 256 | return fd->self.read(&fd->self, buf, count); |
|---|
| 257 | } |
|---|
| 258 | |
|---|
| 259 | static off_t |
|---|
| 260 | b_rseek(struct bfile_io_read_posix *fd, off_t offset, int whence) |
|---|
| 261 | { |
|---|
| 262 | return fd->self.seek(&fd->self, offset, whence); |
|---|
| 263 | } |
|---|
| 264 | |
|---|
| 265 | static ssize_t |
|---|
| 266 | b_write(struct bfile_io_write_posix *fd, const void *buf, size_t count) |
|---|
| 267 | { |
|---|
| 268 | return fd->self.write(&fd->self, buf, count); |
|---|
| 269 | } |
|---|
| 270 | |
|---|
| 271 | static off_t |
|---|
| 272 | b_wseek(struct bfile_io_write_posix *fd, off_t offset, int whence) |
|---|
| 273 | { |
|---|
| 274 | return bfile_io_write_posix_seek(fd, offset, whence); |
|---|
| 275 | } |
|---|
| 276 | |
|---|
| 277 | static NEXUS_Error |
|---|
| 278 | b_pvrfifo_write_sync(struct bfile_io_write_fifo *file) |
|---|
| 279 | { |
|---|
| 280 | void *buf; |
|---|
| 281 | off_t off, rc_off; |
|---|
| 282 | int rc; |
|---|
| 283 | NEXUS_Error b_rc = NEXUS_SUCCESS; |
|---|
| 284 | |
|---|
| 285 | off = file->meta_offset; |
|---|
| 286 | |
|---|
| 287 | if(file->meta != file) { /* lock meta file if we aren't meta */ |
|---|
| 288 | for(;;) { |
|---|
| 289 | b_lock(file->meta); |
|---|
| 290 | if(file->meta->header->busy==0) { |
|---|
| 291 | break; |
|---|
| 292 | } |
|---|
| 293 | b_unlock(file->meta); |
|---|
| 294 | BDBG_WRN(("b_pvrfifo_write_sync: %#lx collision in access to the meta file %#lx", (unsigned long)file, (unsigned long)file->meta)); |
|---|
| 295 | BKNI_Sleep(1); |
|---|
| 296 | } |
|---|
| 297 | } |
|---|
| 298 | if(file->meta_size < off+sizeof(file->header->data)) { |
|---|
| 299 | file->meta_size = off+sizeof(file->header->data); |
|---|
| 300 | } |
|---|
| 301 | |
|---|
| 302 | rc_off = b_wseek(&file->meta->data, off, SEEK_SET); |
|---|
| 303 | if(rc_off != off) { |
|---|
| 304 | b_rc = BERR_TRACE(NEXUS_UNKNOWN); |
|---|
| 305 | goto done; |
|---|
| 306 | } |
|---|
| 307 | buf = &file->header->data; |
|---|
| 308 | rc = b_write(&file->meta->data, buf, sizeof(file->header->data)); |
|---|
| 309 | if(rc!=sizeof(file->header->data)) { |
|---|
| 310 | b_rc = BERR_TRACE(NEXUS_UNKNOWN); |
|---|
| 311 | goto done; |
|---|
| 312 | } |
|---|
| 313 | |
|---|
| 314 | done: |
|---|
| 315 | if(file->meta != file) { |
|---|
| 316 | b_unlock(file->meta); |
|---|
| 317 | } |
|---|
| 318 | return b_rc; |
|---|
| 319 | } |
|---|
| 320 | |
|---|
| 321 | static void |
|---|
| 322 | b_pvrfifo_write_next_unit(struct bfile_io_write_fifo *file) |
|---|
| 323 | { |
|---|
| 324 | struct bpvrfifo_entry *entry; |
|---|
| 325 | unsigned i; |
|---|
| 326 | |
|---|
| 327 | entry = B_ENTRY(file, 0); |
|---|
| 328 | /* reached the end of file, now is a time to allocate new chunk */ |
|---|
| 329 | if (entry->doff == file->start) { |
|---|
| 330 | BDBG_MSG_IO(file, ("write tail")); |
|---|
| 331 | /* try to allocate new entry at the end of file */ |
|---|
| 332 | for(entry=NULL,i=1;i<BFIFO_N_ENTRYS;i++) { |
|---|
| 333 | entry = B_ENTRY(file, i); |
|---|
| 334 | if(entry->doff==-1) { /* empty entry */ |
|---|
| 335 | if(entry[-1].doff + entry[-1].size < file->size) { /* last entry shall not span to the end of file */ |
|---|
| 336 | entry->voff = file->offset; |
|---|
| 337 | entry->doff = entry[-1].doff + entry[-1].size; |
|---|
| 338 | entry->size = 0; |
|---|
| 339 | entry->no = file->next_chunk; |
|---|
| 340 | } else { |
|---|
| 341 | BDBG_MSG(("bpvrfifo_write: %#lx no space at the end of file", (unsigned long)file)); |
|---|
| 342 | entry = NULL; |
|---|
| 343 | } |
|---|
| 344 | break; |
|---|
| 345 | } |
|---|
| 346 | } |
|---|
| 347 | if(!entry) { |
|---|
| 348 | BDBG_MSG(("bpvrfifo_write: %#lx overflow", (unsigned long)file)); |
|---|
| 349 | } |
|---|
| 350 | } else { |
|---|
| 351 | BDBG_MSG_IO(file, ("write wraparound")); |
|---|
| 352 | for(i=0;i<BFIFO_N_ENTRYS;i++) { /* find first not empty entry */ |
|---|
| 353 | if(B_ENTRY_IS_EMPTY(B_ENTRY(file,i))) { |
|---|
| 354 | break; |
|---|
| 355 | } |
|---|
| 356 | } |
|---|
| 357 | /* new entry _always_ should go on top, so shift old entrys down, so we could keep entries sorted by the 'doff' field */ |
|---|
| 358 | for(;i>0;i--) { |
|---|
| 359 | *B_ENTRY(file,i) = *B_ENTRY(file, i-1); |
|---|
| 360 | } |
|---|
| 361 | entry = B_ENTRY(file, 0); |
|---|
| 362 | entry->voff = file->offset; |
|---|
| 363 | entry->doff = file->start; |
|---|
| 364 | entry->size = 0; |
|---|
| 365 | entry->no = file->next_chunk; |
|---|
| 366 | } |
|---|
| 367 | return; |
|---|
| 368 | } |
|---|
| 369 | |
|---|
| 370 | static const char * |
|---|
| 371 | b_pvrfifo_make_chunk_name(char *buf, size_t buf_size, const char *template, const char *file_name, unsigned chunk_no) |
|---|
| 372 | { |
|---|
| 373 | BKNI_Snprintf(buf, buf_size, template, file_name, chunk_no/64, chunk_no%64); |
|---|
| 374 | return buf; |
|---|
| 375 | } |
|---|
| 376 | |
|---|
| 377 | static NEXUS_Error |
|---|
| 378 | b_pvrfifo_remove_chunk(char *buf, size_t buf_size, const char *template, const char *file_name, unsigned chunk_no) |
|---|
| 379 | { |
|---|
| 380 | NEXUS_Error rc; |
|---|
| 381 | |
|---|
| 382 | BDBG_MSG(("b_pvrfifo_remove_chunk: %s removing chunk %u", file_name, chunk_no)); |
|---|
| 383 | b_pvrfifo_make_chunk_name(buf, buf_size, template, file_name, chunk_no); |
|---|
| 384 | rc = unlink(buf); |
|---|
| 385 | if(rc!=0) { |
|---|
| 386 | return BERR_TRACE(NEXUS_UNKNOWN); |
|---|
| 387 | } |
|---|
| 388 | return NEXUS_SUCCESS; |
|---|
| 389 | } |
|---|
| 390 | |
|---|
| 391 | static void |
|---|
| 392 | b_pvrfifo_register_new_chunk(struct bfile_io_write_fifo *file) |
|---|
| 393 | { |
|---|
| 394 | unsigned i; |
|---|
| 395 | BDBG_MSG(("b_pvrfifo_register_new_chunk: %#lx allocating chunk %u", (unsigned long)file, file->next_chunk)); |
|---|
| 396 | for(i=0;i<BFIFO_N_ENTRYS;i++) { |
|---|
| 397 | if(file->header->data.h.meta.master.chunk_no[i]==BFIFO_INVALID_CHUNK) { |
|---|
| 398 | file->header->data.h.meta.master.chunk_no[i] = file->next_chunk; |
|---|
| 399 | file->header->data.h.meta.master.chunk_ref_cnt[i] = 1; |
|---|
| 400 | break; |
|---|
| 401 | } |
|---|
| 402 | } |
|---|
| 403 | if(i==BFIFO_N_ENTRYS) { |
|---|
| 404 | BDBG_ERR(("b_pvrfifo_register_new_chunk: %#lx can't allocate space for chunk no %u", (unsigned long)file, (unsigned)file->next_chunk)); |
|---|
| 405 | } |
|---|
| 406 | file->next_chunk++; |
|---|
| 407 | return; |
|---|
| 408 | } |
|---|
| 409 | |
|---|
| 410 | static void |
|---|
| 411 | b_pvrfifo_write_next_chunk(struct bfile_io_write_fifo *file) |
|---|
| 412 | { |
|---|
| 413 | struct bpvrfifo_entry *entry; |
|---|
| 414 | unsigned i; |
|---|
| 415 | |
|---|
| 416 | for(i=0;i<BFIFO_N_ENTRYS;i++) { |
|---|
| 417 | entry = B_ENTRY(file, i); |
|---|
| 418 | if(B_ENTRY_IS_EMPTY(entry)) { |
|---|
| 419 | /* just find empty entry, and allocate new chunk */ |
|---|
| 420 | entry->voff = file->offset; |
|---|
| 421 | entry->doff = 0; |
|---|
| 422 | entry->size = 0; |
|---|
| 423 | entry->no = file->next_chunk; |
|---|
| 424 | b_pvrfifo_register_new_chunk(file); |
|---|
| 425 | b_unlock(file); |
|---|
| 426 | b_pvrfifo_write_sync(file); |
|---|
| 427 | b_lock(file); |
|---|
| 428 | break; |
|---|
| 429 | } |
|---|
| 430 | } |
|---|
| 431 | return; |
|---|
| 432 | } |
|---|
| 433 | |
|---|
| 434 | static ssize_t |
|---|
| 435 | bpvrfifo_write(bfile_io_write_t fd, const void *buf_, size_t length) |
|---|
| 436 | { |
|---|
| 437 | struct bfile_io_write_fifo *file = (struct bfile_io_write_fifo*) fd; |
|---|
| 438 | ssize_t result; |
|---|
| 439 | const void *buf = buf_; |
|---|
| 440 | unsigned i; |
|---|
| 441 | struct bfile_io_write_posix *write_fd; |
|---|
| 442 | |
|---|
| 443 | BDBG_ASSERT(file->header); |
|---|
| 444 | BDBG_MSG_IO(file, (">write: %s %u %lld:%u", file->header->chunked?"chunked":"", file->header->busy, file->offset, (unsigned)length )); |
|---|
| 445 | b_lock(file); |
|---|
| 446 | file->header->busy++; |
|---|
| 447 | file->header->active = true; |
|---|
| 448 | |
|---|
| 449 | for(result=0;length>0;) { |
|---|
| 450 | size_t to_write = 0; |
|---|
| 451 | ssize_t rc; |
|---|
| 452 | struct bpvrfifo_entry *entry; |
|---|
| 453 | off_t boundary = 0; |
|---|
| 454 | off_t rc_off; |
|---|
| 455 | |
|---|
| 456 | /* coverity[use] */ |
|---|
| 457 | for(entry = (struct bpvrfifo_entry *)file->entry_cache, i=0;i<BFIFO_N_ENTRYS;) { |
|---|
| 458 | if(entry==NULL) { |
|---|
| 459 | entry = B_ENTRY(file, i); |
|---|
| 460 | i++; |
|---|
| 461 | if (B_ENTRY_IS_EMPTY(entry)) { |
|---|
| 462 | entry = NULL; |
|---|
| 463 | break; |
|---|
| 464 | } |
|---|
| 465 | } |
|---|
| 466 | if(entry->voff + entry->size == file->offset) { |
|---|
| 467 | boundary = file->size; |
|---|
| 468 | if(!file->header->chunked && !B_ENTRY_IS_EMPTY(&entry[1])) { |
|---|
| 469 | boundary = entry[1].doff; |
|---|
| 470 | } |
|---|
| 471 | to_write = length; |
|---|
| 472 | if (to_write > boundary - (entry->doff + entry->size)) { |
|---|
| 473 | to_write = boundary - (entry->doff + entry->size); |
|---|
| 474 | } |
|---|
| 475 | BDBG_MSG_IO(file, ( "to_write:%u file->size:%lld entry[1].doff:%lld entry->doff:%lld entry->size:%u", to_write, file->size, entry[1].doff, entry->doff, entry->size)); /* add this */ |
|---|
| 476 | if(to_write>0) { |
|---|
| 477 | break; |
|---|
| 478 | } |
|---|
| 479 | } |
|---|
| 480 | entry = NULL; |
|---|
| 481 | } |
|---|
| 482 | file->entry_cache = entry; |
|---|
| 483 | if (!entry) { |
|---|
| 484 | BDBG_WRN(("can't write to descriptor %#x:%lld", (unsigned)file,file->offset)); |
|---|
| 485 | if(result==0) { |
|---|
| 486 | result = -1; |
|---|
| 487 | } |
|---|
| 488 | break; |
|---|
| 489 | } |
|---|
| 490 | if(file->header->chunked) { |
|---|
| 491 | write_fd = &file->chunk_data; |
|---|
| 492 | if(file->chunk_data_no != entry->no) { |
|---|
| 493 | off_t rc; |
|---|
| 494 | if(file->chunk_data_no != BFIFO_INVALID_CHUNK) { |
|---|
| 495 | bfile_io_write_posix_close(&file->chunk_data); |
|---|
| 496 | file->chunk_data_no = BFIFO_INVALID_CHUNK; |
|---|
| 497 | } |
|---|
| 498 | b_pvrfifo_make_chunk_name(file->chunk_name, sizeof(file->chunk_name), file->header->data.h.meta.master.chunkTemplate, file->file_name, entry->no); |
|---|
| 499 | b_unlock(file); |
|---|
| 500 | rc = bfile_io_write_posix_open(write_fd, file->chunk_name, file->direct); |
|---|
| 501 | b_lock(file); |
|---|
| 502 | if(rc) { |
|---|
| 503 | BDBG_WRN(("can't open file %s", file->chunk_name)); |
|---|
| 504 | if(result==0) { |
|---|
| 505 | result = -1; |
|---|
| 506 | } |
|---|
| 507 | break; |
|---|
| 508 | } |
|---|
| 509 | file->chunk_data_no = entry->no; |
|---|
| 510 | } |
|---|
| 511 | } else { |
|---|
| 512 | write_fd = &file->data; |
|---|
| 513 | } |
|---|
| 514 | /* BDBG_ASSERT(boundary>0); */ |
|---|
| 515 | BDBG_MSG_IO(file, (">writing:%#x [%lld/%lld/%lld/%d] (%u/%u/%lld) %#x", entry->voff, entry->doff, boundary, entry-B_ENTRY(file,0), (unsigned)result, (unsigned)to_write, (unsigned)length, file->offset, (unsigned)buf)); |
|---|
| 516 | b_unlock(file); |
|---|
| 517 | rc_off = b_wseek(write_fd, entry->doff + entry->size, SEEK_SET); |
|---|
| 518 | b_lock(file); |
|---|
| 519 | BDBG_MSG_IO(file, ("wseek:%#x %lld -> %lld", entry->doff + entry->size, rc_off)); |
|---|
| 520 | if (rc_off != entry->doff + entry->size) { |
|---|
| 521 | if (result==0) { |
|---|
| 522 | if (rc_off < 0) { |
|---|
| 523 | result = (ssize_t)rc_off; /* propagate error */ |
|---|
| 524 | } else { |
|---|
| 525 | result = -1; |
|---|
| 526 | } |
|---|
| 527 | } |
|---|
| 528 | break; |
|---|
| 529 | } |
|---|
| 530 | b_unlock(file); |
|---|
| 531 | rc = b_write(write_fd, buf, to_write); |
|---|
| 532 | b_lock(file); |
|---|
| 533 | BDBG_MSG_IO(file, ("<writing:%#x [%lld/%lld/%lld/%d] (%u/%u/%lld) %#x->%d", entry->voff, entry->doff, boundary, entry-B_ENTRY(file,0), (unsigned)result, (unsigned)to_write, (unsigned)length, file->offset, (unsigned)buf, (int)rc)); |
|---|
| 534 | if (rc<=0) { |
|---|
| 535 | if (result==0) { |
|---|
| 536 | result = rc; /* propagate error */ |
|---|
| 537 | } |
|---|
| 538 | break; |
|---|
| 539 | } |
|---|
| 540 | BDBG_ASSERT((size_t)rc <= to_write); |
|---|
| 541 | result += rc; |
|---|
| 542 | length -= (size_t) rc; |
|---|
| 543 | buf = (const uint8_t *)buf + rc; |
|---|
| 544 | entry->size = entry->size + rc; |
|---|
| 545 | file->offset = file->offset + rc; |
|---|
| 546 | BDBG_ASSERT(entry->doff+entry->size <= file->size); |
|---|
| 547 | if (entry->doff + entry->size == boundary) { |
|---|
| 548 | file->entry_cache = NULL; |
|---|
| 549 | if(file->header->chunked) { |
|---|
| 550 | b_pvrfifo_write_next_chunk(file); |
|---|
| 551 | } else { |
|---|
| 552 | b_pvrfifo_write_next_unit(file); |
|---|
| 553 | } |
|---|
| 554 | } |
|---|
| 555 | } |
|---|
| 556 | file->header->busy--; |
|---|
| 557 | B_DUMP_ENTRYS(file); |
|---|
| 558 | BDBG_MSG_IO(file, ("<write: %s %u %lld:%u", file->header->chunked?"chunked":"", file->header->busy, file->offset, (unsigned)length )); |
|---|
| 559 | if(file->writeSnapshotFile) { |
|---|
| 560 | bfile_fifo_write_snapshot_locked(file->writeSnapshotFile); |
|---|
| 561 | file->writeSnapshotFile = NULL; |
|---|
| 562 | } |
|---|
| 563 | b_unlock(file); |
|---|
| 564 | return result; |
|---|
| 565 | } |
|---|
| 566 | |
|---|
| 567 | static ssize_t |
|---|
| 568 | bpvrfifo_read(bfile_io_read_t fd, void *buf_, size_t length) |
|---|
| 569 | { |
|---|
| 570 | struct bfile_io_read_fifo *file = (struct bfile_io_read_fifo*) fd; |
|---|
| 571 | ssize_t result; |
|---|
| 572 | void *buf = buf_; |
|---|
| 573 | unsigned i; |
|---|
| 574 | ssize_t rc; |
|---|
| 575 | struct bfile_io_read_posix *read_fd; |
|---|
| 576 | |
|---|
| 577 | |
|---|
| 578 | BDBG_ASSERT(file->header); |
|---|
| 579 | BDBG_MSG_IO(file, (">read:%u %lld:%u", file->header->busy, file->cur_pos, (unsigned)length)); |
|---|
| 580 | b_lock(file); |
|---|
| 581 | file->header->busy++; |
|---|
| 582 | for(result=0;length>0;) { |
|---|
| 583 | off_t rc_off, seek_off; |
|---|
| 584 | size_t to_read = length; |
|---|
| 585 | |
|---|
| 586 | { |
|---|
| 587 | const struct bpvrfifo_entry *entry; /* when lock is released writer could update move entries around, so protect access to the volatile storage */ |
|---|
| 588 | |
|---|
| 589 | if(file->trim_count != file->header->trim_count) { |
|---|
| 590 | file->trim_count = file->header->trim_count; |
|---|
| 591 | file->entry_cache = NULL; |
|---|
| 592 | } |
|---|
| 593 | |
|---|
| 594 | for(entry=file->entry_cache,i=0;i<BFIFO_N_ENTRYS;) { |
|---|
| 595 | if(entry==NULL) { |
|---|
| 596 | entry = B_ENTRY(file,i); |
|---|
| 597 | i++; |
|---|
| 598 | if (B_ENTRY_IS_EMPTY(entry)) { |
|---|
| 599 | entry = NULL; |
|---|
| 600 | break; |
|---|
| 601 | } |
|---|
| 602 | } |
|---|
| 603 | if( entry->voff <= file->cur_pos && |
|---|
| 604 | entry->voff + entry->size > file->cur_pos) { |
|---|
| 605 | to_read = length; |
|---|
| 606 | if (to_read > entry->size - (file->cur_pos - entry->voff)) { |
|---|
| 607 | to_read = entry->size - (file->cur_pos - entry->voff); |
|---|
| 608 | } |
|---|
| 609 | if(to_read > 0) { |
|---|
| 610 | break; |
|---|
| 611 | } |
|---|
| 612 | } |
|---|
| 613 | entry = NULL; |
|---|
| 614 | } |
|---|
| 615 | file->entry_cache = (struct bpvrfifo_entry *)entry; |
|---|
| 616 | if (!entry) { |
|---|
| 617 | if (result==0) { |
|---|
| 618 | if (B_ENTRY(file, 0)->voff > file->cur_pos) { |
|---|
| 619 | B_DUMP_ENTRY(file,0); |
|---|
| 620 | B_DUMP_ENTRY(file,1); |
|---|
| 621 | BDBG_WRN(("bpvrfifo_read: out of bounds offset %#x,%lld", (unsigned)file,file->cur_pos)); |
|---|
| 622 | result = -1; |
|---|
| 623 | } |
|---|
| 624 | } |
|---|
| 625 | break; |
|---|
| 626 | } |
|---|
| 627 | if(file->header->chunked) { |
|---|
| 628 | read_fd = &file->chunk_data; |
|---|
| 629 | if(file->chunk_data_no != entry->no) { |
|---|
| 630 | NEXUS_Error rc; |
|---|
| 631 | if(file->chunk_data_no != BFIFO_INVALID_CHUNK) { |
|---|
| 632 | bfile_io_read_posix_close(&file->chunk_data); |
|---|
| 633 | file->chunk_data_no = BFIFO_INVALID_CHUNK; |
|---|
| 634 | } |
|---|
| 635 | b_pvrfifo_make_chunk_name(file->chunk_name, sizeof(file->chunk_name), file->chunkTemplate, file->master_name, entry->no); |
|---|
| 636 | b_unlock(file); |
|---|
| 637 | rc = bfile_io_read_posix_open(read_fd, file->chunk_name, file->direct); |
|---|
| 638 | b_lock(file); |
|---|
| 639 | if(rc!=NEXUS_SUCCESS) { |
|---|
| 640 | BDBG_WRN(("can't open file %s", file->chunk_name)); |
|---|
| 641 | if(result==0) { |
|---|
| 642 | result = -1; |
|---|
| 643 | } |
|---|
| 644 | break; |
|---|
| 645 | } |
|---|
| 646 | file->chunk_data_no = entry->no; |
|---|
| 647 | } |
|---|
| 648 | } else { |
|---|
| 649 | read_fd = &file->data; |
|---|
| 650 | } |
|---|
| 651 | seek_off = entry->doff + (file->cur_pos - entry->voff); |
|---|
| 652 | BDBG_MSG_IO(file, (">reading: [%lld/%lld/%d -> %lld] (%u/%u/%u/%lld) %#x", entry->voff, entry->doff, entry-B_ENTRY(file,0), seek_off, (unsigned)result, (unsigned)to_read, (unsigned)length, file->cur_pos, (unsigned)buf)); |
|---|
| 653 | } |
|---|
| 654 | b_unlock(file); |
|---|
| 655 | rc_off = b_rseek(read_fd, seek_off, SEEK_SET); |
|---|
| 656 | b_lock(file); |
|---|
| 657 | BDBG_MSG_IO(file, ("rseek: %lld -> %lld", seek_off, rc_off)); |
|---|
| 658 | if (rc_off != seek_off) { |
|---|
| 659 | if (result==0) { |
|---|
| 660 | if (rc_off < 0) { |
|---|
| 661 | result = (ssize_t)rc_off; /* propagate error */ |
|---|
| 662 | } else { |
|---|
| 663 | BDBG_WRN(("bpvrfifo_read: %#lx can't seek to %lld(instead %lld)", (unsigned long)file, seek_off, rc_off)); |
|---|
| 664 | result = -1; |
|---|
| 665 | } |
|---|
| 666 | } |
|---|
| 667 | break; |
|---|
| 668 | } |
|---|
| 669 | b_unlock(file); |
|---|
| 670 | rc = b_read(read_fd, buf, to_read); |
|---|
| 671 | b_lock(file); |
|---|
| 672 | BDBG_MSG_IO(file, ("<reading: %lld (%u/%u/%u/%lld) %#x->%d", seek_off, (unsigned)result, (unsigned)to_read, (unsigned)length, file->cur_pos, (unsigned)buf, (int)rc)); |
|---|
| 673 | if (rc!=(ssize_t)to_read) { |
|---|
| 674 | if (result==0) { |
|---|
| 675 | result = rc; /* propagate error */ |
|---|
| 676 | } |
|---|
| 677 | break; |
|---|
| 678 | } |
|---|
| 679 | BDBG_ASSERT((size_t)rc <= to_read); |
|---|
| 680 | result += rc; |
|---|
| 681 | buf = (uint8_t *)buf + rc; |
|---|
| 682 | length -= (size_t) rc; |
|---|
| 683 | file->cur_pos = file->cur_pos + rc; |
|---|
| 684 | } |
|---|
| 685 | file->header->busy--; |
|---|
| 686 | B_DUMP_ENTRYS(file); |
|---|
| 687 | BDBG_MSG_IO(file, ("<read:%u %lld:%u=%d", file->header->busy, file->cur_pos, (unsigned)length, (int)result)); |
|---|
| 688 | |
|---|
| 689 | b_unlock(file); |
|---|
| 690 | return result; |
|---|
| 691 | } |
|---|
| 692 | |
|---|
| 693 | |
|---|
| 694 | static int |
|---|
| 695 | bpvrfifo_bounds_locked(const struct bfile_io_read_fifo *file, off_t *first, off_t *last) |
|---|
| 696 | { |
|---|
| 697 | unsigned i; |
|---|
| 698 | |
|---|
| 699 | BDBG_ASSERT(file->header); |
|---|
| 700 | |
|---|
| 701 | if (B_ENTRY_IS_EMPTY(B_ENTRY(file,0))) { |
|---|
| 702 | *first = *last = 0; |
|---|
| 703 | } else { |
|---|
| 704 | *first = B_ENTRY(file,0)->voff; |
|---|
| 705 | *last = B_ENTRY(file,0)->voff + B_ENTRY(file,0)->size; |
|---|
| 706 | } |
|---|
| 707 | |
|---|
| 708 | for(i=1;i<BFIFO_N_ENTRYS;i++) { |
|---|
| 709 | if (B_ENTRY_IS_EMPTY(B_ENTRY(file,i))) { |
|---|
| 710 | break; |
|---|
| 711 | } |
|---|
| 712 | if(B_ENTRY(file,i)->voff >= *last) { |
|---|
| 713 | *last = B_ENTRY(file,i)->voff + B_ENTRY(file,i)->size; |
|---|
| 714 | } |
|---|
| 715 | if(B_ENTRY(file,i)->voff < *first) { |
|---|
| 716 | *first = B_ENTRY(file,i)->voff; |
|---|
| 717 | } |
|---|
| 718 | } |
|---|
| 719 | |
|---|
| 720 | if( file->header->trim_gap ) { |
|---|
| 721 | *first += (off_t)(file->header->trim_gap); |
|---|
| 722 | } |
|---|
| 723 | |
|---|
| 724 | return 0; |
|---|
| 725 | } |
|---|
| 726 | |
|---|
| 727 | static int |
|---|
| 728 | bpvrfifo_bounds(bfile_io_read_t fd, off_t *first, off_t *last ) |
|---|
| 729 | { |
|---|
| 730 | struct bfile_io_read_fifo *file = (struct bfile_io_read_fifo *) fd; |
|---|
| 731 | int rc; |
|---|
| 732 | |
|---|
| 733 | BDBG_ASSERT(file->header); |
|---|
| 734 | b_lock(file); /* don't need to set busy because lock isn't released */ |
|---|
| 735 | |
|---|
| 736 | BDBG_MSG_IO(file, (">bounds")); |
|---|
| 737 | rc = bpvrfifo_bounds_locked(file, first, last); |
|---|
| 738 | BDBG_MSG_IO(file, ("<bounds: %lld..%lld", *first, *last)); |
|---|
| 739 | b_unlock(file); |
|---|
| 740 | return rc; |
|---|
| 741 | } |
|---|
| 742 | |
|---|
| 743 | static off_t |
|---|
| 744 | bpvrfifo_trim(bfile_io_write_t fd, off_t trim_pos) |
|---|
| 745 | { |
|---|
| 746 | struct bfile_io_write_fifo *file = (struct bfile_io_write_fifo *) fd; |
|---|
| 747 | off_t result; |
|---|
| 748 | unsigned i,j; |
|---|
| 749 | struct bpvrfifo_entry *entry; |
|---|
| 750 | bool dirty = false; |
|---|
| 751 | |
|---|
| 752 | BDBG_ASSERT(file->header); |
|---|
| 753 | b_lock(file); |
|---|
| 754 | BDBG_MSG_IO(file, (">trim:%u %lld", file->header->busy, trim_pos)); |
|---|
| 755 | file->header->active = true; |
|---|
| 756 | result = 0; |
|---|
| 757 | if (file->header->busy) { |
|---|
| 758 | goto done; |
|---|
| 759 | } |
|---|
| 760 | |
|---|
| 761 | /* trim_pos = (trim_pos) & (~(4096-1)); */ |
|---|
| 762 | if (trim_pos>file->offset) { |
|---|
| 763 | trim_pos = file->offset; |
|---|
| 764 | } else if (trim_pos<0) { |
|---|
| 765 | trim_pos = 0; |
|---|
| 766 | } |
|---|
| 767 | |
|---|
| 768 | for(i=0;i<BFIFO_N_ENTRYS;i++) { |
|---|
| 769 | entry = B_ENTRY(file,i); |
|---|
| 770 | |
|---|
| 771 | if (B_ENTRY_IS_EMPTY(entry)) { |
|---|
| 772 | break; |
|---|
| 773 | } else if( entry->voff >= trim_pos) { |
|---|
| 774 | continue; |
|---|
| 775 | } else if (entry->voff + entry->size > trim_pos ) { |
|---|
| 776 | entry->size -= trim_pos - entry->voff; |
|---|
| 777 | entry->doff += trim_pos - entry->voff; |
|---|
| 778 | entry->voff = trim_pos; |
|---|
| 779 | result = trim_pos; |
|---|
| 780 | } else { |
|---|
| 781 | if (result < entry->voff + entry->size) { |
|---|
| 782 | result = entry->voff + entry->size; |
|---|
| 783 | } |
|---|
| 784 | if(file->header->chunked) { |
|---|
| 785 | /* close current chunk */ |
|---|
| 786 | if(file->chunk_data_no == entry->no) { |
|---|
| 787 | bfile_io_write_posix_close(&file->chunk_data); |
|---|
| 788 | file->chunk_data_no = BFIFO_INVALID_CHUNK; |
|---|
| 789 | } |
|---|
| 790 | /* XXX it's posible that readers still have chunk opened */ |
|---|
| 791 | for(j=0;j<BFIFO_N_ENTRYS;j++) { |
|---|
| 792 | if(file->header->data.h.meta.master.chunk_no[j]==entry->no) { |
|---|
| 793 | /* bingo found chunk */ |
|---|
| 794 | if(file->header->data.h.meta.master.chunk_ref_cnt[j]>0) { |
|---|
| 795 | file->header->data.h.meta.master.chunk_ref_cnt[j]--; |
|---|
| 796 | if(file->header->data.h.meta.master.chunk_ref_cnt[j]==0) { |
|---|
| 797 | b_pvrfifo_remove_chunk(file->chunk_name, sizeof(file->chunk_name), file->header->data.h.meta.master.chunkTemplate, file->file_name, entry->no); |
|---|
| 798 | file->header->data.h.meta.master.chunk_no[j]=BFIFO_INVALID_CHUNK; |
|---|
| 799 | } |
|---|
| 800 | } |
|---|
| 801 | break; |
|---|
| 802 | } |
|---|
| 803 | } |
|---|
| 804 | if(j==BFIFO_N_ENTRYS) { |
|---|
| 805 | BDBG_ERR(("bpvrfifo_trim: %#lx unknown chunk no %u", (unsigned long)file, (unsigned)entry->no)); |
|---|
| 806 | } |
|---|
| 807 | } |
|---|
| 808 | dirty = true; |
|---|
| 809 | B_ENTRY_CLEAR(B_ENTRY(file,i)); /* mark entry as unused */ |
|---|
| 810 | } |
|---|
| 811 | } |
|---|
| 812 | /* collapse empty entries */ |
|---|
| 813 | for(i=0;i<BFIFO_N_ENTRYS;i++) { |
|---|
| 814 | if (B_ENTRY_IS_EMPTY(B_ENTRY(file,i))) { |
|---|
| 815 | for(j=i+1;j<BFIFO_N_ENTRYS;j++) { |
|---|
| 816 | if (!B_ENTRY_IS_EMPTY(B_ENTRY(file,j))) { |
|---|
| 817 | *B_ENTRY(file, i) = *B_ENTRY(file, j); |
|---|
| 818 | B_ENTRY_CLEAR(B_ENTRY(file, j)); |
|---|
| 819 | break; |
|---|
| 820 | } |
|---|
| 821 | } |
|---|
| 822 | if (j==BFIFO_N_ENTRYS) { |
|---|
| 823 | break; |
|---|
| 824 | } |
|---|
| 825 | } |
|---|
| 826 | } |
|---|
| 827 | entry = B_ENTRY(file, 0); |
|---|
| 828 | if(file->header->chunked) { |
|---|
| 829 | if (B_ENTRY_IS_EMPTY(entry)) { |
|---|
| 830 | entry->doff = 0; |
|---|
| 831 | entry->voff = result; |
|---|
| 832 | entry->size = 0; |
|---|
| 833 | entry->no = file->next_chunk; |
|---|
| 834 | b_pvrfifo_register_new_chunk(file); |
|---|
| 835 | dirty = true; |
|---|
| 836 | } |
|---|
| 837 | } else { |
|---|
| 838 | if (B_ENTRY_IS_EMPTY(entry)) { |
|---|
| 839 | /* file was trimed to bones, create new entry */ |
|---|
| 840 | entry->doff = file->start; |
|---|
| 841 | entry->voff = result; |
|---|
| 842 | entry->size = 0; |
|---|
| 843 | entry->no = file->next_chunk; |
|---|
| 844 | } |
|---|
| 845 | } |
|---|
| 846 | done: |
|---|
| 847 | B_DUMP_ENTRYS(file); |
|---|
| 848 | file->entry_cache = NULL; |
|---|
| 849 | file->header->trim_count++; |
|---|
| 850 | BDBG_MSG_IO(file, ("<trim:%u %lld", file->header->busy, result)); |
|---|
| 851 | if(dirty && file->header->chunked) { |
|---|
| 852 | /* XXX write to the file with acquired lock */ |
|---|
| 853 | b_pvrfifo_write_sync(file); |
|---|
| 854 | } |
|---|
| 855 | b_unlock(file); |
|---|
| 856 | return result; |
|---|
| 857 | } |
|---|
| 858 | |
|---|
| 859 | static off_t |
|---|
| 860 | bpvrfifo_seek(bfile_io_read_t fd, off_t offset, int whence) |
|---|
| 861 | { |
|---|
| 862 | struct bfile_io_read_fifo *file = (struct bfile_io_read_fifo *) fd; |
|---|
| 863 | off_t size,begin; |
|---|
| 864 | int rc; |
|---|
| 865 | |
|---|
| 866 | BDBG_MSG_IO(file,(">seek: %lld %d", offset, whence)); |
|---|
| 867 | b_lock(file); |
|---|
| 868 | |
|---|
| 869 | if (whence==SEEK_CUR && offset==0) { |
|---|
| 870 | /* special case, which is used to rerrieve current position, without bound checking */ |
|---|
| 871 | offset = file->cur_pos; |
|---|
| 872 | goto done; |
|---|
| 873 | } |
|---|
| 874 | rc = bpvrfifo_bounds_locked(file, &begin, &size); |
|---|
| 875 | if (rc<0) { |
|---|
| 876 | offset = -1; |
|---|
| 877 | goto error; |
|---|
| 878 | } |
|---|
| 879 | /* locate where file begins */ |
|---|
| 880 | switch(whence) { |
|---|
| 881 | case SEEK_CUR: |
|---|
| 882 | offset = file->cur_pos + offset; |
|---|
| 883 | break; |
|---|
| 884 | case SEEK_END: |
|---|
| 885 | offset = size + offset; |
|---|
| 886 | break; |
|---|
| 887 | case SEEK_SET: |
|---|
| 888 | break; |
|---|
| 889 | default: |
|---|
| 890 | BDBG_ERR(("unknown seek whence %d", whence)); |
|---|
| 891 | goto error; |
|---|
| 892 | } |
|---|
| 893 | if (offset == file->cur_pos) { |
|---|
| 894 | goto done; |
|---|
| 895 | } |
|---|
| 896 | if (offset < 0 || offset >= size) { |
|---|
| 897 | BDBG_WRN(("<seek out out bounds 0..%lld..%lld", offset, size)); |
|---|
| 898 | offset = -1; |
|---|
| 899 | goto error; |
|---|
| 900 | } |
|---|
| 901 | if (offset < begin) { |
|---|
| 902 | offset = begin; |
|---|
| 903 | } |
|---|
| 904 | |
|---|
| 905 | /* just assign new offset */ |
|---|
| 906 | done: |
|---|
| 907 | file->cur_pos = offset; |
|---|
| 908 | error: |
|---|
| 909 | BDBG_MSG_IO(file, ("<seek: %lld", offset)); |
|---|
| 910 | b_unlock(file); |
|---|
| 911 | return offset; |
|---|
| 912 | } |
|---|
| 913 | |
|---|
| 914 | static const struct bfile_io_write bpvrfifo_io_write = { |
|---|
| 915 | bpvrfifo_write, |
|---|
| 916 | bpvrfifo_trim, |
|---|
| 917 | BIO_DEFAULT_PRIORITY |
|---|
| 918 | }; |
|---|
| 919 | |
|---|
| 920 | static const struct bfile_io_read bpvrfifo_io_read = { |
|---|
| 921 | bpvrfifo_read, |
|---|
| 922 | bpvrfifo_seek, |
|---|
| 923 | bpvrfifo_bounds, |
|---|
| 924 | BIO_DEFAULT_PRIORITY |
|---|
| 925 | }; |
|---|
| 926 | |
|---|
| 927 | static void |
|---|
| 928 | b_pvrfifo_header_init(struct bpvrfifo_header *header) |
|---|
| 929 | { |
|---|
| 930 | BDBG_ASSERT(header); |
|---|
| 931 | BDBG_CASSERT(sizeof(header->data) == sizeof(header->data.buf)); /* for proper aligment, size of the header shall be equal to size of the buffer */ |
|---|
| 932 | BKNI_Memset(header,0,sizeof(*header)); |
|---|
| 933 | header->data.h.signature = bpvrfifo_signature; |
|---|
| 934 | header->busy = 0; |
|---|
| 935 | header->prev_trim = 0; |
|---|
| 936 | header->trim_gap = 0; |
|---|
| 937 | header->trim_count = 0; |
|---|
| 938 | header->chunked = false; |
|---|
| 939 | header->active = false; |
|---|
| 940 | return; |
|---|
| 941 | } |
|---|
| 942 | |
|---|
| 943 | |
|---|
| 944 | |
|---|
| 945 | int |
|---|
| 946 | b_file_strcpy(char *dest, size_t buf_len, const char *src) |
|---|
| 947 | { |
|---|
| 948 | return BKNI_Snprintf(dest, buf_len, "%s", src); |
|---|
| 949 | } |
|---|
| 950 | |
|---|
| 951 | static struct bfile_io_write_fifo * |
|---|
| 952 | bpvrfifo_write_open(const char *fname, bool direct, off_t start, struct bfile_io_write_fifo *meta, off_t meta_offset ) |
|---|
| 953 | { |
|---|
| 954 | struct bfile_io_write_fifo *file = BKNI_Malloc(sizeof(*file)); |
|---|
| 955 | BERR_Code rc; |
|---|
| 956 | unsigned i; |
|---|
| 957 | |
|---|
| 958 | if (!file) { |
|---|
| 959 | BERR_TRACE(NEXUS_OUT_OF_SYSTEM_MEMORY); |
|---|
| 960 | goto err_alloc; |
|---|
| 961 | } |
|---|
| 962 | if(meta==NULL) { |
|---|
| 963 | meta = file; |
|---|
| 964 | } |
|---|
| 965 | BKNI_Memset(file, 0, sizeof(*file)); |
|---|
| 966 | file->direct = direct; |
|---|
| 967 | file->header = &file->_header; |
|---|
| 968 | file->meta = meta; |
|---|
| 969 | file->meta_offset = meta_offset; |
|---|
| 970 | file->meta_size = 0; |
|---|
| 971 | b_pvrfifo_header_init(file->header); |
|---|
| 972 | file->writeSnapshotFile = NULL; |
|---|
| 973 | rc = BKNI_CreateMutex(&file->header->lock); |
|---|
| 974 | if (rc!=BERR_SUCCESS) { |
|---|
| 975 | goto err_lock; |
|---|
| 976 | } |
|---|
| 977 | |
|---|
| 978 | file->data = file->data_; |
|---|
| 979 | file->chunk_data = file->chunk_data_; |
|---|
| 980 | file->chunk_data_no = BFIFO_INVALID_CHUNK; /* clear chunk file */ |
|---|
| 981 | rc = bfile_io_write_posix_open(&file->data, fname, direct); |
|---|
| 982 | if(rc!=NEXUS_SUCCESS) { goto err_open_data; } |
|---|
| 983 | /* initialize data */ |
|---|
| 984 | file->self = bpvrfifo_io_write; |
|---|
| 985 | file->start = start; |
|---|
| 986 | file->ref_cnt = 1; |
|---|
| 987 | file->next_chunk = 0; |
|---|
| 988 | file->entry_cache = NULL; |
|---|
| 989 | file->size = 512 * 1024; |
|---|
| 990 | file->header->data.h.type = bpvrfifo_type_unit; |
|---|
| 991 | BKNI_Memcpy(file->header->data.h.meta.master.chunkTemplate, b_file_chunkTemplate, sizeof(b_file_chunkTemplate)); |
|---|
| 992 | b_file_strcpy(file->file_name, sizeof(file->file_name), fname); /* save filename for further use */ |
|---|
| 993 | for(i=0;i<BFIFO_N_ENTRYS;i++) { |
|---|
| 994 | B_ENTRY_CLEAR(B_ENTRY(file, i)); |
|---|
| 995 | file->header->data.h.meta.master.chunk_no[i] = BFIFO_INVALID_CHUNK; |
|---|
| 996 | file->header->data.h.meta.master.chunk_ref_cnt[i] = 0; |
|---|
| 997 | } |
|---|
| 998 | B_ENTRY_CLEAR(B_ENTRY(file, BFIFO_N_ENTRYS)); |
|---|
| 999 | B_ENTRY(file, 0)->doff = file->start; |
|---|
| 1000 | B_ENTRY(file, 0)->no = 0; |
|---|
| 1001 | return file; |
|---|
| 1002 | |
|---|
| 1003 | err_open_data: |
|---|
| 1004 | BKNI_DestroyMutex(file->header->lock); |
|---|
| 1005 | err_lock: |
|---|
| 1006 | BKNI_Free(file); |
|---|
| 1007 | err_alloc: |
|---|
| 1008 | return NULL; |
|---|
| 1009 | } |
|---|
| 1010 | |
|---|
| 1011 | static bfile_io_write_t |
|---|
| 1012 | bpvrfifo_write_file(struct bfile_io_write_fifo *file) |
|---|
| 1013 | { |
|---|
| 1014 | return &file->self; |
|---|
| 1015 | } |
|---|
| 1016 | |
|---|
| 1017 | /* decrement reference counter and once it reaches 0 then release memory */ |
|---|
| 1018 | static void |
|---|
| 1019 | bpvrfifo_write_release(struct bfile_io_write_fifo *file) |
|---|
| 1020 | { |
|---|
| 1021 | bool last; |
|---|
| 1022 | |
|---|
| 1023 | b_lock(file); |
|---|
| 1024 | BDBG_ASSERT(file->header); |
|---|
| 1025 | BDBG_MSG_IO(file, ("release:%u:%u", file->ref_cnt, file->header->busy)); |
|---|
| 1026 | BDBG_ASSERT(file->ref_cnt); |
|---|
| 1027 | file->ref_cnt--; |
|---|
| 1028 | last = file->ref_cnt==0; |
|---|
| 1029 | BDBG_ASSERT(!last || file->header->busy==0); |
|---|
| 1030 | b_unlock(file); |
|---|
| 1031 | if (last) { |
|---|
| 1032 | BKNI_DestroyMutex(file->header->lock); |
|---|
| 1033 | BKNI_Free(file); |
|---|
| 1034 | } |
|---|
| 1035 | return; |
|---|
| 1036 | } |
|---|
| 1037 | |
|---|
| 1038 | static void |
|---|
| 1039 | bpvrfifo_write_close(struct bfile_io_write_fifo *file) |
|---|
| 1040 | { |
|---|
| 1041 | bfile_io_write_posix_close(&file->data); |
|---|
| 1042 | bpvrfifo_write_release(file); |
|---|
| 1043 | return; |
|---|
| 1044 | } |
|---|
| 1045 | |
|---|
| 1046 | static struct bfile_io_read_fifo * |
|---|
| 1047 | bpvrfifo_read_open(const char *fname, bool direct, struct bfile_io_write_fifo *writer, struct bfile_io_read_fifo *meta, off_t meta_off) |
|---|
| 1048 | { |
|---|
| 1049 | struct bfile_io_read_fifo *file = BKNI_Malloc(sizeof(*file)); |
|---|
| 1050 | NEXUS_Error rc; |
|---|
| 1051 | |
|---|
| 1052 | if (!file) { |
|---|
| 1053 | rc = BERR_TRACE(NEXUS_OUT_OF_SYSTEM_MEMORY); |
|---|
| 1054 | goto err_alloc; |
|---|
| 1055 | } |
|---|
| 1056 | if(meta==NULL) { |
|---|
| 1057 | meta = file; |
|---|
| 1058 | } |
|---|
| 1059 | file->direct = direct; |
|---|
| 1060 | file->entry_cache = NULL; |
|---|
| 1061 | file->trim_count = 0; |
|---|
| 1062 | file->data = file->data_; |
|---|
| 1063 | file->chunk_data = file->chunk_data_; |
|---|
| 1064 | file->chunk_data_no = BFIFO_INVALID_CHUNK; |
|---|
| 1065 | rc = bfile_io_read_posix_open(&file->data, fname, direct); |
|---|
| 1066 | if (rc!=NEXUS_SUCCESS) { rc = BERR_TRACE(rc); goto err_open_data; } |
|---|
| 1067 | file->writer = writer; |
|---|
| 1068 | if (writer) { |
|---|
| 1069 | b_lock(writer); |
|---|
| 1070 | writer->ref_cnt++; |
|---|
| 1071 | file->header = writer->header; |
|---|
| 1072 | file->chunkTemplate = writer->header->data.h.meta.master.chunkTemplate; |
|---|
| 1073 | BKNI_Memcpy(file->master_name, writer->file_name, sizeof(file->master_name)); |
|---|
| 1074 | b_unlock(writer); |
|---|
| 1075 | } else { |
|---|
| 1076 | BERR_Code rc; |
|---|
| 1077 | void *buf; |
|---|
| 1078 | off_t rc_off; |
|---|
| 1079 | ssize_t p_rc; |
|---|
| 1080 | |
|---|
| 1081 | file->header = BKNI_Malloc(sizeof(*file->header)); |
|---|
| 1082 | if(!file->header) { |
|---|
| 1083 | BERR_TRACE(NEXUS_OUT_OF_SYSTEM_MEMORY); |
|---|
| 1084 | goto err_hdr_alloc; |
|---|
| 1085 | } |
|---|
| 1086 | b_pvrfifo_header_init(file->header); |
|---|
| 1087 | rc = BKNI_CreateMutex(&file->header->lock); |
|---|
| 1088 | if (rc!=BERR_SUCCESS) { |
|---|
| 1089 | BERR_TRACE(NEXUS_OUT_OF_SYSTEM_MEMORY); |
|---|
| 1090 | goto err_lock; |
|---|
| 1091 | } |
|---|
| 1092 | rc_off = b_rseek(&meta->data, meta_off, SEEK_SET); |
|---|
| 1093 | if(rc_off!=meta_off) { |
|---|
| 1094 | BERR_TRACE(NEXUS_UNKNOWN); |
|---|
| 1095 | goto err_rseek; |
|---|
| 1096 | } |
|---|
| 1097 | buf = &file->header->data; |
|---|
| 1098 | p_rc = b_read(&meta->data, buf, sizeof(file->header->data)); |
|---|
| 1099 | if (p_rc!=sizeof(file->header->data) || BKNI_Memcmp(&file->header->data.h.signature, &bpvrfifo_signature, sizeof(bpvrfifo_signature))!=0) { |
|---|
| 1100 | BERR_TRACE(NEXUS_INVALID_PARAMETER); |
|---|
| 1101 | goto err_meta; |
|---|
| 1102 | } |
|---|
| 1103 | file->header->chunked = file->header->data.h.type != bpvrfifo_type_unit; |
|---|
| 1104 | if(file->header->data.h.type == bpvrfifo_type_snapshot) { |
|---|
| 1105 | BKNI_Memcpy(file->master_name, file->header->data.h.meta.snapshot.master_file, sizeof(file->master_name)); |
|---|
| 1106 | file->chunkTemplate = file->header->data.h.meta.snapshot.chunkTemplate; |
|---|
| 1107 | } else { |
|---|
| 1108 | b_file_strcpy(file->master_name, sizeof(file->master_name), fname); |
|---|
| 1109 | file->chunkTemplate = file->header->data.h.meta.master.chunkTemplate; |
|---|
| 1110 | } |
|---|
| 1111 | } |
|---|
| 1112 | file->self = bpvrfifo_io_read; |
|---|
| 1113 | return file; |
|---|
| 1114 | |
|---|
| 1115 | err_meta: |
|---|
| 1116 | err_rseek: |
|---|
| 1117 | err_lock: |
|---|
| 1118 | if(!writer) { |
|---|
| 1119 | BKNI_Free(file->header); |
|---|
| 1120 | } |
|---|
| 1121 | err_hdr_alloc: |
|---|
| 1122 | bfile_io_read_posix_close(&file->data); |
|---|
| 1123 | err_open_data: |
|---|
| 1124 | BKNI_Free(file); |
|---|
| 1125 | err_alloc: |
|---|
| 1126 | return NULL; |
|---|
| 1127 | } |
|---|
| 1128 | |
|---|
| 1129 | static bfile_io_read_t |
|---|
| 1130 | bpvrfifo_read_file(struct bfile_io_read_fifo *file) |
|---|
| 1131 | { |
|---|
| 1132 | return &file->self; |
|---|
| 1133 | } |
|---|
| 1134 | |
|---|
| 1135 | |
|---|
| 1136 | static void |
|---|
| 1137 | bpvrfifo_read_close(struct bfile_io_read_fifo *file) |
|---|
| 1138 | { |
|---|
| 1139 | bfile_io_read_posix_close(&file->data); |
|---|
| 1140 | if(file->writer) { |
|---|
| 1141 | bpvrfifo_write_release(file->writer); |
|---|
| 1142 | } else { |
|---|
| 1143 | BKNI_DestroyMutex(file->header->lock); |
|---|
| 1144 | BKNI_Free(file->header); |
|---|
| 1145 | } |
|---|
| 1146 | BKNI_Free(file); |
|---|
| 1147 | return; |
|---|
| 1148 | } |
|---|
| 1149 | |
|---|
| 1150 | #define B_TRIM_TIMER 5000 |
|---|
| 1151 | #define B_TRIM_TRY_TIMER 30 |
|---|
| 1152 | |
|---|
| 1153 | struct bfile_out_desc { |
|---|
| 1154 | struct bfile_io_write_fifo *file; |
|---|
| 1155 | unsigned trim_count; |
|---|
| 1156 | off_t trim_off; |
|---|
| 1157 | }; |
|---|
| 1158 | |
|---|
| 1159 | struct NEXUS_ChunkedFifoRecord { |
|---|
| 1160 | struct NEXUS_FileRecord self; |
|---|
| 1161 | struct bfile_out_desc data; |
|---|
| 1162 | struct bfile_out_desc index; |
|---|
| 1163 | struct bfile_io_read_fifo *rd_index; |
|---|
| 1164 | unsigned index_entrysize; |
|---|
| 1165 | BNAV_Player_Handle bcm_player; |
|---|
| 1166 | NEXUS_TimerHandle timer; /* currently active timer or NULL */ |
|---|
| 1167 | NEXUS_Time lastSnapshotTime; |
|---|
| 1168 | NEXUS_ChunkedFifoRecordSettings cfg; |
|---|
| 1169 | }; |
|---|
| 1170 | |
|---|
| 1171 | struct bfile_in_fifo { |
|---|
| 1172 | struct NEXUS_FilePlay self; |
|---|
| 1173 | struct bfile_io_read_fifo *data; |
|---|
| 1174 | struct bfile_io_read_fifo *index; |
|---|
| 1175 | struct NEXUS_ChunkedFifoRecord *writer; |
|---|
| 1176 | }; |
|---|
| 1177 | |
|---|
| 1178 | #define GET_INDEX_FILEIO(fp) (&((NEXUS_ChunkedFifoRecordHandle) fp)->rd_index->self) |
|---|
| 1179 | |
|---|
| 1180 | static long |
|---|
| 1181 | bp_read(void *buffer, long size, long count, void *fp ) |
|---|
| 1182 | { |
|---|
| 1183 | bfile_io_read_t f = GET_INDEX_FILEIO(fp); |
|---|
| 1184 | |
|---|
| 1185 | return (long)f->read(f, buffer, (size_t)(count*size)); |
|---|
| 1186 | } |
|---|
| 1187 | |
|---|
| 1188 | static long |
|---|
| 1189 | bp_tell( void *fp ) |
|---|
| 1190 | { |
|---|
| 1191 | bfile_io_read_t f = GET_INDEX_FILEIO(fp); |
|---|
| 1192 | return (long)f->seek(f, 0, SEEK_CUR); |
|---|
| 1193 | } |
|---|
| 1194 | |
|---|
| 1195 | #if 0 |
|---|
| 1196 | static int |
|---|
| 1197 | bp_seek( void *fp, long offset, int origin ) |
|---|
| 1198 | { |
|---|
| 1199 | bfile_io_read_t f = GET_INDEX_FILEIO(fp); |
|---|
| 1200 | off_t rc; |
|---|
| 1201 | rc = f->seek(f, (off_t)offset, origin); |
|---|
| 1202 | if ( rc == (off_t)-1) { |
|---|
| 1203 | return -1; |
|---|
| 1204 | } |
|---|
| 1205 | return 0; |
|---|
| 1206 | } |
|---|
| 1207 | #endif |
|---|
| 1208 | |
|---|
| 1209 | static int |
|---|
| 1210 | bp_bounds(BNAV_Player_Handle handle, void *fp, long *firstIndex, long *lastIndex) |
|---|
| 1211 | { |
|---|
| 1212 | bfile_io_read_t f = GET_INDEX_FILEIO(fp); |
|---|
| 1213 | off_t first, last; |
|---|
| 1214 | unsigned index_entrysize =((NEXUS_ChunkedFifoRecordHandle)fp)->index_entrysize; |
|---|
| 1215 | |
|---|
| 1216 | f->bounds(f, &first, &last); |
|---|
| 1217 | |
|---|
| 1218 | BSTD_UNUSED(handle); |
|---|
| 1219 | *firstIndex = first/index_entrysize; |
|---|
| 1220 | *lastIndex = (last-1)/index_entrysize; |
|---|
| 1221 | |
|---|
| 1222 | return 0; |
|---|
| 1223 | } |
|---|
| 1224 | |
|---|
| 1225 | static int |
|---|
| 1226 | trim_bp_bounds( BNAV_Player_Handle handle, void *fp, long *firstIndex, long *lastIndex ) |
|---|
| 1227 | { |
|---|
| 1228 | bfile_io_read_t fd = GET_INDEX_FILEIO(fp); |
|---|
| 1229 | off_t first, last; |
|---|
| 1230 | unsigned index_entrysize =((NEXUS_ChunkedFifoRecordHandle)fp)->index_entrysize; |
|---|
| 1231 | int rc; |
|---|
| 1232 | |
|---|
| 1233 | struct bfile_io_read_fifo *file = (struct bfile_io_read_fifo *)fd; |
|---|
| 1234 | BDBG_ASSERT(file->header); |
|---|
| 1235 | b_lock(file); |
|---|
| 1236 | rc = bpvrfifo_bounds_locked(file, &first, &last ); |
|---|
| 1237 | if( file->header->trim_gap ) { |
|---|
| 1238 | /* Untrimmed file start is first offset minus trim gap */ |
|---|
| 1239 | first -= (off_t)(file->header->trim_gap); |
|---|
| 1240 | } |
|---|
| 1241 | b_unlock(file); |
|---|
| 1242 | |
|---|
| 1243 | |
|---|
| 1244 | BSTD_UNUSED(handle); |
|---|
| 1245 | *firstIndex = first/index_entrysize; |
|---|
| 1246 | *lastIndex = (last-1)/index_entrysize; |
|---|
| 1247 | |
|---|
| 1248 | return 0; |
|---|
| 1249 | } |
|---|
| 1250 | |
|---|
| 1251 | static int |
|---|
| 1252 | trim_bp_seek( void *fp, long offset, int origin ) |
|---|
| 1253 | { |
|---|
| 1254 | bfile_io_read_t f = GET_INDEX_FILEIO(fp); |
|---|
| 1255 | unsigned index_entrysize =((NEXUS_ChunkedFifoRecordHandle)fp)->index_entrysize; |
|---|
| 1256 | long saveOffset = 0; |
|---|
| 1257 | struct bfile_io_read_fifo *file = (struct bfile_io_read_fifo *)f; |
|---|
| 1258 | off_t rc; |
|---|
| 1259 | |
|---|
| 1260 | if( file->header->trim_gap ) { |
|---|
| 1261 | BNAV_Player_Handle dummyHandle = NULL; |
|---|
| 1262 | long firstIdx, lastIdx; |
|---|
| 1263 | |
|---|
| 1264 | /* Find beginning trimmed area */ |
|---|
| 1265 | trim_bp_bounds( dummyHandle, fp, &firstIdx, &lastIdx ); |
|---|
| 1266 | saveOffset = firstIdx*index_entrysize; |
|---|
| 1267 | |
|---|
| 1268 | if( offset && offset < firstIdx*(int)index_entrysize ) { |
|---|
| 1269 | /* But don't adjust for a tell request ( offset=0 , origin=SEEK_SET ) */ |
|---|
| 1270 | offset = firstIdx*index_entrysize; |
|---|
| 1271 | } |
|---|
| 1272 | } |
|---|
| 1273 | |
|---|
| 1274 | rc = f->seek(f, (off_t)offset, origin); |
|---|
| 1275 | if ( rc == (off_t)-1) { |
|---|
| 1276 | return -1; |
|---|
| 1277 | } |
|---|
| 1278 | |
|---|
| 1279 | |
|---|
| 1280 | if ( offset==0 && saveOffset ) { |
|---|
| 1281 | /* Fix up cur_pos to actual trim area beginning */ |
|---|
| 1282 | b_lock(file); |
|---|
| 1283 | file->cur_pos = saveOffset; |
|---|
| 1284 | b_unlock(file); |
|---|
| 1285 | } |
|---|
| 1286 | else if ( offset < file->cur_pos ) { |
|---|
| 1287 | /* If get in here , it means trimming is happening */ |
|---|
| 1288 | b_lock(file); |
|---|
| 1289 | file->cur_pos = offset; |
|---|
| 1290 | b_unlock(file); |
|---|
| 1291 | } |
|---|
| 1292 | |
|---|
| 1293 | return 0; |
|---|
| 1294 | } |
|---|
| 1295 | |
|---|
| 1296 | |
|---|
| 1297 | static void |
|---|
| 1298 | bfile_fifo_close_in(NEXUS_FilePlayHandle f) |
|---|
| 1299 | { |
|---|
| 1300 | struct bfile_in_fifo *file = (struct bfile_in_fifo *)f; |
|---|
| 1301 | |
|---|
| 1302 | BDBG_ASSERT(file->data); |
|---|
| 1303 | BDBG_ASSERT(file->index); |
|---|
| 1304 | bpvrfifo_read_close(file->data); |
|---|
| 1305 | bpvrfifo_read_close(file->index); |
|---|
| 1306 | BKNI_Free(file); |
|---|
| 1307 | return; |
|---|
| 1308 | } |
|---|
| 1309 | |
|---|
| 1310 | NEXUS_FilePlayHandle |
|---|
| 1311 | NEXUS_ChunkedFifoPlay_Open(const char *fname, const char *indexname, NEXUS_ChunkedFifoRecordHandle writer) |
|---|
| 1312 | { |
|---|
| 1313 | struct bfile_in_fifo *file; |
|---|
| 1314 | NEXUS_Error rc; |
|---|
| 1315 | |
|---|
| 1316 | if (fname==NULL) { rc = BERR_TRACE(NEXUS_INVALID_PARAMETER); return NULL; } |
|---|
| 1317 | if (indexname==NULL) { rc = BERR_TRACE(NEXUS_INVALID_PARAMETER); return NULL; } |
|---|
| 1318 | |
|---|
| 1319 | file = BKNI_Malloc(sizeof(*file)); |
|---|
| 1320 | if (!file) { rc = BERR_TRACE(NEXUS_OUT_OF_SYSTEM_MEMORY); goto err_alloc; } |
|---|
| 1321 | BKNI_Memset(file, 0, sizeof(*file)); |
|---|
| 1322 | |
|---|
| 1323 | file->index = bpvrfifo_read_open(indexname, false, writer?writer->index.file:NULL, NULL, 0); |
|---|
| 1324 | if (!file->index) { goto err_index;} |
|---|
| 1325 | |
|---|
| 1326 | file->data = bpvrfifo_read_open(fname, true, writer?writer->data.file:NULL, file->index, sizeof(file->index->header->data)); |
|---|
| 1327 | if (!file->data) { goto err_data;} |
|---|
| 1328 | |
|---|
| 1329 | if (writer==NULL) { |
|---|
| 1330 | struct bpvrfifo_header *buf; |
|---|
| 1331 | ssize_t rc; |
|---|
| 1332 | |
|---|
| 1333 | buf = file->index->header; |
|---|
| 1334 | b_rseek(&file->index->data, 0, SEEK_SET); |
|---|
| 1335 | rc = b_read(&file->index->data, &buf->data, sizeof(buf->data)); |
|---|
| 1336 | if (rc!=sizeof(buf->data) || buf->data.h.signature.signature[0]!=bpvrfifo_signature.signature[0]) { |
|---|
| 1337 | rc = BERR_TRACE(NEXUS_INVALID_PARAMETER); |
|---|
| 1338 | goto err_meta; |
|---|
| 1339 | } |
|---|
| 1340 | |
|---|
| 1341 | buf = file->data->header; |
|---|
| 1342 | b_rseek(&file->index->data, sizeof(buf->data), SEEK_SET); |
|---|
| 1343 | rc = b_read(&file->index->data, buf, sizeof(buf->data)); |
|---|
| 1344 | if (rc!=sizeof(buf->data) || buf->data.h.signature.signature[0]!=bpvrfifo_signature.signature[0]) { |
|---|
| 1345 | rc = BERR_TRACE(NEXUS_INVALID_PARAMETER); |
|---|
| 1346 | goto err_meta; |
|---|
| 1347 | } |
|---|
| 1348 | } |
|---|
| 1349 | |
|---|
| 1350 | file->self.file.index = bpvrfifo_read_file(file->index); |
|---|
| 1351 | file->self.file.data = bpvrfifo_read_file(file->data); |
|---|
| 1352 | |
|---|
| 1353 | file->self.file.close = bfile_fifo_close_in; |
|---|
| 1354 | |
|---|
| 1355 | return &file->self; |
|---|
| 1356 | |
|---|
| 1357 | err_meta: |
|---|
| 1358 | bpvrfifo_read_close(file->data); |
|---|
| 1359 | err_data: |
|---|
| 1360 | bpvrfifo_read_close(file->index); |
|---|
| 1361 | err_index: |
|---|
| 1362 | BKNI_Free(file); |
|---|
| 1363 | err_alloc: |
|---|
| 1364 | return NULL; |
|---|
| 1365 | } |
|---|
| 1366 | |
|---|
| 1367 | static void |
|---|
| 1368 | bfile_fifo_write_snapshot_locked(struct NEXUS_ChunkedFifoRecord *file) |
|---|
| 1369 | { |
|---|
| 1370 | const struct bpvrfifo_header *buf; |
|---|
| 1371 | |
|---|
| 1372 | buf = file->index.file->header; |
|---|
| 1373 | b_wseek(&file->index.file->data, 0, SEEK_SET); |
|---|
| 1374 | b_write(&file->index.file->data, &buf->data, sizeof(buf->data)); |
|---|
| 1375 | |
|---|
| 1376 | buf = file->data.file->header; |
|---|
| 1377 | b_wseek(&file->index.file->data, sizeof(buf->data), SEEK_SET); |
|---|
| 1378 | b_write(&file->index.file->data, &buf->data, sizeof(buf->data)); |
|---|
| 1379 | return; |
|---|
| 1380 | } |
|---|
| 1381 | |
|---|
| 1382 | static void |
|---|
| 1383 | bfile_fifo_close_out(NEXUS_FileRecordHandle f) |
|---|
| 1384 | { |
|---|
| 1385 | struct NEXUS_ChunkedFifoRecord *file = (struct NEXUS_ChunkedFifoRecord *)f; |
|---|
| 1386 | |
|---|
| 1387 | if (file->timer) { |
|---|
| 1388 | NEXUS_CancelTimer(file->timer); |
|---|
| 1389 | } |
|---|
| 1390 | if (file->bcm_player) { |
|---|
| 1391 | BNAV_Player_Close(file->bcm_player); |
|---|
| 1392 | } |
|---|
| 1393 | |
|---|
| 1394 | b_lock(file->index.file); |
|---|
| 1395 | bfile_fifo_write_snapshot_locked(file); |
|---|
| 1396 | bfile_fifo_write_snapshot_locked(file); |
|---|
| 1397 | b_unlock(file->index.file); |
|---|
| 1398 | |
|---|
| 1399 | bpvrfifo_read_close(file->rd_index); |
|---|
| 1400 | bpvrfifo_write_close(file->data.file); |
|---|
| 1401 | bpvrfifo_write_close(file->index.file); |
|---|
| 1402 | BKNI_Free(file); |
|---|
| 1403 | return; |
|---|
| 1404 | } |
|---|
| 1405 | |
|---|
| 1406 | static void |
|---|
| 1407 | b_trim_try_player(NEXUS_ChunkedFifoRecordHandle file) |
|---|
| 1408 | { |
|---|
| 1409 | if (file->bcm_player==NULL) { |
|---|
| 1410 | BNAV_DecoderFeatures features = {1,1,1,1}; |
|---|
| 1411 | BNAV_Player_Settings cfg; |
|---|
| 1412 | |
|---|
| 1413 | BNAV_Player_GetDefaultSettings(&cfg); |
|---|
| 1414 | |
|---|
| 1415 | cfg.videoPid = 0x1FFF; /* since BNAV_Player doesn't like 0 */ |
|---|
| 1416 | cfg.filePointer = file; |
|---|
| 1417 | cfg.normalPlayBufferSize = 1024*128; |
|---|
| 1418 | cfg.decoderFeatures = features; |
|---|
| 1419 | cfg.readCb = bp_read; |
|---|
| 1420 | cfg.tellCb = bp_tell; |
|---|
| 1421 | cfg.seekCb = trim_bp_seek; |
|---|
| 1422 | cfg.boundsCb = trim_bp_bounds; |
|---|
| 1423 | cfg.transportTimestampEnabled = false; |
|---|
| 1424 | if (BNAV_Player_Open(&file->bcm_player, &cfg)!=0) { |
|---|
| 1425 | return; |
|---|
| 1426 | } |
|---|
| 1427 | BNAV_Player_GetSettings(file->bcm_player, &cfg); |
|---|
| 1428 | file->index_entrysize = BNAV_GetEntrySize(cfg.navVersion); |
|---|
| 1429 | } |
|---|
| 1430 | return; |
|---|
| 1431 | } |
|---|
| 1432 | |
|---|
| 1433 | /* this functions return true if trim was successfull and false otherwise */ |
|---|
| 1434 | static bool |
|---|
| 1435 | b_try_trim_file(struct bfile_out_desc *desc) |
|---|
| 1436 | { |
|---|
| 1437 | off_t rc; |
|---|
| 1438 | |
|---|
| 1439 | if (desc->trim_count==0) { |
|---|
| 1440 | return true; |
|---|
| 1441 | } |
|---|
| 1442 | if (desc->trim_off>0) { |
|---|
| 1443 | BDBG_MSG((">try_trim %#x:%u %lld", (unsigned)desc->file, desc->trim_count, desc->trim_off)); |
|---|
| 1444 | rc = desc->file->self.trim(&desc->file->self, desc->trim_off); |
|---|
| 1445 | BDBG_MSG(("<try_trim %#x:%u %lld:%lld", (unsigned)desc->file, desc->trim_count, desc->trim_off, rc)); |
|---|
| 1446 | if (rc == 0) { |
|---|
| 1447 | desc->trim_count++; |
|---|
| 1448 | return false; |
|---|
| 1449 | } |
|---|
| 1450 | if (rc<0) { |
|---|
| 1451 | BDBG_WRN(("trim has failed")); |
|---|
| 1452 | return true; |
|---|
| 1453 | } |
|---|
| 1454 | } |
|---|
| 1455 | desc->trim_count = 0; |
|---|
| 1456 | return true; |
|---|
| 1457 | } |
|---|
| 1458 | |
|---|
| 1459 | #define B_GET_OFF_T(p) ((p)->offsetLo|(((uint64_t)(p)->offsetHi)<<32)) |
|---|
| 1460 | |
|---|
| 1461 | /* this function called from the timer context */ |
|---|
| 1462 | static void |
|---|
| 1463 | b_trim_timer(void *file_) |
|---|
| 1464 | { |
|---|
| 1465 | NEXUS_ChunkedFifoRecordHandle file = file_; |
|---|
| 1466 | unsigned timeout = B_TRIM_TIMER; |
|---|
| 1467 | long firstIndex, lastIndex; |
|---|
| 1468 | BNAV_Player_Position first, last; |
|---|
| 1469 | int rc; |
|---|
| 1470 | unsigned long interval; |
|---|
| 1471 | NEXUS_Time start, stop; |
|---|
| 1472 | |
|---|
| 1473 | NEXUS_Time_Get(&start); |
|---|
| 1474 | if(file->cfg.snapshotInterval != 0 && (NEXUS_Time_Diff(&start, &file->lastSnapshotTime)/1000)>=(long)file->cfg.snapshotInterval) { |
|---|
| 1475 | b_lock(file->index.file); |
|---|
| 1476 | file->index.file->writeSnapshotFile = file; /* we can't write data right there since it could overlap with running write operation and would corrupt the file write pointer */ |
|---|
| 1477 | b_unlock(file->index.file); |
|---|
| 1478 | file->lastSnapshotTime = start; |
|---|
| 1479 | } |
|---|
| 1480 | if (file->index.trim_count || file->data.trim_count) { |
|---|
| 1481 | /* trim index first */ |
|---|
| 1482 | if (!b_try_trim_file(&file->index)) { |
|---|
| 1483 | timeout = B_TRIM_TRY_TIMER; |
|---|
| 1484 | goto done; |
|---|
| 1485 | } |
|---|
| 1486 | if (!b_try_trim_file(&file->data)) { |
|---|
| 1487 | timeout = B_TRIM_TRY_TIMER; |
|---|
| 1488 | goto done; |
|---|
| 1489 | } |
|---|
| 1490 | /* this effectively limits rate of succesfull trims to one each B_TRIM_TIMER */ |
|---|
| 1491 | goto done; |
|---|
| 1492 | } |
|---|
| 1493 | |
|---|
| 1494 | b_trim_try_player(file); |
|---|
| 1495 | if(file->bcm_player==NULL) { |
|---|
| 1496 | BDBG_WRN(("index file is empty, trim can't be activated")); |
|---|
| 1497 | goto done; |
|---|
| 1498 | } |
|---|
| 1499 | rc = trim_bp_bounds(file->bcm_player, file, &firstIndex, &lastIndex); |
|---|
| 1500 | if (rc!=0) { |
|---|
| 1501 | BDBG_WRN(("can't obtain file bounds")); |
|---|
| 1502 | goto done; |
|---|
| 1503 | } |
|---|
| 1504 | rc = BNAV_Player_GetPositionInformation(file->bcm_player, firstIndex, &first); |
|---|
| 1505 | if (rc!=0) { |
|---|
| 1506 | BDBG_WRN(("can't obtain first position ")); |
|---|
| 1507 | rc = BNAV_Player_GetPositionInformation(file->bcm_player, firstIndex+1, &first); |
|---|
| 1508 | if (rc!=0) { |
|---|
| 1509 | BDBG_WRN(("..2nd Attempt also failed !")); |
|---|
| 1510 | goto done; |
|---|
| 1511 | } |
|---|
| 1512 | } |
|---|
| 1513 | rc = BNAV_Player_GetPositionInformation(file->bcm_player, lastIndex, &last); |
|---|
| 1514 | if (rc!=0) { |
|---|
| 1515 | BDBG_WRN(("can't obtain last position")); |
|---|
| 1516 | goto done; |
|---|
| 1517 | } |
|---|
| 1518 | |
|---|
| 1519 | BDBG_INSTANCE_MSG(file, ("position %ld:%lu:%lld %ld:%lu:%lld ", |
|---|
| 1520 | firstIndex, first.timestamp,B_GET_OFF_T(&first), lastIndex, last.timestamp, B_GET_OFF_T(&last))); |
|---|
| 1521 | |
|---|
| 1522 | interval = file->cfg.interval*1000; |
|---|
| 1523 | |
|---|
| 1524 | if (last.timestamp - first.timestamp > interval) { |
|---|
| 1525 | long index; |
|---|
| 1526 | off_t off; |
|---|
| 1527 | |
|---|
| 1528 | index = BNAV_Player_FindIndexFromTimestamp(file->bcm_player, last.timestamp - interval); |
|---|
| 1529 | if (index<0) { |
|---|
| 1530 | BDBG_WRN(("can't obtain new index")); |
|---|
| 1531 | goto done; |
|---|
| 1532 | } |
|---|
| 1533 | last = first; /* needed for debuging to save previous first */ |
|---|
| 1534 | rc = BNAV_Player_GetPositionInformation(file->bcm_player, index, &first); |
|---|
| 1535 | if (rc!=0) { |
|---|
| 1536 | BDBG_WRN(("can't obtain new position")); |
|---|
| 1537 | goto done; |
|---|
| 1538 | } |
|---|
| 1539 | BDBG_MSG(("trimming from %d:%u:%lld to %d:%u:%lld", last.index, last.timestamp, B_GET_OFF_T(&last), index, first.timestamp, B_GET_OFF_T(&first))); |
|---|
| 1540 | off = index*file->index_entrysize; |
|---|
| 1541 | BDBG_MSG(("trimming index old %lld new %lld", (int64_t)file->index.trim_off, (int64_t)off)); |
|---|
| 1542 | file->index.trim_off = off; |
|---|
| 1543 | file->index.trim_count = 1; |
|---|
| 1544 | |
|---|
| 1545 | file->index.file->header->trim_gap = (index - file->index.file->header->prev_trim)*file->index_entrysize; |
|---|
| 1546 | |
|---|
| 1547 | file->index.file->header->prev_trim = last.index; |
|---|
| 1548 | |
|---|
| 1549 | off = B_GET_OFF_T(&first); |
|---|
| 1550 | #ifdef DIRECT_IO_SUPPORT |
|---|
| 1551 | off -= off % B_DATA_ALIGN; |
|---|
| 1552 | #endif |
|---|
| 1553 | BDBG_MSG(("trimming data old %lld new %lld", (int64_t)file->data.trim_off, (int64_t)off)); |
|---|
| 1554 | file->data.trim_off = off; |
|---|
| 1555 | file->data.trim_count = 1; |
|---|
| 1556 | |
|---|
| 1557 | timeout = B_TRIM_TRY_TIMER; /* do a trim on the next timer callout */ |
|---|
| 1558 | } |
|---|
| 1559 | done: |
|---|
| 1560 | file->timer = NEXUS_ScheduleTimer(timeout, b_trim_timer, file); /* schedulle another heartbeat for the trim */ |
|---|
| 1561 | NEXUS_Time_Get(&stop); |
|---|
| 1562 | BDBG_MSG(("trim_timer(%#x) %ldms", (unsigned)file , NEXUS_Time_Diff(&stop, &start))); |
|---|
| 1563 | |
|---|
| 1564 | if (!file->timer) { |
|---|
| 1565 | BDBG_ERR(("trim hearbeat has died")); |
|---|
| 1566 | return; |
|---|
| 1567 | } |
|---|
| 1568 | |
|---|
| 1569 | return; |
|---|
| 1570 | } |
|---|
| 1571 | |
|---|
| 1572 | |
|---|
| 1573 | NEXUS_ChunkedFifoRecordHandle |
|---|
| 1574 | NEXUS_ChunkedFifoRecord_Create(const char *fname, const char *indexname) |
|---|
| 1575 | { |
|---|
| 1576 | NEXUS_ChunkedFifoRecordHandle file; |
|---|
| 1577 | NEXUS_Error rc; |
|---|
| 1578 | |
|---|
| 1579 | if (fname==NULL) { rc=BERR_TRACE(NEXUS_INVALID_PARAMETER); return NULL; } |
|---|
| 1580 | if (indexname==NULL) { rc=BERR_TRACE(NEXUS_INVALID_PARAMETER); return NULL; } |
|---|
| 1581 | |
|---|
| 1582 | file = BKNI_Malloc(sizeof(*file)); |
|---|
| 1583 | if (!file) { rc=BERR_TRACE(NEXUS_INVALID_PARAMETER); goto err_alloc; } |
|---|
| 1584 | |
|---|
| 1585 | BKNI_Memset(file, 0, sizeof *file); |
|---|
| 1586 | |
|---|
| 1587 | file->cfg.interval = 30; |
|---|
| 1588 | file->cfg.snapshotInterval = 0; |
|---|
| 1589 | file->cfg.data.soft = 512*1024*1024; |
|---|
| 1590 | file->cfg.data.hard = 1024*1024*1024; |
|---|
| 1591 | file->cfg.data.soft -= file->cfg.data.soft % B_DATA_ALIGN; |
|---|
| 1592 | file->cfg.data.hard -= file->cfg.data.hard % B_DATA_ALIGN; |
|---|
| 1593 | file->cfg.index.soft = 4*1024*1024; |
|---|
| 1594 | file->cfg.index.hard = 8*1024*1024; |
|---|
| 1595 | |
|---|
| 1596 | file->cfg.index.chunkSize = 0; |
|---|
| 1597 | BKNI_Memcpy(file->cfg.chunkTemplate, b_file_chunkTemplate, sizeof(b_file_chunkTemplate)); |
|---|
| 1598 | |
|---|
| 1599 | file->data.trim_count = 0; |
|---|
| 1600 | |
|---|
| 1601 | NEXUS_Time_Get(&file->lastSnapshotTime); |
|---|
| 1602 | |
|---|
| 1603 | /* we save meta data in the index file, it's used because data usually is O_DIRECT, e.g. meta writes are slower and it puts constraints on the alligment of in memory meta buffer */ |
|---|
| 1604 | file->data.file = bpvrfifo_write_open(fname, true, 0, file->index.file, sizeof(file->index.file->header->data)); |
|---|
| 1605 | if (!file->data.file) { goto err_data;} |
|---|
| 1606 | file->data.file->size = file->cfg.data.soft; |
|---|
| 1607 | |
|---|
| 1608 | file->index.trim_count = 0; |
|---|
| 1609 | file->index.file = bpvrfifo_write_open(indexname, false, 2*sizeof(file->data.file->header->data), NULL, 0); |
|---|
| 1610 | if (!file->index.file) { goto err_index;} |
|---|
| 1611 | file->index.file->size = file->cfg.index.soft; |
|---|
| 1612 | |
|---|
| 1613 | /* Do not set O_DIRECT flag for index */ |
|---|
| 1614 | file->rd_index = bpvrfifo_read_open(indexname, false, file->index.file, NULL, 0); |
|---|
| 1615 | if (!file->rd_index) { goto err_rd_index;} |
|---|
| 1616 | |
|---|
| 1617 | file->self.index = bpvrfifo_write_file(file->index.file); |
|---|
| 1618 | file->self.data = bpvrfifo_write_file(file->data.file); |
|---|
| 1619 | |
|---|
| 1620 | file->self.close = bfile_fifo_close_out; |
|---|
| 1621 | |
|---|
| 1622 | file->index_entrysize = BNAV_GetEntrySize(BNAV_VersionOriginal); /* default */ |
|---|
| 1623 | file->bcm_player = NULL; |
|---|
| 1624 | |
|---|
| 1625 | file->index.trim_count = file->data.trim_count = 0; |
|---|
| 1626 | file->index.trim_off = file->data.trim_off = 0; |
|---|
| 1627 | |
|---|
| 1628 | /* timer shall be the last call in the initialization sequence */ |
|---|
| 1629 | file->timer = NEXUS_ScheduleTimer(B_TRIM_TIMER, b_trim_timer, file); /* schedulle heartbeat for the trim */ |
|---|
| 1630 | if (!file->timer) { goto err_timer; } |
|---|
| 1631 | |
|---|
| 1632 | return file; |
|---|
| 1633 | |
|---|
| 1634 | err_timer: |
|---|
| 1635 | bpvrfifo_read_close(file->rd_index); |
|---|
| 1636 | err_rd_index: |
|---|
| 1637 | bpvrfifo_write_close(file->index.file); |
|---|
| 1638 | err_index: |
|---|
| 1639 | bpvrfifo_write_close(file->data.file); |
|---|
| 1640 | err_data: |
|---|
| 1641 | BKNI_Free(file); |
|---|
| 1642 | err_alloc: |
|---|
| 1643 | return NULL; |
|---|
| 1644 | } |
|---|
| 1645 | |
|---|
| 1646 | NEXUS_Error |
|---|
| 1647 | bfile_io_write_set(struct bfile_io_write_fifo *file, const NEXUS_ChunkedFifoRecordLimit *cfg, const char *template) |
|---|
| 1648 | { |
|---|
| 1649 | BDBG_ASSERT(file); |
|---|
| 1650 | BDBG_ASSERT(cfg); |
|---|
| 1651 | |
|---|
| 1652 | if(file->header->active && (file->header->chunked != (cfg->chunkSize!=0))) { |
|---|
| 1653 | return BERR_TRACE(NEXUS_INVALID_PARAMETER); |
|---|
| 1654 | } |
|---|
| 1655 | for(;;) { |
|---|
| 1656 | b_lock(file); |
|---|
| 1657 | if(file->header->busy==0) { |
|---|
| 1658 | break; |
|---|
| 1659 | } |
|---|
| 1660 | b_unlock(file); |
|---|
| 1661 | BDBG_WRN(("bfile_io_write_fifo: %#lx collision in access to the file", (unsigned long)file)); |
|---|
| 1662 | BKNI_Sleep(1); |
|---|
| 1663 | } |
|---|
| 1664 | |
|---|
| 1665 | file->header->data.h.type = cfg->chunkSize != 0 ? bpvrfifo_type_master : bpvrfifo_type_unit; |
|---|
| 1666 | if(!file->header->chunked && cfg->chunkSize != 0) { |
|---|
| 1667 | B_ENTRY(file, 0)->doff = 0; /* data in chunk always starts from 0 */ |
|---|
| 1668 | B_ENTRY(file, 0)->no = file->next_chunk; |
|---|
| 1669 | b_pvrfifo_register_new_chunk(file); |
|---|
| 1670 | } |
|---|
| 1671 | |
|---|
| 1672 | file->header->chunked = cfg->chunkSize != 0; |
|---|
| 1673 | if(template) { |
|---|
| 1674 | b_file_strcpy(file->header->data.h.meta.master.chunkTemplate, sizeof(file->header->data.h.meta.master.chunkTemplate), template); |
|---|
| 1675 | } |
|---|
| 1676 | if(file->header->chunked) { |
|---|
| 1677 | file->size = cfg->chunkSize; |
|---|
| 1678 | } else { |
|---|
| 1679 | file->size = cfg->soft; |
|---|
| 1680 | } |
|---|
| 1681 | b_unlock(file); |
|---|
| 1682 | return NEXUS_SUCCESS; |
|---|
| 1683 | } |
|---|
| 1684 | |
|---|
| 1685 | |
|---|
| 1686 | NEXUS_FileRecordHandle |
|---|
| 1687 | NEXUS_ChunkedFifoRecord_GetFile(NEXUS_ChunkedFifoRecordHandle file) |
|---|
| 1688 | { |
|---|
| 1689 | return &file->self; |
|---|
| 1690 | } |
|---|
| 1691 | |
|---|
| 1692 | NEXUS_Error |
|---|
| 1693 | NEXUS_ChunkedFifoRecord_GetPosition(NEXUS_ChunkedFifoRecordHandle file, NEXUS_FilePosition *first, NEXUS_FilePosition *last) |
|---|
| 1694 | { |
|---|
| 1695 | long firstIndex, lastIndex; |
|---|
| 1696 | BNAV_Player_Position pos; |
|---|
| 1697 | int rc; |
|---|
| 1698 | |
|---|
| 1699 | b_trim_try_player(file); |
|---|
| 1700 | if(file->bcm_player==NULL) { |
|---|
| 1701 | BDBG_MSG(("index file is empty, position can't be extracted")); |
|---|
| 1702 | /* fill them with zeros */ |
|---|
| 1703 | if(first) { |
|---|
| 1704 | first->mpegFileOffset = 0; |
|---|
| 1705 | first->indexOffset = NEXUS_FILE_INVALID_POSITION; |
|---|
| 1706 | first->timestamp = NEXUS_FILE_INVALID_POSITION; |
|---|
| 1707 | } |
|---|
| 1708 | if(last) { /* fill them with zeros */ |
|---|
| 1709 | last->mpegFileOffset = 0; |
|---|
| 1710 | last->indexOffset = NEXUS_FILE_INVALID_POSITION; |
|---|
| 1711 | last->timestamp = NEXUS_FILE_INVALID_POSITION; |
|---|
| 1712 | } |
|---|
| 1713 | return NEXUS_SUCCESS; |
|---|
| 1714 | } |
|---|
| 1715 | rc = bp_bounds(file->bcm_player, file, &firstIndex, &lastIndex); |
|---|
| 1716 | if (rc!=0) { return BERR_TRACE(NEXUS_UNKNOWN); } |
|---|
| 1717 | if (first) { |
|---|
| 1718 | rc = BNAV_Player_GetPositionInformation(file->bcm_player, firstIndex, &pos); |
|---|
| 1719 | if (rc!=0) { return BERR_TRACE(NEXUS_UNKNOWN); } |
|---|
| 1720 | first->indexOffset = pos.index; |
|---|
| 1721 | first->timestamp = pos.timestamp; |
|---|
| 1722 | first->mpegFileOffset = B_GET_OFF_T(&pos); |
|---|
| 1723 | } |
|---|
| 1724 | if (last) { |
|---|
| 1725 | rc = BNAV_Player_GetPositionInformation(file->bcm_player, lastIndex, &pos); |
|---|
| 1726 | if (rc!=0) { return BERR_TRACE(NEXUS_UNKNOWN); } |
|---|
| 1727 | last->indexOffset = pos.index; |
|---|
| 1728 | last->timestamp = pos.timestamp; |
|---|
| 1729 | last->mpegFileOffset = B_GET_OFF_T(&pos); |
|---|
| 1730 | } |
|---|
| 1731 | return NEXUS_SUCCESS; |
|---|
| 1732 | } |
|---|
| 1733 | |
|---|
| 1734 | void |
|---|
| 1735 | NEXUS_ChunkedFifoRecord_GetSettings(NEXUS_ChunkedFifoRecordHandle file, NEXUS_ChunkedFifoRecordSettings *settings) |
|---|
| 1736 | { |
|---|
| 1737 | /* settings are read only, so wa don't need synchronization here */ |
|---|
| 1738 | *settings = file->cfg; |
|---|
| 1739 | return; |
|---|
| 1740 | } |
|---|
| 1741 | |
|---|
| 1742 | |
|---|
| 1743 | NEXUS_Error |
|---|
| 1744 | NEXUS_ChunkedFifoRecord_SetSettings(NEXUS_ChunkedFifoRecordHandle file, const NEXUS_ChunkedFifoRecordSettings *settings) |
|---|
| 1745 | { |
|---|
| 1746 | NEXUS_Error rc = NEXUS_SUCCESS; |
|---|
| 1747 | if ( |
|---|
| 1748 | settings->index.soft <= 2*sizeof(*file->data.file->header) || |
|---|
| 1749 | settings->index.soft >= 2*1024*1024*(off_t)1024 || |
|---|
| 1750 | settings->index.hard <= 2*sizeof(*file->data.file->header) || |
|---|
| 1751 | settings->index.hard >= 2*1024*1024*(off_t)1024 || |
|---|
| 1752 | settings->index.hard < settings->index.soft || |
|---|
| 1753 | settings->data.soft <= B_DATA_ALIGN || |
|---|
| 1754 | settings->data.hard <= B_DATA_ALIGN || |
|---|
| 1755 | settings->data.hard < settings->index.soft ) |
|---|
| 1756 | { |
|---|
| 1757 | return BERR_TRACE(NEXUS_INVALID_PARAMETER); |
|---|
| 1758 | } |
|---|
| 1759 | /* we don't need synchronization here either */ |
|---|
| 1760 | file->cfg = *settings; |
|---|
| 1761 | file->cfg.data.chunkSize -= file->cfg.data.chunkSize % B_DATA_ALIGN; |
|---|
| 1762 | file->cfg.data.soft -= file->cfg.data.soft % B_DATA_ALIGN; |
|---|
| 1763 | file->cfg.data.hard -= file->cfg.data.hard % B_DATA_ALIGN; |
|---|
| 1764 | BDBG_INSTANCE_MSG(file, ("fifo_out_set: %u index(%lld:%lld) data(%lld:%lld)", file->cfg.interval, file->cfg.data.soft, file->cfg.data.hard, file->cfg.index.soft, file->cfg.index.hard)); |
|---|
| 1765 | /* XXX we should truncate file somewhere, sometime */ |
|---|
| 1766 | b_lock(file->index.file); |
|---|
| 1767 | file->index.file->size = file->cfg.index.soft; |
|---|
| 1768 | b_unlock(file->index.file); |
|---|
| 1769 | b_lock(file->data.file); |
|---|
| 1770 | file->data.file->size = file->cfg.data.soft; |
|---|
| 1771 | b_unlock(file->data.file); |
|---|
| 1772 | |
|---|
| 1773 | rc = bfile_io_write_set(file->index.file, &settings->index, settings->chunkTemplate); |
|---|
| 1774 | if(rc!=NEXUS_SUCCESS) { |
|---|
| 1775 | goto err_index; |
|---|
| 1776 | } |
|---|
| 1777 | |
|---|
| 1778 | rc = bfile_io_write_set(file->data.file, &settings->data, settings->chunkTemplate); |
|---|
| 1779 | if(rc!=NEXUS_SUCCESS) { |
|---|
| 1780 | goto err_data; |
|---|
| 1781 | } |
|---|
| 1782 | |
|---|
| 1783 | return NEXUS_SUCCESS; |
|---|
| 1784 | err_data: |
|---|
| 1785 | err_index: |
|---|
| 1786 | return rc; |
|---|
| 1787 | } |
|---|
| 1788 | |
|---|