summaryrefslogtreecommitdiff
path: root/fs/ocfs2/stackglue.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ocfs2/stackglue.c')
-rw-r--r--fs/ocfs2/stackglue.c142
1 files changed, 135 insertions, 7 deletions
diff --git a/fs/ocfs2/stackglue.c b/fs/ocfs2/stackglue.c
index 99538043fc17..0aec2fcf2175 100644
--- a/fs/ocfs2/stackglue.c
+++ b/fs/ocfs2/stackglue.c
@@ -18,6 +18,7 @@
* General Public License for more details.
*/
+#include "cluster/masklog.h"
#include "stackglue.h"
static struct ocfs2_locking_protocol *lproto;
@@ -77,7 +78,126 @@ static int flags_to_o2dlm(u32 flags)
}
#undef map_flag
-enum dlm_status ocfs2_dlm_lock(struct dlm_ctxt *dlm,
+/*
+ * Map an o2dlm status to standard errno values.
+ *
+ * o2dlm only uses a handful of these, and returns even fewer to the
+ * caller. Still, we try to assign sane values to each error.
+ *
+ * The following value pairs have special meanings to dlmglue, thus
+ * the right hand side needs to stay unique - never duplicate the
+ * mapping elsewhere in the table!
+ *
+ * DLM_NORMAL: 0
+ * DLM_NOTQUEUED: -EAGAIN
+ * DLM_CANCELGRANT: -DLM_ECANCEL
+ * DLM_CANCEL: -DLM_EUNLOCK
+ */
+/* Keep in sync with dlmapi.h */
+static int status_map[] = {
+ [DLM_NORMAL] = 0, /* Success */
+ [DLM_GRANTED] = -EINVAL,
+ [DLM_DENIED] = -EACCES,
+ [DLM_DENIED_NOLOCKS] = -EACCES,
+ [DLM_WORKING] = -EBUSY,
+ [DLM_BLOCKED] = -EINVAL,
+ [DLM_BLOCKED_ORPHAN] = -EINVAL,
+ [DLM_DENIED_GRACE_PERIOD] = -EACCES,
+ [DLM_SYSERR] = -ENOMEM, /* It is what it is */
+ [DLM_NOSUPPORT] = -EPROTO,
+ [DLM_CANCELGRANT] = -DLM_ECANCEL, /* Cancel after grant */
+ [DLM_IVLOCKID] = -EINVAL,
+ [DLM_SYNC] = -EINVAL,
+ [DLM_BADTYPE] = -EINVAL,
+ [DLM_BADRESOURCE] = -EINVAL,
+ [DLM_MAXHANDLES] = -ENOMEM,
+ [DLM_NOCLINFO] = -EINVAL,
+ [DLM_NOLOCKMGR] = -EINVAL,
+ [DLM_NOPURGED] = -EINVAL,
+ [DLM_BADARGS] = -EINVAL,
+ [DLM_VOID] = -EINVAL,
+ [DLM_NOTQUEUED] = -EAGAIN, /* Trylock failed */
+ [DLM_IVBUFLEN] = -EINVAL,
+ [DLM_CVTUNGRANT] = -EPERM,
+ [DLM_BADPARAM] = -EINVAL,
+ [DLM_VALNOTVALID] = -EINVAL,
+ [DLM_REJECTED] = -EPERM,
+ [DLM_ABORT] = -EINVAL,
+ [DLM_CANCEL] = -DLM_EUNLOCK, /* Successful cancel */
+ [DLM_IVRESHANDLE] = -EINVAL,
+ [DLM_DEADLOCK] = -EDEADLK,
+ [DLM_DENIED_NOASTS] = -EINVAL,
+ [DLM_FORWARD] = -EINVAL,
+ [DLM_TIMEOUT] = -ETIMEDOUT,
+ [DLM_IVGROUPID] = -EINVAL,
+ [DLM_VERS_CONFLICT] = -EOPNOTSUPP,
+ [DLM_BAD_DEVICE_PATH] = -ENOENT,
+ [DLM_NO_DEVICE_PERMISSION] = -EPERM,
+ [DLM_NO_CONTROL_DEVICE] = -ENOENT,
+ [DLM_RECOVERING] = -ENOTCONN,
+ [DLM_MIGRATING] = -ERESTART,
+ [DLM_MAXSTATS] = -EINVAL,
+};
+static int dlm_status_to_errno(enum dlm_status status)
+{
+ BUG_ON(status > (sizeof(status_map) / sizeof(status_map[0])));
+
+ return status_map[status];
+}
+
+static void o2dlm_lock_ast_wrapper(void *astarg)
+{
+ BUG_ON(lproto == NULL);
+
+ lproto->lp_lock_ast(astarg);
+}
+
+static void o2dlm_blocking_ast_wrapper(void *astarg, int level)
+{
+ BUG_ON(lproto == NULL);
+
+ lproto->lp_blocking_ast(astarg, level);
+}
+
+static void o2dlm_unlock_ast_wrapper(void *astarg, enum dlm_status status)
+{
+ int error;
+
+ BUG_ON(lproto == NULL);
+
+ /*
+ * XXX: CANCEL values are sketchy.
+ *
+ * Currently we have preserved the o2dlm paradigm. You can get
+ * unlock_ast() whether the cancel succeded or not.
+ *
+ * First, we're going to pass DLM_EUNLOCK just like fs/dlm does for
+ * successful unlocks. That is a clean behavior.
+ *
+ * In o2dlm, you can get both the lock_ast() for the lock being
+ * granted and the unlock_ast() for the CANCEL failing. A
+ * successful cancel sends DLM_NORMAL here. If the
+ * lock grant happened before the cancel arrived, you get
+ * DLM_CANCELGRANT. For now, we'll use DLM_ECANCEL to signify
+ * CANCELGRANT - the CANCEL was supposed to happen but didn't. We
+ * can then use DLM_EUNLOCK to signify a successful CANCEL -
+ * effectively, the CANCEL caused the lock to roll back.
+ *
+ * In the future, we will likely move the o2dlm to send only one
+ * ast - either unlock_ast() for a successful CANCEL or lock_ast()
+ * when the grant succeeds. At that point, we'll send DLM_ECANCEL
+ * for all cancel results (CANCELGRANT will no longer exist).
+ */
+ error = dlm_status_to_errno(status);
+
+ /* Successful unlock is DLM_EUNLOCK */
+ if (!error)
+ error = -DLM_EUNLOCK;
+
+ lproto->lp_unlock_ast(astarg, error);
+}
+
+int ocfs2_dlm_lock(struct dlm_ctxt *dlm,
int mode,
struct dlm_lockstatus *lksb,
u32 flags,
@@ -85,27 +205,35 @@ enum dlm_status ocfs2_dlm_lock(struct dlm_ctxt *dlm,
unsigned int namelen,
void *astarg)
{
+ enum dlm_status status;
int o2dlm_mode = mode_to_o2dlm(mode);
int o2dlm_flags = flags_to_o2dlm(flags);
+ int ret;
BUG_ON(lproto == NULL);
- return dlmlock(dlm, o2dlm_mode, lksb, o2dlm_flags, name, namelen,
- lproto->lp_lock_ast, astarg,
- lproto->lp_blocking_ast);
+ status = dlmlock(dlm, o2dlm_mode, lksb, o2dlm_flags, name, namelen,
+ o2dlm_lock_ast_wrapper, astarg,
+ o2dlm_blocking_ast_wrapper);
+ ret = dlm_status_to_errno(status);
+ return ret;
}
-enum dlm_status ocfs2_dlm_unlock(struct dlm_ctxt *dlm,
+int ocfs2_dlm_unlock(struct dlm_ctxt *dlm,
struct dlm_lockstatus *lksb,
u32 flags,
void *astarg)
{
+ enum dlm_status status;
int o2dlm_flags = flags_to_o2dlm(flags);
+ int ret;
BUG_ON(lproto == NULL);
- return dlmunlock(dlm, lksb, o2dlm_flags,
- lproto->lp_unlock_ast, astarg);
+ status = dlmunlock(dlm, lksb, o2dlm_flags,
+ o2dlm_unlock_ast_wrapper, astarg);
+ ret = dlm_status_to_errno(status);
+ return ret;
}