[Ocfs2-tools-devel] [PATCH 1/5] debugfs.ocfs2: Fix lockname encoding and decoding

Sunil Mushran sunil.mushran at oracle.com
Wed Oct 8 16:05:43 PDT 2008


debugfs.ocfs2 allows users to encode and decode various locknames
used by OCFS2. This patch makes the tool understand the new locknames
flock, open and dentry introduced in the filesystem.

Signed-off-by: Sunil Mushran <sunil.mushran at oracle.com>
---
 debugfs.ocfs2/commands.c            |   53 +++++---------
 debugfs.ocfs2/main.c                |   49 +++++++------
 debugfs.ocfs2/utils.c               |   37 ++++++----
 include/ocfs2-kernel/ocfs2_lockid.h |   35 +++++++++
 include/ocfs2/ocfs2.h               |   10 ++-
 libocfs2/dlm.c                      |    8 +-
 libocfs2/lockid.c                   |  133 +++++++++++++++++++++--------------
 7 files changed, 195 insertions(+), 130 deletions(-)

diff --git a/debugfs.ocfs2/commands.c b/debugfs.ocfs2/commands.c
index 83cb5b6..ea20080 100644
--- a/debugfs.ocfs2/commands.c
+++ b/debugfs.ocfs2/commands.c
@@ -1399,52 +1399,39 @@ static void do_rdump(char **args)
 /*
  * do_encode_lockres()
  *
+ * This function only encodes the Super and the Inode lock. For the
+ * rest, use the --encode parameter directly.
  */
 static void do_encode_lockres (char **args)
 {
-	struct ocfs2_dinode *inode;
+	struct ocfs2_dinode *inode = (struct ocfs2_dinode *)gbls.blockbuf;
 	uint64_t blkno;
-	char *buf = NULL;
+	uint32_t gen = 0;
 	errcode_t ret = 0;
-	char suprlock[50] = "\0";
-	char metalock[50] = "\0";
-	char datalock[50] = "\0";
-	char rdwrlock[50] = "\0";
+	char lock[OCFS2_LOCK_ID_MAX_LEN];
+	enum ocfs2_lock_type type = OCFS2_LOCK_TYPE_META;
 
 	if (process_inode_args(args, &blkno))
-		return ;
+		return;
 
-	if (blkno == OCFS2_SUPER_BLOCK_BLKNO) {
-		ret = ocfs2_encode_lockres(OCFS2_LOCK_TYPE_SUPER, blkno, 0,
-					   suprlock);
-	} else {
-		buf = gbls.blockbuf;
-		ret = ocfs2_read_inode(gbls.fs, blkno, buf);
-		if (!ret) {
-			inode = (struct ocfs2_dinode *)buf;
-			ocfs2_encode_lockres(OCFS2_LOCK_TYPE_META, blkno,
-					     inode->i_generation, metalock);
-			ocfs2_encode_lockres(OCFS2_LOCK_TYPE_DATA, blkno,
-					     inode->i_generation, datalock);
-			ocfs2_encode_lockres(OCFS2_LOCK_TYPE_RW, blkno,
-					     inode->i_generation, rdwrlock);
+	if (blkno == OCFS2_SUPER_BLOCK_BLKNO)
+		type = OCFS2_LOCK_TYPE_SUPER;
+	else {
+		ret = ocfs2_read_inode(gbls.fs, blkno, (char *)inode);
+		if (ret) {
+			com_err(args[0], ret, "while reading inode %"PRIu64"",
+				blkno);
+			return;
 		}
+		gen = inode->i_generation;
 	}
 
-	if (ret) {
-		com_err(args[0], ret, "while reading inode %"PRIu64"", blkno);
-		return ;
-	}
+	ret = ocfs2_encode_lockres(type, blkno, gen, 0, lock);
+	if (ret)
+		return;
 
 	printf("\t");
-	if (*suprlock)
-		printf("%s ", suprlock);
-	if (*metalock)
-		printf("%s ", metalock);
-	if (*datalock)
-		printf("%s ", datalock);
-	if (*rdwrlock)
-		printf("%s ", rdwrlock);
+	printf("%s ", lock);
 	printf("\n");
 
 	return ;
diff --git a/debugfs.ocfs2/main.c b/debugfs.ocfs2/main.c
index 722b339..ce55e00 100644
--- a/debugfs.ocfs2/main.c
+++ b/debugfs.ocfs2/main.c
@@ -48,7 +48,7 @@ static void usage (char *progname)
 {
 	g_print ("usage: %s -l [<logentry> ... [allow|off|deny]] ...\n", progname);
 	g_print ("usage: %s -d, --decode <lockres>\n", progname);
-	g_print ("usage: %s -e, --encode <lock type> <block num> <generation>\n", progname);
+	g_print ("usage: %s -e, --encode <lock type> <block num> <generation|parent>\n", progname);
 	g_print ("usage: %s [-f cmdfile] [-R request] [-i] [-s backup#] [-V] [-w] [-n] [-?] [device]\n", progname);
 	g_print ("\t-f, --file <cmdfile>\t\tExecute commands in cmdfile\n");
 	g_print ("\t-R, --request <command>\t\tExecute a single command\n");
@@ -117,8 +117,9 @@ static void process_decode_lockres(int argc, char **argv, int startind)
 	int i;
 	errcode_t ret;
 	enum ocfs2_lock_type type;
-	uint64_t blkno;
-	uint32_t generation;
+	uint64_t blkno = 0;
+	uint32_t generation = 0;
+	uint64_t parent = 0;
 
 	if (startind + 1 > argc) {
 		usage(gbls.progname);
@@ -126,34 +127,34 @@ static void process_decode_lockres(int argc, char **argv, int startind)
 	}
 
 	for (i = startind; i < argc; ++i) {
-		ret = ocfs2_decode_lockres(argv[i], -1, &type, &blkno,
-					   &generation);
-		if (ret) {
-			com_err(gbls.progname, ret, "while decoding lockres %s",
-				argv[i]);
+		ret = ocfs2_decode_lockres(argv[i], &type, &blkno,
+					   &generation, &parent);
+		if (ret)
 			continue;
-		}
 
 		printf("Lockres:    %s\n", argv[i]);
-		printf("Type:       %s\n",
-		       ocfs2_get_lock_type_string(type));
-		printf("Block:      %"PRIu64"\n", blkno);
-		printf("Generation: 0x%08x\n", generation);
+		printf("Type:       %s\n", ocfs2_lock_type_string(type));
+		if (blkno)
+			printf("Block:      %"PRIu64"\n", blkno);
+		if (generation)
+			printf("Generation: 0x%08x\n", generation);
+		if (parent)
+			printf("Parent:	    %"PRIu64"\n", parent);
 		printf("\n");
 	}
 
 	return ;
 }
 
-/* [M|D|S] [blkno] [generation] */
 static void process_encode_lockres(int argc, char **argv, int startind)
 {
 	int i;
 	errcode_t ret;
 	enum ocfs2_lock_type type;
 	uint64_t blkno;
-	uint32_t generation;
-	char lockres[50];
+	uint64_t extra; /* generation or parent */
+	char lock[OCFS2_LOCK_ID_MAX_LEN];
+	char tmp[OCFS2_LOCK_ID_MAX_LEN];
 
 	if (startind + 3 > argc) {
 		usage(gbls.progname);
@@ -164,15 +165,21 @@ static void process_encode_lockres(int argc, char **argv, int startind)
 
 	type = ocfs2_get_lock_type(argv[i++][0]);
 	blkno = strtoull(argv[i++], NULL, 0);
-	generation = strtoul(argv[i++], NULL, 0);
-
-	ret = ocfs2_encode_lockres(type, blkno, generation, lockres);
+	extra = strtoull(argv[i++], NULL, 0);
+
+	if (type == OCFS2_LOCK_TYPE_DENTRY) {
+		ret = ocfs2_encode_lockres(type, blkno, 0, extra, tmp);
+		if (!ret)
+			ret = ocfs2_printable_lockres(tmp, lock, sizeof(lock));
+	} else
+		ret = ocfs2_encode_lockres(type, blkno, (uint32_t)extra, 0,
+					   lock);
 	if (ret) {
-		com_err(gbls.progname, ret, "while encoding lockres");
+		com_err(gbls.progname, ret, "while encoding lockname");
 		return ;
 	}
 
-	printf("%s\n", lockres);
+	printf("%s\n", lock);
 
 	return ;
 }
diff --git a/debugfs.ocfs2/utils.c b/debugfs.ocfs2/utils.c
index ff2624d..1c302c9 100644
--- a/debugfs.ocfs2/utils.c
+++ b/debugfs.ocfs2/utils.c
@@ -307,30 +307,37 @@ void close_pager(FILE *stream)
  * inodestr_to_inode()
  *
  * Returns ino if string is of the form <ino>
- *
- * Copyright (C) 1993, 1994 Theodore Ts'o.  This file may be
- * redistributed under the terms of the GNU Public License.
  */
 int inodestr_to_inode(char *str, uint64_t *blkno)
 {
 	int len;
+	char *buf = NULL;
 	char *end;
+	int ret = OCFS2_ET_INVALID_LOCKRES;
 
 	len = strlen(str);
-	if ((len > 2) && (str[0] == '<') && (str[len-1] == '>')) {
-		if (ocfs2_get_lock_type(str[1]) < OCFS2_NUM_LOCK_TYPES) {
-			if (!ocfs2_decode_lockres(str+1, len-2, NULL, blkno,
-						  NULL))
-				return 0;
-			else
-				return -1;
-		}
-		*blkno = strtoull(str+1, &end, 0);
-		if (*end=='>')
-			return 0;
+	if (!((len > 2) && (str[0] == '<') && (str[len - 1] == '>')))
+		goto bail;
+
+	ret = OCFS2_ET_NO_MEMORY;
+	buf = strndup(str + 1, len - 2);
+	if (!buf)
+		goto bail;
+
+	ret = 0;
+	if (ocfs2_get_lock_type(buf[0]) < OCFS2_NUM_LOCK_TYPES)
+		ret = ocfs2_decode_lockres(buf, NULL, blkno, NULL, NULL);
+	else {
+		*blkno = strtoull(buf, &end, 0);
+		if (*end)
+			ret = OCFS2_ET_INVALID_LOCKRES;
 	}
 
-	return -1;
+bail:
+	if (buf)
+		free(buf);
+
+	return ret;
 }
 
 /*
diff --git a/include/ocfs2-kernel/ocfs2_lockid.h b/include/ocfs2-kernel/ocfs2_lockid.h
index 7dd9e1e..82c200f 100644
--- a/include/ocfs2-kernel/ocfs2_lockid.h
+++ b/include/ocfs2-kernel/ocfs2_lockid.h
@@ -35,12 +35,17 @@
 #define OCFS2_LOCK_ID_MAX_LEN  32
 #define OCFS2_LOCK_ID_PAD "000000"
 
+#define OCFS2_DENTRY_LOCK_INO_START 18
+
 enum ocfs2_lock_type {
 	OCFS2_LOCK_TYPE_META = 0,
 	OCFS2_LOCK_TYPE_DATA,
 	OCFS2_LOCK_TYPE_SUPER,
 	OCFS2_LOCK_TYPE_RENAME,
 	OCFS2_LOCK_TYPE_RW,
+	OCFS2_LOCK_TYPE_DENTRY,
+	OCFS2_LOCK_TYPE_OPEN,
+	OCFS2_LOCK_TYPE_FLOCK,
 	OCFS2_NUM_LOCK_TYPES
 };
 
@@ -63,6 +68,15 @@ static inline char ocfs2_lock_type_char(enum ocfs2_lock_type type)
 		case OCFS2_LOCK_TYPE_RW:
 			c = 'W';
 			break;
+		case OCFS2_LOCK_TYPE_DENTRY:
+			c = 'N';
+			break;
+		case OCFS2_LOCK_TYPE_OPEN:
+			c = 'O';
+			break;
+		case OCFS2_LOCK_TYPE_FLOCK:
+			c = 'F';
+			break;
 		default:
 			c = '\0';
 	}
@@ -70,4 +84,25 @@ static inline char ocfs2_lock_type_char(enum ocfs2_lock_type type)
 	return c;
 }
 
+static char *ocfs2_lock_type_strings[] = {
+	[OCFS2_LOCK_TYPE_META] = "Meta",
+	[OCFS2_LOCK_TYPE_DATA] = "Data",
+	[OCFS2_LOCK_TYPE_SUPER] = "Super",
+	[OCFS2_LOCK_TYPE_RENAME] = "Rename",
+	/* Need to differntiate from [R]ename.. serializing writes is the
+	 * important job it does, anyway. */
+	[OCFS2_LOCK_TYPE_RW] = "Write/Read",
+	[OCFS2_LOCK_TYPE_DENTRY] = "Dentry",
+	[OCFS2_LOCK_TYPE_OPEN] = "Open",
+	[OCFS2_LOCK_TYPE_FLOCK] = "Flock",
+};
+
+static inline const char *ocfs2_lock_type_string(enum ocfs2_lock_type type)
+{
+#ifdef __KERNEL__
+	BUG_ON(type >= OCFS2_NUM_LOCK_TYPES);
+#endif
+	return ocfs2_lock_type_strings[type];
+}
+
 #endif  /* OCFS2_LOCKID_H */
diff --git a/include/ocfs2/ocfs2.h b/include/ocfs2/ocfs2.h
index fbc3146..84818b8 100644
--- a/include/ocfs2/ocfs2.h
+++ b/include/ocfs2/ocfs2.h
@@ -579,10 +579,14 @@ enum ocfs2_lock_type ocfs2_get_lock_type(char c);
 char *ocfs2_get_lock_type_string(enum ocfs2_lock_type type);
 
 errcode_t ocfs2_encode_lockres(enum ocfs2_lock_type type, uint64_t blkno,
-			       uint32_t generation, char *lockres);
+			       uint32_t generation, uint64_t parent,
+			       char *lockres);
 
-errcode_t ocfs2_decode_lockres(char *lockres, int len, enum ocfs2_lock_type *type,
-			       uint64_t *blkno, uint32_t *generation);
+errcode_t ocfs2_decode_lockres(char *lockres, enum ocfs2_lock_type *type,
+			       uint64_t *blkno, uint32_t *generation,
+			       uint64_t *parent);
+
+errcode_t ocfs2_printable_lockres(char *lockres, char *name, int len);
 
 /* write the superblock at the specific block. */
 errcode_t ocfs2_write_backup_super(ocfs2_filesys *fs, uint64_t blkno);
diff --git a/libocfs2/dlm.c b/libocfs2/dlm.c
index cf5f61b..3a5015c 100644
--- a/libocfs2/dlm.c
+++ b/libocfs2/dlm.c
@@ -253,7 +253,7 @@ errcode_t ocfs2_super_lock(ocfs2_filesys *fs)
 	errcode_t ret;
 
 	ocfs2_encode_lockres(OCFS2_LOCK_TYPE_SUPER, OCFS2_SUPER_BLOCK_BLKNO,
-			     0, lock_name);
+			     0, 0, lock_name);
 
 	ret = o2dlm_lock(fs->fs_dlm_ctxt, lock_name,
 			 O2DLM_TRYLOCK, O2DLM_LEVEL_EXMODE);
@@ -267,7 +267,7 @@ errcode_t ocfs2_super_unlock(ocfs2_filesys *fs)
 	errcode_t ret;
 
 	ocfs2_encode_lockres(OCFS2_LOCK_TYPE_SUPER, OCFS2_SUPER_BLOCK_BLKNO,
-			     0, lock_name);
+			     0, 0, lock_name);
 
 	ret = o2dlm_unlock(fs->fs_dlm_ctxt, lock_name);
 
@@ -283,7 +283,7 @@ errcode_t ocfs2_meta_lock(ocfs2_filesys *fs,
 	errcode_t ret;
 
 	ocfs2_encode_lockres(OCFS2_LOCK_TYPE_META, ci->ci_blkno,
-			     ci->ci_inode->i_generation, lock_name);
+			     ci->ci_inode->i_generation, 0, lock_name);
 
 	ret = o2dlm_lock(fs->fs_dlm_ctxt, lock_name, flags, level);
 
@@ -297,7 +297,7 @@ errcode_t ocfs2_meta_unlock(ocfs2_filesys *fs,
 	errcode_t ret;
 
 	ocfs2_encode_lockres(OCFS2_LOCK_TYPE_META, ci->ci_blkno,
-			     ci->ci_inode->i_generation, lock_name);
+			     ci->ci_inode->i_generation, 0, lock_name);
 
 	ret = o2dlm_unlock(fs->fs_dlm_ctxt, lock_name);
 
diff --git a/libocfs2/lockid.c b/libocfs2/lockid.c
index 7046e51..01ae2d2 100644
--- a/libocfs2/lockid.c
+++ b/libocfs2/lockid.c
@@ -5,7 +5,7 @@
  *
  * Encode and decode lockres name
  *
- * Copyright (C) 2004 Oracle.  All rights reserved.
+ * Copyright (C) 2004, 2008 Oracle.  All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public
@@ -22,6 +22,7 @@
  * Boston, MA 021110-1307, USA.
  */
 
+#include "ocfs2/byteorder.h"
 #include "ocfs2/ocfs2.h"
 
 #include <string.h>
@@ -40,32 +41,27 @@ enum ocfs2_lock_type ocfs2_get_lock_type(char c)
 		return OCFS2_LOCK_TYPE_RENAME;
 	case 'W':
 		return OCFS2_LOCK_TYPE_RW;
+	case 'N':
+		return OCFS2_LOCK_TYPE_DENTRY;
+	case 'O':
+		return OCFS2_LOCK_TYPE_OPEN;
+	case 'F':
+		return OCFS2_LOCK_TYPE_FLOCK;
 	default:
 		return OCFS2_NUM_LOCK_TYPES;
 	}
 }
 
