"Fossies" - the Fresh Open Source Software Archive

Member "glusterfs-8.6/xlators/protocol/client/src/client-lk.c" (20 Aug 2021, 14228 Bytes) of package /linux/misc/glusterfs-8.6.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "client-lk.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 8.5_vs_8.6.

    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/common-utils.h>
   12 #include <glusterfs/xlator.h>
   13 #include "client.h"
   14 #include <glusterfs/lkowner.h>
   15 #include "client-messages.h"
   16 
   17 static void
   18 __insert_and_merge(clnt_fd_ctx_t *fdctx, client_posix_lock_t *lock);
   19 
   20 static void
   21 __dump_client_lock(client_posix_lock_t *lock)
   22 {
   23     xlator_t *this = NULL;
   24 
   25     this = THIS;
   26 
   27     gf_smsg(
   28         this->name, GF_LOG_INFO, 0, PC_MSG_CLIENT_LOCK_INFO, "fd=%p", lock->fd,
   29         "fl_type=%s", lock->fl_type == F_WRLCK ? "Write-Lock" : "Read-Lock",
   30         "lk-owner=%s", lkowner_utoa(&lock->owner), "l_start=%" PRId64,
   31         lock->user_flock.l_start, "l_len=%" PRId64, lock->user_flock.l_len,
   32         "start=%" PRId64, lock->fl_start, "end=%" PRId64, lock->fl_end, NULL);
   33 }
   34 
   35 static int
   36 dump_client_locks_fd(clnt_fd_ctx_t *fdctx)
   37 {
   38     client_posix_lock_t *lock = NULL;
   39     int count = 0;
   40 
   41     list_for_each_entry(lock, &fdctx->lock_list, list)
   42     {
   43         __dump_client_lock(lock);
   44         count++;
   45     }
   46 
   47     return count;
   48 }
   49 
   50 int
   51 dump_client_locks(inode_t *inode)
   52 {
   53     fd_t *fd = NULL;
   54     xlator_t *this = NULL;
   55     clnt_fd_ctx_t *fdctx = NULL;
   56     clnt_conf_t *conf = NULL;
   57 
   58     int total_count = 0;
   59     int locks_fd_count = 0;
   60 
   61     this = THIS;
   62     conf = this->private;
   63 
   64     LOCK(&inode->lock);
   65     {
   66         list_for_each_entry(fd, &inode->fd_list, inode_list)
   67         {
   68             locks_fd_count = 0;
   69 
   70             pthread_spin_lock(&conf->fd_lock);
   71             fdctx = this_fd_get_ctx(fd, this);
   72             if (fdctx)
   73                 locks_fd_count = dump_client_locks_fd(fdctx);
   74             pthread_spin_unlock(&conf->fd_lock);
   75 
   76             total_count += locks_fd_count;
   77         }
   78     }
   79     UNLOCK(&inode->lock);
   80 
   81     return total_count;
   82 }
   83 
   84 static off_t
   85 __get_lock_length(off_t start, off_t end)
   86 {
   87     if (end == LLONG_MAX)
   88         return 0;
   89     else
   90         return (end - start + 1);
   91 }
   92 
   93 /* Add two locks */
   94 static client_posix_lock_t *
   95 add_locks(client_posix_lock_t *l1, client_posix_lock_t *l2)
   96 {
   97     client_posix_lock_t *sum = NULL;
   98 
   99     sum = GF_CALLOC(1, sizeof(*sum), gf_client_mt_clnt_lock_t);
  100     if (!sum)
  101         return NULL;
  102     INIT_LIST_HEAD(&sum->list);
  103 
  104     sum->fl_start = min(l1->fl_start, l2->fl_start);
  105     sum->fl_end = max(l1->fl_end, l2->fl_end);
  106 
  107     sum->user_flock.l_start = sum->fl_start;
  108     sum->user_flock.l_len = __get_lock_length(sum->fl_start, sum->fl_end);
  109 
  110     return sum;
  111 }
  112 
  113 /* Return true if the locks overlap, false otherwise */
  114 static int
  115 locks_overlap(client_posix_lock_t *l1, client_posix_lock_t *l2)
  116 {
  117     /*
  118        Note:
  119        FUSE always gives us absolute offsets, so no need to worry
  120        about SEEK_CUR or SEEK_END
  121     */
  122 
  123     return ((l1->fl_end >= l2->fl_start) && (l2->fl_end >= l1->fl_start));
  124 }
  125 
  126 static void
  127 __delete_client_lock(client_posix_lock_t *lock)
  128 {
  129     list_del_init(&lock->list);
  130 }
  131 
  132 /* Destroy a posix_lock */
  133 static void
  134 __destroy_client_lock(client_posix_lock_t *lock)
  135 {
  136     GF_FREE(lock);
  137 }
  138 
  139 /* Subtract two locks */
  140 struct _values {
  141     client_posix_lock_t *locks[3];
  142 };
  143 
  144 /* {big} must always be contained inside {small} */
  145 static struct _values
  146 subtract_locks(client_posix_lock_t *big, client_posix_lock_t *small)
  147 {
  148     struct _values v = {.locks = {0, 0, 0}};
  149 
  150     if ((big->fl_start == small->fl_start) && (big->fl_end == small->fl_end)) {
  151         /* both edges coincide with big */
  152         v.locks[0] = GF_MALLOC(sizeof(client_posix_lock_t),
  153                                gf_client_mt_clnt_lock_t);
  154         GF_ASSERT(v.locks[0]);
  155         memcpy(v.locks[0], big, sizeof(client_posix_lock_t));
  156         v.locks[0]->fl_type = small->fl_type;
  157     } else if ((small->fl_start > big->fl_start) &&
  158                (small->fl_end < big->fl_end)) {
  159         /* both edges lie inside big */
  160         v.locks[0] = GF_MALLOC(sizeof(client_posix_lock_t),
  161                                gf_client_mt_clnt_lock_t);
  162         GF_ASSERT(v.locks[0]);
  163         memcpy(v.locks[0], big, sizeof(client_posix_lock_t));
  164         v.locks[0]->fl_end = small->fl_start - 1;
  165         v.locks[0]->user_flock.l_len = __get_lock_length(v.locks[0]->fl_start,
  166                                                          v.locks[0]->fl_end);
  167         v.locks[1] = GF_MALLOC(sizeof(client_posix_lock_t),
  168                                gf_client_mt_clnt_lock_t);
  169         GF_ASSERT(v.locks[1]);
  170         memcpy(v.locks[1], small, sizeof(client_posix_lock_t));
  171         v.locks[2] = GF_MALLOC(sizeof(client_posix_lock_t),
  172                                gf_client_mt_clnt_lock_t);
  173         GF_ASSERT(v.locks[2]);
  174         memcpy(v.locks[2], big, sizeof(client_posix_lock_t));
  175         v.locks[2]->fl_start = small->fl_end + 1;
  176         v.locks[2]->user_flock.l_start = small->fl_end + 1;
  177     }
  178     /* one edge coincides with big */
  179     else if (small->fl_start == big->fl_start) {
  180         v.locks[0] = GF_MALLOC(sizeof(client_posix_lock_t),
  181                                gf_client_mt_clnt_lock_t);
  182         GF_ASSERT(v.locks[0]);
  183         memcpy(v.locks[0], big, sizeof(client_posix_lock_t));
  184         v.locks[0]->fl_start = small->fl_end + 1;
  185         v.locks[0]->user_flock.l_start = small->fl_end + 1;
  186         v.locks[1] = GF_MALLOC(sizeof(client_posix_lock_t),
  187                                gf_client_mt_clnt_lock_t);
  188         GF_ASSERT(v.locks[1]);
  189         memcpy(v.locks[1], small, sizeof(client_posix_lock_t));
  190     } else if (small->fl_end == big->fl_end) {
  191         v.locks[0] = GF_MALLOC(sizeof(client_posix_lock_t),
  192                                gf_client_mt_clnt_lock_t);
  193         GF_ASSERT(v.locks[0]);
  194         memcpy(v.locks[0], big, sizeof(client_posix_lock_t));
  195         v.locks[0]->fl_end = small->fl_start - 1;
  196         v.locks[0]->user_flock.l_len = __get_lock_length(v.locks[0]->fl_start,
  197                                                          v.locks[0]->fl_end);
  198 
  199         v.locks[1] = GF_MALLOC(sizeof(client_posix_lock_t),
  200                                gf_client_mt_clnt_lock_t);
  201         GF_ASSERT(v.locks[1]);
  202         memcpy(v.locks[1], small, sizeof(client_posix_lock_t));
  203     } else {
  204         /* LOG-TODO : decide what more info is required here*/
  205         gf_smsg("client-protocol", GF_LOG_CRITICAL, 0, PC_MSG_LOCK_ERROR, NULL);
  206     }
  207 
  208     return v;
  209 }
  210 
  211 static void
  212 __delete_unlck_locks(clnt_fd_ctx_t *fdctx)
  213 {
  214     client_posix_lock_t *l = NULL;
  215     client_posix_lock_t *tmp = NULL;
  216 
  217     list_for_each_entry_safe(l, tmp, &fdctx->lock_list, list)
  218     {
  219         if (l->fl_type == F_UNLCK) {
  220             __delete_client_lock(l);
  221             __destroy_client_lock(l);
  222         }
  223     }
  224 }
  225 
  226 static void
  227 __insert_lock(clnt_fd_ctx_t *fdctx, client_posix_lock_t *lock)
  228 {
  229     list_add_tail(&lock->list, &fdctx->lock_list);
  230 
  231     return;
  232 }
  233 
  234 static void
  235 __insert_and_merge(clnt_fd_ctx_t *fdctx, client_posix_lock_t *lock)
  236 {
  237     client_posix_lock_t *conf = NULL;
  238     client_posix_lock_t *t = NULL;
  239     client_posix_lock_t *sum = NULL;
  240     int i = 0;
  241     struct _values v = {.locks = {0, 0, 0}};
  242 
  243     list_for_each_entry_safe(conf, t, &fdctx->lock_list, list)
  244     {
  245         if (!locks_overlap(conf, lock))
  246             continue;
  247 
  248         if (is_same_lkowner(&conf->owner, &lock->owner)) {
  249             if (conf->fl_type == lock->fl_type) {
  250                 sum = add_locks(lock, conf);
  251 
  252                 sum->fd = lock->fd;
  253                 sum->owner = conf->owner;
  254 
  255                 __delete_client_lock(conf);
  256                 __destroy_client_lock(conf);
  257 
  258                 __destroy_client_lock(lock);
  259                 __insert_and_merge(fdctx, sum);
  260 
  261                 return;
  262             } else {
  263                 sum = add_locks(lock, conf);
  264 
  265                 sum->fd = conf->fd;
  266                 sum->owner = conf->owner;
  267 
  268                 v = subtract_locks(sum, lock);
  269 
  270                 __delete_client_lock(conf);
  271                 __destroy_client_lock(conf);
  272 
  273                 __delete_client_lock(lock);
  274                 __destroy_client_lock(lock);
  275 
  276                 __destroy_client_lock(sum);
  277 
  278                 for (i = 0; i < 3; i++) {
  279                     if (!v.locks[i])
  280                         continue;
  281 
  282                     INIT_LIST_HEAD(&v.locks[i]->list);
  283                     __insert_and_merge(fdctx, v.locks[i]);
  284                 }
  285 
  286                 __delete_unlck_locks(fdctx);
  287                 return;
  288             }
  289         }
  290 
  291         if (lock->fl_type == F_UNLCK) {
  292             continue;
  293         }
  294 
  295         if ((conf->fl_type == F_RDLCK) && (lock->fl_type == F_RDLCK)) {
  296             __insert_lock(fdctx, lock);
  297             return;
  298         }
  299     }
  300 
  301     /* no conflicts, so just insert */
  302     if (lock->fl_type != F_UNLCK) {
  303         __insert_lock(fdctx, lock);
  304     } else {
  305         __destroy_client_lock(lock);
  306     }
  307 }
  308 
  309 static void
  310 client_setlk(clnt_fd_ctx_t *fdctx, client_posix_lock_t *lock)
  311 {
  312     __insert_and_merge(fdctx, lock);
  313 }
  314 
  315 static void
  316 destroy_client_lock(client_posix_lock_t *lock)
  317 {
  318     GF_FREE(lock);
  319 }
  320 
  321 void
  322 destroy_client_locks_from_list(struct list_head *deleted)
  323 {
  324     client_posix_lock_t *lock = NULL;
  325     client_posix_lock_t *tmp = NULL;
  326     xlator_t *this = THIS;
  327     int count = 0;
  328 
  329     list_for_each_entry_safe(lock, tmp, deleted, list)
  330     {
  331         list_del_init(&lock->list);
  332         destroy_client_lock(lock);
  333         count++;
  334     }
  335 
  336     /* FIXME: Need to actually print the locks instead of count */
  337     gf_msg_trace(this->name, 0, "Number of locks cleared=%d", count);
  338 }
  339 
  340 void
  341 __delete_granted_locks_owner_from_fdctx(clnt_fd_ctx_t *fdctx,
  342                                         gf_lkowner_t *owner,
  343                                         struct list_head *deleted)
  344 {
  345     client_posix_lock_t *lock = NULL;
  346     client_posix_lock_t *tmp = NULL;
  347 
  348     gf_boolean_t is_null_lkowner = _gf_false;
  349 
  350     if (is_lk_owner_null(owner)) {
  351         is_null_lkowner = _gf_true;
  352     }
  353 
  354     list_for_each_entry_safe(lock, tmp, &fdctx->lock_list, list)
  355     {
  356         if (is_null_lkowner || is_same_lkowner(&lock->owner, owner)) {
  357             list_del_init(&lock->list);
  358             list_add_tail(&lock->list, deleted);
  359         }
  360     }
  361 }
  362 
  363 int32_t
  364 delete_granted_locks_owner(fd_t *fd, gf_lkowner_t *owner)
  365 {
  366     clnt_fd_ctx_t *fdctx = NULL;
  367     xlator_t *this = NULL;
  368     clnt_conf_t *conf = NULL;
  369     int ret = 0;
  370     struct list_head deleted_locks;
  371 
  372     this = THIS;
  373     conf = this->private;
  374     INIT_LIST_HEAD(&deleted_locks);
  375 
  376     pthread_spin_lock(&conf->fd_lock);
  377     {
  378         fdctx = this_fd_get_ctx(fd, this);
  379         if (!fdctx) {
  380             pthread_spin_unlock(&conf->fd_lock);
  381 
  382             gf_smsg(this->name, GF_LOG_WARNING, EINVAL, PC_MSG_FD_CTX_INVALID,
  383                     NULL);
  384             ret = -1;
  385             goto out;
  386         }
  387         __delete_granted_locks_owner_from_fdctx(fdctx, owner, &deleted_locks);
  388     }
  389     pthread_spin_unlock(&conf->fd_lock);
  390 
  391     destroy_client_locks_from_list(&deleted_locks);
  392 out:
  393     return ret;
  394 }
  395 
  396 int32_t
  397 client_cmd_to_gf_cmd(int32_t cmd, int32_t *gf_cmd)
  398 {
  399     int ret = 0;
  400 
  401     if (cmd == F_GETLK || cmd == F_GETLK64)
  402         *gf_cmd = GF_LK_GETLK;
  403     else if (cmd == F_SETLK || cmd == F_SETLK64)
  404         *gf_cmd = GF_LK_SETLK;
  405     else if (cmd == F_SETLKW || cmd == F_SETLKW64)
  406         *gf_cmd = GF_LK_SETLKW;
  407     else if (cmd == F_RESLK_LCK)
  408         *gf_cmd = GF_LK_RESLK_LCK;
  409     else if (cmd == F_RESLK_LCKW)
  410         *gf_cmd = GF_LK_RESLK_LCKW;
  411     else if (cmd == F_RESLK_UNLCK)
  412         *gf_cmd = GF_LK_RESLK_UNLCK;
  413     else if (cmd == F_GETLK_FD)
  414         *gf_cmd = GF_LK_GETLK_FD;
  415     else
  416         ret = -1;
  417 
  418     return ret;
  419 }
  420 
  421 static client_posix_lock_t *
  422 new_client_lock(struct gf_flock *flock, gf_lkowner_t *owner, int32_t cmd,
  423                 fd_t *fd)
  424 {
  425     client_posix_lock_t *new_lock = NULL;
  426 
  427     new_lock = GF_CALLOC(1, sizeof(*new_lock), gf_client_mt_clnt_lock_t);
  428     if (!new_lock) {
  429         goto out;
  430     }
  431 
  432     INIT_LIST_HEAD(&new_lock->list);
  433     new_lock->fd = fd;
  434     memcpy(&new_lock->user_flock, flock, sizeof(struct gf_flock));
  435 
  436     new_lock->fl_type = flock->l_type;
  437     new_lock->fl_start = flock->l_start;
  438 
  439     if (flock->l_len == 0)
  440         new_lock->fl_end = LLONG_MAX;
  441     else
  442         new_lock->fl_end = flock->l_start + flock->l_len - 1;
  443 
  444     new_lock->owner = *owner;
  445 
  446     new_lock->cmd = cmd; /* Not really useful */
  447 
  448 out:
  449     return new_lock;
  450 }
  451 
  452 void
  453 client_save_number_fds(clnt_conf_t *conf, int count)
  454 {
  455     LOCK(&conf->rec_lock);
  456     {
  457         conf->reopen_fd_count = count;
  458     }
  459     UNLOCK(&conf->rec_lock);
  460 }
  461 
  462 int
  463 client_add_lock_for_recovery(fd_t *fd, struct gf_flock *flock,
  464                              gf_lkowner_t *owner, int32_t cmd)
  465 {
  466     clnt_fd_ctx_t *fdctx = NULL;
  467     xlator_t *this = NULL;
  468     client_posix_lock_t *lock = NULL;
  469     clnt_conf_t *conf = NULL;
  470 
  471     int ret = 0;
  472 
  473     this = THIS;
  474     conf = this->private;
  475 
  476     pthread_spin_lock(&conf->fd_lock);
  477 
  478     fdctx = this_fd_get_ctx(fd, this);
  479     if (!fdctx) {
  480         pthread_spin_unlock(&conf->fd_lock);
  481 
  482         gf_smsg(this->name, GF_LOG_WARNING, 0, PC_MSG_FD_GET_FAIL, NULL);
  483         ret = -EBADFD;
  484         goto out;
  485     }
  486 
  487     lock = new_client_lock(flock, owner, cmd, fd);
  488     if (!lock) {
  489         pthread_spin_unlock(&conf->fd_lock);
  490 
  491         ret = -ENOMEM;
  492         goto out;
  493     }
  494 
  495     client_setlk(fdctx, lock);
  496 
  497     pthread_spin_unlock(&conf->fd_lock);
  498 
  499 out:
  500     return ret;
  501 }
  502 
  503 int32_t
  504 client_dump_locks(char *name, inode_t *inode, dict_t *dict)
  505 {
  506     int ret = 0;
  507     dict_t *new_dict = NULL;
  508     char dict_string[256];
  509 
  510     GF_ASSERT(dict);
  511     new_dict = dict;
  512 
  513     ret = dump_client_locks(inode);
  514     snprintf(dict_string, 256, "%d locks dumped in log file", ret);
  515 
  516     ret = dict_set_dynstr(new_dict, CLIENT_DUMP_LOCKS, dict_string);
  517     if (ret) {
  518         gf_smsg(THIS->name, GF_LOG_WARNING, 0, PC_MSG_DICT_SET_FAIL, "lock=%s",
  519                 CLIENT_DUMP_LOCKS, NULL);
  520         goto out;
  521     }
  522 
  523 out:
  524 
  525     return ret;
  526 }
  527 
  528 int32_t
  529 is_client_dump_locks_cmd(char *name)
  530 {
  531     int ret = 0;
  532 
  533     if (strcmp(name, CLIENT_DUMP_LOCKS) == 0)
  534         ret = 1;
  535 
  536     return ret;
  537 }