wok-current annotate linux-cloop/stuff/cloop.u @ rev 18829

cloop: deduplicate support (again)
author Pascal Bellard <pascal.bellard@slitaz.org>
date Sun Jan 17 14:23:08 2016 +0100 (2016-01-17)
parents 8fe10eb4f215
children 36e9a3dcd5de
rev   line source
pascal@17000 1 --- cloop.h
pascal@17000 2 +++ cloop.h
pascal@18828 3 @@ -20,6 +20,80 @@
pascal@17000 4 /* data_index (num_blocks 64bit pointers, network order)... */
pascal@17000 5 /* compressed data (gzip block compressed format)... */
pascal@17000 6
pascal@17000 7 +struct cloop_tail
pascal@17000 8 +{
pascal@17000 9 + u_int32_t table_size;
pascal@17000 10 + u_int32_t index_size;
pascal@17000 11 + u_int32_t num_blocks;
pascal@17000 12 +};
pascal@17000 13 +
pascal@17000 14 +struct block_info
pascal@17000 15 +{
pascal@17000 16 + loff_t offset; /* 64-bit offsets of compressed block */
pascal@17000 17 + u_int32_t size; /* 32-bit compressed block size */
pascal@17000 18 + u_int32_t optidx; /* 32-bit index number */
pascal@17000 19 +};
pascal@17000 20 +
pascal@17000 21 +static inline char *build_index(struct block_info *offsets, unsigned long n)
pascal@17000 22 +{
pascal@17000 23 + u_int32_t *ofs32 = (u_int32_t *) offsets;
pascal@17000 24 + loff_t *ofs64 = (loff_t *) offsets;
pascal@17000 25 +
pascal@17000 26 + if (ofs32[0] == 0) {
pascal@17000 27 + if (ofs32[2]) { /* ACCELERATED KNOPPIX V1.0 */
pascal@17000 28 + while (n--) {
pascal@17000 29 + offsets[n].offset = __be64_to_cpu(offsets[n].offset);
pascal@17000 30 + offsets[n].size = ntohl(offsets[n].size);
pascal@17000 31 + }
pascal@17000 32 + return (char *) "128BE accelerated knoppix 1.0";
pascal@17000 33 + }
pascal@17000 34 + else { /* V2.0 */
pascal@17361 35 + loff_t last = __be64_to_cpu(ofs64[n - 1]);
pascal@17000 36 + while (n--) {
pascal@17000 37 + offsets[n].size = last -
pascal@17000 38 + (offsets[n].offset = __be64_to_cpu(ofs64[n]));
pascal@17000 39 + last = offsets[n].offset;
pascal@17000 40 + }
pascal@17000 41 + return (char *) "64BE v2.0";
pascal@17000 42 + }
pascal@17000 43 + }
pascal@17000 44 + else if (ofs32[1] == 0) { /* V1.0 */
pascal@17361 45 + loff_t last = __le64_to_cpu(ofs64[n - 1]);
pascal@17000 46 + while (n--) {
pascal@17000 47 + offsets[n].size = last -
pascal@17000 48 + (offsets[n].offset = __le64_to_cpu(ofs64[n]));
pascal@17000 49 + last = offsets[n].offset;
pascal@17000 50 + }
pascal@17000 51 + return (char *) "64LE v1.0";
pascal@17000 52 + }
pascal@17000 53 + else if (ntohl(ofs32[0]) == (4*n) + 0x8C) { /* V0.68 */
pascal@17361 54 + loff_t last = ntohl(ofs32[n - 1]);
pascal@17000 55 + while (n--) {
pascal@17000 56 + offsets[n].size = last -
pascal@17000 57 + (offsets[n].offset = ntohl(ofs32[n]));
pascal@17000 58 + last = offsets[n].offset;
pascal@17000 59 + }
pascal@17000 60 + return (char *) "32BE v0.68";
pascal@17000 61 + }
pascal@17000 62 + else { /* V3.0 */
pascal@17169 63 + unsigned long i;
pascal@17168 64 + loff_t j;
pascal@17000 65 +
pascal@17169 66 + for (i = n; i-- != 0; )
pascal@17000 67 + offsets[i].size = ntohl(ofs32[i]);
pascal@17000 68 + for (i = 0, j = sizeof(struct cloop_head); i < n; i++) {
pascal@17000 69 + offsets[i].offset = j;
pascal@18828 70 + if (offsets[i].size & 0x80000000) {
pascal@18829 71 + unsigned long k = offsets[i].size & 0x7FFFFFFF;
pascal@18828 72 + offsets[i].offset = offsets[k].offset;
pascal@18828 73 + offsets[i].size = offsets[k].size;
pascal@18828 74 + }
pascal@18828 75 + else j += offsets[i].size;
pascal@17000 76 + }
pascal@17000 77 + return (char *) "32BE v3.0";
pascal@17000 78 + }
pascal@17000 79 +}
pascal@17000 80 +
pascal@17000 81 /* Cloop suspend IOCTL */
pascal@17000 82 #define CLOOP_SUSPEND 0x4C07
pascal@17000 83
pascal@17000 84 --- cloop.c
pascal@17000 85 +++ cloop.c
pascal@17000 86 @@ -5,11 +5,18 @@
pascal@17000 87 * A cloop file looks like this:
pascal@17000 88 * [32-bit uncompressed block size: network order]
pascal@17000 89 * [32-bit number of blocks (n_blocks): network order]
pascal@17000 90 - * [64-bit file offsets of start of blocks: network order]
pascal@17000 91 + * [for version < 3]
pascal@17000 92 + * [32-bit, 64-bit or 128-bit file offsets of start of blocks]
pascal@17000 93 * ...
pascal@17000 94 * (n_blocks + 1).
pascal@17000 95 * n_blocks consisting of:
pascal@17000 96 * [compressed block]
pascal@17000 97 + * ...
pascal@17000 98 + * [for version >= 3]
pascal@17000 99 + * [compressed list of 32-bit block sizes]
pascal@17000 100 + * [32-bit compressed index size: network order]
pascal@17000 101 + * [32-bit index size = 4: network order]
pascal@17000 102 + * [32-bit number of blocks (n_blocks): network order]
pascal@17000 103 *
pascal@17000 104 * Every version greatly inspired by code seen in loop.c
pascal@17000 105 * by Theodore Ts'o, 3/29/93.
pascal@17000 106 @@ -115,7 +122,7 @@
pascal@17000 107 struct cloop_head head;
pascal@17000 108
pascal@17000 109 /* An array of offsets of compressed blocks within the file */
pascal@17000 110 - loff_t *offsets;
pascal@17000 111 + struct block_info *offsets;
pascal@17000 112
pascal@17000 113 /* We buffer some uncompressed blocks for performance */
pascal@17000 114 int buffered_blocknum[BUFFERED_BLOCKS];
pascal@17000 115 @@ -256,11 +263,11 @@
pascal@17000 116 return i;
pascal@17000 117 }
pascal@17000 118
pascal@17000 119 - buf_length = be64_to_cpu(clo->offsets[blocknum+1]) - be64_to_cpu(clo->offsets[blocknum]);
pascal@17000 120 + buf_length = clo->offsets[blocknum].size;
pascal@17000 121
pascal@17000 122 /* Load one compressed block from the file. */
pascal@17000 123 cloop_read_from_file(clo, clo->backing_file, (char *)clo->compressed_buffer,
pascal@17000 124 - be64_to_cpu(clo->offsets[blocknum]), buf_length);
pascal@17000 125 + clo->offsets[blocknum].offset, buf_length);
pascal@17000 126
pascal@17000 127 buflen = ntohl(clo->head.block_size);
pascal@17000 128
pascal@17000 129 @@ -275,9 +282,9 @@
pascal@17000 130 if (ret != 0)
pascal@17000 131 {
pascal@17000 132 printk(KERN_ERR "%s: zlib decompression error %i uncompressing block %u %u/%lu/%u/%u "
pascal@17000 133 - "%Lu-%Lu\n", cloop_name, ret, blocknum,
pascal@17000 134 + "%Lu:%u\n", cloop_name, ret, blocknum,
pascal@17000 135 ntohl(clo->head.block_size), buflen, buf_length, buf_done,
pascal@17000 136 - be64_to_cpu(clo->offsets[blocknum]), be64_to_cpu(clo->offsets[blocknum+1]));
pascal@17000 137 + clo->offsets[blocknum].offset, clo->offsets[blocknum].size);
pascal@17000 138 clo->buffered_blocknum[clo->current_bufnum] = -1;
pascal@17000 139 return -1;
pascal@17000 140 }
pascal@17000 141 @@ -489,30 +496,73 @@
pascal@17000 142 cloop_name, ntohl(clo->head.block_size));
pascal@17000 143 error=-EBADF; goto error_release;
pascal@17000 144 }
pascal@17000 145 - if (clo->head.preamble[0x0B]!='V'||clo->head.preamble[0x0C]<'1')
pascal@17000 146 - {
pascal@17000 147 - printk(KERN_ERR "%s: Cannot read old 32-bit (version 0.68) images, "
pascal@17000 148 - "please use an older version of %s for this file.\n",
pascal@17000 149 - cloop_name, cloop_name);
pascal@17000 150 - error=-EBADF; goto error_release;
pascal@17000 151 - }
pascal@17000 152 - if (clo->head.preamble[0x0C]<'2')
pascal@17000 153 - {
pascal@17000 154 - printk(KERN_ERR "%s: Cannot read old architecture-dependent "
pascal@17000 155 - "(format <= 1.0) images, please use an older "
pascal@17000 156 - "version of %s for this file.\n",
pascal@17000 157 - cloop_name, cloop_name);
pascal@17000 158 - error=-EBADF; goto error_release;
pascal@17000 159 - }
pascal@17000 160 - total_offsets=ntohl(clo->head.num_blocks)+1;
pascal@17000 161 - if (!isblkdev && (sizeof(struct cloop_head)+sizeof(loff_t)*
pascal@17000 162 + total_offsets=ntohl(clo->head.num_blocks);
pascal@17000 163 + if (!isblkdev && (sizeof(struct cloop_head)+sizeof(struct block_info)*
pascal@17000 164 total_offsets > inode->i_size))
pascal@17000 165 {
pascal@17000 166 printk(KERN_ERR "%s: file too small for %u blocks\n",
pascal@17000 167 cloop_name, ntohl(clo->head.num_blocks));
pascal@17000 168 error=-EBADF; goto error_release;
pascal@17000 169 }
pascal@17000 170 - clo->offsets = cloop_malloc(sizeof(loff_t) * total_offsets);
pascal@17000 171 + if (total_offsets + 1 == 0) /* Version >= 3.0 */
pascal@17000 172 + {
pascal@17000 173 + struct cloop_tail tail;
pascal@17000 174 + if(isblkdev)
pascal@17000 175 + {
pascal@17000 176 + /* No end of file: can't find index */
pascal@17000 177 + printk(KERN_ERR "%s: no V3 support for block device\n",
pascal@17000 178 + cloop_name);
pascal@17000 179 + error=-EBADF; goto error_release;
pascal@17000 180 + }
pascal@17000 181 + bytes_read = cloop_read_from_file(clo, file, (void *) &tail,
pascal@17000 182 + inode->i_size - sizeof(struct cloop_tail),
pascal@17000 183 + sizeof(struct cloop_tail));
pascal@17000 184 + if(bytes_read == sizeof(struct cloop_tail))
pascal@17000 185 + {
pascal@17000 186 + unsigned long len, zlen;
pascal@17000 187 + void *zbuf;
pascal@17000 188 + clo->head.num_blocks = tail.num_blocks;
pascal@17000 189 + total_offsets = ntohl(clo->head.num_blocks);
pascal@17000 190 + clo->offsets = cloop_malloc(sizeof(struct block_info) * total_offsets);
pascal@17000 191 + if (!clo->offsets)
pascal@17000 192 + {
pascal@17000 193 + printk(KERN_ERR "%s: can't alloc index\n",
pascal@17000 194 + cloop_name);
pascal@17000 195 + error=-EBADF; goto error_release;
pascal@17000 196 + }
pascal@17000 197 + zbuf = &clo->offsets[total_offsets/2];
pascal@17000 198 + zlen = ntohl(tail.table_size);
pascal@17000 199 + len = ntohl(tail.index_size) * total_offsets;
pascal@17000 200 + bytes_read = cloop_read_from_file(clo, file, zbuf,
pascal@17000 201 + inode->i_size - zlen - sizeof(struct cloop_tail),
pascal@17000 202 + zlen);
pascal@17000 203 + if (bytes_read != zlen)
pascal@17000 204 + {
pascal@17000 205 + printk(KERN_ERR "%s: can't read index\n",
pascal@17000 206 + cloop_name);
pascal@17000 207 + error=-EBADF; goto error_release;
pascal@17000 208 + }
pascal@17000 209 + clo->zstream.workspace = cloop_malloc(zlib_inflate_workspacesize());
pascal@17000 210 + if(!clo->zstream.workspace)
pascal@17000 211 + {
pascal@17000 212 + printk(KERN_ERR "%s: can't alloc index workspace\n",
pascal@17000 213 + cloop_name);
pascal@17000 214 + error=-EBADF; goto error_release;
pascal@17000 215 + }
pascal@17000 216 + zlib_inflateInit(&clo->zstream);
pascal@17000 217 + uncompress(clo, (void *) clo->offsets, &len, zbuf, zlen);
pascal@17000 218 + cloop_free(clo->zstream.workspace, zlib_inflate_workspacesize());
pascal@17000 219 + clo->zstream.workspace = NULL;
pascal@17000 220 + break;
pascal@17000 221 + }
pascal@17000 222 + else
pascal@17000 223 + {
pascal@17000 224 + printk(KERN_ERR "%s: can't find index\n",
pascal@17000 225 + cloop_name);
pascal@17000 226 + error=-EBADF; goto error_release;
pascal@17000 227 + }
pascal@17000 228 + }
pascal@17000 229 + clo->offsets = cloop_malloc(sizeof(struct block_info) * total_offsets);
pascal@17000 230 if (!clo->offsets)
pascal@17000 231 {
pascal@17000 232 printk(KERN_ERR "%s: out of kernel mem for offsets\n", cloop_name);
pascal@17365 233 @@ -521,19 +571,22 @@
pascal@17000 234 }
pascal@17000 235 num_readable = MIN(total_offsets - offsets_read,
pascal@17000 236 (clo->underlying_blksize - offset)
pascal@17000 237 - / sizeof(loff_t));
pascal@17000 238 - memcpy(&clo->offsets[offsets_read], bbuf+offset, num_readable * sizeof(loff_t));
pascal@17000 239 + / sizeof(struct block_info));
pascal@17000 240 + memcpy(&clo->offsets[offsets_read], bbuf+offset, num_readable * sizeof(struct block_info));
pascal@17000 241 offsets_read += num_readable;
pascal@17000 242 }
pascal@17000 243 { /* Search for largest block rather than estimate. KK. */
pascal@17000 244 int i;
pascal@17000 245 - for(i=0;i<total_offsets-1;i++)
pascal@17000 246 + char *version = build_index(clo->offsets, ntohl(clo->head.num_blocks));
pascal@17361 247 + for(i=0,clo->largest_block=0;i<total_offsets;i++)
pascal@17000 248 {
pascal@17000 249 - loff_t d=be64_to_cpu(clo->offsets[i+1]) - be64_to_cpu(clo->offsets[i]);
pascal@17000 250 - clo->largest_block=MAX(clo->largest_block,d);
pascal@17000 251 + clo->largest_block=MAX(clo->largest_block,clo->offsets[i].size);
pascal@17000 252 }
pascal@17000 253 - printk(KERN_INFO "%s: %s: %u blocks, %u bytes/block, largest block is %lu bytes.\n",
pascal@17000 254 - cloop_name, filename, ntohl(clo->head.num_blocks),
pascal@17365 255 + i = ntohl(clo->head.block_size);
pascal@17365 256 + i += i/1000 + 12 + 4; /* max gzip block size */
pascal@17365 257 + if (clo->largest_block > i) clo->largest_block = i; /* broken index ? */
pascal@17000 258 + printk(KERN_INFO "%s: %s: %s, %u blocks, %u bytes/block, largest block is %lu bytes.\n",
pascal@17000 259 + cloop_name, filename, version, ntohl(clo->head.num_blocks),
pascal@17000 260 ntohl(clo->head.block_size), clo->largest_block);
pascal@17000 261 }
pascal@17000 262 /* Combo kmalloc used too large chunks (>130000). */
pascal@17365 263 @@ -565,16 +618,6 @@
pascal@17000 264 error=-ENOMEM; goto error_release_free_all;
pascal@17000 265 }
pascal@17000 266 zlib_inflateInit(&clo->zstream);
pascal@17000 267 - if(!isblkdev &&
pascal@17000 268 - be64_to_cpu(clo->offsets[ntohl(clo->head.num_blocks)]) != inode->i_size)
pascal@17000 269 - {
pascal@17000 270 - printk(KERN_ERR "%s: final offset wrong (%Lu not %Lu)\n",
pascal@17000 271 - cloop_name,
pascal@17000 272 - be64_to_cpu(clo->offsets[ntohl(clo->head.num_blocks)]),
pascal@17000 273 - inode->i_size);
pascal@17000 274 - cloop_free(clo->zstream.workspace, zlib_inflate_workspacesize()); clo->zstream.workspace=NULL;
pascal@17000 275 - goto error_release_free_all;
pascal@17000 276 - }
pascal@17000 277 {
pascal@17000 278 int i;
pascal@17000 279 for(i=0; i<BUFFERED_BLOCKS; i++) clo->buffered_blocknum[i] = -1;
pascal@17365 280 @@ -653,7 +696,7 @@
pascal@17000 281 }
pascal@17000 282 }
pascal@17000 283 error_release_free:
pascal@17000 284 - cloop_free(clo->offsets, sizeof(loff_t) * total_offsets);
pascal@17000 285 + cloop_free(clo->offsets, sizeof(struct block_info) * total_offsets);
pascal@17000 286 clo->offsets=NULL;
pascal@17000 287 error_release:
pascal@17000 288 if(bbuf) cloop_free(bbuf, clo->underlying_blksize);