[Ocfs2-tools-devel] [PATCH v2 1/1] defragfs.ocfs2: Implement ocfs2 defragmentation tool
Larry Chen
lchen at suse.com
Mon Oct 22 02:07:18 PDT 2018
Hi Joseph,
I cheked the patch set of o2info.
These are o2info patch set.
0000 coverletter
0001 public headers diff
0002 all source code
0003~0006 add some option
For me, public headers do not need to be modified, so I directly
submitted the source code patches.
For the framework, I thinks defragmentation tool is a simple tool which
does not need a framework. Actually it's just a loop of calling ioctl
against each file.
Maybe I should split the source code into different ones, like the first
patch only supports defrag a single regular file, and then a patch
supports defrag a dir and then a patch that supports a block dev.
But that's not easy to modify a patch. And I think that's really a new
small project, so to make it clear, I add more comments to describe the
main functions and the framework.
If possible, could you please review the source code?
Thanks
Larry
On 10/19/18 11:56 AM, Joseph Qi wrote:
> I still suggest split this big patch into several appropriate small
> ones. You know, review a patch with thousand lines of code is a
> headache...
>
> Thanks,
> Joseph
>
> On 18/10/17 15:20, Larry Chen 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;
>> +}
>> +
>>
>
More information about the Ocfs2-tools-devel
mailing list