-char *ocfs2_get_lock_type_string(enum ocfs2_lock_type type)
-{
-	switch (type) {
-	case OCFS2_LOCK_TYPE_META:
-		return "Metadata";
-	case OCFS2_LOCK_TYPE_DATA:
-		return "Data";
-	case OCFS2_LOCK_TYPE_SUPER:
-		return "Superblock";
-	case OCFS2_LOCK_TYPE_RENAME:
-		return "Rename";
-	case OCFS2_LOCK_TYPE_RW:
-		return "Write/Read";
-	default:
-		return NULL;
-	}
-}
-
+/*
+ * This function encodes the lockname just like the filesystem. Meaning
+ * the dentry lock gets encoded in its binary form.
+ */
 errcode_t ocfs2_encode_lockres(enum ocfs2_lock_type type, uint64_t blkno,
-			       uint32_t generation, char *lockres)
+			       uint32_t generation, uint64_t parent,
+			       char *lockres)
 {
+	uint64_t b;
+
 	if (type >= OCFS2_NUM_LOCK_TYPES)
 		return OCFS2_ET_INVALID_LOCKRES;
 
@@ -73,53 +69,82 @@ errcode_t ocfs2_encode_lockres(enum ocfs2_lock_type type, uint64_t blkno,
 	generation = ((type == OCFS2_LOCK_TYPE_SUPER) ||
 		      (type == OCFS2_LOCK_TYPE_RENAME)) ? 0 : generation;
 
-	snprintf(lockres, OCFS2_LOCK_ID_MAX_LEN, "%c%s%016"PRIx64"%08x",
-		 ocfs2_lock_type_char(type), OCFS2_LOCK_ID_PAD,
-		 blkno, generation);
+	if (type != OCFS2_LOCK_TYPE_DENTRY) {
+		snprintf(lockres, OCFS2_LOCK_ID_MAX_LEN, "%c%s%016"PRIx64"%08x",
+			 ocfs2_lock_type_char(type), OCFS2_LOCK_ID_PAD,
+			 blkno, generation);
+	} else {
+		snprintf(lockres, OCFS2_DENTRY_LOCK_INO_START, "%c%016llx",
+			 ocfs2_lock_type_char(OCFS2_LOCK_TYPE_DENTRY),
+			 (long long)parent);
+		b = bswap_64(blkno);
+		memcpy(&lockres[OCFS2_DENTRY_LOCK_INO_START], &b, sizeof(b));
+	}
 
 	return 0;
 }
 
-errcode_t ocfs2_decode_lockres(char *lockres, int len, enum ocfs2_lock_type *type,
-			       uint64_t *blkno, uint32_t *generation)
+errcode_t ocfs2_decode_lockres(char *lockres, enum ocfs2_lock_type *type,
+			       uint64_t *blkno, uint32_t *generation,
+			       uint64_t *parent)
 {
-	char *lock = NULL;
-	errcode_t ret = OCFS2_ET_NO_MEMORY;
-	char blkstr[20];
 	int i = 0;
+	enum ocfs2_lock_type t;
+	char *l = lockres;
+	uint64_t b = 0;
+	uint64_t p = 0;
+	uint32_t g = 0;
 	
-	if (len != -1) {
-		lock = calloc(len+1, 1);
-		if (!lock)
-			goto bail;
-		strncpy(lock, lockres, len);
-	} else
-		lock = lockres;
-
-	ret = OCFS2_ET_INVALID_LOCKRES;
-	
-	if ((strlen(lock) + 1) != OCFS2_LOCK_ID_MAX_LEN)
-		goto bail;
+	if ((t = ocfs2_get_lock_type(*l)) >= OCFS2_NUM_LOCK_TYPES)
+		return OCFS2_ET_INVALID_LOCKRES;
 
-	if (ocfs2_get_lock_type(lock[0]) >= OCFS2_NUM_LOCK_TYPES)
-		goto bail;
+	if (t != OCFS2_LOCK_TYPE_DENTRY) {
+		i = sscanf(l + 1, OCFS2_LOCK_ID_PAD"%016llx%08x", &b, &g);
+		if (i != 2)
+			return OCFS2_ET_INVALID_LOCKRES;
+	} else {
+		i = sscanf(l + 1, "%016llx", &p);
+		if (i != 1)
+			return OCFS2_ET_INVALID_LOCKRES;
+		b = strtoull(&l[OCFS2_DENTRY_LOCK_INO_START], NULL, 16);
+	}
 
 	if (type)
-		*type = ocfs2_get_lock_type(lock[i]);
+		*type = t;
 
-	i = 1 + strlen(OCFS2_LOCK_ID_PAD);
-	memset(blkstr, 0, sizeof(blkstr));
-	memcpy(blkstr, &lock[i], 16);
 	if (blkno)
-		*blkno = strtoull(blkstr, NULL, 16);
+		*blkno = b;
 
-	i += 16;
 	if (generation)
-		*generation = strtoul(&lock[i], NULL, 16);
+		*generation = g;
 
-	ret = 0;
-bail:
-	if (len != -1 && lock)
-		free(lock);
-	return ret;
+	if (parent)
+		*parent = p;
+
+	return 0;
+}
+
+/*
+ * This function is useful when printing the dentry lock. It converts the
+ * dentry lockname into a string using the same scheme as used in dlmglue.
+ */
+errcode_t ocfs2_printable_lockres(char *lockres, char *name, int len)
+{
+	uint64_t b;
+
+	memset(name, 0, len);
+
+	if (ocfs2_get_lock_type(*lockres) >= OCFS2_NUM_LOCK_TYPES)
+		return OCFS2_ET_INVALID_LOCKRES;
+
+	if (ocfs2_get_lock_type(*lockres) == OCFS2_LOCK_TYPE_DENTRY) {
+		memcpy((uint64_t *)&b,
+		       (char *)&lockres[OCFS2_DENTRY_LOCK_INO_START],
+		       sizeof(uint64_t));
+		snprintf(name, len, "%.*s%08x", OCFS2_DENTRY_LOCK_INO_START - 1,
+			 lockres, (unsigned int)bswap_64(b));
+	} else
+		snprintf(name, len, "%s", lockres);
+
+	return 0;
 }
-- 
1.5.4.3




More information about the Ocfs2-tools-devel mailing list