Welcome to mirror list, hosted at ThFree Co, Russian Federation.

ofd_file_locks.c « static « zdtm « test - github.com/checkpoint-restore/criu.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 5b19532f8bbaa9f3ebb3461b94368b53d2651c9a (plain)
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
#include <sys/file.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>

#include "zdtmtst.h"
#include "fs.h"
#include "ofd_file_locks.h"

static int parse_ofd_lock(char *buf, struct flock *lck)
{
	char fl_flag[10], fl_type[15], fl_option[10], fl_end[32];
	long long start;
	int num;

	if (strncmp(buf, "lock:\t", 6) != 0)
		return 1; /* isn't lock, skip record */

	num = sscanf(buf,
		"%*s %*d: %s %s %s %*d %*x:%*x:%*d %lld %s",
		fl_flag, fl_type, fl_option, &start, fl_end);

	if (num < 4) {
		pr_err("Invalid lock info %s\n", buf);
		return -1;
	}
	if (strcmp(fl_flag, "OFDLCK"))
		return 1;

	lck->l_start = start;

	if (strcmp(fl_end, "EOF")) {
		unsigned long end;

		if (sscanf(fl_end, "%lu", &end) <= 0) {
			pr_err("Invalid lock entry\n");
			return -1;
		}
		lck->l_len = end - lck->l_start + 1;
	} else {
		lck->l_len = 0;
	}
	if (strcmp(fl_option, "WRITE") == 0)
		lck->l_type = F_WRLCK;
	else
		lck->l_type = F_RDLCK;

	return 0;
}

static int read_fd_ofd_lock(int pid, int fd, struct flock *lck)
{
	char path[PATH_MAX];
	char buf[100];
	int num;
	FILE *proc_file = NULL;

	sprintf(path, "/proc/%i/fdinfo/%i", pid, fd);
	proc_file = fopen(path, "r");

	if (!proc_file) {
		pr_err("Can't open %s\n", path);
		return -1;
	}

	num = -1;
	while (fgets(buf, sizeof(buf), proc_file)) {
		num = parse_ofd_lock(buf, lck);
		if (num <= 0)
			break;
	}

	if (fclose(proc_file)) {
		pr_err("Can't close %s\n", path);
		return -1;
	}
	return num;
}

int check_lock_exists(const char *filename, struct flock *lck)
{
	int ret = -1;
	int fd;

	fd = open(filename, O_RDWR, 0666);

	if (lck->l_type == F_RDLCK) {
		/* check, that there is no write lock */
		ret = zdtm_fcntl(fd, F_OFD_GETLK, lck);
		if (ret) {
			pr_err("fcntl failed (%i)\n", ret);
			goto out;
		}
		if (lck->l_type != F_UNLCK) {
			pr_err("OFD lock type do not match\n");
			goto out;
		}
	}

	/* check, that lock is set */
	lck->l_type = F_WRLCK;
	ret = zdtm_fcntl(fd, F_OFD_GETLK, lck);
	if (ret) {
		pr_err("fcntl failed (%i)\n", ret);
		goto out;
	}
	if (lck->l_type == F_UNLCK) {
		pr_err("Lock not found\n");
		goto out;
	}

	ret = 0;
out:
	if (close(fd))
		return -1;
	return ret;
}

static int check_file_locks_match(struct flock *orig_lck, struct flock *lck)
{
	return orig_lck->l_start == lck->l_start &&
		orig_lck->l_len == lck->l_len &&
		orig_lck->l_type == lck->l_type;
}

int check_file_lock_restored(int pid, int fd, struct flock *lck)
{
	struct flock lck_restored;

	if (read_fd_ofd_lock(pid, fd, &lck_restored))
		return -1;

	if (!check_file_locks_match(lck, &lck_restored)) {
		pr_err("Can't restore file lock (fd: %i)\n", fd);
		return -1;
	}
	return 0;
}

/*
 * fcntl() wrapper for ofd locks.
 *
 * Kernel requires ia32 processes to use fcntl64() syscall for ofd:
 * COMPAT_SYSCALL_DEFINE3(fcntl, [..])
 * {
 *	switch (cmd) {
 *	case F_GETLK64:
 *	case F_SETLK64:
 *	case F_SETLKW64:
 *	case F_OFD_GETLK:
 *	case F_OFD_SETLK:
 *	case F_OFD_SETLKW:
 *	return -EINVAL;
 * }
 *
 * Glibc does all the needed wraps for fcntl(), but only from v2.28.
 * To make ofd tests run on the older glibc's - provide zdtm wrap.
 *
 * Note: we don't need the wraps in CRIU itself as parasite/restorer
 * run in 64-bit mode as long as possible, including the time to play
 * with ofd (and they are dumped from CRIU).
 */
int zdtm_fcntl(int fd, int cmd, struct flock *f)
{
#if defined(__i386__)
#ifndef __NR_fcntl64
# define __NR_fcntl64 221
#endif
	struct flock64 f64 = {};
	int ret;

	switch (cmd) {
		case F_OFD_SETLK:
		case F_OFD_SETLKW:
			f64.l_type	= f->l_type;
			f64.l_whence	= f->l_whence;
			f64.l_start	= f->l_start;
			f64.l_len	= f->l_len;
			f64.l_pid	= f->l_pid;
			return syscall(__NR_fcntl64, fd, cmd, &f64);
		case F_OFD_GETLK:
			ret = syscall(__NR_fcntl64, fd, cmd, &f64);
			f->l_type	= f64.l_type;
			f->l_whence	= f64.l_whence;
			f->l_start	= f64.l_start;
			f->l_len	= f64.l_len;
			f->l_pid	= f64.l_pid;
			return ret;
		default:
			break;
	}
#endif
	return fcntl(fd, cmd, f);
}