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>
286e5a582dSMaxim Sobolev #include <err.h>
296e5a582dSMaxim Sobolev #include <stdio.h>
308f8cb840SMaxim Sobolev #include <stdlib.h>
318f8cb840SMaxim Sobolev #include <string.h>
328f8cb840SMaxim Sobolev #include <unistd.h>
338f8cb840SMaxim Sobolev
348f8cb840SMaxim Sobolev #if defined(MKUZ_DEBUG)
35*4fc55e3eSMaxim Sobolev # include <assert.h>
368f8cb840SMaxim Sobolev # include <stdio.h>
378f8cb840SMaxim Sobolev #endif
388f8cb840SMaxim Sobolev
398f8cb840SMaxim Sobolev #include "mkuz_blockcache.h"
40*4fc55e3eSMaxim Sobolev #include "mkuz_blk.h"
418f8cb840SMaxim Sobolev
42*4fc55e3eSMaxim Sobolev struct mkuz_blkcache_itm {
43*4fc55e3eSMaxim Sobolev struct mkuz_blk_info hit;
44*4fc55e3eSMaxim Sobolev struct mkuz_blkcache_itm *next;
458f8cb840SMaxim Sobolev };
468f8cb840SMaxim Sobolev
47*4fc55e3eSMaxim Sobolev static struct mkuz_blkcache {
48*4fc55e3eSMaxim Sobolev struct mkuz_blkcache_itm first[256];
49*4fc55e3eSMaxim Sobolev } blkcache;
508f8cb840SMaxim Sobolev
516e5a582dSMaxim Sobolev static int
verify_match(int fd,const struct mkuz_blk * cbp,struct mkuz_blkcache_itm * bcep)52*4fc55e3eSMaxim Sobolev verify_match(int fd, const struct mkuz_blk *cbp, struct mkuz_blkcache_itm *bcep)
536e5a582dSMaxim Sobolev {
546e5a582dSMaxim Sobolev void *vbuf;
556e5a582dSMaxim Sobolev ssize_t rlen;
566e5a582dSMaxim Sobolev int rval;
576e5a582dSMaxim Sobolev
586e5a582dSMaxim Sobolev rval = -1;
59*4fc55e3eSMaxim Sobolev vbuf = malloc(cbp->info.len);
606e5a582dSMaxim Sobolev if (vbuf == NULL) {
616e5a582dSMaxim Sobolev goto e0;
626e5a582dSMaxim Sobolev }
63*4fc55e3eSMaxim Sobolev if (lseek(fd, bcep->hit.offset, SEEK_SET) < 0) {
646e5a582dSMaxim Sobolev goto e1;
656e5a582dSMaxim Sobolev }
66*4fc55e3eSMaxim Sobolev rlen = read(fd, vbuf, cbp->info.len);
67*4fc55e3eSMaxim Sobolev if (rlen < 0 || (unsigned)rlen != cbp->info.len) {
686e5a582dSMaxim Sobolev goto e2;
696e5a582dSMaxim Sobolev }
70*4fc55e3eSMaxim Sobolev rval = (memcmp(cbp->data, vbuf, cbp->info.len) == 0) ? 1 : 0;
716e5a582dSMaxim Sobolev e2:
72*4fc55e3eSMaxim Sobolev lseek(fd, cbp->info.offset, SEEK_SET);
736e5a582dSMaxim Sobolev e1:
746e5a582dSMaxim Sobolev free(vbuf);
756e5a582dSMaxim Sobolev e0:
766e5a582dSMaxim Sobolev return (rval);
776e5a582dSMaxim Sobolev }
786e5a582dSMaxim Sobolev
79*4fc55e3eSMaxim Sobolev #define I2J(x) ((intmax_t)(x))
80*4fc55e3eSMaxim Sobolev #define U2J(x) ((uintmax_t)(x))
818f8cb840SMaxim Sobolev
82*4fc55e3eSMaxim Sobolev static unsigned char
digest_fold(const unsigned char * mdigest)83*4fc55e3eSMaxim Sobolev digest_fold(const unsigned char *mdigest)
84*4fc55e3eSMaxim Sobolev {
85*4fc55e3eSMaxim Sobolev int i;
86*4fc55e3eSMaxim Sobolev unsigned char rval;
87*4fc55e3eSMaxim Sobolev
88*4fc55e3eSMaxim Sobolev rval = mdigest[0];
89*4fc55e3eSMaxim Sobolev for (i = 1; i < 16; i++) {
90*4fc55e3eSMaxim Sobolev rval = rval ^ mdigest[i];
918f8cb840SMaxim Sobolev }
92*4fc55e3eSMaxim Sobolev return (rval);
93*4fc55e3eSMaxim Sobolev }
94*4fc55e3eSMaxim Sobolev
95*4fc55e3eSMaxim Sobolev struct mkuz_blk_info *
mkuz_blkcache_regblock(int fd,const struct mkuz_blk * bp)96*4fc55e3eSMaxim Sobolev mkuz_blkcache_regblock(int fd, const struct mkuz_blk *bp)
97*4fc55e3eSMaxim Sobolev {
98*4fc55e3eSMaxim Sobolev struct mkuz_blkcache_itm *bcep;
99*4fc55e3eSMaxim Sobolev int rval;
100*4fc55e3eSMaxim Sobolev unsigned char h;
101*4fc55e3eSMaxim Sobolev
102*4fc55e3eSMaxim Sobolev #if defined(MKUZ_DEBUG)
103*4fc55e3eSMaxim Sobolev assert((unsigned)lseek(fd, 0, SEEK_CUR) == bp->info.offset);
104*4fc55e3eSMaxim Sobolev #endif
105*4fc55e3eSMaxim Sobolev h = digest_fold(bp->info.digest);
106*4fc55e3eSMaxim Sobolev if (blkcache.first[h].hit.len == 0) {
107*4fc55e3eSMaxim Sobolev bcep = &blkcache.first[h];
1088f8cb840SMaxim Sobolev } else {
109*4fc55e3eSMaxim Sobolev for (bcep = &blkcache.first[h]; bcep != NULL; bcep = bcep->next) {
110*4fc55e3eSMaxim Sobolev if (bcep->hit.len != bp->info.len)
1118f8cb840SMaxim Sobolev continue;
112*4fc55e3eSMaxim Sobolev if (memcmp(bp->info.digest, bcep->hit.digest,
113*4fc55e3eSMaxim Sobolev sizeof(bp->info.digest)) == 0) {
1148f8cb840SMaxim Sobolev break;
1158f8cb840SMaxim Sobolev }
1168f8cb840SMaxim Sobolev }
1178f8cb840SMaxim Sobolev if (bcep != NULL) {
118*4fc55e3eSMaxim Sobolev rval = verify_match(fd, bp, bcep);
1196e5a582dSMaxim Sobolev if (rval == 1) {
1208f8cb840SMaxim Sobolev #if defined(MKUZ_DEBUG)
121*4fc55e3eSMaxim Sobolev fprintf(stderr, "cache hit %jd, %jd, %jd, %jd\n",
122*4fc55e3eSMaxim Sobolev I2J(bcep->hit.blkno), I2J(bcep->hit.offset),
123*4fc55e3eSMaxim Sobolev I2J(bp->info.offset), I2J(bp->info.len));
1248f8cb840SMaxim Sobolev #endif
1258f8cb840SMaxim Sobolev return (&bcep->hit);
1268f8cb840SMaxim Sobolev }
1276e5a582dSMaxim Sobolev if (rval == 0) {
1286e5a582dSMaxim Sobolev #if defined(MKUZ_DEBUG)
1296e5a582dSMaxim Sobolev fprintf(stderr, "block MD5 collision, you should try lottery, "
1306e5a582dSMaxim Sobolev "man!\n");
1316e5a582dSMaxim Sobolev #endif
1326e5a582dSMaxim Sobolev return (NULL);
1336e5a582dSMaxim Sobolev }
1346e5a582dSMaxim Sobolev warn("verify_match");
1356e5a582dSMaxim Sobolev return (NULL);
1366e5a582dSMaxim Sobolev }
137*4fc55e3eSMaxim Sobolev bcep = malloc(sizeof(struct mkuz_blkcache_itm));
1388f8cb840SMaxim Sobolev if (bcep == NULL)
1398f8cb840SMaxim Sobolev return (NULL);
140*4fc55e3eSMaxim Sobolev memset(bcep, '\0', sizeof(struct mkuz_blkcache_itm));
141*4fc55e3eSMaxim Sobolev bcep->next = blkcache.first[h].next;
142*4fc55e3eSMaxim Sobolev blkcache.first[h].next = bcep;
1438f8cb840SMaxim Sobolev }
144*4fc55e3eSMaxim Sobolev bcep->hit = bp->info;
1458f8cb840SMaxim Sobolev return (NULL);
1468f8cb840SMaxim Sobolev }
147