[Ocfs2-test-devel] [PATCH 2/4] Ocfs2-test: Add generic file operation funcs for libocfs2test.
tristan.ye
tristan.ye at oracle.com
Tue Mar 31 19:06:09 PDT 2009
On Tue, 2009-03-31 at 16:28 -0700, Sunil Mushran wrote:
> Comments inlined.
Cool for pointing these out....
>
> Tristan Ye wrote:
> > Provide generic utility fuctions on file operations for ocfs2-tests.
> >
> > Signed-off-by: Tristan Ye <tristan.ye at oracle.com>
> > ---
> > programs/libocfs2test/file_ops.c | 345 ++++++++++++++++++++++++++++++++++++++
> > programs/libocfs2test/file_ops.h | 88 ++++++++++
> > 2 files changed, 433 insertions(+), 0 deletions(-)
> > create mode 100644 programs/libocfs2test/file_ops.c
> > create mode 100644 programs/libocfs2test/file_ops.h
> >
> > diff --git a/programs/libocfs2test/file_ops.c b/programs/libocfs2test/file_ops.c
> > new file mode 100644
> > index 0000000..c979b5c
> > --- /dev/null
> > +++ b/programs/libocfs2test/file_ops.c
> > @@ -0,0 +1,345 @@
> > +/* -*- mode: c; c-basic-offset: 8; -*-
> > + * vim: noexpandtab sw=8 ts=8 sts=0:
> > + *
> > + * file_ops.c
> > + *
> > + * Provide generic utility fuctions on file operations for ocfs2-tests
> > + *
> > + * Written by tristan.ye at oracle.com
> > + *
> > + * Copyright (C) 2008 Oracle. All rights reserved.
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public
> > + * License version 2 as published by the Free Software Foundation.
> > + *
> > + * 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.
> > + */
> > +
> > +#include "file_ops.h"
> > +
> > +extern unsigned long get_rand(unsigned long min, unsigned long max)
> > +{
> > + if (min == 0 && max == 0)
> > + return 0;
> > +
> > + return min + (rand() % (max - min + 1));
> > +}
> > +
> > +extern char rand_char(void)
> > +{
> > + return 'A' + (char) get_rand(0, 25);
> > +}
> > +
> > +extern int read_at(int fd, void *buf, size_t count, off_t offset)
> > +{
> > + int ret;
> > +
> > + ret = pread(fd, buf, count, offset);
> > +
> > + if (ret < 0) {
> > + ret = errno;
> > + fprintf(stderr, "read error %d: \"%s\"\n", ret, strerror(ret));
> > + return -1;
> > + }
> > +
> > + if (ret != count) {
> > + fprintf(stderr, "Short read: wanted %ld, got %d\n", count, ret);
> > + return -1;
> > + }
> >
>
> Short read is a valid condition. When encountered, one
> is expected to resubmit the read for the remaining count/offset.
>
> while(bytes_read < count) {
> ret = read();
> if (ret > 0)
> bytes_read += ret;
> }
Good idea to continue to read the remainning bytes rather than a direct
exit.
we may still use pread() to read the wanted bytes instead of read()
since the former pread() did not change the file description's offset at
all.
int ret;
int bytes_read;
ret = pread(fd, buf, count, offset);
if (ret < 0) {
ret = errno;
fprintf(stderr, "read error %d: \"%s\"\n", ret, strerror(ret));
return -1;
}
bytes_read = ret;
while (bytes_read < count) {
ret = pread(fd, buf + bytes_read, count - bytes_read, offset +
bytes_read);
if (ret < 0) {
ret = errno;
fprintf(stderr, "read error %d: \"%s\"\n", ret, strerror(ret));
return -1;
}
bytes_read += ret;
}
>
> > +
> > + return 0;
> > +}
> > +
> > +extern int read_at_file(char *pathname, void *buf, size_t count, off_t offset)
> > +{
> > + int fd, ret;
> > +
> > + fd = open64(pathname, FILE_RO_FLAGS);
> > + if (fd < 0) {
> > + fd = errno;
> > + fprintf(stderr, "open file %s failed:%d:%s\n", pathname, fd,
> > + strerror(fd));
> > + return fd;
> > + }
> > +
> > + ret = read_at(fd, buf, count, offset);
> > +
> > + if (ret < 0)
> > + return ret;
> > +
> > + close(fd);
> > +
> > + return 0;
> > +}
> > +
> > +extern int mmap_read_at(int fd, char *buf, size_t count, off_t offset,
> > + size_t page_size)
> > +{
> > + int i, j, ret;
> > + unsigned long mmap_size = page_size;
> > + unsigned long size = offset + count;
> > + char *region;
> > +
> > + while (mmap_size < size)
> > + mmap_size += page_size;
> > +
> > + region = mmap(NULL, mmap_size, PROT_READ, MAP_SHARED, fd, 0);
> > +
> > + if (region == MAP_FAILED) {
> > + ret = errno;
> > + fprintf(stderr, "mmap (read) error %d: \"%s\"\n", ret,
> > + strerror(ret));
> > + return -1;
> > + }
> > +
> > + j = 0;
> > +
> > + for (i = offset; i < size; i++) {
> > + buf[j] = region[i];
> > + j++;
> > + }
> >
>
> memcpy() ?
The above code fragmentation was directly borrowed from mark's
inline-data tests:-)
You're right, ww'd better use a simple memcpy() to simplify the copy.
memcpy(buf, region + offset, size);
>
> > +
> > + munmap(region, mmap_size);
> > +
> > + return 0;
> > +}
> > +
> > +extern int mmap_read_at_file(char *pathname, void *buf, size_t count,
> > + off_t offset, size_t page_size)
> > +{
> > + int fd, ret;
> > +
> > + fd = open64(pathname, FILE_RO_FLAGS);
> > +
> > + if (fd < 0) {
> > + fd = errno;
> > + fprintf(stderr, "open file %s failed:%d:%s\n", pathname, fd,
> > + strerror(fd));
> > + return fd;
> > + }
> >
>
> Use tabs.
>
> > +
> > + ret = mmap_read_at(fd, buf, count, offset, page_size);
> > +
> > + if (ret < 0)
> > + return ret;
> > +
> > + close(fd);
> > +
> > + return ret;
> > +}
> > +
> > +extern int write_at(int fd, const void *buf, size_t count, off_t offset)
> > +{
> > + int ret;
> > +
> > + ret = pwrite(fd, buf, count, offset);
> > +
> > + if (ret < 0) {
> > + ret = errno;
> > + fprintf(stderr, "write error %d: \"%s\"\n", ret, strerror(ret));
> > + return -1;
> > + }
> > +
> > + if (ret != count) {
> > + fprintf(stderr, "Short write: wanted %ld, got %d\n", count, ret);
> > + return -1;
> > + }
> >
>
> Short write is valid.
Yeah, the situation is like short read above:)
>
> > +
> > + return 0;
> > +}
> > +
> > +extern int write_at_file(char *pathname, const void *buf, size_t count,
> > + off_t offset)
> > +{
> > + int fd, ret;
> > +
> > + fd = open64(pathname, FILE_RW_FLAGS);
> > +
> > + if (fd < 0) {
> > + fd = errno;
> > + fprintf(stderr, "open file %s failed:%d:%s\n", pathname, fd,
> > + strerror(fd));
> > + return fd;
> > + }
> > +
> > + ret = write_at(fd, buf, count, offset);
> > +
> > + if (ret < 0)
> > + return ret;
> > +
> > + close(fd);
> > +
> > + return 0;
> > +}
> > +
> > +extern int mmap_write_at(int fd, const char *buf, size_t count, off_t offset,
> > + size_t page_size)
> > +{
> > + int i, j, ret;
> > + unsigned long mmap_size = page_size;
> > + unsigned long size = offset + count;
> > + char *region;
> > +
> > + while (mmap_size < size)
> > + mmap_size += page_size;
> > +
> > + region = mmap(NULL, mmap_size, PROT_WRITE, MAP_SHARED, fd, 0);
> > + if (region == MAP_FAILED) {
> > + ret = errno;
> > + fprintf(stderr, "mmap (write) error %d: \"%s\"\n", ret,
> > + strerror(ret));
> > + return -1;
> > + }
> > +
> > + j = 0;
> > +
> > + for (i = offset; i < size; i++)
> > + region[i] = buf[j++];
> >
>
> memcpy()?
memcpy(buf, region + offset, size);
>
> > +
> > + munmap(region, mmap_size);
> > +
> > + return 0;
> > +}
> > +
> > +extern int mmap_write_at_file(char *pathname, const void *buf, size_t count,
> > + off_t offset, size_t page_size)
> > +{
> > + int fd, ret;
> > +
> > + fd = open64(pathname, FILE_RW_FLAGS);
> > +
> > + if (fd < 0) {
> > + fd = errno;
> > + fprintf(stderr, "open file %s failed:%d:%s\n", pathname, fd,
> > + strerror(fd));
> > + return fd;
> > + }
> > +
> > + ret = mmap_write_at(fd, buf, count, offset, page_size);
> > +
> > + if (ret < 0)
> > + return ret;
> > +
> > + close(fd);
> > +
> > + return 0;
> > +}
> > +
> > +extern int reflink(const char *oldpath, const char *newpath)
> > +{
> > + int fd, ret;
> > + struct reflink_arguments args;
> > +
> > + args.old_path = (__u64)oldpath;
> > + args.new_path = (__u64)newpath;
> > +
> > + fd = open64(oldpath, FILE_RO_FLAGS);
> > +
> > + if (fd < 0) {
> > + fd = errno;
> > + fprintf(stderr, "open file %s failed:%d:%s\n", oldpath, fd,
> > + strerror(fd));
> > + return fd;
> > + }
> > +
> > + ret = ioctl(fd, OCFS2_IOC_REFLINK, &args);
> > +
> > + if (ret) {
> > + ret = errno;
> > + fprintf(stderr, "ioctl failed:%d:%s\n", ret, strerror(ret));
> > + return ret;
> > + }
> > +
> > + close(fd);
> > +
> > + return 0;
> > +}
> > +
> > +extern int do_write(int fd, struct write_unit *wu, int write_method, size_t page_size)
> > +{
> > + int ret;
> > + char buf[MAX_WRITE_SIZE];
> > +
> > + memset(buf, wu->w_char, wu->w_len);
> > +
> > + if (write_method == 1)
> > +
> > + ret = mmap_write_at(fd, buf, wu->w_len, wu->w_offset, page_size);
> > + else
> > + ret = write_at(fd, buf, wu->w_len, wu->w_offset);
> > +
> > + return ret;
> > +}
> > +
> > +extern int do_write_file(char *fname, struct write_unit *wu, int write_method,
> > + size_t page_size)
> > +{
> > + int fd, ret;
> > +
> > + fd = open64(fname, FILE_RW_FLAGS);
> > + if (fd < 0) {
> > + fd = errno;
> > + fprintf(stderr, "open file %s failed:%d:%s\n", fname, fd,
> > + strerror(fd));
> > + return fd;
> > + }
> > +
> > + ret = do_write(fd, wu, write_method, page_size);
> > +
> > + close(fd);
> > +
> > + return ret;
> > +}
> > +
> > +extern int get_bs_cs(char * device_name, unsigned int *bs, unsigned long *cs,
> > + unsigned long *max_inline_sz)
> > +{
> > + int ret;
> > + int open_flags = OCFS2_FLAG_HEARTBEAT_DEV_OK | OCFS2_FLAG_RO;
> > +
> > + ocfs2_filesys *fs;
> > + struct ocfs2_super_block *ocfs2_sb;
> > +
> > + ret = ocfs2_open(device_name, open_flags, 0, 0, &fs);
> > +
> > + if (ret < 0) {
> > + com_err("CurrentTest", ret,
> > + "while opening file system.");
> > + return ret;
> > + }
> > +
> > + ocfs2_sb = OCFS2_RAW_SB(fs->fs_super);
> > +
> > + *bs = 1 << ocfs2_sb->s_blocksize_bits;
> > + *cs = 1 << ocfs2_sb->s_clustersize_bits;
> >
>
> *bs = fs->fs_blocksize;
> *cs = fs->fs_clustersize;
Cool for simplifying this.
>
> > + *max_inline_sz = ocfs2_max_inline_data(*bs);
> > +
> > + ocfs2_close(fs);
> > +
> > + return 0;
> > +}
> > +
> > +extern int punch_hole(int fd, struct write_unit *wu)
> > +{
> > + int ret;
> > + struct ocfs2_space_resv sr;
> > +
> > + memset(&sr, 0, sizeof(sr));
> > + sr.l_whence = 0;
> > + sr.l_start = wu->w_offset;
> > + sr.l_len = wu->w_len;
> > +
> > + ret = ioctl(fd, OCFS2_IOC_UNRESVSP64, &sr);
> > + if (ret == -1) {
> > + fprintf(stderr, "ioctl error %d: \"%s\"\n",
> > + errno, strerror(errno));
> > + return -1;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > diff --git a/programs/libocfs2test/file_ops.h b/programs/libocfs2test/file_ops.h
> > new file mode 100644
> > index 0000000..dfe5b92
> > --- /dev/null
> > +++ b/programs/libocfs2test/file_ops.h
> > @@ -0,0 +1,88 @@
> > +/* -*- mode: c; c-basic-offset: 8; -*-
> > + * vim: noexpandtab sw=8 ts=8 sts=0:
> > + *
> > + * file_ops.h
> > + *
> > + * Copyright (C) 2008 Oracle. All rights reserved.
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public
> > + * License version 2 as published by the Free Software Foundation.
> > + *
> > + * 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.
> > + */
> > +
> > +#ifndef FILE_OPS_H
> > +#define FILE_OPS_H
> > +
> > +#define _GNU_SOURCE
> > +#define _XOPEN_SOURCE 500
> > +#define _LARGEFILE64_SOURCE
> > +#include <unistd.h>
> > +#include <errno.h>
> > +#include <sys/types.h>
> > +#include <sys/stat.h>
> > +#include <fcntl.h>
> > +#include <limits.h>
> > +#include <signal.h>
> > +#include <sys/mman.h>
> > +#include <sys/ioctl.h>
> > +#include <inttypes.h>
> > +#include <linux/types.h>
> > +
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <string.h>
> > +#include <assert.h>
> > +#include <getopt.h>
> > +
> > +#include <ocfs2/ocfs2.h>
> > +
> > +#define OCFS2_MAX_FILENAME_LEN 255
> > +#define MAX_WRITE_SIZE 32768
> > +#define RAND_CHAR_START 'A'
> > +#define MAGIC_HOLE_CHAR (RAND_CHAR_START - 1)
> > +
> > +#define FILE_RW_FLAGS (O_CREAT|O_RDWR)
> > +#define FILE_RO_FLAGS (O_RDONLY)
> > +#define FILE_AP_FLAGS (O_CREAT|O_RDWR|O_APPEND)
> > +
> > +#define FILE_MODE (S_IRUSR|S_IWUSR|S_IXUSR|S_IROTH|\
> > + S_IWOTH|S_IXOTH|S_IRGRP|S_IWGRP|S_IXGRP)
> > +
> > +struct write_unit {
> > + char w_char;
> > + unsigned long w_offset;
> > + unsigned int w_len;
> > +};
> > +
> > +unsigned long get_rand(unsigned long min, unsigned long max);
> > +char rand_char(void);
> > +
> > +int read_at(int fd, void *buf, size_t count, off_t offset);
> > +int read_at_file(char *pathname, void *buf, size_t count, off_t offset);
> > +int mmap_read_at(int fd, char *buf, size_t count, off_t offset,
> > + size_t page_size);
> > +int mmap_read_at_file(char *pathname, void *buf, size_t count, off_t offset,
> > + size_t page_size);
> > +int write_at(int fd, const void *buf, size_t count, off_t offset);
> > +int write_at_file(char *pathname, const void *buf, size_t count, off_t offset);
> > +int mmap_write_at(int fd, const char *buf, size_t count, off_t offset,
> > + size_t page_size);
> > +int mmap_write_at_file(char *pathname, const void *buf, size_t count,
> > + off_t offset, size_t page_size);
> > +
> > +int reflink(const char *oldpath, const char *newpath);
> > +
> > +int do_write(int fd, struct write_unit *wu, int write_method, size_t page_size);
> > +int do_write_file(char *fname, struct write_unit *wu, int write_method,
> > + size_t page_size);
> > +
> > +int get_bs_cs(char * device_name, unsigned int *bs, unsigned long *cs,
> > + unsigned long *max_inline_sz);
> > +
> > +int punch_hole(int fd, struct write_unit *wu);
> > +#endif
> >
>
More information about the Ocfs2-test-devel
mailing list