glusterfs

Форк
0
443 строки · 11.4 Кб
1
/*
2
  Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com>
3
  This file is part of GlusterFS.
4

5
  This file is licensed to you under your choice of the GNU Lesser
6
  General Public License, version 3 or any later version (LGPLv3 or
7
  later), or the GNU General Public License, version 2 (GPLv2), in all
8
  cases as published by the Free Software Foundation.
9
*/
10

11
#include "glusterfs/fd.h"
12
#include "glusterfs/fd-lk.h"
13
#include "glusterfs/libglusterfs-messages.h"
14

15
int32_t
16
_fd_lk_delete_lock(fd_lk_ctx_node_t *lock)
17
{
18
    int32_t ret = -1;
19

20
    GF_VALIDATE_OR_GOTO("fd-lk", lock, out);
21

22
    list_del_init(&lock->next);
23

24
    ret = 0;
25
out:
26
    return ret;
27
}
28

29
int32_t
30
_fd_lk_destroy_lock(fd_lk_ctx_node_t *lock)
31
{
32
    int32_t ret = -1;
33

34
    GF_VALIDATE_OR_GOTO("fd-lk", lock, out);
35

36
    GF_FREE(lock);
37

38
    ret = 0;
39
out:
40
    return ret;
41
}
42

43
int
44
_fd_lk_destroy_lock_list(fd_lk_ctx_t *lk_ctx)
45
{
46
    int ret = -1;
47
    fd_lk_ctx_node_t *lk = NULL;
48
    fd_lk_ctx_node_t *tmp = NULL;
49

50
    GF_VALIDATE_OR_GOTO("fd-lk", lk_ctx, out);
51

52
    list_for_each_entry_safe(lk, tmp, &lk_ctx->lk_list, next)
53
    {
54
        _fd_lk_delete_lock(lk);
55
        _fd_lk_destroy_lock(lk);
56
    }
57
    ret = 0;
58
out:
59
    return ret;
60
}
61

62
int
63
fd_lk_ctx_unref(fd_lk_ctx_t *lk_ctx)
64
{
65
    int ref = -1;
66

67
    GF_VALIDATE_OR_GOTO("fd-lk", lk_ctx, err);
68

69
    ref = GF_ATOMIC_DEC(lk_ctx->ref);
70
    if (ref < 0)
71
        GF_ASSERT(!ref);
72
    if (ref == 0)
73
        _fd_lk_destroy_lock_list(lk_ctx);
74

75
    if (ref == 0) {
76
        LOCK_DESTROY(&lk_ctx->lock);
77
        GF_FREE(lk_ctx);
78
    }
79

80
    return 0;
81
err:
82
    return -1;
83
}
84

85
fd_lk_ctx_t *
86
fd_lk_ctx_ref(fd_lk_ctx_t *lk_ctx)
87
{
88
    if (!lk_ctx) {
89
        gf_msg_callingfn("fd-lk", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
90
                         "invalid argument");
91
        return NULL;
92
    }
93

94
    GF_ATOMIC_INC(lk_ctx->ref);
95

96
    return lk_ctx;
97
}
98

99
fd_lk_ctx_t *
100
fd_lk_ctx_create(void)
101
{
102
    fd_lk_ctx_t *fd_lk_ctx = NULL;
103

104
    fd_lk_ctx = GF_CALLOC(1, sizeof(fd_lk_ctx_t), gf_common_mt_fd_lk_ctx_t);
105
    if (!fd_lk_ctx)
106
        goto out;
107

108
    INIT_LIST_HEAD(&fd_lk_ctx->lk_list);
109

110
    LOCK_INIT(&fd_lk_ctx->lock);
111

112
    fd_lk_ctx = fd_lk_ctx_ref(fd_lk_ctx);
113
out:
114
    return fd_lk_ctx;
115
}
116

117
int
118
_fd_lk_insert_lock(fd_lk_ctx_t *lk_ctx, fd_lk_ctx_node_t *lock)
119
{
120
    list_add_tail(&lock->next, &lk_ctx->lk_list);
121
    return 0;
122
}
123

124
static off_t
125
_fd_lk_get_lock_len(off_t start, off_t end)
126
{
127
    if (end == LLONG_MAX)
128
        return 0;
129
    else
130
        return (end - start + 1);
131
}
132

