/*{ ** Name: DI_slave_write - Request a slave to writes page(s) to a file on disk. ** ** Description: ** This routine was created to make DIwrite more readable once ** error checking had been added. See DIwrite for comments. ** ** Inputs: ** f Pointer to the DI file ** context needed to do I/O. ** diop Pointer to dilru file context. ** buf Pointer to page(s) to write. ** page Value indicating page(s) to write. ** num_of_pages number of pages to write ** ** Outputs: ** err_code Pointer to a variable used ** to return operating system ** errors. ** Returns: ** OK ** other errors. ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 30-nov-1992 (rmuth) ** Created. ** 10-oct-1993 (mikem) ** bug #47624 ** Bug 47624 resulted in CSsuspend()'s from the DI system being woken ** up early. Mainline DI would then procede while the slave would ** actually be processing the requested asynchronous action. Various ** bad things could happen after this depending on timing: (mainline ** DI would change the slave control block before slave read it, ** mainline DI would call DIlru_release() and ignore it failing which ** would cause the control block to never be freed eventually leading ** to the server hanging when it ran out of slave control blocks, ... ** ** Fixes were made to scf to hopefully eliminate the unwanted ** CSresume()'s. In addition defensive code has been added to DI ** to catch cases of returning from CSresume while the slave is ** operating, and to check for errors from DIlru_release(). Before ** causing a slave to take action the master will set the slave ** control block status to DI_INPROGRESS, the slave in turn will not ** change this status until it has completed the operation. ** ** The off by one error was caused by the CSsuspend called by ** DI_slave_send() returning early in the case of a DIwrite() of one ** page. The old write loop would increment disl->pre_seek before the ** slave had actually read the control block so the slave would write ** the data from page N to the N+1 location in the file. The ** DI_INPROGRESS flag should stop this, and at least in the one page ** write case we no longer increment disl->pre_seek. ** 23-aug-1993 (bryanp) ** If segment isn't yet mapped, map it! ** 01-oct-1998 (somsa01) ** Return DI_NODISKSPACE when we are out of disk space. */ static STATUS DI_slave_write( DI_IO *f, DI_OP *diop, char *buf, i4 page, i4 num_of_pages, CL_ERR_DESC *err_code) { register DI_SLAVE_CB *disl; ME_SEG_INFO *seginfo; bool direct_write; STATUS big_status = OK, small_status = OK; STATUS intern_status = OK, status; /* unix variables */ int bytes_to_write; do { disl = diop->di_evcb; bytes_to_write = (f->io_bytes_per_page * (num_of_pages)); /* ** Determine whether we're writing from shared memory, and set ** up the segment ID and offset correctly. */ seginfo = ME_find_seg( buf, (char *)buf + bytes_to_write, &ME_segpool); if (seginfo != 0 && (seginfo->flags & ME_SLAVEMAPPED_MASK) == 0) { status = DI_lru_slmapmem(seginfo, &intern_status, &small_status); if (status) break; } if (seginfo != 0 && (seginfo->flags & ME_SLAVEMAPPED_MASK) != 0) { direct_write = TRUE; MEcopy( (PTR)seginfo->key, sizeof(disl->seg_key), (PTR)disl->seg_key); disl->seg_offset = (char *)buf - (char *)seginfo->addr; } else { direct_write = FALSE; seginfo = ME_find_seg(disl->buf, disl->buf, &ME_segpool); if (seginfo) { MEcopy( (PTR)seginfo->key, sizeof(disl->seg_key), (PTR)disl->seg_key); disl->seg_offset= (char *)disl->buf - (char *)seginfo->addr; } else { small_status = DI_BADWRITE; break; } } /* Send file properties to slave */ FPROP_COPY(f->io_fprop,disl->io_fprop); disl->pre_seek = (OFFSET_TYPE)(f->io_bytes_per_page) * (OFFSET_TYPE)(page); disl->file_op = DI_SL_WRITE; /* ** Write the data */ do { if (direct_write) disl->length = bytes_to_write; else { disl->length = min(bytes_to_write, Cs_srv_block.cs_size_io_buf); MEcopy((PTR)buf, disl->length, (PTR)disl->buf); } DI_slave_send( disl->dest_slave_no, diop, &big_status, &small_status, &intern_status); if (( big_status != OK ) || (small_status != OK )) break; if ((small_status = disl->status) != OK ) { STRUCT_ASSIGN_MACRO(disl->errcode, *err_code); } if ((small_status != OK) || (disl->length == 0)) { switch( err_code->errnum ) { case EFBIG: small_status = DI_BADEXTEND; break; case ENOSPC: small_status = DI_NODISKSPACE; break; #ifdef EDQUOT case EDQUOT: small_status = DI_EXCEED_LIMIT; break; #endif default: small_status = DI_BADWRITE; break; } break; } bytes_to_write -= disl->length; buf += disl->length; if (bytes_to_write > 0) disl->pre_seek += (OFFSET_TYPE)disl->length; } while ( bytes_to_write > 0); } while (FALSE); if (big_status != OK ) small_status = big_status; if (small_status != OK ) DIlru_set_di_error( &small_status, err_code, intern_status, DI_GENERAL_ERR); return( small_status ); }
/***************************************************************************** ** Name: MEshared_free() - Free shared memory ** ** Description: ** Free a region of shared memory and return new region for potential ** futher freeing of the break region. ** ** If there is attached shared memory in the region being ** freed then those pages should only be marked free if the whole ** segment can be detached. ** ** There is a small table of attached segments which is scanned. ** ** Inputs: ** addr address of region ** pages number of pages to check ** ** Outputs: ** addr new address of region ** pages new number of pages ** err_code CL_ERR_DESC ** ** Returns: ** OK ** ME_NOT_ALLOCATED ** ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 07-apr-1997 (canor01) ** When the shared memory is attached to existing memory ** the file handle will be null, so don't try to close it. ** 10-apr-1997 (canor01) ** If the address of the memory to be freed does not fall ** within the shared memory range, return ME_NOT_ALLOCATED. ** *****************************************************************************/ STATUS MEshared_free(PTR *addr, SIZE_TYPE *pages, CL_ERR_DESC *err_code) { STATUS status = OK; register ME_SEG_INFO *seginf; char *lower, *upper, *last; SIZE_TYPE off, len; QUEUE *next_queue; CLEAR_ERR(err_code); lower = (char *) *addr; upper = lower + ME_MPAGESIZE * *pages; last = NULL; gen_Psem(&ME_segpool_sem); seginf = ME_find_seg(lower, upper, &ME_segpool); if ( seginf == NULL ) { /* memory address was not within shared memory range */ gen_Vsem(&ME_segpool_sem); return( ME_NOT_ALLOCATED ); } for ( ; seginf; seginf = ME_find_seg(lower, upper, next_queue)) { next_queue = &seginf->q; if (last && last != seginf->eaddr) { status = ME_NOT_ALLOCATED; break; } last = seginf->addr; off = 0; len = seginf->npages; if (lower > seginf->addr) { off = (lower - seginf->addr) / ME_MPAGESIZE; len -= off; } if (upper < seginf->eaddr) { len -= (seginf->eaddr - upper) / ME_MPAGESIZE; } if (MEalloctst(seginf->allocvec, (i4)off, (i4)len, TRUE)) { status = ME_NOT_ALLOCATED; break; } MEclearpg(seginf->allocvec, (i4)off, (i4)len); if (!MEalloctst(seginf->allocvec, 0, seginf->npages, FALSE)) { /* detach segment */ /* * WARNING::: if the address is NOT the BASE of a * shared memory segment obtained from MapViewOfFile, * we're either gonna fail or puke. Good luck! */ status = UnmapViewOfFile(seginf->addr); if (status == FALSE) { status = GetLastError(); SETCLOS2ERR(err_code, status, ER_mmap); gen_Vsem(&ME_segpool_sem); return (ME_BAD_PARAM); } status = CloseHandle(seginf->mem_handle); if (status == FALSE) { status = GetLastError(); SETCLOS2ERR(err_code, status, ER_close); gen_Vsem(&ME_segpool_sem); return (ME_BAD_PARAM); } /* ** if just attaching to existing memory, ** there will just be a memory handle, but ** the file_handle will be NULL. */ if ( seginf->file_handle ) { FlushFileBuffers(seginf->file_handle); status = CloseHandle(seginf->file_handle); } if (status == FALSE) { status = GetLastError(); SETCLOS2ERR(err_code, status, ER_close); gen_Vsem(&ME_segpool_sem); return (ME_BAD_PARAM); } else { status = OK; } next_queue = ME_rem_seg(seginf); *addr = (PTR) NULL; } } gen_Vsem(&ME_segpool_sem); return status; }
/*{ ** Name: DI_slave_read - Request a slave to read page(s) from a file on disk. ** ** Description: ** This routine was created to make DIread more readable once ** error checking had been added. See DIread for comments. ** ** Inputs: ** f Pointer to the DI file ** context needed to do I/O. ** diop Pointer to dilru file context. ** buf Pointer to page(s) to read. ** page Value indicating page(s) to read. ** num_of_pages number of pages to read. ** ** Outputs: ** err_code Pointer to a variable used ** to return operating system ** errors. ** Returns: ** OK ** other errors. ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 30-nov-1992 (rmuth) ** Created. ** 10-mar-1993 (mikem) ** Changed the type of the first parameter to DI_send_ev_to_slave() and ** the 2nd parameter to DI_slave_send(), so that DI_send_ev_to_slave() ** could access the slave control block's status. ** This routine will now initialize the status to DI_INPROGRESS, before ** making the request and the slave will change the status once the ** operation is complete. ** 23-aug-1993 (bryanp) ** If memory segment isn't yet mapped, map it. */ static STATUS DI_slave_read( DI_IO *f, DI_OP *diop, char *buf, i4 page, i4 num_of_pages, i4 *n, CL_ERR_DESC *err_code) { register DI_SLAVE_CB *disl; ME_SEG_INFO *seginfo; bool direct_read; STATUS small_status = OK, big_status = OK, intern_status = OK, status; /* unix variables */ int bytes_to_read; int bytes_read = 0; do { disl = diop->di_evcb; disl->pre_seek = (OFFSET_TYPE)(f->io_bytes_per_page) * (OFFSET_TYPE)(page); bytes_to_read = f->io_bytes_per_page * num_of_pages; /* ** determine whether we're reading into shared memory, and set ** up the segment ID and offset correctly */ seginfo = ME_find_seg( buf, (char *)buf + bytes_to_read, &ME_segpool); if (seginfo != 0 && (seginfo->flags & ME_SLAVEMAPPED_MASK) == 0) { status = DI_lru_slmapmem(seginfo, &intern_status, &small_status); if (status) break; } if (seginfo != 0 && (seginfo->flags & ME_SLAVEMAPPED_MASK) != 0) { MEcopy( (PTR)seginfo->key, sizeof(disl->seg_key), (PTR)disl->seg_key); disl->seg_offset = (char *)buf - (char *)seginfo->addr; direct_read = TRUE; } else { direct_read = FALSE; seginfo = ME_find_seg(disl->buf, disl->buf, &ME_segpool); if (seginfo) { MEcopy( (PTR)seginfo->key, sizeof(disl->seg_key), (PTR)disl->seg_key); disl->seg_offset= (char *)disl->buf - (char *)seginfo->addr; } else { small_status = DI_BADREAD; break; } } /* ** seek to place to read */ do { disl->file_op = DI_SL_READ; /* Send file properties to slave */ FPROP_COPY(f->io_fprop,disl->io_fprop); if (direct_read) disl->length = bytes_to_read; else disl->length = min(bytes_to_read, Cs_srv_block.cs_size_io_buf); DI_slave_send( disl->dest_slave_no, diop, &big_status, &small_status, &intern_status); if (( big_status != OK ) || ( small_status != OK )) break; if ((small_status = disl->status) != OK ) { STRUCT_ASSIGN_MACRO(disl->errcode, *err_code); small_status = DI_BADREAD; break; } else { if ( disl->length == 0 ) { small_status = DI_ENDFILE; #ifdef xDEV_TST TRdisplay("num_pages %d\n, read_op = %x", num_of_pages, 0x70000000); DIlru_dump(); #endif /* xDev_TST */ break; } } /* ** Read data ok */ if (! direct_read) { MEcopy((PTR)disl->buf, disl->length, (PTR)buf); buf += disl->length; } bytes_to_read -= disl->length; disl->pre_seek += (OFFSET_TYPE)disl->length; bytes_read += disl->length; } while ( bytes_to_read > 0); } while (FALSE); if ( bytes_read > 0 ) *n = bytes_read / f->io_bytes_per_page; if ( big_status != OK ) small_status = big_status; if (small_status != OK ) DIlru_set_di_error( &small_status, err_code, intern_status, DI_GENERAL_ERR); return(small_status); }