glusterfs
443 строки · 11.4 Кб
1/*
2Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com>
3This file is part of GlusterFS.
4
5This file is licensed to you under your choice of the GNU Lesser
6General Public License, version 3 or any later version (LGPLv3 or
7later), or the GNU General Public License, version 2 (GPLv2), in all
8cases 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
15int32_t
16_fd_lk_delete_lock(fd_lk_ctx_node_t *lock)17{
18int32_t ret = -1;19
20GF_VALIDATE_OR_GOTO("fd-lk", lock, out);21
22list_del_init(&lock->next);23
24ret = 0;25out:26return ret;27}
28
29int32_t
30_fd_lk_destroy_lock(fd_lk_ctx_node_t *lock)31{
32int32_t ret = -1;33
34GF_VALIDATE_OR_GOTO("fd-lk", lock, out);35
36GF_FREE(lock);37
38ret = 0;39out:40return ret;41}
42
43int
44_fd_lk_destroy_lock_list(fd_lk_ctx_t *lk_ctx)45{
46int ret = -1;47fd_lk_ctx_node_t *lk = NULL;48fd_lk_ctx_node_t *tmp = NULL;49
50GF_VALIDATE_OR_GOTO("fd-lk", lk_ctx, out);51
52list_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}57ret = 0;58out:59return ret;60}
61
62int
63fd_lk_ctx_unref(fd_lk_ctx_t *lk_ctx)64{
65int ref = -1;66
67GF_VALIDATE_OR_GOTO("fd-lk", lk_ctx, err);68
69ref = GF_ATOMIC_DEC(lk_ctx->ref);70if (ref < 0)71GF_ASSERT(!ref);72if (ref == 0)73_fd_lk_destroy_lock_list(lk_ctx);74
75if (ref == 0) {76LOCK_DESTROY(&lk_ctx->lock);77GF_FREE(lk_ctx);78}79
80return 0;81err:82return -1;83}
84
85fd_lk_ctx_t *86fd_lk_ctx_ref(fd_lk_ctx_t *lk_ctx)87{
88if (!lk_ctx) {89gf_msg_callingfn("fd-lk", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,90"invalid argument");91return NULL;92}93
94GF_ATOMIC_INC(lk_ctx->ref);95
96return lk_ctx;97}
98
99fd_lk_ctx_t *100fd_lk_ctx_create(void)101{
102fd_lk_ctx_t *fd_lk_ctx = NULL;103
104fd_lk_ctx = GF_CALLOC(1, sizeof(fd_lk_ctx_t), gf_common_mt_fd_lk_ctx_t);105if (!fd_lk_ctx)106goto out;107
108INIT_LIST_HEAD(&fd_lk_ctx->lk_list);109
110LOCK_INIT(&fd_lk_ctx->lock);111
112fd_lk_ctx = fd_lk_ctx_ref(fd_lk_ctx);113out:114return fd_lk_ctx;115}
116
117int
118_fd_lk_insert_lock(fd_lk_ctx_t *lk_ctx, fd_lk_ctx_node_t *lock)119{
120list_add_tail(&lock->next, &lk_ctx->lk_list);121return 0;122}
123
124static off_t125_fd_lk_get_lock_len(off_t start, off_t end)126{
127if (end == LLONG_MAX)128return 0;129else130return (end - start + 1);131}
132
133static fd_lk_ctx_node_t *134fd_lk_ctx_node_new(int32_t cmd, struct gf_flock *flock)135{
136fd_lk_ctx_node_t *new_lock = NULL;137
138new_lock = GF_CALLOC(1, sizeof(fd_lk_ctx_node_t),139gf_common_mt_fd_lk_ctx_node_t);140if (caa_unlikely(!new_lock))141goto out;142
143new_lock->cmd = cmd;144
145if (flock) {146new_lock->fl_type = flock->l_type;147new_lock->fl_start = flock->l_start;148
149if (flock->l_len == 0)150new_lock->fl_end = LLONG_MAX;151else152new_lock->fl_end = flock->l_start + flock->l_len - 1;153
154gf_flock_copy(&new_lock->user_flock, flock);155}156
157INIT_LIST_HEAD(&new_lock->next);158out:159return new_lock;160}
161
162int32_t
163_fd_lk_delete_unlck_locks(fd_lk_ctx_t *lk_ctx)164{
165int32_t ret = -1;166fd_lk_ctx_node_t *tmp = NULL;167fd_lk_ctx_node_t *lk = NULL;168
169GF_VALIDATE_OR_GOTO("fd-lk", lk_ctx, out);170
171list_for_each_entry_safe(lk, tmp, &lk_ctx->lk_list, next)172{173if (lk->fl_type == F_UNLCK) {174_fd_lk_delete_lock(lk);175_fd_lk_destroy_lock(lk);176}177}178out:179return ret;180}
181
182int
183fd_lk_overlap(fd_lk_ctx_node_t *l1, fd_lk_ctx_node_t *l2)184{
185if (l1->fl_end >= l2->fl_start && l2->fl_end >= l1->fl_start)186return 1;187
188return 0;189}
190
191static fd_lk_ctx_node_t *192_fd_lk_add_locks(fd_lk_ctx_node_t *l1, fd_lk_ctx_node_t *l2)193{
194fd_lk_ctx_node_t *sum = NULL;195
196sum = fd_lk_ctx_node_new(0, NULL);197if (caa_unlikely(!sum))198goto out;199
200sum->fl_start = min(l1->fl_start, l2->fl_start);201sum->fl_end = max(l1->fl_end, l2->fl_end);202
203sum->user_flock.l_start = sum->fl_start;204sum->user_flock.l_len = _fd_lk_get_lock_len(sum->fl_start, sum->fl_end);205out:206return sum;207}
208
209/* Subtract two locks */
210struct _values {211fd_lk_ctx_node_t *locks[3];212};213
214static int32_t215_fd_lk_sub_locks(struct _values *v, fd_lk_ctx_node_t *big,216fd_lk_ctx_node_t *small)217{
218int32_t ret = -1;219
220if ((big->fl_start == small->fl_start) && (big->fl_end == small->fl_end)) {221/* both edges coincide with big */222v->locks[0] = GF_MALLOC(sizeof(fd_lk_ctx_node_t),223gf_common_mt_fd_lk_ctx_node_t);224if (!v->locks[0])225goto out;226
227memcpy(v->locks[0], big, sizeof(fd_lk_ctx_node_t));228
229v->locks[0]->fl_type = small->fl_type;230v->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,234break it down into 3 different locks. */
235v->locks[0] = GF_MALLOC(sizeof(fd_lk_ctx_node_t),236gf_common_mt_fd_lk_ctx_node_t);237if (!v->locks[0])238goto out;239
240v->locks[1] = GF_MALLOC(sizeof(fd_lk_ctx_node_t),241gf_common_mt_fd_lk_ctx_node_t);242if (!v->locks[1])243goto out;244
245v->locks[2] = GF_MALLOC(sizeof(fd_lk_ctx_node_t),246gf_common_mt_fd_lk_ctx_node_t);247if (!v->locks[2])248goto out;249
250memcpy(v->locks[0], big, sizeof(fd_lk_ctx_node_t));251v->locks[0]->fl_end = small->fl_start - 1;252v->locks[0]->user_flock.l_len = _fd_lk_get_lock_len(253v->locks[0]->fl_start, v->locks[0]->fl_end);254
255memcpy(v->locks[1], small, sizeof(fd_lk_ctx_node_t));256
257memcpy(v->locks[2], big, sizeof(fd_lk_ctx_node_t));258v->locks[2]->fl_start = small->fl_end + 1;259v->locks[2]->user_flock.l_len = _fd_lk_get_lock_len(260v->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 the263locks into two separate parts */
264v->locks[0] = GF_MALLOC(sizeof(fd_lk_ctx_node_t),265gf_common_mt_fd_lk_ctx_node_t);266if (!v->locks[0])267goto out;268
269v->locks[1] = GF_MALLOC(sizeof(fd_lk_ctx_node_t),270gf_common_mt_fd_lk_ctx_node_t);271if (!v->locks[1])272goto out;273
274memcpy(v->locks[0], small, sizeof(fd_lk_ctx_node_t));275
276memcpy(v->locks[1], big, sizeof(fd_lk_ctx_node_t));277v->locks[1]->fl_start = small->fl_end + 1;278v->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 the281locks into two separate parts */
282v->locks[0] = GF_MALLOC(sizeof(fd_lk_ctx_node_t),283gf_common_mt_fd_lk_ctx_node_t);284if (!v->locks[0])285goto out;286
287v->locks[1] = GF_MALLOC(sizeof(fd_lk_ctx_node_t),288gf_common_mt_fd_lk_ctx_node_t);289if (!v->locks[1])290goto out;291
292memcpy(v->locks[0], big, sizeof(fd_lk_ctx_node_t));293v->locks[0]->fl_end = small->fl_start - 1;294v->locks[0]->user_flock.l_len = _fd_lk_get_lock_len(295v->locks[0]->fl_start, v->locks[0]->fl_end);296
297memcpy(v->locks[1], small, sizeof(fd_lk_ctx_node_t));298} else {299/* We should never come to this case */300GF_ASSERT(!"Invalid case");301}302ret = 0;303out:304return ret;305}
306
307static void308_fd_lk_insert_and_merge(fd_lk_ctx_t *lk_ctx, fd_lk_ctx_node_t *lock)309{
310int32_t ret = -1;311int32_t i = 0;312fd_lk_ctx_node_t *entry = NULL;313fd_lk_ctx_node_t *t = NULL;314fd_lk_ctx_node_t *sum = NULL;315struct _values v = {.locks = {0, 0, 0}};316
317list_for_each_entry_safe(entry, t, &lk_ctx->lk_list, next)318{319if (!fd_lk_overlap(entry, lock))320continue;321
322if (entry->fl_type == lock->fl_type) {323sum = _fd_lk_add_locks(entry, lock);324if (!sum)325return;326sum->fl_type = entry->fl_type;327sum->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);332return;333} else {334sum = _fd_lk_add_locks(entry, lock);335sum->fl_type = lock->fl_type;336sum->user_flock.l_type = lock->fl_type;337ret = _fd_lk_sub_locks(&v, sum, lock);338if (ret)339return;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
348for (i = 0; i < 3; i++) {349if (!v.locks[i])350continue;351
352INIT_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);356return;357}358}359
360/* no conflicts, so just insert */361if (lock->fl_type != F_UNLCK) {362_fd_lk_insert_lock(lk_ctx, lock);363} else {364_fd_lk_destroy_lock(lock);365}366}
367
368static void369print_lock_list(fd_lk_ctx_t *lk_ctx)370{
371fd_lk_ctx_node_t *lk = NULL;372
373gf_msg_debug("fd-lk", 0, "lock list:");374
375list_for_each_entry(lk, &lk_ctx->lk_list, next)376gf_msg_debug("fd-lk", 0,377"owner = %s, cmd = %s fl_type = %s,"378" fs_start = %" PRId64 ", fs_end = %" PRId64379", "380"user_flock: l_type = %s, l_start = %" PRId64381", "382"l_len = %" PRId64 ", ",383lkowner_utoa(&lk->user_flock.l_owner), get_lk_cmd(lk->cmd),384get_lk_type(lk->fl_type), lk->fl_start, lk->fl_end,385get_lk_type(lk->user_flock.l_type), lk->user_flock.l_start,386lk->user_flock.l_len);387}
388
389int
390fd_lk_insert_and_merge(fd_t *fd, int32_t cmd, struct gf_flock *flock)391{
392int32_t ret = -1;393fd_lk_ctx_t *lk_ctx = NULL;394fd_lk_ctx_node_t *lk = NULL;395
396GF_VALIDATE_OR_GOTO("fd-lk", fd, out);397GF_VALIDATE_OR_GOTO("fd-lk", flock, out);398
399lk_ctx = fd_lk_ctx_ref(fd->lk_ctx);400lk = fd_lk_ctx_node_new(cmd, flock);401
402if (caa_unlikely(lk == NULL))403goto out;404
405gf_msg_debug("fd-lk", 0,406"new lock request: owner = %s, fl_type = %s"407", fs_start = %" PRId64 ", fs_end = %" PRId64408", user_flock:"409" l_type = %s, l_start = %" PRId64 ", l_len = %" PRId64,410lkowner_utoa(&flock->l_owner), get_lk_type(lk->fl_type),411lk->fl_start, lk->fl_end, get_lk_type(lk->user_flock.l_type),412lk->user_flock.l_start, lk->user_flock.l_len);413
414LOCK(&lk_ctx->lock);415{416_fd_lk_insert_and_merge(lk_ctx, lk);417print_lock_list(lk_ctx);418}419UNLOCK(&lk_ctx->lock);420
421fd_lk_ctx_unref(lk_ctx);422
423ret = 0;424out:425return ret;426}
427
428gf_boolean_t
429fd_lk_ctx_empty(fd_lk_ctx_t *lk_ctx)430{
431gf_boolean_t verdict = _gf_true;432
433if (!lk_ctx)434return _gf_true;435
436LOCK(&lk_ctx->lock);437{438verdict = list_empty(&lk_ctx->lk_list);439}440UNLOCK(&lk_ctx->lock);441
442return verdict;443}
444