"Fossies" - the Fresh Open Source Software Archive

Member "glusterfs-8.2/xlators/features/locks/src/clear.c" (16 Sep 2020, 12245 Bytes) of package /linux/misc/glusterfs-8.2.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 "clear.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2    Copyright (c) 2006-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 #include <unistd.h>
   11 #include <fcntl.h>
   12 #include <limits.h>
   13 #include <pthread.h>
   14 
   15 #include <glusterfs/glusterfs.h>
   16 #include <glusterfs/compat.h>
   17 #include <glusterfs/xlator.h>
   18 #include <glusterfs/logging.h>
   19 #include <glusterfs/common-utils.h>
   20 
   21 #include "locks.h"
   22 #include "common.h"
   23 #include <glusterfs/statedump.h>
   24 #include "clear.h"
   25 
   26 const char *clrlk_type_names[CLRLK_TYPE_MAX] = {
   27     [CLRLK_INODE] = "inode",
   28     [CLRLK_ENTRY] = "entry",
   29     [CLRLK_POSIX] = "posix",
   30 };
   31 
   32 int
   33 clrlk_get_kind(char *kind)
   34 {
   35     char *clrlk_kinds[CLRLK_KIND_MAX] = {"dummy", "blocked", "granted", "all"};
   36     int ret_kind = CLRLK_KIND_MAX;
   37     int i = 0;
   38 
   39     for (i = CLRLK_BLOCKED; i < CLRLK_KIND_MAX; i++) {
   40         if (!strcmp(clrlk_kinds[i], kind)) {
   41             ret_kind = i;
   42             break;
   43         }
   44     }
   45 
   46     return ret_kind;
   47 }
   48 
   49 int
   50 clrlk_get_type(char *type)
   51 {
   52     char *clrlk_types[CLRLK_TYPE_MAX] = {"inode", "entry", "posix"};
   53     int ret_type = CLRLK_TYPE_MAX;
   54     int i = 0;
   55 
   56     for (i = CLRLK_INODE; i < CLRLK_TYPE_MAX; i++) {
   57         if (!strcmp(clrlk_types[i], type)) {
   58             ret_type = i;
   59             break;
   60         }
   61     }
   62 
   63     return ret_type;
   64 }
   65 
   66 int
   67 clrlk_get_lock_range(char *range_str, struct gf_flock *ulock,
   68                      gf_boolean_t *chk_range)
   69 {
   70     int ret = -1;
   71 
   72     if (!chk_range)
   73         goto out;
   74 
   75     if (!range_str) {
   76         ret = 0;
   77         *chk_range = _gf_false;
   78         goto out;
   79     }
   80 
   81     if (sscanf(range_str,
   82                "%hd,%" PRId64 "-"
   83                "%" PRId64,
   84                &ulock->l_whence, &ulock->l_start, &ulock->l_len) != 3) {
   85         goto out;
   86     }
   87 
   88     ret = 0;
   89     *chk_range = _gf_true;
   90 out:
   91     return ret;
   92 }
   93 
   94 int
   95 clrlk_parse_args(const char *cmd, clrlk_args *args)
   96 {
   97     char *opts = NULL;
   98     char *cur = NULL;
   99     char *tok = NULL;
  100     char *sptr = NULL;
  101     char *free_ptr = NULL;
  102     char kw[KW_MAX] = {
  103         [KW_TYPE] = 't',
  104         [KW_KIND] = 'k',
  105     };
  106     int ret = -1;
  107     int i = 0;
  108 
  109     GF_ASSERT(cmd);
  110     free_ptr = opts = GF_CALLOC(1, strlen(cmd), gf_common_mt_char);
  111     if (!opts)
  112         goto out;
  113 
  114     if (sscanf(cmd, GF_XATTR_CLRLK_CMD ".%s", opts) < 1) {
  115         ret = -1;
  116         goto out;
  117     }
  118 
  119     /*clr_lk_prefix.ttype.kkind.args, args - type specific*/
  120     cur = opts;
  121     for (i = 0; i < KW_MAX && (tok = strtok_r(cur, ".", &sptr));
  122          cur = NULL, i++) {
  123         if (tok[0] != kw[i]) {
  124             ret = -1;
  125             goto out;
  126         }
  127         if (i == KW_TYPE)
  128             args->type = clrlk_get_type(tok + 1);
  129         if (i == KW_KIND)
  130             args->kind = clrlk_get_kind(tok + 1);
  131     }
  132 
  133     if ((args->type == CLRLK_TYPE_MAX) || (args->kind == CLRLK_KIND_MAX))
  134         goto out;
  135 
  136     /*optional args, neither range nor basename can 'legally' contain
  137      * "/" in them*/
  138     tok = strtok_r(NULL, "/", &sptr);
  139     if (tok)
  140         args->opts = gf_strdup(tok);
  141 
  142     ret = 0;
  143 out:
  144     GF_FREE(free_ptr);
  145     return ret;
  146 }
  147 
  148 int
  149 clrlk_clear_posixlk(xlator_t *this, pl_inode_t *pl_inode, clrlk_args *args,
  150                     int *blkd, int *granted, int *op_errno)
  151 {
  152     posix_lock_t *plock = NULL;
  153     posix_lock_t *tmp = NULL;
  154     struct gf_flock ulock = {
  155         0,
  156     };
  157     int ret = -1;
  158     int bcount = 0;
  159     int gcount = 0;
  160     gf_boolean_t chk_range = _gf_false;
  161 
  162     if (clrlk_get_lock_range(args->opts, &ulock, &chk_range)) {
  163         *op_errno = EINVAL;
  164         goto out;
  165     }
  166 
  167     pthread_mutex_lock(&pl_inode->mutex);
  168     {
  169         list_for_each_entry_safe(plock, tmp, &pl_inode->ext_list, list)
  170         {
  171             if ((plock->blocked && !(args->kind & CLRLK_BLOCKED)) ||
  172                 (!plock->blocked && !(args->kind & CLRLK_GRANTED)))
  173                 continue;
  174 
  175             if (chk_range && (plock->user_flock.l_whence != ulock.l_whence ||
  176                               plock->user_flock.l_start != ulock.l_start ||
  177                               plock->user_flock.l_len != ulock.l_len))
  178                 continue;
  179 
  180             list_del_init(&plock->list);
  181             if (plock->blocked) {
  182                 bcount++;
  183                 pl_trace_out(this, plock->frame, NULL, NULL, F_SETLKW,
  184                              &plock->user_flock, -1, EAGAIN, NULL);
  185 
  186                 STACK_UNWIND_STRICT(lk, plock->frame, -1, EAGAIN,
  187                                     &plock->user_flock, NULL);
  188 
  189             } else {
  190                 gcount++;
  191             }
  192             __destroy_lock(plock);
  193         }
  194     }
  195     pthread_mutex_unlock(&pl_inode->mutex);
  196     grant_blocked_locks(this, pl_inode);
  197     ret = 0;
  198 out:
  199     *blkd = bcount;
  200     *granted = gcount;
  201     return ret;
  202 }
  203 
  204 /* Returns 0 on success and -1 on failure */
  205 int
  206 clrlk_clear_inodelk(xlator_t *this, pl_inode_t *pl_inode, pl_dom_list_t *dom,
  207                     clrlk_args *args, int *blkd, int *granted, int *op_errno)
  208 {
  209     posix_locks_private_t *priv;
  210     pl_inode_lock_t *ilock = NULL;
  211     pl_inode_lock_t *tmp = NULL;
  212     struct gf_flock ulock = {
  213         0,
  214     };
  215     int ret = -1;
  216     int bcount = 0;
  217     int gcount = 0;
  218     gf_boolean_t chk_range = _gf_false;
  219     struct list_head *pcontend = NULL;
  220     struct list_head released;
  221     struct list_head contend;
  222     struct timespec now = {};
  223 
  224     INIT_LIST_HEAD(&released);
  225 
  226     priv = this->private;
  227     if (priv->notify_contention) {
  228         pcontend = &contend;
  229         INIT_LIST_HEAD(pcontend);
  230         timespec_now(&now);
  231     }
  232 
  233     if (clrlk_get_lock_range(args->opts, &ulock, &chk_range)) {
  234         *op_errno = EINVAL;
  235         goto out;
  236     }
  237 
  238     if (args->kind & CLRLK_BLOCKED)
  239         goto blkd;
  240 
  241     if (args->kind & CLRLK_GRANTED)
  242         goto granted;
  243 
  244 blkd:
  245     pthread_mutex_lock(&pl_inode->mutex);
  246     {
  247         list_for_each_entry_safe(ilock, tmp, &dom->blocked_inodelks,
  248                                  blocked_locks)
  249         {
  250             if (chk_range && (ilock->user_flock.l_whence != ulock.l_whence ||
  251                               ilock->user_flock.l_start != ulock.l_start ||
  252                               ilock->user_flock.l_len != ulock.l_len))
  253                 continue;
  254 
  255             bcount++;
  256             list_del_init(&ilock->client_list);
  257             list_del_init(&ilock->blocked_locks);
  258             list_add(&ilock->blocked_locks, &released);
  259         }
  260     }
  261     pthread_mutex_unlock(&pl_inode->mutex);
  262 
  263     if (!list_empty(&released)) {
  264         list_for_each_entry_safe(ilock, tmp, &released, blocked_locks)
  265         {
  266             list_del_init(&ilock->blocked_locks);
  267             pl_trace_out(this, ilock->frame, NULL, NULL, F_SETLKW,
  268                          &ilock->user_flock, -1, EAGAIN, ilock->volume);
  269             STACK_UNWIND_STRICT(inodelk, ilock->frame, -1, EAGAIN, NULL);
  270             // No need to take lock as the locks are only in one list
  271             __pl_inodelk_unref(ilock);
  272         }
  273     }
  274 
  275     if (!(args->kind & CLRLK_GRANTED)) {
  276         ret = 0;
  277         goto out;
  278     }
  279 
  280 granted:
  281     pthread_mutex_lock(&pl_inode->mutex);
  282     {
  283         list_for_each_entry_safe(ilock, tmp, &dom->inodelk_list, list)
  284         {
  285             if (chk_range && (ilock->user_flock.l_whence != ulock.l_whence ||
  286                               ilock->user_flock.l_start != ulock.l_start ||
  287                               ilock->user_flock.l_len != ulock.l_len))
  288                 continue;
  289 
  290             gcount++;
  291             list_del_init(&ilock->client_list);
  292             list_del_init(&ilock->list);
  293             list_add(&ilock->list, &released);
  294         }
  295     }
  296     pthread_mutex_unlock(&pl_inode->mutex);
  297 
  298     list_for_each_entry_safe(ilock, tmp, &released, list)
  299     {
  300         list_del_init(&ilock->list);
  301         // No need to take lock as the locks are only in one list
  302         __pl_inodelk_unref(ilock);
  303     }
  304 
  305     ret = 0;
  306 out:
  307     grant_blocked_inode_locks(this, pl_inode, dom, &now, pcontend);
  308     if (pcontend != NULL) {
  309         inodelk_contention_notify(this, pcontend);
  310     }
  311     *blkd = bcount;
  312     *granted = gcount;
  313     return ret;
  314 }
  315 
  316 /* Returns 0 on success and -1 on failure */
  317 int
  318 clrlk_clear_entrylk(xlator_t *this, pl_inode_t *pl_inode, pl_dom_list_t *dom,
  319                     clrlk_args *args, int *blkd, int *granted, int *op_errno)
  320 {
  321     posix_locks_private_t *priv;
  322     pl_entry_lock_t *elock = NULL;
  323     pl_entry_lock_t *tmp = NULL;
  324     int bcount = 0;
  325     int gcount = 0;
  326     int ret = -1;
  327     struct list_head *pcontend = NULL;
  328     struct list_head removed;
  329     struct list_head released;
  330     struct list_head contend;
  331     struct timespec now;
  332 
  333     INIT_LIST_HEAD(&released);
  334 
  335     priv = this->private;
  336     if (priv->notify_contention) {
  337         pcontend = &contend;
  338         INIT_LIST_HEAD(pcontend);
  339         timespec_now(&now);
  340     }
  341 
  342     if (args->kind & CLRLK_BLOCKED)
  343         goto blkd;
  344 
  345     if (args->kind & CLRLK_GRANTED)
  346         goto granted;
  347 
  348 blkd:
  349     pthread_mutex_lock(&pl_inode->mutex);
  350     {
  351         list_for_each_entry_safe(elock, tmp, &dom->blocked_entrylks,
  352                                  blocked_locks)
  353         {
  354             if (args->opts) {
  355                 if (!elock->basename || strcmp(elock->basename, args->opts))
  356                     continue;
  357             }
  358 
  359             bcount++;
  360 
  361             list_del_init(&elock->client_list);
  362             list_del_init(&elock->blocked_locks);
  363             list_add_tail(&elock->blocked_locks, &released);
  364         }
  365     }
  366     pthread_mutex_unlock(&pl_inode->mutex);
  367 
  368     if (!list_empty(&released)) {
  369         list_for_each_entry_safe(elock, tmp, &released, blocked_locks)
  370         {
  371             list_del_init(&elock->blocked_locks);
  372             entrylk_trace_out(this, elock->frame, elock->volume, NULL, NULL,
  373                               elock->basename, ENTRYLK_LOCK, elock->type, -1,
  374                               EAGAIN);
  375             STACK_UNWIND_STRICT(entrylk, elock->frame, -1, EAGAIN, NULL);
  376 
  377             __pl_entrylk_unref(elock);
  378         }
  379     }
  380 
  381     if (!(args->kind & CLRLK_GRANTED)) {
  382         ret = 0;
  383         goto out;
  384     }
  385 
  386 granted:
  387     INIT_LIST_HEAD(&removed);
  388     pthread_mutex_lock(&pl_inode->mutex);
  389     {
  390         list_for_each_entry_safe(elock, tmp, &dom->entrylk_list, domain_list)
  391         {
  392             if (args->opts) {
  393                 if (!elock->basename || strcmp(elock->basename, args->opts))
  394                     continue;
  395             }
  396 
  397             gcount++;
  398             list_del_init(&elock->client_list);
  399             list_del_init(&elock->domain_list);
  400             list_add_tail(&elock->domain_list, &removed);
  401 
  402             __pl_entrylk_unref(elock);
  403         }
  404     }
  405     pthread_mutex_unlock(&pl_inode->mutex);
  406 
  407     grant_blocked_entry_locks(this, pl_inode, dom, &now, pcontend);
  408     if (pcontend != NULL) {
  409         entrylk_contention_notify(this, pcontend);
  410     }
  411 
  412     ret = 0;
  413 out:
  414     *blkd = bcount;
  415     *granted = gcount;
  416     return ret;
  417 }
  418 
  419 int
  420 clrlk_clear_lks_in_all_domains(xlator_t *this, pl_inode_t *pl_inode,
  421                                clrlk_args *args, int *blkd, int *granted,
  422                                int *op_errno)
  423 {
  424     pl_dom_list_t *dom = NULL;
  425     int ret = -1;
  426     int tmp_bcount = 0;
  427     int tmp_gcount = 0;
  428 
  429     if (list_empty(&pl_inode->dom_list)) {
  430         ret = 0;
  431         goto out;
  432     }
  433 
  434     list_for_each_entry(dom, &pl_inode->dom_list, inode_list)
  435     {
  436         tmp_bcount = tmp_gcount = 0;
  437 
  438         switch (args->type) {
  439             case CLRLK_INODE:
  440                 ret = clrlk_clear_inodelk(this, pl_inode, dom, args,
  441                                           &tmp_bcount, &tmp_gcount, op_errno);
  442                 if (ret)
  443                     goto out;
  444                 break;
  445             case CLRLK_ENTRY:
  446                 ret = clrlk_clear_entrylk(this, pl_inode, dom, args,
  447                                           &tmp_bcount, &tmp_gcount, op_errno);
  448                 if (ret)
  449                     goto out;
  450                 break;
  451         }
  452 
  453         *blkd += tmp_bcount;
  454         *granted += tmp_gcount;
  455     }
  456 
  457     ret = 0;
  458 out:
  459     return ret;
  460 }