Beispiel #1
0
/*{
** 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 );
}
Beispiel #2
0
/*****************************************************************************
** 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;
}
Beispiel #3
0
/*{
** 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);
  }