133
static fd_lk_ctx_node_t *
134
fd_lk_ctx_node_new(int32_t cmd, struct gf_flock *flock)
135
{
136
    fd_lk_ctx_node_t *new_lock = NULL;
137

138
    new_lock = GF_CALLOC(1, sizeof(fd_lk_ctx_node_t),
139
                         gf_common_mt_fd_lk_ctx_node_t);
140
    if (caa_unlikely(!new_lock))
141
        goto out;
142

143
    new_lock->cmd = cmd;
144

145
    if (flock) {
146
        new_lock->fl_type = flock->l_type;
147
        new_lock->fl_start = flock->l_start;
148

149
        if (flock->l_len == 0)
150
            new_lock->fl_end = LLONG_MAX;
151
        else
152
            new_lock->fl_end = flock->l_start + flock->l_len - 1;
153

154
        gf_flock_copy(&new_lock->user_flock, flock);
155
    }
156

157
    INIT_LIST_HEAD(&new_lock->next);
158
out:
159
    return new_lock;
160
}
161

162
int32_t
163
_fd_lk_delete_unlck_locks(fd_lk_ctx_t *lk_ctx)
164
{
165
    int32_t ret = -1;
166
    fd_lk_ctx_node_t *tmp = NULL;
167
    fd_lk_ctx_node_t *lk = NULL;
168

169
    GF_VALIDATE_OR_GOTO("fd-lk", lk_ctx, out);
170

171
    list_for_each_entry_safe(lk, tmp, &lk_ctx->lk_list, next)
172
    {
173
        if (lk->fl_type == F_UNLCK) {
174
            _fd_lk_delete_lock(lk);
175
            _fd_lk_destroy_lock(lk);
176
        }
177
    }
178
out:
179
    return ret;
180
}
181

182
int
183
fd_lk_overlap(fd_lk_ctx_node_t *l1, fd_lk_ctx_node_t *l2)
184
{
185
    if (l1->fl_end >= l2->fl_start && l2->fl_end >= l1->fl_start)
186
        return 1;
187

188
    return 0;
189
}
190

191
static fd_lk_ctx_node_t *
192
_fd_lk_add_locks(fd_lk_ctx_node_t *l1, fd_lk_ctx_node_t *l2)
193
{
194
    fd_lk_ctx_node_t *sum = NULL;
195

196
    sum = fd_lk_ctx_node_new(0, NULL);
197
    if (caa_unlikely(!sum))
198
        goto out;
199

200
    sum->fl_start = min(l1->fl_start, l2->fl_start);
201
    sum->fl_end = max(l1->fl_end, l2->fl_end);
202

203
    sum->user_flock.l_start = sum->fl_start;
204
    sum->user_flock.l_len = _fd_lk_get_lock_len(sum->fl_start, sum->fl_end);
205
out:
206
    return sum;
207
}
208

209
/* Subtract two locks */
210
struct _values {
211
    fd_lk_ctx_node_t *locks[3];
212
};
213

214
static int32_t
215
_fd_lk_sub_locks(struct _values *v, fd_lk_ctx_node_t *big,
216
                 fd_lk_ctx_node_t *small)
