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; }
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(); }
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; }
/* 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; }
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; } }