Exemple #1
0
bool_t
node_sync( intgen_t fd, off64_t off )
{
    /* sanity checks
     */
    ASSERT( sizeof( node_hdr_t ) <= NODE_HDRSZ );

    /* map the abstraction header
     */
    ASSERT( ( NODE_HDRSZ & pgmask ) == 0 );
    ASSERT( off <= ( off64_t )OFF64MAX );
    ASSERT( ! ( off % ( off64_t )pgsz ));
    node_hdrp = ( node_hdr_t * )mmap_autogrow(
                    NODE_HDRSZ,
                    fd,
                    off );
    if ( node_hdrp == (node_hdr_t *)-1 ) {
        mlog( MLOG_NORMAL | MLOG_ERROR, _(
                  "unable to map node hdr of size %d: %s\n"),
              NODE_HDRSZ,
              strerror( errno ));
        return BOOL_FALSE;
    }

    /* save transient context
     */
    node_fd = fd;

    /* initialize the window abstraction
     */
    win_init( fd,
              node_hdrp->nh_firstsegoff,
              node_hdrp->nh_segsz,
              node_hdrp->nh_segtblsz,
              node_hdrp->nh_winmapmax );

    return BOOL_TRUE;
}
Exemple #2
0
void
win_map( segix_t segix, void **pp )
{
	off64_t segoff;
	win_t *winp;

	CRITICAL_BEGIN();

#ifdef TREE_DEBUG
	mlog(MLOG_DEBUG | MLOG_TREE | MLOG_NOLOCK,
	     "win_map(segix=%u,addr=%p)\n", segix, pp);
#endif
	/* resize the array if necessary */
	if ( segix >= tranp->t_segmaplen )
		win_segmap_resize( segix );

	/* see if segment already mapped. if ref cnt zero,
	 * remove from LRU list.
	 */
	winp = tranp->t_segmap[segix];
	if ( winp ) {
#ifdef TREE_DEBUG
		mlog(MLOG_DEBUG | MLOG_TREE | MLOG_NOLOCK,
		     "win_map(): requested segment already mapped\n");
#endif
		if ( winp->w_refcnt == 0 ) {
			ASSERT( tranp->t_lruheadp );
			ASSERT( tranp->t_lrutailp );
			if ( tranp->t_lruheadp == winp ) {
				if ( tranp->t_lrutailp == winp ) {
					tranp->t_lruheadp = 0;
					tranp->t_lrutailp = 0;
				} else {
					tranp->t_lruheadp = winp->w_nextp;
					tranp->t_lruheadp->w_prevp = 0;
				}
			} else {
				if ( tranp->t_lrutailp == winp ) {
					tranp->t_lrutailp = winp->w_prevp;
					tranp->t_lrutailp->w_nextp = 0;
				} else {
					winp->w_prevp->w_nextp = winp->w_nextp;
					winp->w_nextp->w_prevp = winp->w_prevp;
				}
			}
			winp->w_prevp = 0;
			winp->w_nextp = 0;
		} else {
			ASSERT( ! winp->w_prevp );
			ASSERT( ! winp->w_nextp );
		}
		winp->w_refcnt++;
		*pp = winp->w_p;
		CRITICAL_END();
		return;
	}

	/* Allocate a new descriptor if we haven't yet hit the maximum,
	 * otherwise reuse any descriptor on the LRU list.
	 */
	if ( tranp->t_wincnt < tranp->t_winmax ) {
#ifdef TREE_DEBUG
		mlog(MLOG_DEBUG | MLOG_TREE | MLOG_NOLOCK,
		     "win_map(): create a new window\n");
#endif
		winp = ( win_t * )calloc( 1, sizeof( win_t ));
		ASSERT( winp );
		tranp->t_wincnt++;
	} else if ( tranp->t_lruheadp ) {
		/* REFERENCED */
		intgen_t rval;
#ifdef TREE_DEBUG
		mlog(MLOG_DEBUG | MLOG_TREE | MLOG_NOLOCK,
		     "win_map(): get head from lru freelist & unmap\n");
#endif
		ASSERT( tranp->t_lrutailp );
		winp = tranp->t_lruheadp;
		tranp->t_lruheadp = winp->w_nextp;
		if ( tranp->t_lruheadp ) {
			tranp->t_lruheadp->w_prevp = 0;
		} else {
			tranp->t_lrutailp = 0;
		}
		tranp->t_segmap[winp->w_segix] = NULL;
		rval = munmap( winp->w_p, tranp->t_segsz );
		ASSERT( ! rval );
		memset( ( void * )winp, 0, sizeof( win_t ));
	} else {
		ASSERT( tranp->t_wincnt == tranp->t_winmax );
		*pp = NULL;
		CRITICAL_END();
		mlog( MLOG_NORMAL | MLOG_WARNING, _(
		      "all map windows in use. Check virtual memory limits\n"));
		return;
	}

	/* calculate offset of segment
	 */
	segoff = segix * ( off64_t )tranp->t_segsz;

	/* map the window
	 */
	ASSERT( tranp->t_segsz >= 1 );
	ASSERT( tranp->t_firstoff
		<=
		OFF64MAX - segoff - ( off64_t )tranp->t_segsz + 1ll );
	ASSERT( ! ( tranp->t_segsz % pgsz ));
	ASSERT( ! ( ( tranp->t_firstoff + segoff ) % ( off64_t )pgsz ));
#ifdef TREE_DEBUG
	mlog(MLOG_DEBUG | MLOG_TREE | MLOG_NOLOCK,
	     "win_map(): mmap segment at %lld, size = %llu\n",
	    ( off64_t )( tranp->t_firstoff + segoff ), tranp->t_segsz);
#endif
	tranp->t_winmmaps++;
	winp->w_p = mmap_autogrow(
			    tranp->t_segsz,
			    tranp->t_fd,
			    ( off64_t )( tranp->t_firstoff + segoff ));
	if ( winp->w_p == (void *)-1 ) {
		int	error = errno;
		mlog( MLOG_NORMAL | MLOG_ERROR, _(
		      "win_map(): unable to map a node segment of size %d at %d: %s\n"),
		      tranp->t_segsz, tranp->t_firstoff + segoff,
		      strerror( error ));

		tranp->t_wincnt--;
		tranp->t_winmax--;
		CRITICAL_END();
		free(winp);

		if (error == ENOMEM && tranp->t_lruheadp) {
			mlog( MLOG_NORMAL | MLOG_ERROR,
		      		_("win_map(): try to select a different win_t\n"));
			win_map(segix, pp);
			return;
		}
		*pp = NULL;
		return;
	}
	winp->w_segix  = segix;
	ASSERT( winp->w_refcnt == 0 );
	winp->w_refcnt++;
	tranp->t_segmap[winp->w_segix] = winp;

	*pp = winp->w_p;

	CRITICAL_END();
}
Exemple #3
0
bool_t
inomap_sync_pers( char *hkdir )
{
	char *perspath;
	pers_t *persp;
	hnk_t *hnkp;

	/* sanity checks
	 */
	ASSERT( sizeof( hnk_t ) == HNKSZ );
	ASSERT( HNKSZ >= pgsz );
	ASSERT( ! ( HNKSZ % pgsz ));

	/* only needed once per session
	 */
	if ( pers_fd >= 0 ) {
		return BOOL_TRUE;
	}

	/* open the backing store. if not present, ok, hasn't been created yet
	 */
	perspath = open_pathalloc( hkdir, PERS_NAME, 0 );
	pers_fd = open( perspath, O_RDWR );
	if ( pers_fd < 0 ) {
		return BOOL_TRUE;
	}

	/* mmap the persistent hdr
	 */
	persp = ( pers_t * ) mmap_autogrow(
				     PERSSZ,
				     pers_fd,
				     ( off64_t )0 );
	if ( persp == ( pers_t * )-1 ) {
		mlog( MLOG_NORMAL | MLOG_ERROR,
		      "unable to map %s hdr: %s\n",
		      perspath,
		      strerror( errno ));
		return BOOL_FALSE;
	}

	/* read the pers hdr
	 */
	hnkcnt = persp->hnkcnt;
	segcnt = persp->segcnt;
	last_ino_added = persp->last_ino_added;

	/* mmap the pers inomap
	 */
	ASSERT( hnkcnt * sizeof( hnk_t ) <= ( size64_t )INT32MAX );
	roothnkp = ( hnk_t * ) mmap_autogrow(
				       sizeof( hnk_t ) * ( size_t )hnkcnt,
				       pers_fd,
				       ( off64_t )PERSSZ );
	if ( roothnkp == ( hnk_t * )-1 ) {
		mlog( MLOG_NORMAL | MLOG_ERROR,
		      "unable to map %s: %s\n",
		      perspath,
		      strerror( errno ));
		return BOOL_FALSE;
	}

	/* correct the next pointers
	 */
	for ( hnkp = roothnkp
	      ;
	      hnkp < roothnkp + ( intgen_t )hnkcnt - 1
	      ;
	      hnkp++ ) {
		hnkp->nextp = hnkp + 1;
	}
	hnkp->nextp = 0;

	/* calculate the tail pointers
	 */
	tailhnkp = hnkp;
	ASSERT( hnkcnt > 0 );
	lastsegp = &tailhnkp->seg[ ( intgen_t )( segcnt
						 -
						 SEGPERHNK * ( hnkcnt - 1 )
						 -
						 1 ) ];
	
	/* now all inomap operators will work
	 */
	return BOOL_TRUE;
}
Exemple #4
0
/* ARGSUSED */
bool_t
node_init( intgen_t fd,
           off64_t off,
           size_t usrnodesz,
           ix_t nodehkix,
           size_t nodealignsz,
           size64_t vmsz,
           size64_t dirs_nondirs_cnt )
{
    size64_t nodesz;
    size64_t winmap_mem;
    size64_t segsz;
    size64_t segtablesz;
    size64_t nodesperseg;
    size64_t minsegsz;
    size64_t winmapmax;
    intgen_t rval;

    /* sanity checks
     */
    ASSERT( sizeof( node_hdr_t ) <= NODE_HDRSZ );
    ASSERT( sizeof( nh_t ) < sizeof( off64_t ));
    ASSERT( nodehkix < usrnodesz );
    ASSERT( usrnodesz >= sizeof( char * ) + 1 );
    /* so node is at least big enough to hold
     * the free list linkage and the housekeeping byte
     */
    ASSERT( nodehkix > sizeof( char * ));
    /* since beginning of each node is used to
     * link it in the free list.
     */

    /* adjust the user's node size to meet user's alignment constraint
    */
    nodesz = ( usrnodesz + nodealignsz - 1 ) & ~( nodealignsz - 1 );

#define	WINMAP_MAX	20	/* maximum number of windows to use */
#define	WINMAP_MIN	4	/* minimum number of windows to use */
#define	HARDLINK_FUDGE	1.2	/* approx 1.2 hard links per file */

    /* Calculate the expected size of the segment table using the number
     * of dirs and non-dirs.  Since we don't know how many hard-links
     * there will be, scale the size upward using HARDLINK_FUDGE.
     */

    segtablesz = ( (size64_t)(HARDLINK_FUDGE * (double)dirs_nondirs_cnt) * nodesz);

    /* Figure out how much memory is available for use by winmaps, and
     * use that to pick an appropriate winmapmax, segsz, and nodesperseg,
     * the goal being that if at all possible we want the entire segment
     * table to be mapped so that we aren't constantly mapping and
     * unmapping winmaps.  There must be at least WINMAP_MIN winmaps
     * because references can be held on more than one winmap at the
     * same time.  More winmaps are generally better to reduce the
     * number of nodes that are unmapped if unmapping does occur.
     */

    minsegsz = pgsz * nodesz;	/* must be pgsz and nodesz multiple */
    winmap_mem = min(vmsz, segtablesz);
    segsz = (((winmap_mem / WINMAP_MAX) + minsegsz - 1) / minsegsz) * minsegsz;
    segsz = max(segsz, minsegsz);

    nodesperseg = segsz / nodesz;

    winmapmax = min(WINMAP_MAX, vmsz / segsz);
    winmapmax = max(winmapmax, WINMAP_MIN);

    /* map the abstraction header
     */
    ASSERT( ( NODE_HDRSZ & pgmask ) == 0 );
    ASSERT( ! ( NODE_HDRSZ % pgsz ));
    ASSERT( off <= OFF64MAX );
    ASSERT( ! ( off % ( off64_t )pgsz ));
    node_hdrp = ( node_hdr_t * )mmap_autogrow(
                    NODE_HDRSZ,
                    fd,
                    off );
    if ( node_hdrp == (node_hdr_t *)-1 ) {
        mlog( MLOG_NORMAL | MLOG_ERROR, _(
                  "unable to map node hdr of size %d: %s\n"),
              NODE_HDRSZ,
              strerror( errno ));
        return BOOL_FALSE;
    }

    /* initialize and save persistent context.
     */
    node_hdrp->nh_nodesz = nodesz;
    node_hdrp->nh_nodehkix = nodehkix;
    node_hdrp->nh_segsz = segsz;
    node_hdrp->nh_segtblsz = segtablesz;
    node_hdrp->nh_winmapmax = winmapmax;
    node_hdrp->nh_nodesperseg = nodesperseg;
    node_hdrp->nh_nodealignsz = nodealignsz;
    node_hdrp->nh_freenix = NIX_NULL;
    node_hdrp->nh_firstsegoff = off + ( off64_t )NODE_HDRSZ;
    node_hdrp->nh_virgsegreloff = 0;
    node_hdrp->nh_virgrelnix = 0;

    /* save transient context
     */
    node_fd = fd;

    /* autogrow the first segment
     */
    mlog( MLOG_DEBUG,
          "pre-growing new node array segment at %lld "
          "size %lld\n",
          node_hdrp->nh_firstsegoff,
          ( off64_t )node_hdrp->nh_segsz );
    rval = ftruncate64( node_fd,
                        node_hdrp->nh_firstsegoff
                        +
                        ( off64_t )node_hdrp->nh_segsz );
    if ( rval ) {
        mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_TREE, _(
                  "unable to autogrow first node segment: %s (%d)\n"),
              strerror( errno ),
              errno );
        return BOOL_FALSE;
    }

    /* initialize the window abstraction
     */
    win_init( fd,
              node_hdrp->nh_firstsegoff,
              segsz,
              segtablesz,
              winmapmax );

    /* announce the results
     */
    mlog( MLOG_DEBUG | MLOG_TREE,
          "node_init:"
          " vmsz = %llu (0x%llx)"
          " segsz = %u (0x%x)"
          " segtblsz = %llu (0x%llx)"
          " nodesperseg = %u (0x%x)"
          " winmapmax = %llu (0x%llx)"
          "\n",
          vmsz, vmsz,
          segsz, segsz,
          segtablesz, segtablesz,
          nodesperseg, nodesperseg,
          winmapmax, winmapmax );

    return BOOL_TRUE;
}
Exemple #5
0
rv_t
inomap_restore_pers( drive_t *drivep,
		     content_inode_hdr_t *scrhdrp,
		     char *hkdir )
{
	drive_ops_t *dop = drivep->d_opsp;
	char *perspath;
	pers_t *persp;
	hnk_t *pershnkp;
	hnk_t *tmphnkp;
	intgen_t fd;
	/* REFERENCED */
	intgen_t nread;
	intgen_t rval;
	/* REFERENCED */
	intgen_t rval1;
	int i;
	bool_t ok;

	/* sanity checks
	 */
	ASSERT( INOPERSEG == ( sizeof( (( seg_t * )0 )->lobits ) * NBBY ));
	ASSERT( sizeof( hnk_t ) == HNKSZ );
	ASSERT( HNKSZ >= pgsz );
	ASSERT( ! ( HNKSZ % pgsz ));
	ASSERT( sizeof( pers_t ) <= PERSSZ );

	/* get inomap info from media hdr
	 */
	hnkcnt = scrhdrp->cih_inomap_hnkcnt;
	segcnt = scrhdrp->cih_inomap_segcnt;
	last_ino_added = scrhdrp->cih_inomap_lastino;

	/* truncate and open the backing store
	 */
	perspath = open_pathalloc( hkdir, PERS_NAME, 0 );
	( void )unlink( perspath );
	fd = open( perspath,
		   O_RDWR | O_CREAT,
		   S_IRUSR | S_IWUSR );
	if ( fd < 0 ) {
		mlog( MLOG_NORMAL | MLOG_ERROR,
		      "could not open %s: %s\n",
		      perspath,
		      strerror( errno ));
		return RV_ERROR;
	}

	/* mmap the persistent hdr and space for the map
	 */
	ASSERT( sizeof( hnk_t ) * ( size_t )hnkcnt >= pgsz );
	ASSERT( ! ( sizeof( hnk_t ) * ( size_t )hnkcnt % pgsz ));
	persp = ( pers_t * ) mmap_autogrow(
				     PERSSZ
				     +
				     sizeof( hnk_t ) * ( size_t )hnkcnt,
				     fd,
				     ( off64_t )0 );
	if ( persp == ( pers_t * )-1 ) {
		mlog( MLOG_NORMAL | MLOG_ERROR,
		      "unable to map %s: %s\n",
		      perspath,
		      strerror( errno ));
		return RV_ERROR;
	}

	/* load the pers hdr
	 */
	persp->hnkcnt = hnkcnt;
	persp->segcnt = segcnt;
	persp->last_ino_added = last_ino_added;

	tmphnkp = ( hnk_t * )calloc( ( size_t )hnkcnt, sizeof( hnk_t ));
	ASSERT( tmphnkp );

	/* read the map in from media
	 */
	nread = read_buf( ( char * )tmphnkp,
			  sizeof( hnk_t ) * ( size_t )hnkcnt,
			  ( void * )drivep,
			  ( rfp_t )dop->do_read,
			  ( rrbfp_t )dop->do_return_read_buf,
			  &rval );

	pershnkp = (hnk_t *)((char *)persp + PERSSZ);
	for(i = 0; i < hnkcnt; i++) {
		xlate_hnk(&tmphnkp[i], &pershnkp[i], 1);
	}
	free(tmphnkp);

	mlog(MLOG_NITTY, "inomap_restore_pers: pre-munmap\n");

	/* close up
	 */
	rval1 = munmap( ( void * )persp,
		        PERSSZ
		        +
		        sizeof( hnk_t ) * ( size_t )hnkcnt );
	ASSERT( ! rval1 );
	( void )close( fd );
	free( ( void * )perspath );

	mlog(MLOG_NITTY, "inomap_restore_pers: post-munmap\n");

	/* check the return code from read
	 */
	switch( rval ) {
	case 0:
		ASSERT( ( size_t )nread == sizeof( hnk_t ) * ( size_t )hnkcnt );
		ok = inomap_sync_pers( hkdir );
		if ( ! ok ) {
			return RV_ERROR;
		}
		return RV_OK;
	case DRIVE_ERROR_EOD:
	case DRIVE_ERROR_EOF:
	case DRIVE_ERROR_EOM:
	case DRIVE_ERROR_MEDIA:
	case DRIVE_ERROR_CORRUPTION:
		return RV_CORRUPT;
	case DRIVE_ERROR_DEVICE:
		return RV_DRIVE;
	case DRIVE_ERROR_CORE:
	default:
		return RV_CORE;
	}
}