blob: 8a5aa0f588ee7036a5dcff7821329b8622114770 [file] [log] [blame]
/*
* 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;
}