[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