Home | History | Annotate | Download | only in diskomizer
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #pragma ident	"@(#)recent.c	1.5	09/05/26 SMI"
     28 
     29 /*
     30  * Recent writes.
     31  *
     32  *	The idea here is to keep a per process, per device list of offests
     33  *	that have been recently written. This is so that when an event
     34  *	occurs diskomizer can quickly check that the last few IO's to
     35  *	go complete were good.
     36  *
     37  *	The intention is that while the blocks are still being held as
     38  *	recently written, they are locked and therefore not able to be
     39  *	written again.  The down side of this is that they are not elegible
     40  *	to be read either.
     41  *
     42  *	This can be turned on by setting the size of the recent write log
     43  *	to zero.
     44  */
     45 
     46 #include "diskomizer64mpism.h"
     47 
     48 static ullong_t retoff(struct recent_blocks *blks, ullong_t off);
     49 static ullong_t minus1(struct recent_blocks *blks);
     50 static void *zero(void);
     51 ullong_t (*push_recent)(struct recent_blocks *blks, ullong_t off) = retoff;
     52 ullong_t (*pop_recent)(struct recent_blocks *blks) = minus1;
     53 int (*snapshot_recent)(struct recent_blocks *blks) =
     54 	(int (*)(struct recent_blocks *blks))zero;
     55 
     56 static ullong_t
     57 retoff(struct recent_blocks *blks, ullong_t x)
     58 {
     59 	return (x);
     60 }
     61 static ullong_t
     62 minus1(struct recent_blocks *blks)
     63 {
     64 	return ((ullong_t)-1);
     65 }
     66 static void *
     67 zero(void)
     68 {
     69 	return (NULL);
     70 }
     71 /*
     72  * Push the offset onto the list of recent writes.  If the list is full
     73  * return the offset of the oldest io so that it can be freed
     74  */
     75 ullong_t
     76 do_push_recent(struct recent_blocks *blks, ullong_t off)
     77 {
     78 	ullong_t retoff;
     79 
     80 	retoff = blks->recent_blocks[blks->first];
     81 	blks->recent_blocks[blks->last] = off;
     82 	blks->last = (blks->last + 1) % blks->length;
     83 	if (blks->last == blks->first) {
     84 		blks->first = (blks->first + 1) % blks->length;
     85 		return (retoff);
     86 	}
     87 	return (-1);
     88 }
     89 /*
     90  * snapshot the recently written blocks, leaving the log empty.
     91  */
     92 int
     93 do_snapshot_recent(struct recent_blocks *blks)
     94 {
     95 	int x = blks->frozen_block_count;
     96 	int i;
     97 
     98 	blks->frozen_block_count = 0;
     99 
    100 	for (i = blks->first; i != blks->last; i = (i + 1) % blks->length) {
    101 		blks->recent_blocks[blks->length + blks->frozen_block_count++] =
    102 		    blks->recent_blocks[i];
    103 		blks->recent_blocks[i] = -1;
    104 	}
    105 	blks->first = i;
    106 	return (x);
    107 }
    108 /*
    109  * pop an entry from the  snapshot
    110  */
    111 ullong_t
    112 do_pop_recent(struct recent_blocks *blks)
    113 {
    114 	if (blks->frozen_block_count == 0)
    115 		return ((ullong_t)-1);
    116 	return (blks->recent_blocks[blks->length + --blks->frozen_block_count]);
    117 }
    118 struct recent_blocks *
    119 init_recent(short count)
    120 {
    121 	struct recent_blocks *blks;
    122 
    123 	if (count <= 0)
    124 		return (NULL);
    125 	blks = malloc(sizeof (struct recent_blocks) +
    126 	    ((count - 1) * 2 * sizeof (ullong_t)));
    127 	if (blks == NULL)
    128 		return (NULL);
    129 	blks->length = count;
    130 	blks->first = 0;
    131 	blks->last = 0;
    132 	blks->recent_blocks[0] = -1;
    133 	push_recent = do_push_recent;
    134 	snapshot_recent = do_snapshot_recent;
    135 	pop_recent = do_pop_recent;
    136 	return (blks);
    137 }
    138