18f8cb840SMaxim Sobolev /* 28f8cb840SMaxim Sobolev * Copyright (c) 2016 Maxim Sobolev <sobomax@FreeBSD.org> 38f8cb840SMaxim Sobolev * All rights reserved. 48f8cb840SMaxim Sobolev * 58f8cb840SMaxim Sobolev * Redistribution and use in source and binary forms, with or without 68f8cb840SMaxim Sobolev * modification, are permitted provided that the following conditions 78f8cb840SMaxim Sobolev * are met: 88f8cb840SMaxim Sobolev * 1. Redistributions of source code must retain the above copyright 98f8cb840SMaxim Sobolev * notice, this list of conditions and the following disclaimer. 108f8cb840SMaxim Sobolev * 2. Redistributions in binary form must reproduce the above copyright 118f8cb840SMaxim Sobolev * notice, this list of conditions and the following disclaimer in the 128f8cb840SMaxim Sobolev * documentation and/or other materials provided with the distribution. 138f8cb840SMaxim Sobolev * 148f8cb840SMaxim Sobolev * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 158f8cb840SMaxim Sobolev * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 168f8cb840SMaxim Sobolev * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 178f8cb840SMaxim Sobolev * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 188f8cb840SMaxim Sobolev * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 198f8cb840SMaxim Sobolev * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 208f8cb840SMaxim Sobolev * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 218f8cb840SMaxim Sobolev * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 228f8cb840SMaxim Sobolev * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 238f8cb840SMaxim Sobolev * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 248f8cb840SMaxim Sobolev * SUCH DAMAGE. 258f8cb840SMaxim Sobolev */ 268f8cb840SMaxim Sobolev 278f8cb840SMaxim Sobolev #include <sys/cdefs.h> 288f8cb840SMaxim Sobolev __FBSDID("$FreeBSD$"); 298f8cb840SMaxim Sobolev 306e5a582dSMaxim Sobolev #include <err.h> 316e5a582dSMaxim Sobolev #include <stdio.h> 328f8cb840SMaxim Sobolev #include <stdlib.h> 338f8cb840SMaxim Sobolev #include <string.h> 348f8cb840SMaxim Sobolev #include <unistd.h> 358f8cb840SMaxim Sobolev 368f8cb840SMaxim Sobolev #if defined(MKUZ_DEBUG) 37*4fc55e3eSMaxim Sobolev # include <assert.h> 388f8cb840SMaxim Sobolev # include <stdio.h> 398f8cb840SMaxim Sobolev #endif 408f8cb840SMaxim Sobolev 418f8cb840SMaxim Sobolev #include "mkuz_blockcache.h" 42*4fc55e3eSMaxim Sobolev #include "mkuz_blk.h" 438f8cb840SMaxim Sobolev 44*4fc55e3eSMaxim Sobolev struct mkuz_blkcache_itm { 45*4fc55e3eSMaxim Sobolev struct mkuz_blk_info hit; 46*4fc55e3eSMaxim Sobolev struct mkuz_blkcache_itm *next; 478f8cb840SMaxim Sobolev }; 488f8cb840SMaxim Sobolev 49*4fc55e3eSMaxim Sobolev static struct mkuz_blkcache { 50*4fc55e3eSMaxim Sobolev struct mkuz_blkcache_itm first[256]; 51*4fc55e3eSMaxim Sobolev } blkcache; 528f8cb840SMaxim Sobolev 536e5a582dSMaxim Sobolev static int 54*4fc55e3eSMaxim Sobolev verify_match(int fd, const struct mkuz_blk *cbp, struct mkuz_blkcache_itm *bcep) 556e5a582dSMaxim Sobolev { 566e5a582dSMaxim Sobolev void *vbuf; 576e5a582dSMaxim Sobolev ssize_t rlen; 586e5a582dSMaxim Sobolev int rval; 596e5a582dSMaxim Sobolev 606e5a582dSMaxim Sobolev rval = -1; 61*4fc55e3eSMaxim Sobolev vbuf = malloc(cbp->info.len); 626e5a582dSMaxim Sobolev if (vbuf == NULL) { 636e5a582dSMaxim Sobolev goto e0; 646e5a582dSMaxim Sobolev } 65*4fc55e3eSMaxim Sobolev if (lseek(fd, bcep->hit.offset, SEEK_SET) < 0) { 666e5a582dSMaxim Sobolev goto e1; 676e5a582dSMaxim Sobolev } 68*4fc55e3eSMaxim Sobolev rlen = read(fd, vbuf, cbp->info.len); 69*4fc55e3eSMaxim Sobolev if (rlen < 0 || (unsigned)rlen != cbp->info.len) { 706e5a582dSMaxim Sobolev goto e2; 716e5a582dSMaxim Sobolev } 72*4fc55e3eSMaxim Sobolev rval = (memcmp(cbp->data, vbuf, cbp->info.len) == 0) ? 1 : 0; 736e5a582dSMaxim Sobolev e2: 74*4fc55e3eSMaxim Sobolev lseek(fd, cbp->info.offset, SEEK_SET); 756e5a582dSMaxim Sobolev e1: 766e5a582dSMaxim Sobolev free(vbuf); 776e5a582dSMaxim Sobolev e0: 786e5a582dSMaxim Sobolev return (rval); 796e5a582dSMaxim Sobolev } 806e5a582dSMaxim Sobolev 81*4fc55e3eSMaxim Sobolev #define I2J(x) ((intmax_t)(x)) 82*4fc55e3eSMaxim Sobolev #define U2J(x) ((uintmax_t)(x)) 838f8cb840SMaxim Sobolev 84*4fc55e3eSMaxim Sobolev static unsigned char 85*4fc55e3eSMaxim Sobolev digest_fold(const unsigned char *mdigest) 86*4fc55e3eSMaxim Sobolev { 87*4fc55e3eSMaxim Sobolev int i; 88*4fc55e3eSMaxim Sobolev unsigned char rval; 89*4fc55e3eSMaxim Sobolev 90*4fc55e3eSMaxim Sobolev rval = mdigest[0]; 91*4fc55e3eSMaxim Sobolev for (i = 1; i < 16; i++) { 92*4fc55e3eSMaxim Sobolev rval = rval ^ mdigest[i]; 938f8cb840SMaxim Sobolev } 94*4fc55e3eSMaxim Sobolev return (rval); 95*4fc55e3eSMaxim Sobolev } 96*4fc55e3eSMaxim Sobolev 97*4fc55e3eSMaxim Sobolev struct mkuz_blk_info * 98*4fc55e3eSMaxim Sobolev mkuz_blkcache_regblock(int fd, const struct mkuz_blk *bp) 99*4fc55e3eSMaxim Sobolev { 100*4fc55e3eSMaxim Sobolev struct mkuz_blkcache_itm *bcep; 101*4fc55e3eSMaxim Sobolev int rval; 102*4fc55e3eSMaxim Sobolev unsigned char h; 103*4fc55e3eSMaxim Sobolev 104*4fc55e3eSMaxim Sobolev #if defined(MKUZ_DEBUG) 105*4fc55e3eSMaxim Sobolev assert((unsigned)lseek(fd, 0, SEEK_CUR) == bp->info.offset); 106*4fc55e3eSMaxim Sobolev #endif 107*4fc55e3eSMaxim Sobolev h = digest_fold(bp->info.digest); 108*4fc55e3eSMaxim Sobolev if (blkcache.first[h].hit.len == 0) { 109*4fc55e3eSMaxim Sobolev bcep = &blkcache.first[h]; 1108f8cb840SMaxim Sobolev } else { 111*4fc55e3eSMaxim Sobolev for (bcep = &blkcache.first[h]; bcep != NULL; bcep = bcep->next) { 112*4fc55e3eSMaxim Sobolev if (bcep->hit.len != bp->info.len) 1138f8cb840SMaxim Sobolev continue; 114*4fc55e3eSMaxim Sobolev if (memcmp(bp->info.digest, bcep->hit.digest, 115*4fc55e3eSMaxim Sobolev sizeof(bp->info.digest)) == 0) { 1168f8cb840SMaxim Sobolev break; 1178f8cb840SMaxim Sobolev } 1188f8cb840SMaxim Sobolev } 1198f8cb840SMaxim Sobolev if (bcep != NULL) { 120*4fc55e3eSMaxim Sobolev rval = verify_match(fd, bp, bcep); 1216e5a582dSMaxim Sobolev if (rval == 1) { 1228f8cb840SMaxim Sobolev #if defined(MKUZ_DEBUG) 123*4fc55e3eSMaxim Sobolev fprintf(stderr, "cache hit %jd, %jd, %jd, %jd\n", 124*4fc55e3eSMaxim Sobolev I2J(bcep->hit.blkno), I2J(bcep->hit.offset), 125*4fc55e3eSMaxim Sobolev I2J(bp->info.offset), I2J(bp->info.len)); 1268f8cb840SMaxim Sobolev #endif 1278f8cb840SMaxim Sobolev return (&bcep->hit); 1288f8cb840SMaxim Sobolev } 1296e5a582dSMaxim Sobolev if (rval == 0) { 1306e5a582dSMaxim Sobolev #if defined(MKUZ_DEBUG) 1316e5a582dSMaxim Sobolev fprintf(stderr, "block MD5 collision, you should try lottery, " 1326e5a582dSMaxim Sobolev "man!\n"); 1336e5a582dSMaxim Sobolev #endif 1346e5a582dSMaxim Sobolev return (NULL); 1356e5a582dSMaxim Sobolev } 1366e5a582dSMaxim Sobolev warn("verify_match"); 1376e5a582dSMaxim Sobolev return (NULL); 1386e5a582dSMaxim Sobolev } 139*4fc55e3eSMaxim Sobolev bcep = malloc(sizeof(struct mkuz_blkcache_itm)); 1408f8cb840SMaxim Sobolev if (bcep == NULL) 1418f8cb840SMaxim Sobolev return (NULL); 142*4fc55e3eSMaxim Sobolev memset(bcep, '\0', sizeof(struct mkuz_blkcache_itm)); 143*4fc55e3eSMaxim Sobolev bcep->next = blkcache.first[h].next; 144*4fc55e3eSMaxim Sobolev blkcache.first[h].next = bcep; 1458f8cb840SMaxim Sobolev } 146*4fc55e3eSMaxim Sobolev bcep->hit = bp->info; 1478f8cb840SMaxim Sobolev return (NULL); 1488f8cb840SMaxim Sobolev } 149