217
{
218
    int32_t ret = -1;
219

220
    if ((big->fl_start == small->fl_start) && (big->fl_end == small->fl_end)) {
221
        /* both edges coincide with big */
222
        v->locks[0] = GF_MALLOC(sizeof(fd_lk_ctx_node_t),
223
                                gf_common_mt_fd_lk_ctx_node_t);
224
        if (!v->locks[0])
225
            goto out;
226

227
        memcpy(v->locks[0], big, sizeof(fd_lk_ctx_node_t));
228

229
        v->locks[0]->fl_type = small->fl_type;
230
        v->locks[0]->user_flock.l_type = small->fl_type;
231
    } else if ((small->fl_start > big->fl_start) &&
232
               (small->fl_end < big->fl_end)) {
233
        /* small lock is completely inside big lock,
234
           break it down into 3 different locks. */
235
        v->locks[0] = GF_MALLOC(sizeof(fd_lk_ctx_node_t),
236
                                gf_common_mt_fd_lk_ctx_node_t);
237
        if (!v->locks[0])
238
            goto out;
239

240
        v->locks[1] = GF_MALLOC(sizeof(fd_lk_ctx_node_t),
241
                                gf_common_mt_fd_lk_ctx_node_t);
242
        if (!v->locks[1])
243
            goto out;
244

245
        v->locks[2] = GF_MALLOC(sizeof(fd_lk_ctx_node_t),
246
                                gf_common_mt_fd_lk_ctx_node_t);
247
        if (!v->locks[2])
248
            goto out;
249

250
        memcpy(v->locks[0], big, sizeof(fd_lk_ctx_node_t));
251
        v->locks[0]->fl_end = small->fl_start - 1;
252
        v->locks[0]->user_flock.l_len = _fd_lk_get_lock_len(
253
            v->locks[0]->fl_start, v->locks[0]->fl_end);
254

255
        memcpy(v->locks[1], small, sizeof(fd_lk_ctx_node_t));
256

257
        memcpy(v->locks[2], big, sizeof(fd_lk_ctx_node_t));
258
        v->locks[2]->fl_start = small->fl_end + 1;
259
        v->locks[2]->user_flock.l_len = _fd_lk_get_lock_len(
260
            v->locks[2]->fl_start, v->locks[2]->fl_end);
261
    } else if (small->fl_start == big->fl_start) {
262
        /* One of the ends co-incide, break the
263
           locks into two separate parts */
264
        v->locks[0] = GF_MALLOC(sizeof(fd_lk_ctx_node_t),
265
                                gf_common_mt_fd_lk_ctx_node_t);
266
        if (!v->locks[0])
267
            goto out;
268

269
        v->locks[1] = GF_MALLOC(sizeof(fd_lk_ctx_node_t),
270
                                gf_common_mt_fd_lk_ctx_node_t);
271
        if (!v->locks[1])
272
            goto out;
273

274
        memcpy(v->locks[0], small, sizeof(fd_lk_ctx_node_t));
275

276
        memcpy(v->locks[1], big, sizeof(fd_lk_ctx_node_t));
277
        v->locks[1]->fl_start = small->fl_end + 1;
278
        v->locks[1]->user_flock.l_start = small->fl_end + 1;
279
    } else if (small->fl_end == big->fl_end) {
280
        /* One of the ends co-incide, break the
281
           locks into two separate parts */
282
        v->locks[0] = GF_MALLOC(sizeof(fd_lk_ctx_node_t),
283
                                gf_common_mt_fd_lk_ctx_node_t);
284
        if (!v->locks[0])
285
            goto out;
286

287
        v->locks[1] = GF_MALLOC(sizeof(fd_lk_ctx_node_t),
288
                                gf_common_mt_fd_lk_ctx_node_t);
289
        if (!v->locks[1])
290
            goto out;
291

292
        memcpy(v->locks[0], big, sizeof(fd_lk_ctx_node_t));
293
        v->locks[0]->fl_end = small->fl_start - 1;
294
        v->locks[0]->user_flock.l_len = _fd_lk_get_lock_len(
295
            v->locks[0]->fl_start, v->locks[0]->fl_end);
296

297
        memcpy(v->locks[1], small, sizeof(fd_lk_ctx_node_t));
298
    } else {
299
        /* We should never come to this case */
300
        GF_ASSERT(!"Invalid case");
301
    }
302
    ret = 0;
303
out:
304
    return ret;
305
}
306

307
static void
308
_fd_lk_insert_and_merge(fd_lk_ctx_t *lk_ctx, fd_lk_ctx_node_t *lock)
309
{
310
    int32_t ret = -1;
311
    int32_t i = 0;
312
    fd_lk_ctx_node_t *entry = NULL;
313
    fd_lk_ctx_node_t *t = NULL;
314
    fd_lk_ctx_node_t *sum = NULL;
315
    struct _values v = {.locks = {0, 0, 0}};
316

317
    list_for_each_entry_safe(entry, t, &lk_ctx->lk_list, next)
318
    {
319
        if (!fd_lk_overlap(entry, lock))
320
            continue;
321

322
        if (entry->fl_type == lock->fl_type) {
323
            sum = _fd_lk_add_locks(entry, lock);
324
            if (!sum)
325
                return;
326
            sum->fl_type = entry->fl_type;
327
            sum->user_flock.l_type = entry->fl_type;
328
            _fd_lk_delete_lock(entry);
329
            _fd_lk_destroy_lock(entry);
330
            _fd_lk_destroy_lock(lock);
331
            _fd_lk_insert_and_merge(lk_ctx, sum);
332
            return;
333
        } else {
334
            sum = _fd_lk_add_locks(entry, lock);
335
            sum->fl_type = lock->fl_type;
336
            sum->user_flock.l_type = lock->fl_type;
337
            ret = _fd_lk_sub_locks(&v, sum, lock);
338
            if (ret)
339
                return;
340
            _fd_lk_delete_lock(entry);
341
            _fd_lk_destroy_lock(entry);
342

343
            _fd_lk_delete_lock(lock);
344
            _fd_lk_destroy_lock(lock);
345

346
            _fd_lk_destroy_lock(sum);
347

348
            for (i = 0; i < 3; i++) {
349
                if (!v.locks[i])
350
                    continue;
351

352
                INIT_LIST_HEAD(&v.locks[i]->next);
353
                _fd_lk_insert_and_merge(lk_ctx, v.locks[i]);
354
            }
355
            _fd_lk_delete_unlck_locks(lk_ctx);
356
            return;
357
        }
358
    }
359

360
    /* no conflicts, so just insert */
361
    if (lock->fl_type != F_UNLCK) {
362
        _fd_lk_insert_lock(lk_ctx, lock);
363
    } else {
364
        _fd_lk_destroy_lock(lock);
365
    }
366
}
367

