File: chunk_operations_eio.c

package info (click to toggle)
lizardfs 3.12.0%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 8,064 kB
  • sloc: cpp: 91,899; sh: 9,341; python: 3,878; ansic: 3,109; pascal: 128; makefile: 57
file content (126 lines) | stat: -rw-r--r-- 3,239 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <dlfcn.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>

typedef ssize_t (*pread_t)(int, void *, size_t, off_t);
typedef ssize_t (*pwrite_t)(int, const void *, size_t, off_t);
typedef int (*close_t)(int);
typedef int (*fsync_t)(int);

#define FILENAME_BUFSIZE 1024
#define COMMAND_BUFSIZE FILENAME_BUFSIZE

// only files with this substring in their name ale influenced by this library
#define FILENAME_TRIGGER "/chunk_"

// offset in a file used in some scenarios
#define FAR_OFFSET_THRESHOLD 102400

// for files which match FILENAME_TRIGGER, this library will cause the following functions to fail:
// * pread always fails with EIO if file name contains "pread_EIO"
// * pwrite always fails with EIO if file name contains "pwrite_EIO"
// * close always fails with EIO if file name contains "close_EIO"
// * fsync always fails with EIO if file name contains "fsync_EIO"
// * pread fails with EIO if offset>FAR_OFFSET_THRESHOLD and file name contains "pread_far_EIO"
// * pwrite fails with EIO if offset>FAR_OFFSET_THRESHOLD and file name contains "pwrite_far_EIO"

static char *read_filename(int fd, char *buf, int bufsize) {
	char fdpath[COMMAND_BUFSIZE] = {0};
	int procfd;

	sprintf(fdpath, "/proc/self/fd/%d", fd);
	memset(buf, 0, bufsize);
	readlink(fdpath, buf, bufsize);
	return buf;
}

static int err_on_operation(int fd, const char* opname, size_t offset) {
	char filename[FILENAME_BUFSIZE] = {0};
	char always_eio_trigger[COMMAND_BUFSIZE] = {0};
	char far_eio_trigger[COMMAND_BUFSIZE] = {0};

	read_filename(fd, filename, FILENAME_BUFSIZE);
	if (!strstr(filename, FILENAME_TRIGGER)) {
		return 0;
	}

	// prepare substrings of the filename which trigger errors in various scenarios
	sprintf(always_eio_trigger, "%s_EIO", opname);
	sprintf(far_eio_trigger, "%s_far_EIO", opname);
	if (strstr(filename, always_eio_trigger)) {
		return EIO;
	} else if (strstr(filename, far_eio_trigger) && offset > FAR_OFFSET_THRESHOLD) {
		return EIO;
	} else {
		return 0;
	}
}

// define functions overridden by this library

ssize_t pread(int fd, void *buf, size_t count, off_t offset) {
	int err;
	static pread_t _pread = NULL;

	err = err_on_operation(fd, "pread", offset);
	if (err) {
		errno = err;
		return -1;
	}
	if (!_pread) {
		_pread = (pread_t)dlsym(RTLD_NEXT, "pread");
	}
	return _pread(fd, buf, count, offset);
}

ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset) {
	int err;
	static pwrite_t _pwrite = NULL;

	err = err_on_operation(fd, "pwrite", offset);
	if (err) {
		errno = err;
		return -1;
	}
	if (!_pwrite) {
		_pwrite = (pwrite_t)dlsym(RTLD_NEXT, "pwrite");
	}
	return _pwrite(fd, buf, count, offset);
}

int close(int fd) {
	int err;
	static close_t _close = NULL;

	err = err_on_operation(fd, "close", 0);
	if (err) {
		errno = err;
		return -1;
	}
	if (!_close) {
		_close = (close_t)dlsym(RTLD_NEXT, "close");
	}
	return _close(fd);
}

int fsync(int fd) {
	int err;
	static fsync_t _fsync = NULL;

	err = err_on_operation(fd, "fsync", 0);
	if (err) {
		errno = err;
		return -1;
	}
	if (!_fsync) {
		_fsync = (fsync_t)dlsym(RTLD_NEXT, "fsync");
	}
	return _fsync(fd);
}