| /* |
| * Copyright (c) 2011 Cyril Hrubis <chrubis@suse.cz> |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See |
| * the GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| |
| #ifndef LTP_AIODIO_COMMON_SPARSE |
| #define LTP_AIODIO_COMMON_SPARSE |
| |
| /* |
| * This code tries to create dirty free blocks on |
| * the HDD so there is a chance that blocks to be allocated |
| * for a file are filled with something else than zeroes. |
| * |
| * The usefulness of this is IMHO questionable. |
| */ |
| static void dirty_freeblocks(int size) |
| { |
| int fd; |
| void *p; |
| int pg; |
| char *filename = "dirty_freeblocks"; |
| |
| pg = getpagesize(); |
| size = ((size + pg - 1) / pg) * pg; |
| |
| fd = open(filename, O_CREAT|O_RDWR|O_EXCL, 0600); |
| |
| if (fd < 0) |
| tst_brkm(TBROK|TERRNO, cleanup, "failed to open '%s'", filename); |
| |
| SAFE_FTRUNCATE(cleanup, fd, size); |
| |
| p = SAFE_MMAP(cleanup, NULL, size, PROT_WRITE|PROT_READ, MAP_SHARED|MAP_FILE, fd, 0); |
| |
| memset(p, 0xaa, size); |
| msync(p, size, MS_SYNC); |
| munmap(p, size); |
| close(fd); |
| unlink(filename); |
| } |
| |
| /* |
| * Scale value by kilo, mega, or giga. |
| */ |
| long long scale_by_kmg(long long value, char scale) |
| { |
| switch (scale) { |
| case 'g': |
| case 'G': |
| value *= 1024; |
| case 'm': |
| case 'M': |
| value *= 1024; |
| case 'k': |
| case 'K': |
| value *= 1024; |
| break; |
| case '\0': |
| break; |
| default: |
| usage(); |
| break; |
| } |
| return value; |
| } |
| |
| char *check_zero(char *buf, int size) |
| { |
| char *p; |
| |
| p = buf; |
| |
| while (size > 0) { |
| if (*buf != 0) { |
| fprintf(stderr, "non zero buffer at buf[%d] => 0x%02x,%02x,%02x,%02x\n", |
| buf - p, (unsigned int)buf[0], |
| size > 1 ? (unsigned int)buf[1] : 0, |
| size > 2 ? (unsigned int)buf[2] : 0, |
| size > 3 ? (unsigned int)buf[3] : 0); |
| return buf; |
| } |
| buf++; |
| size--; |
| } |
| |
| return NULL; |
| } |
| |
| /* |
| * Make sure we read only zeroes, |
| * either there is a hole in the file, |
| * or zeroes were actually written by parent. |
| */ |
| static void read_sparse(char *filename, int filesize) |
| { |
| int fd; |
| int i, j, r; |
| char buf[4096]; |
| |
| /* |
| * Wait for the file to appear. |
| */ |
| for (i = 0; i < 10000; i++) { |
| fd = open(filename, O_RDONLY); |
| |
| if (fd != -1) |
| break; |
| |
| if (debug) |
| fprintf(stderr, "Child %i waits for '%s' to appear\n", |
| getpid(), filename); |
| |
| usleep(100000); |
| } |
| |
| if (fd == -1) { |
| if (debug) |
| fprintf(stderr, "Child %i failed to open '%s'\n", |
| getpid(), filename); |
| exit(10); |
| } |
| |
| if (debug) |
| fprintf(stderr, "Child %i has opened '%s' for reading\n", |
| getpid(), filename); |
| |
| for (i = 0; i < 100000000; i++) { |
| off_t offset = 0; |
| char *badbuf; |
| |
| if (debug) |
| fprintf(stderr, "Child %i loop %i\n", getpid(), i); |
| |
| lseek(fd, SEEK_SET, 0); |
| for (j = 0; j < filesize+1; j += sizeof(buf)) { |
| r = read(fd, buf, sizeof(buf)); |
| if (r > 0) { |
| if ((badbuf = check_zero(buf, r))) { |
| fprintf(stderr, "non-zero read at offset %d\n", |
| offset + badbuf - buf); |
| exit(10); |
| } |
| } |
| offset += r; |
| } |
| } |
| |
| exit(0); |
| } |
| |
| #endif /* LTP_AIODIO_COMMON_SPARSE */ |