368
static void
369
print_lock_list(fd_lk_ctx_t *lk_ctx)
370
{
371
    fd_lk_ctx_node_t *lk = NULL;
372

373
    gf_msg_debug("fd-lk", 0, "lock list:");
374

375
    list_for_each_entry(lk, &lk_ctx->lk_list, next)
376
        gf_msg_debug("fd-lk", 0,
377
                     "owner = %s, cmd = %s fl_type = %s,"
378
                     " fs_start = %" PRId64 ", fs_end = %" PRId64
379
                     ", "
380
                     "user_flock: l_type = %s, l_start = %" PRId64
381
                     ", "
382
                     "l_len = %" PRId64 ", ",
383
                     lkowner_utoa(&lk->user_flock.l_owner), get_lk_cmd(lk->cmd),
384
                     get_lk_type(lk->fl_type), lk->fl_start, lk->fl_end,
385
                     get_lk_type(lk->user_flock.l_type), lk->user_flock.l_start,
386
                     lk->user_flock.l_len);
387
}
388

389
int
390
fd_lk_insert_and_merge(fd_t *fd, int32_t cmd, struct gf_flock *flock)
391
{
392
    int32_t ret = -1;
393
    fd_lk_ctx_t *lk_ctx = NULL;
394
    fd_lk_ctx_node_t *lk = NULL;
395

396
    GF_VALIDATE_OR_GOTO("fd-lk", fd, out);
397
    GF_VALIDATE_OR_GOTO("fd-lk", flock, out);
398

399
    lk_ctx = fd_lk_ctx_ref(fd->lk_ctx);
400
    lk = fd_lk_ctx_node_new(cmd, flock);
401

402
    if (caa_unlikely(lk == NULL))
403
        goto out;
404

405
    gf_msg_debug("fd-lk", 0,
406
                 "new lock request: owner = %s, fl_type = %s"
407
                 ", fs_start = %" PRId64 ", fs_end = %" PRId64
408
                 ", user_flock:"
409
                 " l_type = %s, l_start = %" PRId64 ", l_len = %" PRId64,
410
                 lkowner_utoa(&flock->l_owner), get_lk_type(lk->fl_type),
411
                 lk->fl_start, lk->fl_end, get_lk_type(lk->user_flock.l_type),
412
                 lk->user_flock.l_start, lk->user_flock.l_len);
413

414
    LOCK(&lk_ctx->lock);
415
    {
416
        _fd_lk_insert_and_merge(lk_ctx, lk);
417
        print_lock_list(lk_ctx);
418
    }
419
    UNLOCK(&lk_ctx->lock);
420

421
    fd_lk_ctx_unref(lk_ctx);
422

423
    ret = 0;
424
out:
425
    return ret;
426
}
427

428
gf_boolean_t
429
fd_lk_ctx_empty(fd_lk_ctx_t *lk_ctx)
430
{
431
    gf_boolean_t verdict = _gf_true;
432

433
    if (!lk_ctx)
434
        return _gf_true;
435

436
    LOCK(&lk_ctx->lock);
437
    {
438
        verdict = list_empty(&lk_ctx->lk_list);
439
    }
440
    UNLOCK(&lk_ctx->lock);
441

442
    return verdict;
443
}
444

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.