/* Copyright (c) 2006-2012 Red Hat, Inc. This file is part of GlusterFS. This file is licensed to you under your choice of the GNU Lesser General Public License, version 3 or any later version (LGPLv3 or later), or the GNU General Public License, version 2 (GPLv2), in all cases as published by the Free Software Foundation. */ #include #include #include #include #ifndef _CONFIG_H #define _CONFIG_H #include "config.h" #endif #include "glusterfs.h" #include "compat.h" #include "xlator.h" #include "inode.h" #include "logging.h" #include "common-utils.h" #include "locks.h" #include "common.h" #include "statedump.h" #include "clear.h" int clrlk_get_kind (char *kind) { char *clrlk_kinds[CLRLK_KIND_MAX] = {"dummy", "blocked", "granted", "all"}; int ret_kind = CLRLK_KIND_MAX; int i = 0; for (i = CLRLK_BLOCKED; i < CLRLK_KIND_MAX; i++) { if (!strcmp (clrlk_kinds[i], kind)) { ret_kind = i; break; } } return ret_kind; } int clrlk_get_type (char *type) { char *clrlk_types[CLRLK_TYPE_MAX] = {"inode", "entry", "posix"}; int ret_type = CLRLK_TYPE_MAX; int i = 0; for (i = CLRLK_INODE; i < CLRLK_TYPE_MAX; i++) { if (!strcmp (clrlk_types[i], type)) { ret_type = i; break; } } return ret_type; } int clrlk_get_lock_range (char *range_str, struct gf_flock *ulock, gf_boolean_t *chk_range) { int ret = -1; if (!chk_range) goto out; if (!range_str) { ret = 0; *chk_range = _gf_false; goto out; } if (sscanf (range_str, "%hd,%"PRId64"-""%"PRId64, &ulock->l_whence, &ulock->l_start, &ulock->l_len) != 3) { goto out; } ret = 0; *chk_range = _gf_true; out: return ret; } int clrlk_parse_args (const char* cmd, clrlk_args *args) { char *opts = NULL; char *cur = NULL; char *tok = NULL; char *sptr = NULL; char *free_ptr = NULL; char kw[KW_MAX] = {[KW_TYPE] = 't', [KW_KIND] = 'k', }; int ret = -1; int i = 0; GF_ASSERT (cmd); free_ptr = opts = GF_CALLOC (1, strlen (cmd), gf_common_mt_char); if (!opts) goto out; if (sscanf (cmd, GF_XATTR_CLRLK_CMD".%s", opts) < 1) { ret = -1; goto out; } /*clr_lk_prefix.ttype.kkind.args, args - type specific*/ cur = opts; for (i = 0; i < KW_MAX && (tok = strtok_r (cur, ".", &sptr)); cur = NULL, i++) { if (tok[0] != kw[i]) { ret = -1; goto out; } if (i == KW_TYPE) args->type = clrlk_get_type (tok+1); if (i == KW_KIND) args->kind = clrlk_get_kind (tok+1); } if ((args->type == CLRLK_TYPE_MAX) || (args->kind == CLRLK_KIND_MAX)) goto out; /*optional args, neither range nor basename can 'legally' contain * "/" in them*/ tok = strtok_r (NULL, "/", &sptr); if (tok) args->opts = gf_strdup (tok); ret = 0; out: GF_FREE (free_ptr); return ret; } int clrlk_clear_posixlk (xlator_t *this, pl_inode_t *pl_inode, clrlk_args *args, int *blkd, int *granted, int *op_errno) { posix_lock_t *plock = NULL; posix_lock_t *tmp = NULL; struct gf_flock ulock = {0, }; int ret = -1; int bcount = 0; int gcount = 0; gf_boolean_t chk_range = _gf_false; if (clrlk_get_lock_range (args->opts, &ulock, &chk_range)) { *op_errno = EINVAL; goto out; } pthread_mutex_lock (&pl_inode->mutex); { list_for_each_entry_safe (plock, tmp, &pl_inode->ext_list, list) { if ((plock->blocked && !(args->kind & CLRLK_BLOCKED)) || (!plock->blocked && !(args->kind & CLRLK_GRANTED))) continue; if (chk_range && (plock->user_flock.l_whence != ulock.l_whence || plock->user_flock.l_start != ulock.l_start || plock->user_flock.l_len != ulock.l_len)) continue; list_del_init (&plock->list); if (plock->blocked) { bcount++; pl_trace_out (this, plock->frame, NULL, NULL, F_SETLKW, &plock->user_flock, -1, EAGAIN, NULL); STACK_UNWIND_STRICT (lk, plock->frame, -1, EAGAIN, &plock->user_flock, NULL); } else { gcount++; } GF_FREE (plock); } } pthread_mutex_unlock (&pl_inode->mutex); grant_blocked_locks (this, pl_inode); ret = 0; out: *blkd = bcount; *granted = gcount; return ret; } /* Returns 0 on success and -1 on failure */ int clrlk_clear_inodelk (xlator_t *this, pl_inode_t *pl_inode, pl_dom_list_t *dom, clrlk_args *args, int *blkd, int *granted, int *op_errno) { pl_inode_lock_t *ilock = NULL; pl_inode_lock_t *tmp = NULL; struct gf_flock ulock = {0, }; int ret = -1; int bcount = 0; int gcount = 0; gf_boolean_t chk_range = _gf_false; struct list_head released; INIT_LIST_HEAD (&released); if (clrlk_get_lock_range (args->opts, &ulock, &chk_range)) { *op_errno = EINVAL; goto out; } if (args->kind & CLRLK_BLOCKED) goto blkd; if (args->kind & CLRLK_GRANTED) goto granted; blkd: pthread_mutex_lock (&pl_inode->mutex); { list_for_each_entry_safe (ilock, tmp, &dom->blocked_inodelks, blocked_locks) { if (chk_range && (ilock->user_flock.l_whence != ulock.l_whence || ilock->user_flock.l_start != ulock.l_start || ilock->user_flock.l_len != ulock.l_len)) continue; bcount++; list_del_init (&ilock->blocked_locks); list_add (&ilock->blocked_locks, &released); } } pthread_mutex_unlock (&pl_inode->mutex); list_for_each_entry_safe (ilock, tmp, &released, blocked_locks) { list_del_init (&ilock->blocked_locks); pl_trace_out (this, ilock->frame, NULL, NULL, F_SETLKW, &ilock->user_flock, -1, EAGAIN, ilock->volume); STACK_UNWIND_STRICT (inodelk, ilock->frame, -1, EAGAIN, NULL); //No need to take lock as the locks are only in one list __pl_inodelk_unref (ilock); } if (!(args->kind & CLRLK_GRANTED)) { ret = 0; goto out; } granted: pthread_mutex_lock (&pl_inode->mutex); { list_for_each_entry_safe (ilock, tmp, &dom->inodelk_list, list) { if (chk_range && (ilock->user_flock.l_whence != ulock.l_whence || ilock->user_flock.l_start != ulock.l_start || ilock->user_flock.l_len != ulock.l_len)) continue; gcount++; list_del_init (&ilock->list); list_add (&ilock->list, &released); } } pthread_mutex_unlock (&pl_inode->mutex); list_for_each_entry_safe (ilock, tmp, &released, list) { list_del_init (&ilock->list); //No need to take lock as the locks are only in one list __pl_inodelk_unref (ilock); } ret = 0; out: grant_blocked_inode_locks (this, pl_inode, dom); *blkd = bcount; *granted = gcount; return ret; } /* Returns 0 on success and -1 on failure */ int clrlk_clear_entrylk (xlator_t *this, pl_inode_t *pl_inode, pl_dom_list_t *dom, clrlk_args *args, int *blkd, int *granted, int *op_errno) { pl_entry_lock_t *elock = NULL; pl_entry_lock_t *tmp = NULL; int bcount = 0; int gcount = 0; int ret = -1; struct list_head removed; struct list_head released; INIT_LIST_HEAD (&released); if (args->kind & CLRLK_BLOCKED) goto blkd; if (args->kind & CLRLK_GRANTED) goto granted; blkd: pthread_mutex_lock (&pl_inode->mutex); { list_for_each_entry_safe (elock, tmp, &dom->blocked_entrylks, blocked_locks) { if (args->opts) { if (!elock->basename || strcmp (elock->basename, args->opts)) continue; } bcount++; list_del_init (&elock->blocked_locks); list_add_tail (&elock->blocked_locks, &released); } } pthread_mutex_unlock (&pl_inode->mutex); list_for_each_entry_safe (elock, tmp, &released, blocked_locks) { list_del_init (&elock->blocked_locks); entrylk_trace_out (this, elock->frame, elock->volume, NULL, NULL, elock->basename, ENTRYLK_LOCK, elock->type, -1, EAGAIN); STACK_UNWIND_STRICT (entrylk, elock->frame, -1, EAGAIN, NULL); __pl_entrylk_unref (elock); } if (!(args->kind & CLRLK_GRANTED)) { ret = 0; goto out; } granted: INIT_LIST_HEAD (&removed); pthread_mutex_lock (&pl_inode->mutex); { list_for_each_entry_safe (elock, tmp, &dom->entrylk_list, domain_list) { if (args->opts) { if (!elock->basename || strcmp (elock->basename, args->opts)) continue; } gcount++; list_del_init (&elock->domain_list); list_add_tail (&elock->domain_list, &removed); __pl_entrylk_unref (elock); } } pthread_mutex_unlock (&pl_inode->mutex); grant_blocked_entry_locks (this, pl_inode, dom); ret = 0; out: *blkd = bcount; *granted = gcount; return ret; } int clrlk_clear_lks_in_all_domains (xlator_t *this, pl_inode_t *pl_inode, clrlk_args *args, int *blkd, int *granted, int *op_errno) { pl_dom_list_t *dom = NULL; int ret = -1; int tmp_bcount = 0; int tmp_gcount = 0; if (list_empty (&pl_inode->dom_list)) { ret = 0; goto out; } list_for_each_entry (dom, &pl_inode->dom_list, inode_list) { tmp_bcount = tmp_gcount = 0; switch (args->type) { case CLRLK_INODE: ret = clrlk_clear_inodelk (this, pl_inode, dom, args, &tmp_bcount, &tmp_gcount, op_errno); if (ret) goto out; break; case CLRLK_ENTRY: ret = clrlk_clear_entrylk (this, pl_inode, dom, args, &tmp_bcount, &tmp_gcount, op_errno); if (ret) goto out; break; } *blkd += tmp_bcount; *granted += tmp_gcount; } ret = 0; out: return ret; }