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