bcache.c (136097) | bcache.c (298230) |
---|---|
1/*- 2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> | 1/*- 2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> |
3 * Copyright 2015 Toomas Soome <tsoome@me.com> |
|
3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright --- 9 unchanged lines hidden (view full) --- 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> | 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright --- 9 unchanged lines hidden (view full) --- 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28#include <sys/cdefs.h> |
28__FBSDID("$FreeBSD: head/sys/boot/common/bcache.c 136097 2004-10-03 16:34:01Z stefanf $"); | 29#include <sys/param.h> 30__FBSDID("$FreeBSD: head/sys/boot/common/bcache.c 298230 2016-04-18 23:09:22Z allanjude $"); |
29 30/* | 31 32/* |
31 * Simple LRU block cache | 33 * Simple hashed block cache |
32 */ 33 34#include <sys/stdint.h> 35 36#include <stand.h> 37#include <string.h> | 34 */ 35 36#include <sys/stdint.h> 37 38#include <stand.h> 39#include <string.h> |
38#include <bitstring.h> | 40#include <strings.h> |
39 40#include "bootstrap.h" 41 42/* #define BCACHE_DEBUG */ 43 44#ifdef BCACHE_DEBUG | 41 42#include "bootstrap.h" 43 44/* #define BCACHE_DEBUG */ 45 46#ifdef BCACHE_DEBUG |
45#define BCACHE_TIMEOUT 10 | |
46# define DEBUG(fmt, args...) printf("%s: " fmt "\n" , __func__ , ## args) 47#else | 47# define DEBUG(fmt, args...) printf("%s: " fmt "\n" , __func__ , ## args) 48#else |
48#define BCACHE_TIMEOUT 2 | |
49# define DEBUG(fmt, args...) 50#endif 51 | 49# define DEBUG(fmt, args...) 50#endif 51 |
52 | |
53struct bcachectl 54{ 55 daddr_t bc_blkno; | 52struct bcachectl 53{ 54 daddr_t bc_blkno; |
56 time_t bc_stamp; | |
57 int bc_count; 58}; 59 | 55 int bc_count; 56}; 57 |
60static struct bcachectl *bcache_ctl; 61static caddr_t bcache_data; 62static bitstr_t *bcache_miss; 63static u_int bcache_nblks; 64static u_int bcache_blksize; 65static u_int bcache_hits, bcache_misses, bcache_ops, bcache_bypasses; 66static u_int bcache_flushes; 67static u_int bcache_bcount; | 58/* 59 * bcache per device node. cache is allocated on device first open and freed 60 * on last close, to save memory. The issue there is the size; biosdisk 61 * supports up to 31 (0x1f) devices. Classic setup would use single disk 62 * to boot from, but this has changed with zfs. 63 */ 64struct bcache { 65 struct bcachectl *bcache_ctl; 66 caddr_t bcache_data; 67 u_int bcache_nblks; 68 size_t ra; 69}; |
68 | 70 |
69static void bcache_invalidate(daddr_t blkno); 70static void bcache_insert(caddr_t buf, daddr_t blkno); 71static int bcache_lookup(caddr_t buf, daddr_t blkno); | 71static u_int bcache_total_nblks; /* set by bcache_init */ 72static u_int bcache_blksize; /* set by bcache_init */ 73static u_int bcache_numdev; /* set by bcache_add_dev */ 74/* statistics */ 75static u_int bcache_units; /* number of devices with cache */ 76static u_int bcache_unit_nblks; /* nblocks per unit */ 77static u_int bcache_hits; 78static u_int bcache_misses; 79static u_int bcache_ops; 80static u_int bcache_bypasses; 81static u_int bcache_bcount; 82static u_int bcache_rablks; |
72 | 83 |
84#define BHASH(bc, blkno) ((blkno) & ((bc)->bcache_nblks - 1)) 85#define BCACHE_LOOKUP(bc, blkno) \ 86 ((bc)->bcache_ctl[BHASH((bc), (blkno))].bc_blkno != (blkno)) 87#define BCACHE_READAHEAD 256 88#define BCACHE_MINREADAHEAD 32 89 90static void bcache_invalidate(struct bcache *bc, daddr_t blkno); 91static void bcache_insert(struct bcache *bc, daddr_t blkno); 92static void bcache_free_instance(struct bcache *bc); 93 |
|
73/* 74 * Initialise the cache for (nblks) of (bsize). 75 */ | 94/* 95 * Initialise the cache for (nblks) of (bsize). 96 */ |
76int | 97void |
77bcache_init(u_int nblks, size_t bsize) 78{ | 98bcache_init(u_int nblks, size_t bsize) 99{ |
79 /* discard any old contents */ 80 if (bcache_data != NULL) { 81 free(bcache_data); 82 bcache_data = NULL; 83 free(bcache_ctl); 84 } 85 86 /* Allocate control structures */ 87 bcache_nblks = nblks; | 100 /* set up control data */ 101 bcache_total_nblks = nblks; |
88 bcache_blksize = bsize; | 102 bcache_blksize = bsize; |
89 bcache_data = malloc(bcache_nblks * bcache_blksize); 90 bcache_ctl = (struct bcachectl *)malloc(bcache_nblks * sizeof(struct bcachectl)); 91 bcache_miss = bit_alloc((bcache_nblks + 1) / 2); 92 if ((bcache_data == NULL) || (bcache_ctl == NULL) || (bcache_miss == NULL)) { 93 if (bcache_miss) 94 free(bcache_miss); 95 if (bcache_ctl) 96 free(bcache_ctl); 97 if (bcache_data) 98 free(bcache_data); 99 bcache_data = NULL; 100 return(ENOMEM); 101 } 102 103 return(0); | |
104} 105 106/* | 103} 104 105/* |
107 * Flush the cache | 106 * add number of devices to bcache. we have to divide cache space 107 * between the devices, so bcache_add_dev() can be used to set up the 108 * number. The issue is, we need to get the number before actual allocations. 109 * bcache_add_dev() is supposed to be called from device init() call, so the 110 * assumption is, devsw dv_init is called for plain devices first, and 111 * for zfs, last. |
108 */ 109void | 112 */ 113void |
110bcache_flush(void) | 114bcache_add_dev(int devices) |
111{ | 115{ |
112 u_int i; | 116 bcache_numdev += devices; 117} |
113 | 118 |
114 bcache_flushes++; | 119void * 120bcache_allocate(void) 121{ 122 u_int i; 123 struct bcache *bc = malloc(sizeof (struct bcache)); 124 int disks = bcache_numdev; |
115 | 125 |
126 if (disks == 0) 127 disks = 1; /* safe guard */ 128 129 if (bc == NULL) { 130 errno = ENOMEM; 131 return (bc); 132 } 133 134 /* 135 * the bcache block count must be power of 2 for hash function 136 */ 137 i = fls(disks) - 1; /* highbit - 1 */ 138 if (disks > (1 << i)) /* next power of 2 */ 139 i++; 140 141 bc->bcache_nblks = bcache_total_nblks >> i; 142 bcache_unit_nblks = bc->bcache_nblks; 143 bc->bcache_data = malloc(bc->bcache_nblks * bcache_blksize); 144 if (bc->bcache_data == NULL) { 145 /* dont error out yet. fall back to 32 blocks and try again */ 146 bc->bcache_nblks = 32; 147 bc->bcache_data = malloc(bc->bcache_nblks * bcache_blksize); 148 } 149 150 bc->bcache_ctl = malloc(bc->bcache_nblks * sizeof(struct bcachectl)); 151 152 if ((bc->bcache_data == NULL) || (bc->bcache_ctl == NULL)) { 153 bcache_free_instance(bc); 154 errno = ENOMEM; 155 return(NULL); 156 } 157 |
|
116 /* Flush the cache */ | 158 /* Flush the cache */ |
117 for (i = 0; i < bcache_nblks; i++) { 118 bcache_ctl[i].bc_count = -1; 119 bcache_ctl[i].bc_blkno = -1; | 159 for (i = 0; i < bc->bcache_nblks; i++) { 160 bc->bcache_ctl[i].bc_count = -1; 161 bc->bcache_ctl[i].bc_blkno = -1; |
120 } | 162 } |
163 bcache_units++; 164 bc->ra = BCACHE_READAHEAD; /* optimistic read ahead */ 165 return (bc); |
|
121} 122 | 166} 167 |
168void 169bcache_free(void *cache) 170{ 171 struct bcache *bc = cache; 172 173 if (bc == NULL) 174 return; 175 176 bcache_free_instance(bc); 177 bcache_units--; 178} 179 |
|
123/* 124 * Handle a write request; write directly to the disk, and populate the 125 * cache with the new values. 126 */ 127static int | 180/* 181 * Handle a write request; write directly to the disk, and populate the 182 * cache with the new values. 183 */ 184static int |
128write_strategy(void *devdata, int unit, int rw, daddr_t blk, size_t size, 129 char *buf, size_t *rsize) | 185write_strategy(void *devdata, int rw, daddr_t blk, size_t offset, 186 size_t size, char *buf, size_t *rsize) |
130{ 131 struct bcache_devdata *dd = (struct bcache_devdata *)devdata; | 187{ 188 struct bcache_devdata *dd = (struct bcache_devdata *)devdata; |
189 struct bcache *bc = dd->dv_cache; |
|
132 daddr_t i, nblk; | 190 daddr_t i, nblk; |
133 int err; | |
134 135 nblk = size / bcache_blksize; 136 137 /* Invalidate the blocks being written */ 138 for (i = 0; i < nblk; i++) { | 191 192 nblk = size / bcache_blksize; 193 194 /* Invalidate the blocks being written */ 195 for (i = 0; i < nblk; i++) { |
139 bcache_invalidate(blk + i); | 196 bcache_invalidate(bc, blk + i); |
140 } 141 142 /* Write the blocks */ | 197 } 198 199 /* Write the blocks */ |
143 err = dd->dv_strategy(dd->dv_devdata, rw, blk, size, buf, rsize); 144 145 /* Populate the block cache with the new data */ 146 if (err == 0) { 147 for (i = 0; i < nblk; i++) { 148 bcache_insert(buf + (i * bcache_blksize),blk + i); 149 } 150 } 151 152 return err; | 200 return (dd->dv_strategy(dd->dv_devdata, rw, blk, offset, size, buf, rsize)); |
153} 154 155/* 156 * Handle a read request; fill in parts of the request that can 157 * be satisfied by the cache, use the supplied strategy routine to do 158 * device I/O and then use the I/O results to populate the cache. 159 */ 160static int | 201} 202 203/* 204 * Handle a read request; fill in parts of the request that can 205 * be satisfied by the cache, use the supplied strategy routine to do 206 * device I/O and then use the I/O results to populate the cache. 207 */ 208static int |
161read_strategy(void *devdata, int unit, int rw, daddr_t blk, size_t size, 162 char *buf, size_t *rsize) | 209read_strategy(void *devdata, int rw, daddr_t blk, size_t offset, 210 size_t size, char *buf, size_t *rsize) |
163{ 164 struct bcache_devdata *dd = (struct bcache_devdata *)devdata; | 211{ 212 struct bcache_devdata *dd = (struct bcache_devdata *)devdata; |
165 int p_size, result; 166 daddr_t p_blk, i, j, nblk; | 213 struct bcache *bc = dd->dv_cache; 214 size_t i, nblk, p_size, r_size, complete, ra; 215 int result; 216 daddr_t p_blk; |
167 caddr_t p_buf; 168 | 217 caddr_t p_buf; 218 |
219 if (bc == NULL) { 220 errno = ENODEV; 221 return (-1); 222 } 223 224 if (rsize != NULL) 225 *rsize = 0; 226 |
|
169 nblk = size / bcache_blksize; | 227 nblk = size / bcache_blksize; |
228 if ((nblk == 0 && size != 0) || offset != 0) 229 nblk++; |
|
170 result = 0; | 230 result = 0; |
231 complete = 1; |
|
171 | 232 |
172 /* Satisfy any cache hits up front */ | 233 /* Satisfy any cache hits up front, break on first miss */ |
173 for (i = 0; i < nblk; i++) { | 234 for (i = 0; i < nblk; i++) { |
174 if (bcache_lookup(buf + (bcache_blksize * i), blk + i)) { 175 bit_set(bcache_miss, i); /* cache miss */ 176 bcache_misses++; | 235 if (BCACHE_LOOKUP(bc, (daddr_t)(blk + i))) { 236 bcache_misses += (nblk - i); 237 complete = 0; 238 if (nblk - i > BCACHE_MINREADAHEAD && bc->ra > BCACHE_MINREADAHEAD) 239 bc->ra >>= 1; /* reduce read ahead */ 240 break; |
177 } else { | 241 } else { |
178 bit_clear(bcache_miss, i); /* cache hit */ | |
179 bcache_hits++; 180 } 181 } 182 | 242 bcache_hits++; 243 } 244 } 245 |
183 /* Go back and fill in any misses XXX optimise */ 184 p_blk = -1; 185 p_buf = NULL; 186 p_size = 0; 187 for (i = 0; i < nblk; i++) { 188 if (bit_test(bcache_miss, i)) { 189 /* miss, add to pending transfer */ 190 if (p_blk == -1) { 191 p_blk = blk + i; 192 p_buf = buf + (bcache_blksize * i); 193 p_size = 1; 194 } else { 195 p_size++; 196 } 197 } else if (p_blk != -1) { 198 /* hit, complete pending transfer */ 199 result = dd->dv_strategy(dd->dv_devdata, rw, p_blk, p_size * bcache_blksize, p_buf, NULL); 200 if (result != 0) 201 goto done; 202 for (j = 0; j < p_size; j++) 203 bcache_insert(p_buf + (j * bcache_blksize), p_blk + j); 204 p_blk = -1; 205 } | 246 if (complete) { /* whole set was in cache, return it */ 247 if (bc->ra < BCACHE_READAHEAD) 248 bc->ra <<= 1; /* increase read ahead */ 249 bcopy(bc->bcache_data + (bcache_blksize * BHASH(bc, blk)) + offset, 250 buf, size); 251 goto done; 252 } 253 254 /* 255 * Fill in any misses. From check we have i pointing to first missing 256 * block, read in all remaining blocks + readahead. 257 * We have space at least for nblk - i before bcache wraps. 258 */ 259 p_blk = blk + i; 260 p_buf = bc->bcache_data + (bcache_blksize * BHASH(bc, p_blk)); 261 r_size = bc->bcache_nblks - BHASH(bc, p_blk); /* remaining blocks */ 262 263 p_size = MIN(r_size, nblk - i); /* read at least those blocks */ 264 265 ra = bc->bcache_nblks - BHASH(bc, p_blk + p_size); 266 if (ra != bc->bcache_nblks) { /* do we have RA space? */ 267 ra = MIN(bc->ra, ra); 268 p_size += ra; |
206 } | 269 } |
207 if (p_blk != -1) { 208 /* pending transfer left */ 209 result = dd->dv_strategy(dd->dv_devdata, rw, p_blk, p_size * bcache_blksize, p_buf, NULL); 210 if (result != 0) 211 goto done; 212 for (j = 0; j < p_size; j++) 213 bcache_insert(p_buf + (j * bcache_blksize), p_blk + j); | 270 271 /* invalidate bcache */ 272 for (i = 0; i < p_size; i++) { 273 bcache_invalidate(bc, p_blk + i); |
214 } | 274 } |
215 | 275 r_size = 0; 276 result = dd->dv_strategy(dd->dv_devdata, rw, p_blk, 0, 277 p_size * bcache_blksize, p_buf, &r_size); 278 279 if (result) 280 goto done; 281 282 r_size /= bcache_blksize; 283 for (i = 0; i < r_size; i++) 284 bcache_insert(bc, p_blk + i); 285 286 bcache_rablks += ra; 287 bcopy(bc->bcache_data + (bcache_blksize * BHASH(bc, blk)) + offset, buf, 288 size); 289 |
216 done: 217 if ((result == 0) && (rsize != NULL)) 218 *rsize = size; 219 return(result); 220} 221 222/* | 290 done: 291 if ((result == 0) && (rsize != NULL)) 292 *rsize = size; 293 return(result); 294} 295 296/* |
223 * Requests larger than 1/2 the cache size will be bypassed and go | 297 * Requests larger than 1/2 cache size will be bypassed and go |
224 * directly to the disk. XXX tune this. 225 */ 226int | 298 * directly to the disk. XXX tune this. 299 */ 300int |
227bcache_strategy(void *devdata, int unit, int rw, daddr_t blk, size_t size, 228 char *buf, size_t *rsize) | 301bcache_strategy(void *devdata, int rw, daddr_t blk, size_t offset, 302 size_t size, char *buf, size_t *rsize) |
229{ | 303{ |
230 static int bcache_unit = -1; | |
231 struct bcache_devdata *dd = (struct bcache_devdata *)devdata; | 304 struct bcache_devdata *dd = (struct bcache_devdata *)devdata; |
305 struct bcache *bc = dd->dv_cache; 306 u_int bcache_nblks = 0; 307 int nblk, cblk, ret; 308 size_t csize, isize, total; |
|
232 233 bcache_ops++; 234 | 309 310 bcache_ops++; 311 |
235 if(bcache_unit != unit) { 236 bcache_flush(); 237 bcache_unit = unit; 238 } | 312 if (bc != NULL) 313 bcache_nblks = bc->bcache_nblks; |
239 240 /* bypass large requests, or when the cache is inactive */ | 314 315 /* bypass large requests, or when the cache is inactive */ |
241 if ((bcache_data == NULL) || ((size * 2 / bcache_blksize) > bcache_nblks)) { | 316 if (bc == NULL || 317 (offset == 0 && ((size * 2 / bcache_blksize) > bcache_nblks))) { |
242 DEBUG("bypass %d from %d", size / bcache_blksize, blk); 243 bcache_bypasses++; | 318 DEBUG("bypass %d from %d", size / bcache_blksize, blk); 319 bcache_bypasses++; |
244 return(dd->dv_strategy(dd->dv_devdata, rw, blk, size, buf, rsize)); | 320 return (dd->dv_strategy(dd->dv_devdata, rw, blk, offset, size, buf, 321 rsize)); |
245 } 246 | 322 } 323 |
324 /* normalize offset */ 325 while (offset >= bcache_blksize) { 326 blk++; 327 offset -= bcache_blksize; 328 } 329 |
|
247 switch (rw) { 248 case F_READ: | 330 switch (rw) { 331 case F_READ: |
249 return read_strategy(devdata, unit, rw, blk, size, buf, rsize); | 332 nblk = size / bcache_blksize; 333 if (offset || (size != 0 && nblk == 0)) 334 nblk++; /* read at least one block */ 335 336 ret = 0; 337 total = 0; 338 while(size) { 339 cblk = bcache_nblks - BHASH(bc, blk); /* # of blocks left */ 340 cblk = MIN(cblk, nblk); 341 342 if (size <= bcache_blksize) 343 csize = size; 344 else { 345 csize = cblk * bcache_blksize; 346 if (offset) 347 csize -= (bcache_blksize - offset); 348 } 349 350 ret = read_strategy(devdata, rw, blk, offset, 351 csize, buf+total, &isize); 352 if (ret != 0) 353 return (ret); 354 blk += (offset+isize) / bcache_blksize; 355 offset = 0; 356 total += isize; 357 size -= isize; 358 nblk = size / bcache_blksize; 359 } 360 361 if (rsize) 362 *rsize = total; 363 364 return (ret); |
250 case F_WRITE: | 365 case F_WRITE: |
251 return write_strategy(devdata, unit, rw, blk, size, buf, rsize); | 366 return write_strategy(devdata, rw, blk, offset, size, buf, rsize); |
252 } 253 return -1; 254} 255 | 367 } 368 return -1; 369} 370 |
256 | |
257/* | 371/* |
258 * Insert a block into the cache. Retire the oldest block to do so, if required. 259 * 260 * XXX the LRU algorithm will fail after 2^31 blocks have been transferred. | 372 * Free allocated bcache instance |
261 */ 262static void | 373 */ 374static void |
263bcache_insert(caddr_t buf, daddr_t blkno) | 375bcache_free_instance(struct bcache *bc) |
264{ | 376{ |
265 time_t now; 266 int cand, ocount; 267 u_int i; 268 269 time(&now); 270 cand = 0; /* assume the first block */ 271 ocount = bcache_ctl[0].bc_count; 272 273 /* find the oldest block */ 274 for (i = 1; i < bcache_nblks; i++) { 275 if (bcache_ctl[i].bc_blkno == blkno) { 276 /* reuse old entry */ 277 cand = i; 278 break; 279 } 280 if (bcache_ctl[i].bc_count < ocount) { 281 ocount = bcache_ctl[i].bc_count; 282 cand = i; 283 } | 377 if (bc != NULL) { 378 if (bc->bcache_ctl) 379 free(bc->bcache_ctl); 380 if (bc->bcache_data) 381 free(bc->bcache_data); 382 free(bc); |
284 } | 383 } |
285 286 DEBUG("insert blk %d -> %d @ %d # %d", blkno, cand, now, bcache_bcount); 287 bcopy(buf, bcache_data + (bcache_blksize * cand), bcache_blksize); 288 bcache_ctl[cand].bc_blkno = blkno; 289 bcache_ctl[cand].bc_stamp = now; 290 bcache_ctl[cand].bc_count = bcache_bcount++; | |
291} 292 293/* | 384} 385 386/* |
294 * Look for a block in the cache. Blocks more than BCACHE_TIMEOUT seconds old 295 * may be stale (removable media) and thus are discarded. Copy the block out 296 * if successful and return zero, or return nonzero on failure. | 387 * Insert a block into the cache. |
297 */ | 388 */ |
298static int 299bcache_lookup(caddr_t buf, daddr_t blkno) | 389static void 390bcache_insert(struct bcache *bc, daddr_t blkno) |
300{ | 391{ |
301 time_t now; 302 u_int i; | 392 u_int cand; |
303 | 393 |
304 time(&now); | 394 cand = BHASH(bc, blkno); |
305 | 395 |
306 for (i = 0; i < bcache_nblks; i++) 307 /* cache hit? */ 308 if ((bcache_ctl[i].bc_blkno == blkno) && ((bcache_ctl[i].bc_stamp + BCACHE_TIMEOUT) >= now)) { 309 bcopy(bcache_data + (bcache_blksize * i), buf, bcache_blksize); 310 DEBUG("hit blk %d <- %d (now %d then %d)", blkno, i, now, bcache_ctl[i].bc_stamp); 311 return(0); 312 } 313 return(ENOENT); | 396 DEBUG("insert blk %llu -> %u # %d", blkno, cand, bcache_bcount); 397 bc->bcache_ctl[cand].bc_blkno = blkno; 398 bc->bcache_ctl[cand].bc_count = bcache_bcount++; |
314} 315 316/* 317 * Invalidate a block from the cache. 318 */ 319static void | 399} 400 401/* 402 * Invalidate a block from the cache. 403 */ 404static void |
320bcache_invalidate(daddr_t blkno) | 405bcache_invalidate(struct bcache *bc, daddr_t blkno) |
321{ 322 u_int i; 323 | 406{ 407 u_int i; 408 |
324 for (i = 0; i < bcache_nblks; i++) { 325 if (bcache_ctl[i].bc_blkno == blkno) { 326 bcache_ctl[i].bc_count = -1; 327 bcache_ctl[i].bc_blkno = -1; 328 DEBUG("invalidate blk %d", blkno); 329 break; 330 } | 409 i = BHASH(bc, blkno); 410 if (bc->bcache_ctl[i].bc_blkno == blkno) { 411 bc->bcache_ctl[i].bc_count = -1; 412 bc->bcache_ctl[i].bc_blkno = -1; 413 DEBUG("invalidate blk %llu", blkno); |
331 } 332} 333 | 414 } 415} 416 |
417#ifndef BOOT2 |
|
334COMMAND_SET(bcachestat, "bcachestat", "get disk block cache stats", command_bcache); 335 336static int 337command_bcache(int argc, char *argv[]) 338{ | 418COMMAND_SET(bcachestat, "bcachestat", "get disk block cache stats", command_bcache); 419 420static int 421command_bcache(int argc, char *argv[]) 422{ |
339 u_int i; 340 341 for (i = 0; i < bcache_nblks; i++) { 342 printf("%08jx %04x %04x|", (uintmax_t)bcache_ctl[i].bc_blkno, (unsigned int)bcache_ctl[i].bc_stamp & 0xffff, bcache_ctl[i].bc_count & 0xffff); 343 if (((i + 1) % 4) == 0) 344 printf("\n"); | 423 if (argc != 1) { 424 command_errmsg = "wrong number of arguments"; 425 return(CMD_ERROR); |
345 } | 426 } |
346 printf("\n%d ops %d bypasses %d hits %d misses %d flushes\n", bcache_ops, bcache_bypasses, bcache_hits, bcache_misses, bcache_flushes); | 427 428 printf("\ncache blocks: %d\n", bcache_total_nblks); 429 printf("cache blocksz: %d\n", bcache_blksize); 430 printf("cache readahead: %d\n", bcache_rablks); 431 printf("unit cache blocks: %d\n", bcache_unit_nblks); 432 printf("cached units: %d\n", bcache_units); 433 printf("%d ops %d bypasses %d hits %d misses\n", bcache_ops, 434 bcache_bypasses, bcache_hits, bcache_misses); |
347 return(CMD_OK); 348} | 435 return(CMD_OK); 436} |
349 | 437#endif |