| /* |
| * Copyright (c) International Business Machines Corp., 2001-2004 |
| * |
| * 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 |
| */ |
| |
| #define FILE_OFFSET_BITS 64 |
| |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <fcntl.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <assert.h> |
| #include <inttypes.h> |
| #include <assert.h> |
| |
| #include "ffsb.h" |
| #include "fh.h" |
| |
| #include "config.h" |
| |
| /* !!! ugly */ |
| #ifndef HAVE_OPEN64 |
| #define open64 open |
| #endif |
| |
| #ifndef HAVE_FSEEKO64 |
| #define lseek64 lseek |
| #endif |
| |
| /* All these functions read the global mainconfig->bufferedio variable |
| * to determine if they are to do buffered i/o or normal. |
| * |
| * ha, well, they're supposed to anyway...!!! TODO -SR 2006/05/14 |
| */ |
| |
| static void do_stats(struct timeval *start, struct timeval *end, |
| ffsb_thread_t *ft, ffsb_fs_t *fs, syscall_t sys) |
| { |
| struct timeval diff; |
| uint32_t value = 0; |
| |
| if (!ft && !fs) |
| return; |
| |
| timersub(end, start, &diff); |
| |
| value = 1000000 * diff.tv_sec + diff.tv_usec; |
| |
| if (ft && ft_needs_stats(ft, sys)) |
| ft_add_stat(ft, sys, value); |
| if (fs && fs_needs_stats(fs, sys)) |
| fs_add_stat(fs, sys, value); |
| } |
| |
| static int fhopenhelper(char *filename, char *bufflags, int flags, |
| ffsb_thread_t *ft, ffsb_fs_t *fs) |
| { |
| int fd = 0; |
| struct timeval start, end; |
| int need_stats = ft_needs_stats(ft, SYS_OPEN) || |
| fs_needs_stats(fs, SYS_OPEN); |
| |
| flags |= O_LARGEFILE; |
| |
| if (need_stats) |
| gettimeofday(&start, NULL); |
| |
| fd = open64(filename, flags, S_IRWXU); |
| if (fd < 0) { |
| perror(filename); |
| exit(0); |
| } |
| |
| if (need_stats) { |
| gettimeofday(&end, NULL); |
| do_stats(&start, &end, ft, fs, SYS_OPEN); |
| } |
| |
| return fd; |
| } |
| |
| int fhopenread(char *filename, ffsb_thread_t *ft, ffsb_fs_t *fs) |
| { |
| int flags = O_RDONLY; |
| int directio = fs_get_directio(fs); |
| |
| if (directio) |
| flags |= O_DIRECT; |
| return fhopenhelper(filename, "r", flags, ft, fs); |
| } |
| |
| int fhopenappend(char *filename, ffsb_thread_t *ft, ffsb_fs_t *fs) |
| { |
| int flags = O_APPEND | O_WRONLY; |
| int directio = fs_get_directio(fs); |
| |
| if (directio) |
| flags |= O_DIRECT; |
| return fhopenhelper(filename, "a", flags, ft, fs); |
| } |
| |
| int fhopenwrite(char *filename, ffsb_thread_t *ft, ffsb_fs_t *fs) |
| { |
| int flags = O_WRONLY; |
| int directio = fs_get_directio(fs); |
| |
| if (directio) |
| flags |= O_DIRECT; |
| return fhopenhelper(filename, "w", flags, ft, fs); |
| } |
| |
| int fhopencreate(char *filename, ffsb_thread_t *ft, ffsb_fs_t *fs) |
| { |
| int flags = O_CREAT | O_RDWR | O_TRUNC; |
| int directio = fs_get_directio(fs); |
| |
| if (directio) |
| flags |= O_DIRECT; |
| return fhopenhelper(filename, "rw", flags, ft, fs); |
| } |
| |
| void fhread(int fd, void *buf, uint64_t size, ffsb_thread_t *ft, ffsb_fs_t *fs) |
| { |
| ssize_t realsize; |
| struct timeval start, end; |
| int need_stats = ft_needs_stats(ft, SYS_READ) || |
| fs_needs_stats(fs, SYS_READ); |
| |
| assert(size <= SIZE_MAX); |
| if (need_stats) |
| gettimeofday(&start, NULL); |
| realsize = read(fd, buf, size); |
| |
| if (need_stats) { |
| gettimeofday(&end, NULL); |
| do_stats(&start, &end, ft, fs, SYS_READ); |
| } |
| |
| if (realsize != size) { |
| printf("Read %lld instead of %llu bytes.\n", |
| (unsigned long long)realsize, (unsigned long long)size); |
| perror("read"); |
| exit(1); |
| } |
| } |
| |
| void fhwrite(int fd, void *buf, uint32_t size, ffsb_thread_t *ft, ffsb_fs_t *fs) |
| { |
| ssize_t realsize; |
| struct timeval start, end; |
| int need_stats = ft_needs_stats(ft, SYS_WRITE) || |
| fs_needs_stats(fs, SYS_WRITE); |
| |
| assert(size <= SIZE_MAX); |
| if (need_stats) |
| gettimeofday(&start, NULL); |
| |
| realsize = write(fd, buf, size); |
| |
| if (need_stats) { |
| gettimeofday(&end, NULL); |
| do_stats(&start, &end, ft, fs, SYS_WRITE); |
| } |
| |
| if (realsize != size) { |
| printf("Wrote %d instead of %d bytes.\n" |
| "Probably out of disk space\n", realsize, size); |
| perror("write"); |
| exit(1); |
| } |
| } |
| |
| void fhseek(int fd, uint64_t offset, int whence, ffsb_thread_t *ft, |
| ffsb_fs_t *fs) |
| { |
| uint64_t res; |
| struct timeval start, end; |
| int need_stats = ft_needs_stats(ft, SYS_LSEEK) || |
| fs_needs_stats(fs, SYS_LSEEK); |
| |
| if ((whence == SEEK_CUR) && (offset == 0)) |
| return; |
| |
| if (need_stats) |
| gettimeofday(&start, NULL); |
| |
| res = lseek64(fd, offset, whence); |
| |
| if (need_stats) { |
| gettimeofday(&end, NULL); |
| do_stats(&start, &end, ft, fs, SYS_LSEEK); |
| } |
| if ((whence == SEEK_SET) && (res != offset)) |
| perror("seek"); |
| |
| if (res == -1) { |
| if (whence == SEEK_SET) |
| fprintf(stderr, "tried to seek to %lld\n", offset); |
| else |
| fprintf(stderr, "tried to seek from current " |
| "position to %lld\n", offset); |
| |
| perror("seek"); |
| exit(1); |
| } |
| } |
| |
| void fhclose(int fd, ffsb_thread_t *ft, ffsb_fs_t *fs) |
| { |
| struct timeval start, end; |
| int need_stats = ft_needs_stats(ft, SYS_CLOSE) || |
| fs_needs_stats(fs, SYS_CLOSE); |
| |
| if (need_stats) |
| gettimeofday(&start, NULL); |
| |
| close(fd); |
| |
| if (need_stats) { |
| gettimeofday(&end, NULL); |
| do_stats(&start, &end, ft, fs, SYS_CLOSE); |
| } |
| } |
| |
| void fhstat(char *name, ffsb_thread_t *ft, ffsb_fs_t *fs) |
| { |
| struct timeval start, end; |
| struct stat tmp_stat; |
| |
| int need_stats = ft_needs_stats(ft, SYS_STAT) || |
| fs_needs_stats(fs, SYS_CLOSE); |
| |
| if (need_stats) |
| gettimeofday(&start, NULL); |
| |
| if (stat(name, &tmp_stat)) { |
| fprintf (stderr, "stat call failed for file %s\n", name); |
| exit(1); |
| } |
| |
| if (need_stats) { |
| gettimeofday(&end, NULL); |
| do_stats(&start, &end, ft, fs, SYS_STAT); |
| } |
| } |
| |
| int writefile_helper(int fd, uint64_t size, uint32_t blocksize, char *buf, |
| struct ffsb_thread *ft, struct ffsb_fs *fs) |
| { |
| uint64_t iterations, a; |
| uint64_t last; |
| |
| iterations = size / blocksize; |
| last = size % blocksize; |
| |
| for (a = 0; a < iterations; a++) |
| fhwrite(fd, buf, blocksize, ft, fs); |
| |
| if (last) { |
| a++; |
| fhwrite(fd, buf, last, ft, fs); |
| } |
| return a; |
| } |