]>
glassweightruler.freedombox.rocks Git - Ventoy.git/blob - SQUASHFS/squashfs-tools-4.4/squashfs-tools/process_fragments.c
2 * Create a squashfs filesystem. This is a highly compressed read only
6 * Phillip Lougher <phillip@squashfs.org.uk>
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2,
11 * or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 #include <sys/ioctl.h>
37 #include <sys/types.h>
41 #include "caches-queues-lists.h"
42 #include "squashfs_fs.h"
43 #include "mksquashfs.h"
45 #include "progressbar.h"
47 #include "compressor.h"
48 #include "process_fragments.h"
53 extern struct queue
*to_process_frag
;
54 extern struct seq_queue
*to_main
;
55 extern int sparse_files
;
56 extern long long start_offset
;
59 * Compute 16 bit BSD checksum over the data, and check for sparseness
61 static int checksum_sparse(struct file_buffer
*file_buffer
)
63 unsigned char *b
= (unsigned char *) file_buffer
->data
;
64 unsigned short chksum
= 0;
65 int bytes
= file_buffer
->size
, sparse
= TRUE
, value
;
68 chksum
= (chksum
& 1) ? (chksum
>> 1) | 0x8000 : chksum
>> 1;
76 file_buffer
->checksum
= chksum
;
81 static int read_filesystem(int fd
, long long byte
, int bytes
, void *buff
)
85 TRACE("read_filesystem: reading from position 0x%llx, bytes %d\n",
88 if(lseek(fd
, start_offset
+ off
, SEEK_SET
) == -1) {
89 ERROR("read_filesystem: Lseek on destination failed because %s, "
90 "offset=0x%llx\n", strerror(errno
), start_offset
+ off
);
92 } else if(read_bytes(fd
, buff
, bytes
) < bytes
) {
93 ERROR("Read on destination failed\n");
101 static struct file_buffer
*get_fragment(struct fragment
*fragment
,
102 char *data_buffer
, int fd
)
104 struct squashfs_fragment_entry
*disk_fragment
;
105 struct file_buffer
*buffer
, *compressed_buffer
;
106 long long start_block
;
107 int res
, size
, index
= fragment
->index
;
111 * Lookup fragment block in cache.
112 * If the fragment block doesn't exist, then get the compressed version
113 * from the writer cache or off disk, and decompress it.
115 * This routine has two things which complicate the code:
117 * 1. Multiple threads can simultaneously lookup/create the
118 * same buffer. This means a buffer needs to be "locked"
119 * when it is being filled in, to prevent other threads from
120 * using it when it is not ready. This is because we now do
121 * fragment duplicate checking in parallel.
122 * 2. We have two caches which need to be checked for the
123 * presence of fragment blocks: the normal fragment cache
124 * and a "reserve" cache. The reserve cache is used to
125 * prevent an unnecessary pipeline stall when the fragment cache
126 * is full of fragments waiting to be compressed.
128 pthread_cleanup_push((void *) pthread_mutex_unlock
, &dup_mutex
);
129 pthread_mutex_lock(&dup_mutex
);
132 buffer
= cache_lookup_nowait(fragment_buffer
, index
, &locked
);
134 pthread_mutex_unlock(&dup_mutex
);
136 /* got a buffer being filled in. Wait for it */
137 cache_wait_unlock(buffer
);
141 /* not in fragment cache, is it in the reserve cache? */
142 buffer
= cache_lookup_nowait(reserve_cache
, index
, &locked
);
144 pthread_mutex_unlock(&dup_mutex
);
146 /* got a buffer being filled in. Wait for it */
147 cache_wait_unlock(buffer
);
151 /* in neither cache, try to get it from the fragment cache */
152 buffer
= cache_get_nowait(fragment_buffer
, index
);
155 * no room, get it from the reserve cache, this is
156 * dimensioned so it will always have space (no more than
157 * processors + 1 can have an outstanding reserve buffer)
159 buffer
= cache_get_nowait(reserve_cache
, index
);
162 ERROR("no space in reserve cache\n");
167 pthread_mutex_unlock(&dup_mutex
);
169 compressed_buffer
= cache_lookup(fwriter_buffer
, index
);
171 pthread_cleanup_push((void *) pthread_mutex_unlock
, &fragment_mutex
);
172 pthread_mutex_lock(&fragment_mutex
);
173 disk_fragment
= &fragment_table
[index
];
174 size
= SQUASHFS_COMPRESSED_SIZE_BLOCK(disk_fragment
->size
);
175 start_block
= disk_fragment
->start_block
;
176 pthread_cleanup_pop(1);
178 if(SQUASHFS_COMPRESSED_BLOCK(disk_fragment
->size
)) {
182 if(compressed_buffer
)
183 data
= compressed_buffer
->data
;
185 res
= read_filesystem(fd
, start_block
, size
, data_buffer
);
187 ERROR("Failed to read fragment from output"
189 BAD_ERROR("Output filesystem corrupted?\n");
194 res
= compressor_uncompress(comp
, buffer
->data
, data
, size
,
197 BAD_ERROR("%s uncompress failed with error code %d\n",
199 } else if(compressed_buffer
)
200 memcpy(buffer
->data
, compressed_buffer
->data
, size
);
202 res
= read_filesystem(fd
, start_block
, size
, buffer
->data
);
204 ERROR("Failed to read fragment from output "
206 BAD_ERROR("Output filesystem corrupted?\n");
210 cache_unlock(buffer
);
211 cache_block_put(compressed_buffer
);
214 pthread_cleanup_pop(0);
220 struct file_buffer
*get_fragment_cksum(struct file_info
*file
,
221 char *data_buffer
, int fd
, unsigned short *checksum
)
223 struct file_buffer
*frag_buffer
;
224 struct append_file
*append
;
225 int index
= file
->fragment
->index
;
227 frag_buffer
= get_fragment(file
->fragment
, data_buffer
, fd
);
229 pthread_cleanup_push((void *) pthread_mutex_unlock
, &dup_mutex
);
231 for(append
= file_mapping
[index
]; append
; append
= append
->next
) {
232 int offset
= append
->file
->fragment
->offset
;
233 int size
= append
->file
->fragment
->size
;
234 char *data
= frag_buffer
->data
+ offset
;
235 unsigned short cksum
= get_checksum_mem(data
, size
);
237 if(file
== append
->file
)
240 pthread_mutex_lock(&dup_mutex
);
241 append
->file
->fragment_checksum
= cksum
;
242 append
->file
->have_frag_checksum
= TRUE
;
243 pthread_mutex_unlock(&dup_mutex
);
246 pthread_cleanup_pop(0);
252 void *frag_thrd(void *destination_file
)
254 sigset_t sigmask
, old_mask
;
258 sigemptyset(&sigmask
);
259 sigaddset(&sigmask
, SIGINT
);
260 sigaddset(&sigmask
, SIGTERM
);
261 sigaddset(&sigmask
, SIGUSR1
);
262 pthread_sigmask(SIG_BLOCK
, &sigmask
, &old_mask
);
264 fd
= open(destination_file
, O_RDONLY
);
266 BAD_ERROR("frag_thrd: can't open destination for reading\n");
268 data_buffer
= malloc(SQUASHFS_FILE_MAX_SIZE
);
269 if(data_buffer
== NULL
)
272 pthread_cleanup_push((void *) pthread_mutex_unlock
, &dup_mutex
);
275 struct file_buffer
*file_buffer
= queue_get(to_process_frag
);
276 struct file_buffer
*buffer
;
277 int sparse
= checksum_sparse(file_buffer
);
278 struct file_info
*dupl_ptr
;
280 unsigned short checksum
;
284 if(sparse_files
&& sparse
) {
285 file_buffer
->c_byte
= 0;
286 file_buffer
->fragment
= FALSE
;
288 file_buffer
->c_byte
= file_buffer
->size
;
291 * Specutively pull into the fragment cache any fragment blocks
292 * which contain fragments which *this* fragment may be
295 * By ensuring the fragment block is in cache ahead of time
296 * should eliminate the parallelisation stall when the
297 * main thread needs to read the fragment block to do a
298 * duplicate check on it.
300 * If this is a fragment belonging to a larger file
301 * (with additional blocks) then ignore it. Here we're
302 * interested in the "low hanging fruit" of files which
303 * consist of only a fragment
305 if(file_buffer
->file_size
!= file_buffer
->size
) {
306 seq_queue_put(to_main
, file_buffer
);
310 file_size
= file_buffer
->file_size
;
312 pthread_mutex_lock(&dup_mutex
);
313 dupl_ptr
= dupl
[DUP_HASH(file_size
)];
314 pthread_mutex_unlock(&dup_mutex
);
316 file_buffer
->dupl_start
= dupl_ptr
;
317 file_buffer
->duplicate
= FALSE
;
319 for(; dupl_ptr
; dupl_ptr
= dupl_ptr
->next
) {
320 if(file_size
!= dupl_ptr
->file_size
||
321 file_size
!= dupl_ptr
->fragment
->size
)
324 pthread_mutex_lock(&dup_mutex
);
325 flag
= dupl_ptr
->have_frag_checksum
;
326 checksum
= dupl_ptr
->fragment_checksum
;
327 pthread_mutex_unlock(&dup_mutex
);
330 * If we have the checksum and it matches then
331 * read in the fragment block.
333 * If we *don't* have the checksum, then we are
334 * appending, and the fragment block is on the
335 * "old" filesystem. Read it in and checksum
336 * the entire fragment buffer
339 buffer
= get_fragment_cksum(dupl_ptr
,
340 data_buffer
, fd
, &checksum
);
341 if(checksum
!= file_buffer
->checksum
) {
342 cache_block_put(buffer
);
345 } else if(checksum
== file_buffer
->checksum
)
346 buffer
= get_fragment(dupl_ptr
->fragment
,
351 res
= memcmp(file_buffer
->data
, buffer
->data
+
352 dupl_ptr
->fragment
->offset
, file_size
);
353 cache_block_put(buffer
);
355 struct file_buffer
*dup
= malloc(sizeof(*dup
));
358 memcpy(dup
, file_buffer
, sizeof(*dup
));
359 cache_block_put(file_buffer
);
360 dup
->dupl_start
= dupl_ptr
;
361 dup
->duplicate
= TRUE
;
367 seq_queue_put(to_main
, file_buffer
);
370 pthread_cleanup_pop(0);