Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/fs/ceph/locks.c
15109 views
1
#include <linux/ceph/ceph_debug.h>
2
3
#include <linux/file.h>
4
#include <linux/namei.h>
5
6
#include "super.h"
7
#include "mds_client.h"
8
#include <linux/ceph/pagelist.h>
9
10
/**
11
* Implement fcntl and flock locking functions.
12
*/
13
static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file,
14
int cmd, u8 wait, struct file_lock *fl)
15
{
16
struct inode *inode = file->f_dentry->d_inode;
17
struct ceph_mds_client *mdsc =
18
ceph_sb_to_client(inode->i_sb)->mdsc;
19
struct ceph_mds_request *req;
20
int err;
21
u64 length = 0;
22
23
req = ceph_mdsc_create_request(mdsc, operation, USE_AUTH_MDS);
24
if (IS_ERR(req))
25
return PTR_ERR(req);
26
req->r_inode = inode;
27
ihold(inode);
28
29
/* mds requires start and length rather than start and end */
30
if (LLONG_MAX == fl->fl_end)
31
length = 0;
32
else
33
length = fl->fl_end - fl->fl_start + 1;
34
35
dout("ceph_lock_message: rule: %d, op: %d, pid: %llu, start: %llu, "
36
"length: %llu, wait: %d, type: %d", (int)lock_type,
37
(int)operation, (u64)fl->fl_pid, fl->fl_start,
38
length, wait, fl->fl_type);
39
40
req->r_args.filelock_change.rule = lock_type;
41
req->r_args.filelock_change.type = cmd;
42
req->r_args.filelock_change.pid = cpu_to_le64((u64)fl->fl_pid);
43
/* This should be adjusted, but I'm not sure if
44
namespaces actually get id numbers*/
45
req->r_args.filelock_change.pid_namespace =
46
cpu_to_le64((u64)(unsigned long)fl->fl_nspid);
47
req->r_args.filelock_change.start = cpu_to_le64(fl->fl_start);
48
req->r_args.filelock_change.length = cpu_to_le64(length);
49
req->r_args.filelock_change.wait = wait;
50
51
err = ceph_mdsc_do_request(mdsc, inode, req);
52
53
if ( operation == CEPH_MDS_OP_GETFILELOCK){
54
fl->fl_pid = le64_to_cpu(req->r_reply_info.filelock_reply->pid);
55
if (CEPH_LOCK_SHARED == req->r_reply_info.filelock_reply->type)
56
fl->fl_type = F_RDLCK;
57
else if (CEPH_LOCK_EXCL == req->r_reply_info.filelock_reply->type)
58
fl->fl_type = F_WRLCK;
59
else
60
fl->fl_type = F_UNLCK;
61
62
fl->fl_start = le64_to_cpu(req->r_reply_info.filelock_reply->start);
63
length = le64_to_cpu(req->r_reply_info.filelock_reply->start) +
64
le64_to_cpu(req->r_reply_info.filelock_reply->length);
65
if (length >= 1)
66
fl->fl_end = length -1;
67
else
68
fl->fl_end = 0;
69
70
}
71
ceph_mdsc_put_request(req);
72
dout("ceph_lock_message: rule: %d, op: %d, pid: %llu, start: %llu, "
73
"length: %llu, wait: %d, type: %d, err code %d", (int)lock_type,
74
(int)operation, (u64)fl->fl_pid, fl->fl_start,
75
length, wait, fl->fl_type, err);
76
return err;
77
}
78
79
/**
80
* Attempt to set an fcntl lock.
81
* For now, this just goes away to the server. Later it may be more awesome.
82
*/
83
int ceph_lock(struct file *file, int cmd, struct file_lock *fl)
84
{
85
u8 lock_cmd;
86
int err;
87
u8 wait = 0;
88
u16 op = CEPH_MDS_OP_SETFILELOCK;
89
90
fl->fl_nspid = get_pid(task_tgid(current));
91
dout("ceph_lock, fl_pid:%d", fl->fl_pid);
92
93
/* set wait bit as appropriate, then make command as Ceph expects it*/
94
if (F_SETLKW == cmd)
95
wait = 1;
96
if (F_GETLK == cmd)
97
op = CEPH_MDS_OP_GETFILELOCK;
98
99
if (F_RDLCK == fl->fl_type)
100
lock_cmd = CEPH_LOCK_SHARED;
101
else if (F_WRLCK == fl->fl_type)
102
lock_cmd = CEPH_LOCK_EXCL;
103
else
104
lock_cmd = CEPH_LOCK_UNLOCK;
105
106
err = ceph_lock_message(CEPH_LOCK_FCNTL, op, file, lock_cmd, wait, fl);
107
if (!err) {
108
if ( op != CEPH_MDS_OP_GETFILELOCK ){
109
dout("mds locked, locking locally");
110
err = posix_lock_file(file, fl, NULL);
111
if (err && (CEPH_MDS_OP_SETFILELOCK == op)) {
112
/* undo! This should only happen if
113
* the kernel detects local
114
* deadlock. */
115
ceph_lock_message(CEPH_LOCK_FCNTL, op, file,
116
CEPH_LOCK_UNLOCK, 0, fl);
117
dout("got %d on posix_lock_file, undid lock",
118
err);
119
}
120
}
121
122
} else if (err == -ERESTARTSYS) {
123
dout("undoing lock\n");
124
ceph_lock_message(CEPH_LOCK_FCNTL, op, file,
125
CEPH_LOCK_UNLOCK, 0, fl);
126
}
127
return err;
128
}
129
130
int ceph_flock(struct file *file, int cmd, struct file_lock *fl)
131
{
132
u8 lock_cmd;
133
int err;
134
u8 wait = 1;
135
136
fl->fl_nspid = get_pid(task_tgid(current));
137
dout("ceph_flock, fl_pid:%d", fl->fl_pid);
138
139
/* set wait bit, then clear it out of cmd*/
140
if (cmd & LOCK_NB)
141
wait = 0;
142
cmd = cmd & (LOCK_SH | LOCK_EX | LOCK_UN);
143
/* set command sequence that Ceph wants to see:
144
shared lock, exclusive lock, or unlock */
145
if (LOCK_SH == cmd)
146
lock_cmd = CEPH_LOCK_SHARED;
147
else if (LOCK_EX == cmd)
148
lock_cmd = CEPH_LOCK_EXCL;
149
else
150
lock_cmd = CEPH_LOCK_UNLOCK;
151
152
err = ceph_lock_message(CEPH_LOCK_FLOCK, CEPH_MDS_OP_SETFILELOCK,
153
file, lock_cmd, wait, fl);
154
if (!err) {
155
err = flock_lock_file_wait(file, fl);
156
if (err) {
157
ceph_lock_message(CEPH_LOCK_FLOCK,
158
CEPH_MDS_OP_SETFILELOCK,
159
file, CEPH_LOCK_UNLOCK, 0, fl);
160
dout("got %d on flock_lock_file_wait, undid lock", err);
161
}
162
} else if (err == -ERESTARTSYS) {
163
dout("undoing lock\n");
164
ceph_lock_message(CEPH_LOCK_FLOCK,
165
CEPH_MDS_OP_SETFILELOCK,
166
file, CEPH_LOCK_UNLOCK, 0, fl);
167
}
168
return err;
169
}
170
171
/**
172
* Must be called with BKL already held. Fills in the passed
173
* counter variables, so you can prepare pagelist metadata before calling
174
* ceph_encode_locks.
175
*/
176
void ceph_count_locks(struct inode *inode, int *fcntl_count, int *flock_count)
177
{
178
struct file_lock *lock;
179
180
*fcntl_count = 0;
181
*flock_count = 0;
182
183
for (lock = inode->i_flock; lock != NULL; lock = lock->fl_next) {
184
if (lock->fl_flags & FL_POSIX)
185
++(*fcntl_count);
186
else if (lock->fl_flags & FL_FLOCK)
187
++(*flock_count);
188
}
189
dout("counted %d flock locks and %d fcntl locks",
190
*flock_count, *fcntl_count);
191
}
192
193
/**
194
* Encode the flock and fcntl locks for the given inode into the pagelist.
195
* Format is: #fcntl locks, sequential fcntl locks, #flock locks,
196
* sequential flock locks.
197
* Must be called with lock_flocks() already held.
198
* If we encounter more of a specific lock type than expected,
199
* we return the value 1.
200
*/
201
int ceph_encode_locks(struct inode *inode, struct ceph_pagelist *pagelist,
202
int num_fcntl_locks, int num_flock_locks)
203
{
204
struct file_lock *lock;
205
struct ceph_filelock cephlock;
206
int err = 0;
207
int seen_fcntl = 0;
208
int seen_flock = 0;
209
210
dout("encoding %d flock and %d fcntl locks", num_flock_locks,
211
num_fcntl_locks);
212
err = ceph_pagelist_append(pagelist, &num_fcntl_locks, sizeof(u32));
213
if (err)
214
goto fail;
215
for (lock = inode->i_flock; lock != NULL; lock = lock->fl_next) {
216
if (lock->fl_flags & FL_POSIX) {
217
++seen_fcntl;
218
if (seen_fcntl > num_fcntl_locks) {
219
err = -ENOSPC;
220
goto fail;
221
}
222
err = lock_to_ceph_filelock(lock, &cephlock);
223
if (err)
224
goto fail;
225
err = ceph_pagelist_append(pagelist, &cephlock,
226
sizeof(struct ceph_filelock));
227
}
228
if (err)
229
goto fail;
230
}
231
232
err = ceph_pagelist_append(pagelist, &num_flock_locks, sizeof(u32));
233
if (err)
234
goto fail;
235
for (lock = inode->i_flock; lock != NULL; lock = lock->fl_next) {
236
if (lock->fl_flags & FL_FLOCK) {
237
++seen_flock;
238
if (seen_flock > num_flock_locks) {
239
err = -ENOSPC;
240
goto fail;
241
}
242
err = lock_to_ceph_filelock(lock, &cephlock);
243
if (err)
244
goto fail;
245
err = ceph_pagelist_append(pagelist, &cephlock,
246
sizeof(struct ceph_filelock));
247
}
248
if (err)
249
goto fail;
250
}
251
fail:
252
return err;
253
}
254
255
/*
256
* Given a pointer to a lock, convert it to a ceph filelock
257
*/
258
int lock_to_ceph_filelock(struct file_lock *lock,
259
struct ceph_filelock *cephlock)
260
{
261
int err = 0;
262
263
cephlock->start = cpu_to_le64(lock->fl_start);
264
cephlock->length = cpu_to_le64(lock->fl_end - lock->fl_start + 1);
265
cephlock->client = cpu_to_le64(0);
266
cephlock->pid = cpu_to_le64(lock->fl_pid);
267
cephlock->pid_namespace =
268
cpu_to_le64((u64)(unsigned long)lock->fl_nspid);
269
270
switch (lock->fl_type) {
271
case F_RDLCK:
272
cephlock->type = CEPH_LOCK_SHARED;
273
break;
274
case F_WRLCK:
275
cephlock->type = CEPH_LOCK_EXCL;
276
break;
277
case F_UNLCK:
278
cephlock->type = CEPH_LOCK_UNLOCK;
279
break;
280
default:
281
dout("Have unknown lock type %d", lock->fl_type);
282
err = -EINVAL;
283
}
284
285
return err;
286
}
287
288