[Ocfs2-tools-devel] [PATCH v2 1/1] defragfs.ocfs2: Implement ocfs2 defragmentation tool

Gang He ghe at suse.com
Thu Oct 18 19:48:46 PDT 2018


Hello Lei,

The code looks good for me.
The suggestion is to add the related test cases for defragmentation tool in ocfs2-test package.

Thanks
Gang

>>> On 2018/10/17 at 15:20, in message <20181017072043.12316-2-lchen at suse.com>,
Larry Chen <lchen at suse.com> wrote:
> This patch tries to build main framework with necessary *.h and *.c
> files.
> 
> The defragmentation tool supports 3 types of target, single file,
> directory and block device.
> 
> The simplest case is defragment a single file, that is actually call
> ioctl with OCFS2_IOC_MOVE_EXT.
> 
> To defragment a dir means to defrag each file within this dir and its
> subdirectory.
> 
> To defragment a block device means to defrag root directory only if
> there is a ocfs2 file system running on top of it.
> 
> 1. Implement the core function do_file_defrag in main.c
> 
> 2. The function defrag_dir and defrag_block_dev in main.c are core
> ones used for directory and block device as mentioned above.
> 
> 3. Implement necessary utility func in libdefrag.c.
> 
> 4. To support resuming defragmentation works from where it was stopped,
> we use a temp file to record necessary info. Once uses run defrag tool
> with -g option, the temp file will be loaded, and process resumes from
> where it is stopped. This function is mainly implemented in record.c
> 
> 
> Signed-off-by: Larry Chen <lchen at suse.com>
> ---
>  Makefile                           |   2 +-
>  configure.in                       |   1 +
>  defragfs.ocfs2/Makefile            |  40 ++
>  defragfs.ocfs2/commit.sh           |   4 +
>  defragfs.ocfs2/defragfs.ocfs2.8.in |  76 ++++
>  defragfs.ocfs2/include/libdefrag.h |  36 ++
>  defragfs.ocfs2/include/o2defrag.h  |  40 ++
>  defragfs.ocfs2/include/record.h    |  59 +++
>  defragfs.ocfs2/libdefrag.c         | 126 +++++++
>  defragfs.ocfs2/main.c              | 735 
> +++++++++++++++++++++++++++++++++++++
>  defragfs.ocfs2/record.c            | 262 +++++++++++++
>  11 files changed, 1380 insertions(+), 1 deletion(-)
>  create mode 100644 defragfs.ocfs2/Makefile
>  create mode 100755 defragfs.ocfs2/commit.sh
>  create mode 100644 defragfs.ocfs2/defragfs.ocfs2.8.in
>  create mode 100644 defragfs.ocfs2/include/libdefrag.h
>  create mode 100644 defragfs.ocfs2/include/o2defrag.h
>  create mode 100644 defragfs.ocfs2/include/record.h
>  create mode 100644 defragfs.ocfs2/libdefrag.c
>  create mode 100644 defragfs.ocfs2/main.c
>  create mode 100644 defragfs.ocfs2/record.c
> 
> diff --git a/Makefile b/Makefile
> index 955fab9c..5b0c258f 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -23,7 +23,7 @@ endif
>  SUBDIRS1 = include
>  SUBDIRS2 = libtools-internal libo2dlm libo2cb
>  SUBDIRS3 = libocfs2
> -SUBDIRS4 = fsck.ocfs2 mkfs.ocfs2 mounted.ocfs2 tunefs.ocfs2 debugfs.ocfs2 
> o2cb_ctl ocfs2_hb_ctl mount.ocfs2 ocfs2_controld o2image o2info o2monitor 
> extras fswreck patches
> +SUBDIRS4 = fsck.ocfs2 mkfs.ocfs2 mounted.ocfs2 tunefs.ocfs2 debugfs.ocfs2 
> o2cb_ctl ocfs2_hb_ctl mount.ocfs2 ocfs2_controld o2image o2info o2monitor 
> extras fswreck patches defragfs.ocfs2
>  
>  ifdef BUILD_OCFS2CONSOLE
>  SUBDIRS4 += ocfs2console
> diff --git a/configure.in b/configure.in
> index f89f4c21..59f95677 100644
> --- a/configure.in
> +++ b/configure.in
> @@ -476,6 +476,7 @@ o2cb_ctl/ocfs2.cluster.conf.5
>  vendor/common/o2cb.sysconfig.5
>  libocfs2/ocfs2.7
>  vendor/common/ocfs2-tools.spec-generic
> +defragfs.ocfs2/defragfs.ocfs2.8
>  ])
>  
>  AC_OUTPUT
> diff --git a/defragfs.ocfs2/Makefile b/defragfs.ocfs2/Makefile
> new file mode 100644
> index 00000000..8740d33f
> --- /dev/null
> +++ b/defragfs.ocfs2/Makefile
> @@ -0,0 +1,40 @@
> +TOPDIR = ..
> +
> +include $(TOPDIR)/Preamble.make
> +
> +sbindir = $(root_sbindir)
> +SBIN_PROGRAMS = defragfs.ocfs2
> +
> +DEFINES += -DVERSION=\"$(VERSION)\"
> +
> +
> +INCLUDES = -I$(TOPDIR)/include -I./include
> +DEFINES = -DVERSION=\"$(VERSION)\"
> +
> +CFILES = main.c record.c libdefrag.c
> +HFILES =	\
> +	include/libdefrag.h	\
> +	include/o2defrag.h	\
> +	include/record.h
> +
> +OBJS = $(subst .c,.o,$(CFILES))
> +
> +
> +DIST_FILES = $(CFILES) $(HFILES) defragfs.ocfs2.8.in
> +
> +DIST_RULES = dist-subdircreate
> +MANS = defragfs.ocfs2.8
> +
> +defragfs.ocfs2: $(OBJS)
> +	$(LINK)
> +
> +dist-subdircreate:
> +	$(TOPDIR)/mkinstalldirs $(DIST_DIR)/include
> +
> +CLEAN_RULES = defragfs-clean 
> +
> +defragfs-clean:
> +	rm  defragfs.ocfs2.8
> +
> +.PHONY: defragfs-clean
> +include $(TOPDIR)/Postamble.make
> diff --git a/defragfs.ocfs2/commit.sh b/defragfs.ocfs2/commit.sh
> new file mode 100755
> index 00000000..bf1a3738
> --- /dev/null
> +++ b/defragfs.ocfs2/commit.sh
> @@ -0,0 +1,4 @@
> +#!/bin/bash
> +
> +git commit -am "test"
> +git push
> diff --git a/defragfs.ocfs2/defragfs.ocfs2.8.in 
> b/defragfs.ocfs2/defragfs.ocfs2.8.in
> new file mode 100644
> index 00000000..be39639b
> --- /dev/null
> +++ b/defragfs.ocfs2/defragfs.ocfs2.8.in
> @@ -0,0 +1,76 @@
> +.TH "defragfs.ocfs2" "8" "January 2012" "Version @VERSION@" "OCFS2 Manual 
> Pages"
> +.SH NAME
> +defragfs.ocfs2 \- online defragmenter for ocfs2 filesystem
> +.SH SYNOPSIS
> +defragfs.ocfs2 [\-c] [\-v] [\-l] [\-g] [\-h][target]...
> +.SH DESCRIPTION
> +.PP
> +.B defragfs.ocfs2
> +reduces fragmentation of ocfs2 based file. The file targeted by
> +.B defragfs.ocfs2
> +is created on ocfs2 filesystem The targeted file gets more contiguous 
> blocks and improves the file access
> +speed.
> +.PP
> +.I target
> +is a regular file, a directory, or a device that is mounted as ocfs2 
> filesystem.
> +If
> +.I target
> +is a directory,
> +.B defragfs.ocfs2
> +reduces fragmentation of all files in it. If
> +.I target
> +is a device,
> +.B defragfs.ocfs2
> +gets the mount point of it and reduces fragmentation of all files in this 
> mount
> +point.
> +.SH OPTIONS
> +.TP
> +.B \-c
> +Print the numbers of files that should be processed 
> +.TP
> +.B \-v
> +verbose mode, the current fragmentation count and the ideal fragmentation 
> count are
> +printed for each file.
> +.IP
> +If this option is specified,
> +.I target
> +is never defragmented.
> +.TP
> +.B \-l
> +.B defragfs.ocfs2 
> +will run in low io mode, which means it will regularly yield cpu to allow 
> other processes to run.
> +.TP
> +.B \-g
> +.B defragfs.ocfs2
> +regularly records the current progress. So if it is interrupted, the next 
> time you run 
> +.B defragfs.ocfs2
> +with this option, it will resume from the recorded progress. 
> +Note that if this option is specified, other options are ignored and 
> replaced by those that were recorded.
> +.TP
> +.B \-h
> +Print help info
> +
> +.SH NOTES
> +.B defragfs.ocfs2
> +does not support files in lost+found directory. When
> +.I target
> +is a device or a mount point,
> +.B defragfs.ocfs2
> +doesn't defragment files in mount point of other device.
> +.PP
> +It is completely
> +.B not
> +recommended to run against a file while it is actively in another 
> application.
> +Since the read/write of a file involves a dlm lock, this can result in a 
> performance slowdown to both defragfs.ocfs2
> +and the application due to contention.
> +.PP
> +If the file system's free space is fragmented, or if there is
> +insufficient free space available, defragfs.ocfs2 may not be able
> +to improve the file's fragmentation.
> +.PP
> +Non-privileged users can execute
> +.B defragfs.ocfs2
> +to their own file. Therefore, it is desirable to be executed by root user.
> +.SH AUTHOR
> +Written by Larry Chen <lchen at suse.com>
> +
> diff --git a/defragfs.ocfs2/include/libdefrag.h 
> b/defragfs.ocfs2/include/libdefrag.h
> new file mode 100644
> index 00000000..337d1e02
> --- /dev/null
> +++ b/defragfs.ocfs2/include/libdefrag.h
> @@ -0,0 +1,36 @@
> +#ifndef __LIB_DEFERAG_H__
> +#define __LIB_DEFERAG_H__
> +
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <errno.h>
> +#include <linux/limits.h>
> +#include <linux/types.h>
> +
> +#define PRINT_ERR(msg)	\
> +	fprintf(stderr, "[ERROR]\t%s\n", (msg))
> +
> +#define PRINT_FILE_MSG(file, msg) \
> +	fprintf(stdout, "\"%s\":%s\n", (file), msg)
> +
> +#define PRINT_FILE_ERRNO(file)	\
> +	fprintf(stderr, "[ERROR]\"%s\":%s\n", (file), strerror(errno))
> +
> +#define PRINT_FILE_MSG_ERRNO(file, msg) \
> +	fprintf(stderr, "[ERROR]%s:\"%s\" - %s\n", msg, file, strerror(errno))
> +
> +#define PRINT_FILE_ERR(file, msg) \
> +	fprintf(stderr, "[ERROR]\"%s\":%s\n", (file), msg)
> +
> +void *do_malloc(size_t size);
> +
> +int do_read(int fd, void *bytes, size_t count);
> +
> +int do_write(int fd, const void *bytes, size_t count);
> +
> +unsigned int do_csum(const unsigned char *buff, int len);
> +
> +
> +#endif
> diff --git a/defragfs.ocfs2/include/o2defrag.h 
> b/defragfs.ocfs2/include/o2defrag.h
> new file mode 100644
> index 00000000..1ae7376d
> --- /dev/null
> +++ b/defragfs.ocfs2/include/o2defrag.h
> @@ -0,0 +1,40 @@
> +#ifndef __O2DEFRAG_H__
> +#define __O2DEFRAG_H__
> +
> +#define FS_OCFS2 "ocfs2"
> +
> +#define DETAIL			0x01
> +#define STATISTIC		0x02
> +#define GO_ON			0x04
> +#define LOW_IO			0x08
> +
> +#define DEVNAME			0
> +#define DIRNAME			1
> +#define FILENAME		2
> +
> +#define FTW_OPEN_FD		2000
> +
> +#define ROOT_UID		0
> +
> +#define SHOW_FRAG_FILES	5
> +#define SCHEDULE_TIME_LIMIT	5
> +
> +#define RECORD_EVERY_N_FILES	50
> +
> +#ifndef OCFS2_IOC_MOVE_EXT
> +#define OCFS2_IOC_MOVE_EXT	_IOW('o', 6, struct ocfs2_move_extents)
> +#endif
> +
> +struct o2defrag_opt {
> +	int o_num;
> +	char *o_str;
> +};
> +
> +#define declare_opt(n, s)  {\
> +	.o_num = n,\
> +	.o_str = s\
> +}
> +
> +#define PROGRAME_NAME "defragfs.ocfs2"
> +
> +#endif
> diff --git a/defragfs.ocfs2/include/record.h b/defragfs.ocfs2/include/record.h
> new file mode 100644
> index 00000000..25b8659f
> --- /dev/null
> +++ b/defragfs.ocfs2/include/record.h
> @@ -0,0 +1,59 @@
> +#ifndef __RECORD_H__
> +#define __RECORD_H__
> +
> +#include <unistd.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +#include <stdlib.h>
> +#include <errno.h>
> +#include <linux/limits.h>
> +#include <linux/types.h>
> +#include <stdint.h>
> +
> +#define RECORD_FILE_NAME ".ocfs2.defrag.record" //under lost_found dir
> +
> +//#define offset_of(type, member)  &(((type *)0)->(member))
> +#define offset_of(type, member) (unsigned long)(&((type *)0)->member)
> +
> +
> +#define calc_record_file_size(argc) (RECORD_HEADER_LEN + argc * PATH_MAX)
> +
> +/*
> + * record format****************
> + * mode_flag(binary)
> + * inode_no_to_resume
> + * how_many_left
> + * argv[0]'\0'argv[1]'\0'.......argv[n-1]'\0'
> + * check_sum
> + */
> +
> +struct argv_node {
> +	char *a_path;
> +	struct list_head a_list;
> +};
> +
> +
> +struct resume_record {
> +	int r_mode_flag;
> +	ino_t r_inode_no;
> +	int r_argc;
> +	struct list_head r_argvs;
> +};
> +
> +#define RECORD_HEADER_LEN offset_of(struct resume_record, r_argvs)
> +
> +extern void dump_record(char *base_name,
> +			struct resume_record *rr,
> +			void (*dump_mode_flag)(int mode_flag));
> +
> +extern void set_record_file_path(char *path);
> +extern void free_record(struct resume_record *rr);
> +extern void fill_resume_record(struct resume_record *rr,
> +		int mode_flag, char **argv, int argc, ino_t inode_no);
> +extern void free_argv_node(struct argv_node *n);
> +extern int store_record(struct resume_record *rr);
> +extern int load_record(struct resume_record *rr);
> +extern void mv_record(struct resume_record *dst, struct resume_record 
> *src);
> +extern int remove_record(void);
> +#endif
> diff --git a/defragfs.ocfs2/libdefrag.c b/defragfs.ocfs2/libdefrag.c
> new file mode 100644
> index 00000000..200370c2
> --- /dev/null
> +++ b/defragfs.ocfs2/libdefrag.c
> @@ -0,0 +1,126 @@
> +#include <libdefrag.h>
> +#include <unistd.h>
> +
> +void *do_malloc(size_t size)
> +{
> +	void *buf;
> +
> +	buf = calloc(size, 1);
> +
> +	if (buf == NULL) {
> +		fprintf(stderr, "No mem\n");
> +		exit(-1);
> +	}
> +
> +	return buf;
> +}
> +
> +int do_read(int fd, void *bytes, size_t count)
> +{
> +	int total = 0;
> +	int ret;
> +
> +
> +	while (total < count) {
> +		ret = read(fd, bytes + total, count - total);
> +		if (ret < 0) {
> +			ret = -errno;
> +			if ((ret == -EAGAIN) || (ret == -EINTR))
> +				continue;
> +			total = ret;
> +			break;
> +		}
> +		if (ret == 0)
> +			break;
> +		total += ret;
> +	}
> +
> +	return total;
> +}
> +
> +int do_write(int fd, const void *bytes, size_t count)
> +{
> +	int total = 0;
> +	int ret;
> +
> +	while (total < count) {
> +		ret = write(fd, bytes + total, count - total);
> +		if (ret < 0) {
> +			ret = -errno;
> +			if ((ret == -EAGAIN) || (ret == -EINTR))
> +				continue;
> +			else
> +				goto error;
> +		}
> +
> +		total += ret;
> +	}
> +	return total;
> +error:
> +	return ret;
> +}
> +
> +static inline unsigned short from32to16(unsigned int x)
> +{
> +	/* add up 16-bit and 16-bit for 16+c bit */
> +	x = (x & 0xffff) + (x >> 16);
> +	/* add up carry.. */
> +	x = (x & 0xffff) + (x >> 16);
> +	return x;
> +}
> +
> +unsigned int do_csum(const unsigned char *buff, int len)
> +{
> +	int odd;
> +	unsigned int result = 0;
> +
> +	if (len <= 0)
> +		goto out;
> +	odd = 1 & (unsigned long) buff;
> +	if (odd) {
> +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
> +		result += (*buff << 8);
> +#else
> +		result = *buff;
> +#endif
> +		len--;
> +		buff++;
> +	}
> +	if (len >= 2) {
> +		if (2 & (unsigned long) buff) {
> +			result += *(unsigned short *) buff;
> +			len -= 2;
> +			buff += 2;
> +		}
> +		if (len >= 4) {
> +			const unsigned char *end = buff + ((unsigned)len & ~3);
> +			unsigned int carry = 0;
> +
> +			do {
> +				unsigned int w = *(unsigned int *) buff;
> +
> +				buff += 4;
> +				result += carry;
> +				result += w;
> +				carry = (w > result);
> +			} while (buff < end);
> +			result += carry;
> +			result = (result & 0xffff) + (result >> 16);
> +		}
> +		if (len & 2) {
> +			result += *(unsigned short *) buff;
> +			buff += 2;
> +		}
> +	}
> +	if (len & 1)
> +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
> +		result += *buff;
> +#else
> +		result += (*buff << 8);
> +#endif
> +	result = from32to16(result);
> +	if (odd)
> +		result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
> +out:
> +	return result;
> +}
> diff --git a/defragfs.ocfs2/main.c b/defragfs.ocfs2/main.c
> new file mode 100644
> index 00000000..2a110b6e
> --- /dev/null
> +++ b/defragfs.ocfs2/main.c
> @@ -0,0 +1,735 @@
> +#define _GNU_SOURCE
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <fcntl.h>
> +#include <getopt.h>
> +#include <errno.h>
> +#include <malloc.h>
> +#include <time.h>
> +#include <libgen.h>
> +#include <netinet/in.h>
> +#include <inttypes.h>
> +#include <ctype.h>
> +#include <assert.h>
> +#include <sys/ioctl.h>
> +#include <mntent.h>
> +#include <sys/vfs.h>
> +#include <ftw.h>
> +#include <sched.h>
> +#include <signal.h>
> +#include <uuid/uuid.h>
> +
> +#include "ocfs2/ocfs2.h"
> +#include "ocfs2/bitops.h"
> +
> +#include <record.h>
> +#include <libdefrag.h>
> +#include <o2defrag.h>
> +
> +
> +
> +
> +static char	lost_found_dir[PATH_MAX + 1];
> +static int	mode_flag;
> +static unsigned int	regular_count;
> +static unsigned int	succeed_count;
> +static unsigned int skipped_count;
> +static unsigned int processed_count;
> +static uid_t current_uid;
> +static int should_stop;
> +struct resume_record rr;
> +
> +
> +
> +static void usage(char *progname)
> +{
> +	printf("usage: %s [-c] [-v] [-l] [-g] [-h] [FILE | DIRECTORY | DEVICE]...\n",
> +			progname);
> +	printf("\t-c\t\tCalculate how many files will be processed\n");
> +	printf("\t-v\t\tVerbose mode\n");
> +	printf("\t-l\t\tLow io rate mode\n");
> +	printf("\t-g\t\tResume last defrag progress\n");
> +	printf("\t-h\t\tShow this help\n");
> +	exit(0);
> +}
> +
> +/*
> + * get_dev_mount_point() -	Get device's ocfs2 mount point.
> + * @devname:		the device's name.
> + * @mount_point:	the mount point.
> + *
> + * a block device may be mounted on multiple mount points,
> + * this function return on first match
> + */
> +static int get_dev_mount_point(const char *devname, char *mount_point)
> +{
> +	/* Refer to /etc/mtab */
> +	const char *mtab = MOUNTED;
> +	FILE *fp = NULL;
> +	struct mntent *mnt = NULL;
> +	struct stat64 sb;
> +
> +	if (stat64(devname, &sb) < 0) {
> +		PRINT_FILE_MSG_ERRNO(devname, "While getting mount point");
> +		return -1;
> +	}
> +
> +	fp = setmntent(mtab, "r");
> +	if (fp == NULL) {
> +		PRINT_ERR("Couldn't access /etc/mtab");
> +		return -1;
> +	}
> +
> +	while ((mnt = getmntent(fp)) != NULL) {
> +		struct stat64 ms;
> +
> +		/*
> +		 * To handle device symlinks, we see if the
> +		 * device number matches, not the name
> +		 */
> +		if (stat64(mnt->mnt_fsname, &ms) < 0)
> +			continue;
> +		if (sb.st_rdev != ms.st_rdev)
> +			continue;
> +
> +		endmntent(fp);
> +		if (strcmp(mnt->mnt_type, FS_OCFS2) == 0) {
> +			strncpy(mount_point, mnt->mnt_dir,
> +				PATH_MAX);
> +			return 0;
> +		}
> +		PRINT_FILE_MSG(devname, "Not ocfs2 format");
> +		return -1;
> +	}
> +	endmntent(fp);
> +	PRINT_FILE_MSG(devname, "Is not mounted");
> +	return -1;
> +}
> +
> +/*
> + * get_file_backend_info() - Get file's mount point and block dev that it's 
> on.
> + * @file:	the device's name.
> + * @dev:	dev path
> + * @mount_point:	the mount point.
> + *
> + * The file mush be on ocfs2 partition
> + */
> +
> +static int get_file_backend_info(const char *file, char *dev, char 
> *mount_point)
> +{
> +	int maxlen = 0;
> +	int	len, ret;
> +	FILE *fp = NULL;
> +	/* Refer to /etc/mtab */
> +	const char *mtab = MOUNTED;
> +	char real_path[PATH_MAX + 1];
> +	struct mntent *mnt = NULL;
> +	struct statfs64	fsbuf;
> +
> +
> +	/* Get full path */
> +	if (realpath(file, real_path) == NULL) {
> +		PRINT_FILE_MSG_ERRNO(file, "Getting realpath failed");
> +		return -1;
> +	}
> +
> +	if (statfs64(real_path, &fsbuf) < 0) {
> +		PRINT_FILE_MSG_ERRNO(file, "Getting fs state failed");
> +		return -1;
> +	}
> +
> +	if (fsbuf.f_type != OCFS2_SUPER_MAGIC)
> +		return -1;
> +
> +	fp = setmntent(mtab, "r");
> +	if (fp == NULL) {
> +		PRINT_ERR("Couldn't access /etc/mtab");
> +		return -1;
> +	}
> +
> +	while ((mnt = getmntent(fp)) != NULL) {
> +		if (mnt->mnt_fsname[0] != '/')
> +			continue;
> +		len = strlen(mnt->mnt_dir);
> +		ret = memcmp(real_path, mnt->mnt_dir, len);
> +		if (ret != 0)
> +			continue;
> +
> +		if (maxlen >= len)
> +			continue;
> +
> +		maxlen = len;
> +
> +		strncpy(mount_point, mnt->mnt_dir, PATH_MAX);
> +		strncpy(dev, mnt->mnt_fsname, strlen(mnt->mnt_fsname) + 1);
> +	}
> +
> +	endmntent(fp);
> +	return 0;
> +}
> +
> +/*
> + * is_ocfs2() -	Test whether the file on an ocfs2 filesystem.
> + * @file:		the file's name.
> + */
> +static int is_ocfs2(const char *file)
> +{
> +	struct statfs64	fsbuf;
> +	/* Refer to /etc/mtab */
> +	char	file_path[PATH_MAX + 1];
> +
> +	/* Get full path */
> +	if (realpath(file, file_path) == NULL)
> +		return 0;
> +
> +	if (statfs64(file_path, &fsbuf) < 0)
> +		return 0;
> +
> +	if (fsbuf.f_type != OCFS2_SUPER_MAGIC)
> +		return 0;
> +
> +	return 1;
> +}
> +
> +/*
> + * calc_entry_counts() - Calculate file counts.
> + * @file:		file name.
> + * @buf:		file info.
> + * @flag:		file type.
> + * @ftwbuf:		the pointer of a struct FTW.
> + */
> +static int calc_entry_counts(const char *file,
> +		const struct stat64 *buf, int flag, struct FTW *ftwbuf)
> +{
> +	if (lost_found_dir[0] != '\0' &&
> +	    !memcmp(file, lost_found_dir, strnlen(lost_found_dir, PATH_MAX))) {
> +		return 0;
> +	}
> +
> +	if (S_ISREG(buf->st_mode))
> +		regular_count++;
> +	return 0;
> +}
> +
> +/*
> + * print_progress -	Print defrag progress
> + * @file:		file name.
> + * @start:		logical offset for defrag target file
> + * @file_size:		defrag target filesize
> + */
> +static void print_progress(const char *file, int result)
> +{
> +	char *str_res = "Success";
> +
> +	if (result)
> +		str_res = "Failed";
> +	if (mode_flag & DETAIL)
> +		printf("[%u/%u]%s:%s\n",
> +			processed_count, regular_count, file, str_res);
> +	else
> +		printf("\033[79;0H\033[K[%u/%u]%s:%s\t",
> +			processed_count, regular_count, file, str_res);
> +	fflush(stdout);
> +}
> +
> +static int do_file_defrag(const char *file, const struct stat64 *buf,
> +			int flag, struct FTW *ftwbuf)
> +{
> +	/* Defrag the file */
> +	int ret;
> +	int fd;
> +	struct ocfs2_move_extents me = {
> +		.me_start = 0,
> +		.me_len = buf->st_size,
> +		.me_flags = OCFS2_MOVE_EXT_FL_AUTO_DEFRAG,
> +	};
> +
> +	fd = open64(file, O_RDWR, 0400);
> +	if (fd < 0) {
> +		PRINT_FILE_MSG_ERRNO(file, "Open file failed");
> +		return -1;
> +	}
> +
> +	ret = ioctl(fd, OCFS2_IOC_MOVE_EXT, &me);
> +	if (ret < 0)
> +		PRINT_FILE_MSG_ERRNO(file,"Move extent failed");
> +
> +	close(fd);
> +	return ret;
> +}
> +
> +
> +/*
> + * check_file() - Check file attributes.
> + * @file:		the file's name.
> + * @file_stat:		the pointer of the struct stat64.
> + */
> +static int check_file(const char *file, const struct stat64 *file_stat)
> +{
> +	const struct stat64 *buf;
> +	struct stat64 stat_tmp;
> +	int ret;
> +
> +	buf = file_stat;
> +
> +	if (!buf) {
> +		ret = stat64(file, &stat_tmp);
> +		if (ret < 0) {
> +			PRINT_FILE_MSG_ERRNO(file, "Get file stat failed");
> +			return 0;
> +		}
> +		buf = &stat_tmp;
> +	}
> +
> +	if (buf->st_size == 0) {
> +		if (mode_flag & DETAIL)
> +			PRINT_FILE_MSG(file, "File size is 0... skip");
> +		return 0;
> +	}
> +
> +	/* Has no blocks */
> +	if (buf->st_blocks == 0) {
> +		if (mode_flag & DETAIL)
> +			PRINT_FILE_MSG(file, "File has no blocks");
> +		return 0;
> +	}
> +
> +	if (current_uid != ROOT_UID &&
> +		buf->st_uid != current_uid) {
> +		if (mode_flag & DETAIL) {
> +			PRINT_FILE_MSG(file,
> +				"File is not current user's file or current user is not root");
> +		}
> +		return 0;
> +	}
> +	return 1;
> +}
> +
> +/*
> + * defrag_file_ftw() - Check file attributes and call ioctl to defrag.
> + * @file:		the file's name.
> + * @buf:		the pointer of the struct stat64.
> + * @flag:		file type.
> + * @ftwbuf:		the pointer of a struct FTW.
> + */
> +static int defrag_file_ftw(const char *file, const struct stat64 *buf,
> +			int flag, struct FTW *ftwbuf)
> +{
> +	int ret;
> +	time_t run_limit = SCHEDULE_TIME_LIMIT;
> +	static time_t sched_clock;
> +	time_t now, diff;
> +	static int count;
> +
> +
> +	if (rr.r_inode_no) {
> +		if (buf->st_ino != rr.r_inode_no)
> +			goto skip;
> +		else
> +			rr.r_inode_no = 0;
> +	}
> +
> +	if (should_stop || count >= RECORD_EVERY_N_FILES) {
> +		rr.r_inode_no = buf->st_ino;
> +
> +		if (should_stop) {
> +			PRINT_FILE_MSG(file, "Interrupted");
> +			printf("%s ---- interrupted\n", file);
> +		} else {
> +			rr.r_inode_no = 0;
> +			count = 0;
> +		}
> +
> +		if (mode_flag & DETAIL)
> +			printf("\nRecording...\n");
> +		ret = store_record(&rr);
> +
> +		if (ret)
> +			PRINT_ERR("Record failed");
> +		else if (mode_flag & DETAIL)
> +				printf("Record successfully\n"
> +					"Use -g option to resume progress\n");
> +
> +		if (should_stop)
> +			exit(0);
> +	} else
> +		count++;
> +
> +	if (mode_flag & LOW_IO) {
> +		if(sched_clock == 0)
> +			sched_clock = time(NULL);
> +
> +		now = time(NULL);
> +		diff = now - sched_clock;
> +		if (diff > run_limit) {
> +			printf("===========\n");
> +			sched_yield();
> +			sched_clock = now;
> +		}
> +	}
> +
> +	if (lost_found_dir[0] != '\0' &&
> +	    !memcmp(file, lost_found_dir, strnlen(lost_found_dir, PATH_MAX))) {
> +		if (mode_flag & DETAIL)
> +			PRINT_FILE_MSG(file,
> +				"In lost+found dir... ignore");
> +		return 0;
> +	}
> +
> +	if (!S_ISREG(buf->st_mode)) {
> +		if (mode_flag & DETAIL)
> +			PRINT_FILE_MSG(file, "Not regular file... ignore");
> +		return 0;
> +	}
> +
> +	processed_count++;
> +
> +	ret = check_file(file, buf);
> +	if (!ret) {
> +		skipped_count++;
> +		goto out;
> +	}
> +
> +	ret = do_file_defrag(file, buf, flag, ftwbuf);
> +	if (ret == 0)
> +		succeed_count++;
> +out:
> +	print_progress(file, ret);
> +	return 0;
> +skip:
> +	if (mode_flag & DETAIL)
> +		PRINT_FILE_MSG(file, "already done... skip\n");
> +	processed_count++;
> +	skipped_count++;
> +	return 0;
> +}
> +
> +static int defrag_dir(const char *dir_path)
> +{
> +	//lost+found is skipped!
> +	char *real_dir_path = do_malloc(PATH_MAX);
> +	char *dev_path = do_malloc(PATH_MAX);
> +	char *mount_point = do_malloc(PATH_MAX);
> +	char *lost_found = lost_found_dir;
> +	int mount_point_len;
> +	int flags = FTW_PHYS | FTW_MOUNT;
> +
> +	int ret;
> +
> +	if (!is_ocfs2(dir_path)) {
> +		PRINT_FILE_MSG(dir_path, "Not within ocfs2 fs");
> +		return 1;
> +	}
> +
> +	if (realpath(dir_path, real_dir_path) == NULL) {
> +		PRINT_FILE_MSG(dir_path, "Couldn't get full path");
> +		return 1;
> +	}
> +	ret = get_file_backend_info(dir_path, dev_path, mount_point);
> +	if (ret < 0) {
> +		PRINT_FILE_MSG(dir_path, "can not get file back info");
> +		return ret;
> +	}
> +	if (access(dir_path, R_OK) < 0) {
> +		perror(dir_path);
> +		return 1;
> +	}
> +	mount_point_len = strnlen(mount_point, PATH_MAX);
> +	snprintf(lost_found, PATH_MAX, "%s%s", mount_point, "/lost+found");
> +
> +	/* Not the case("defragfs.ocfs2  mount_point_dir") */
> +	if (dir_path[mount_point_len] != '\0') {
> +		/*
> +		 * "defragfs.ocfs2 mount_point_dir/lost+found"
> +		 * or "defragfs.ocfs2 mount_point_dir/lost+found/"
> +		 */
> +		int lf_len = strnlen(lost_found, PATH_MAX);
> +
> +		if (strncmp(lost_found, dir_path, lf_len) == 0
> +			&& (dir_path[lf_len] == '\0'
> +				|| dir_path[lf_len] == '/')) {
> +			PRINT_FILE_MSG(dir_path, 
> +					"defrag won't work within lost+found\n");
> +		}
> +	}
> +
> +	nftw64(real_dir_path, calc_entry_counts, FTW_OPEN_FD, flags);
> +
> +	if (mode_flag & STATISTIC) {
> +		printf("%8d files should be defraged in [%s]\n",
> +				regular_count, real_dir_path);
> +		return 1;
> +	}
> +
> +	nftw64(dir_path, defrag_file_ftw, FTW_OPEN_FD, flags);
> +	return 0;
> +}
> +
> +static int defrag_block_dev(char *dev_path)
> +{
> +	char *mnt_point;
> +	int ret;
> +
> +	mnt_point = do_malloc(PATH_MAX);
> +	ret = get_dev_mount_point(dev_path, mnt_point);
> +	if (ret < 0) {
> +		PRINT_FILE_MSG(dev_path, "Could not find mount point");
> +		return ret;
> +	}
> +
> +	if (mode_flag & DETAIL)
> +		printf("ocfs2 defragmentation for device(%s)\n",
> +			dev_path);
> +
> +	return defrag_dir(mnt_point);
> +}
> +
> +static int defrag_file(char *file_path)
> +{
> +	struct stat64 file_stat;
> +	int ret;
> +
> +	if (!is_ocfs2(file_path)) {
> +		PRINT_FILE_MSG(file_path, "Not on ocfs2 fs\n");
> +		return -1;
> +	}
> +
> +	ret = stat64(file_path, &file_stat);
> +	if (ret < 0) {
> +		PRINT_FILE_MSG(file_path, "get file stat error");
> +		return -1;
> +	}
> +
> +	if (!S_ISREG(file_stat.st_mode)) {
> +		if (mode_flag & DETAIL)
> +			PRINT_FILE_MSG(file_path,
> +				"Not regular file... ignore");
> +		return -1;
> +	}
> +	regular_count++;
> +
> +	/* Empty file */
> +	if (file_stat.st_size == 0) {
> +		if (mode_flag & DETAIL)
> +			PRINT_FILE_MSG(file_path,
> +				"File size is 0... skip");
> +		skipped_count++;
> +		return -1;
> +	}
> +
> +	/* Has no blocks */
> +	if (file_stat.st_blocks == 0) {
> +		if (mode_flag & DETAIL)
> +			PRINT_FILE_MSG(file_path, "File has no blocks");
> +		skipped_count++;
> +		return -1;
> +	}
> +
> +
> +	if (current_uid != ROOT_UID &&
> +		file_stat.st_uid != current_uid) {
> +		if (mode_flag & DETAIL) {
> +			PRINT_FILE_MSG(file_path,
> +				"File is not current user's file or current user is not root");
> +		}
> +		return -1;
> +	}
> +
> +	ret = do_file_defrag(file_path, &file_stat, 0, 0);
> +	if (ret < 0) {
> +		PRINT_FILE_ERRNO(file_path);
> +		return -1;
> +	}
> +
> +	printf("%s: Succeeded\n", file_path);
> +	return 0;
> +}
> +
> +static void handle_signal(int sig)
> +{
> +	switch (sig) {
> +	case SIGTERM:
> +	case SIGINT:
> +		printf("\nProcess Interrupted. signale = %d\n", sig);
> +		should_stop = 1;
> +	}
> +}
> +
> +static struct o2defrag_opt opt_table[] = {
> +	declare_opt(DETAIL, "-v"),
> +	declare_opt(STATISTIC, "-c"),
> +	declare_opt(GO_ON, "-g"),
> +	declare_opt(LOW_IO, "-o"),
> +};
> +
> +static void dump_mode_flag(int mode_flag)
> +{
> +	int i = 0;
> +
> +	for (i = 0; i < sizeof(opt_table)/sizeof(opt_table[0]); i++) {
> +		if (mode_flag & opt_table[i].o_num)
> +			printf(" %s ", opt_table[i].o_str);
> +	}
> +}
> +
> +static int parse_opt(int argc, char **argv, int *_mode_flag)
> +{
> +	char opt;
> +
> +	if (argc == 1)
> +		return 0;
> +
> +	while ((opt = getopt(argc, argv, "gvclh")) != EOF) {
> +		switch (opt) {
> +		case 'v':
> +			*_mode_flag |= DETAIL;
> +			break;
> +		case 'c':
> +			*_mode_flag |= STATISTIC;
> +			break;
> +		case 'g':
> +			*_mode_flag |= GO_ON;
> +			break;
> +		case 'l':
> +			*_mode_flag |= LOW_IO;
> +			break;
> +		case 'h':
> +			usage(PROGRAME_NAME);
> +			exit(0);
> +
> +		default:
> +			break;
> +		}
> +	}
> +	return optind;
> +}
> +
> +
> +static void init_signal_handler(void)
> +{
> +	if (signal(SIGTERM, handle_signal) == SIG_ERR) {
> +		PRINT_ERR("Could not set SIGTERM");
> +		exit(1);
> +	}
> +
> +	if (signal(SIGINT, handle_signal) == SIG_ERR) {
> +		PRINT_ERR("Could not set SIGINT");
> +		exit(1);
> +	}
> +}
> +
> +
> +static void print_version(char *progname)
> +{
> +	printf("%s %s\n", progname, VERSION);
> +}
> +
> +
> +
> +/*
> + * main() -		ocfs2 online defrag.
> + *
> + * @argc:		the number of parameter.
> + * @argv[]:		the pointer array of parameter.
> + */
> +int main(int argc, char *argv[])
> +{
> +	int ret;
> +	char	dir_name[PATH_MAX + 1];
> +	char	dev_name[PATH_MAX + 1];
> +	struct stat64	buf;
> +	int _mode_flag = 0;
> +	int index;
> +	struct resume_record rr_tmp;
> +	struct list_head *pos;
> +
> +	init_signal_handler();
> +
> +	print_version(PROGRAME_NAME);
> +
> +	index = parse_opt(argc, argv, &_mode_flag);
> +
> +	if (_mode_flag & GO_ON) {
> +		ret = load_record(&rr_tmp);
> +		if (ret) {
> +			PRINT_ERR("Load record failed...exit");
> +			exit(0);
> +		}
> +		mv_record(&rr, &rr_tmp);
> +		printf("Record detected...\n Start as:\n");
> +		dump_record(PROGRAME_NAME, &rr, dump_mode_flag);
> +	} else {
> +		if (index == argc || index == 0) {
> +			usage(PROGRAME_NAME);
> +			exit(0);
> +		}
> +
> +		fill_resume_record(&rr, _mode_flag, &argv[index], argc - index, 0);
> +	}
> +
> +	mode_flag = rr.r_mode_flag & ~GO_ON;
> +	current_uid = getuid();
> +
> +	/* Main process */
> +	list_for_each(pos, &rr.r_argvs) {
> +		struct argv_node *n = list_entry(pos, struct argv_node, a_list);
> +		char *path = n->a_path;
> +
> +		succeed_count = 0;
> +		regular_count = 0;
> +		skipped_count = 0;
> +
> +		memset(dir_name, 0, PATH_MAX + 1);
> +		memset(dev_name, 0, PATH_MAX + 1);
> +		memset(lost_found_dir, 0, PATH_MAX + 1);
> +
> +		if (lstat64(path, &buf) < 0) {
> +			perror("Failed to get file info:");
> +			printf("%s\n", path);
> +			continue;
> +		}
> +
> +		/* Handle i.e. lvm device symlinks */
> +		if (S_ISLNK(buf.st_mode)) {
> +			struct stat64	buf2;
> +
> +			if (stat64(path, &buf2) == 0 &&
> +			    S_ISBLK(buf2.st_mode))
> +				buf = buf2;
> +		}
> +
> +		if (S_ISBLK(buf.st_mode)) {
> +			/* Block device */
> +			ret = defrag_block_dev(path);
> +		} else if (S_ISDIR(buf.st_mode)) {
> +			/* Directory */
> +			ret = defrag_dir(path);
> +		} else if (S_ISREG(buf.st_mode)) {
> +			/* Regular file */
> +			ret = defrag_file(path);
> +			continue;
> +		} else {
> +			/* Irregular file */
> +			printf("irregular file\n");
> +			continue;
> +		}
> +
> +		if (!ret) {
> +			printf("\n\tSuccess:\t\t\t[ %u/%u ]\n",
> +					succeed_count, regular_count);
> +			printf("\n\tSkipped:\t\t\t[ %u/%u ]\n",
> +					skipped_count, regular_count);
> +			printf("\n\tFailure:\t\t\t[ %u/%u ]\n",
> +				regular_count - succeed_count - skipped_count,
> +				regular_count);
> +		}
> +
> +		free_argv_node(n);
> +	}
> +
> +	remove_record();
> +	return 0;
> +}
> diff --git a/defragfs.ocfs2/record.c b/defragfs.ocfs2/record.c
> new file mode 100644
> index 00000000..bcf1e395
> --- /dev/null
> +++ b/defragfs.ocfs2/record.c
> @@ -0,0 +1,262 @@
> +#include <unistd.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +#include <stdlib.h>
> +#include <errno.h>
> +#include <linux/limits.h>
> +#include <linux/types.h>
> +#include <stdint.h>
> +#include <stdio.h>
> +#include <string.h>
> +
> +#include <ocfs2-kernel/kernel-list.h>
> +#include <record.h>
> +#include <libdefrag.h>
> +
> +
> +#define MAX_RECORD_FILE_SIZE (2<<20)
> +
> +static char record_path[PATH_MAX] = "/tmp/"RECORD_FILE_NAME;
> +
> +void mv_record(struct resume_record *dst, struct resume_record *src)
> +{
> +	dst->r_argc = src->r_argc;
> +	dst->r_inode_no = src->r_inode_no;
> +	dst->r_mode_flag = src->r_mode_flag;
> +	INIT_LIST_HEAD(&dst->r_argvs);
> +	list_splice(&src->r_argvs, &dst->r_argvs);
> +}
> +
> +void dump_record(char *base_name, struct resume_record *rr,
> +		void (*dump_mode_flag)(int mode_flag))
> +{
> +		struct list_head *pos;
> +		struct argv_node *n;
> +		int mode_flag = rr->r_mode_flag;
> +
> +
> +		printf("%s", base_name);
> +		dump_mode_flag(mode_flag);
> +
> +		list_for_each(pos, &rr->r_argvs) {
> +			n = list_entry(pos, struct argv_node, a_list);
> +			printf(" %s ", n->a_path);
> +		}
> +		puts("");
> +}
> +
> +
> +void free_argv_node(struct argv_node *n)
> +{
> +	list_del(&n->a_list);
> +	if (n->a_path)
> +		free(n->a_path);
> +	free(n);
> +}
> +
> +static inline
> +struct argv_node *allocate_argv_node(int len)
> +{
> +	struct argv_node *n;
> +
> +	n = do_malloc(sizeof(struct argv_node));
> +	n->a_path = do_malloc(len);
> +	return n;
> +}
> +
> +void free_record(struct resume_record *rr)
> +{
> +	struct list_head *pos;
> +	struct argv_node *n;
> +
> +	list_for_each(pos, &rr->r_argvs) {
> +		n = list_entry(pos, struct argv_node, a_list);
> +		free_argv_node(n);
> +	}
> +}
> +
> +static int read_record(int fd, struct resume_record **p, int *len)
> +{
> +	struct stat s;
> +	void *content_buf = NULL;
> +
> +	if (fstat(fd, &s))
> +		goto error;
> +
> +	content_buf = do_malloc(s.st_size);
> +
> +	if (do_read(fd, content_buf, s.st_size) != s.st_size)
> +		goto error;
> +
> +	if (p)
> +		*p = content_buf;
> +	if (len)
> +		*len = s.st_size;
> +	return 0;
> +
> +error:
> +	if (content_buf)
> +		free(content_buf);
> +	if (p)
> +		*p = NULL;
> +	if (len)
> +		*len = 0;
> +	return -errno;
> +
> +}
> +
> +static int is_record_file_valid(void *buf, int len)
> +{
> +	int data_len = len - sizeof(unsigned int);
> +	unsigned int check_sum = *(int *)(buf + data_len);
> +
> +	if (check_sum == do_csum(buf, data_len))
> +		return 1;
> +	return 0;
> +}
> +
> +static int __store_record(int fd, struct resume_record *rr)
> +{
> +	struct list_head *pos;
> +	struct argv_node *n;
> +	int index = 0;
> +	unsigned char *buf = do_malloc(MAX_RECORD_FILE_SIZE);
> +	int len;
> +	int ret;
> +
> +	memcpy(buf, rr, RECORD_HEADER_LEN);
> +	index += RECORD_HEADER_LEN;
> +
> +	list_for_each(pos, &rr->r_argvs) {
> +		n = list_entry(pos, struct argv_node, a_list);
> +		len = strlen(n->a_path) + 1;
> +		if (index + len > MAX_RECORD_FILE_SIZE) {
> +			PRINT_ERR("Arg too long");
> +			ret = -1;
> +			goto out;
> +		}
> +		strcpy((char *)&buf[index], n->a_path);
> +		index += len;
> +	}
> +
> +	*(int *)&buf[index] = do_csum(buf, index);
> +	index += sizeof(int);
> +	ret = do_write(fd, buf, index);
> +
> +out:
> +	free(buf);
> +	if (ret < 0)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +
> +void fill_resume_record(struct resume_record *rr,
> +		int mode_flag, char **argv, int argc, ino_t inode_no)
> +{
> +	int i;
> +	int len;
> +	struct argv_node *node;
> +
> +	rr->r_mode_flag = mode_flag;
> +	rr->r_argc = argc;
> +	rr->r_inode_no = inode_no;
> +	INIT_LIST_HEAD(&rr->r_argvs);
> +	for (i = 0; i < argc; i++) {
> +		len = strlen(argv[i]) + 1;
> +		node = do_malloc(sizeof(struct argv_node));
> +		node->a_path = do_malloc(len);
> +		strcpy(node->a_path, argv[i]);
> +		list_add_tail(&node->a_list, &rr->r_argvs);
> +	}
> +}
> +
> +int remove_record(void)
> +{
> +	int ret;
> +
> +	ret = unlink(record_path);
> +	if (ret && errno != ENOENT) {
> +		perror("while deleting record file");
> +		return -errno;
> +	}
> +	return 0;
> +}
> +
> +int store_record(struct resume_record *rr)
> +{
> +	int fd;
> +
> +	fd = open(record_path,
> +			O_TRUNC | O_CREAT | O_WRONLY, 0600);
> +	if (fd < 0) {
> +		perror("while opening record file");
> +		return -errno;
> +	}
> +	if (__store_record(fd, rr))
> +		goto out;
> +
> +	if (fsync(fd))
> +		goto out;
> +
> +	close(fd);
> +	return 0;
> +out:
> +	return -1;
> +}
> +
> +static int __load_record(int fd, struct resume_record *rr)
> +{
> +	int ret = -1, i;
> +	struct resume_record *rr_tmp = NULL;
> +	char **argv = NULL;
> +	int argc;
> +	char *p;
> +	int len = 0;
> +
> +	if (read_record(fd, &rr_tmp, &len))
> +		goto out;
> +
> +	if (!is_record_file_valid(rr_tmp, len))
> +		goto out;
> +
> +
> +	argc = rr_tmp->r_argc;
> +
> +	argv = do_malloc(sizeof(char *) * argc);
> +
> +	p = (void *)rr_tmp + RECORD_HEADER_LEN;
> +	for (i = 0; i < argc; i++, p++) {
> +		argv[i] = (char *)p;
> +		p += strlen(p) + 1;
> +	}
> +
> +	fill_resume_record(rr, rr_tmp->r_mode_flag,
> +			argv, argc, rr_tmp->r_inode_no);
> +
> +	ret = 0;
> +out:
> +	if (rr_tmp)
> +		free(rr_tmp);
> +	if (argv)
> +		free(argv);
> +	return ret;
> +
> +}
> +
> +int load_record(struct resume_record *rr)
> +{
> +	int ret;
> +	int record_fd = open(record_path, O_RDONLY, 0700);
> +
> +	if (record_fd < 0) {
> +		perror("while opening record file");
> +		return -errno;
> +	}
> +	ret = __load_record(record_fd, rr);
> +	close(record_fd);
> +	return ret;
> +}
> +
> -- 
> 2.13.7
> 
> 
> _______________________________________________
> Ocfs2-tools-devel mailing list
> Ocfs2-tools-devel at oss.oracle.com 
> https://oss.oracle.com/mailman/listinfo/ocfs2-tools-devel



More information about the Ocfs2-tools-devel mailing list