[Ocfs2-tools-devel] [PATCH] libo2dlm: Add support for BASTs

Joel Becker Joel.Becker at oracle.com
Wed Jan 27 18:58:25 PST 2010


[ Here's the userspace side of the poll-is-bast change.  You'll need the
  kernel patch to test it.  Note that it is not smart enough to detect
  pre-change kernels.  I think we have to add that later. -- Joel

ocfs2_dlmfs can now notify userspace of BASTs via poll(2) or select(2).
We need a way for libo2dlm users to actually access this information.

This change introduces two new functions.  The first,
o2dlm_lock_with_bast(), is exactly like o2dlm_lock() except that it
takes a BAST function and returns a file descriptor to poll on.  When
that file descriptor signals data is ready, the program calls the second
new function, o2dlm_process_bast().  This will fire off the appropriate
BAST.

Signed-off-by: Joel Becker <joel.becker at oracle.com>
---
 include/o2dlm/o2dlm.h |   25 ++++++++-
 libo2dlm/o2dlm.c      |  139 +++++++++++++++++++++++++++++++++++++++++++++++--
 libo2dlm/o2dlm_err.et |    3 +
 3 files changed, 161 insertions(+), 6 deletions(-)

diff --git a/include/o2dlm/o2dlm.h b/include/o2dlm/o2dlm.h
index 99bee5f..2cdf12f 100644
--- a/include/o2dlm/o2dlm.h
+++ b/include/o2dlm/o2dlm.h
@@ -74,12 +74,25 @@ errcode_t o2dlm_initialize(const char *dlmfs_path,
  */
 errcode_t o2dlm_lock(struct o2dlm_ctxt *ctxt,
 		     const char *lockid,
-		     int flags,
+		     int lockflags,
 		     enum o2dlm_lock_level level);
 
+/*
+ * Like o2dlm_lock, but also registers a BAST function for this lock.  This
+ * returns a file descriptor in poll_fd that can be fed to select(2) or
+ * poll(2).  When there is POLLIN on the descriptor, call o2dlm_process_bast().
+ */
+errcode_t o2dlm_lock_with_bast(struct o2dlm_ctxt *ctxt,
+			       const char *lockid,
+			       int lockflags,
+			       enum o2dlm_lock_level level,
+			       void (*bast_func)(void *bast_arg),
+			       void *bast_arg,
+			       int *poll_fd);
+
 /* returns 0 on success */
 errcode_t o2dlm_unlock(struct o2dlm_ctxt *ctxt,
-		       char *lockid);
+		       const char *lockid);
 
 /* Read the LVB out of a lock.
  * 'len' is the amount to read into 'lvb'
@@ -102,6 +115,14 @@ errcode_t o2dlm_write_lvb(struct o2dlm_ctxt *ctxt,
 			  unsigned int len,
 			  unsigned int *bytes_written);
 
+
+/*
+ * Call this when select(2) or poll(2) says there is data on poll_fd.  It
+ * will fire off the BAST associated with poll_fd.
+ */
+void o2dlm_process_bast(struct o2dlm_ctxt *ctxt, int poll_fd);
+
+
 /*
  * Unlocks all pending locks and frees the lock context.
  */
diff --git a/libo2dlm/o2dlm.c b/libo2dlm/o2dlm.c
index 49d98ff..ef04600 100644
--- a/libo2dlm/o2dlm.c
+++ b/libo2dlm/o2dlm.c
@@ -46,6 +46,13 @@
 
 #define USER_DLMFS_MAGIC	0x76a9f425
 
+struct o2dlm_lock_bast
+{
+	struct list_head	b_bucket; /* to hang us off of the bast list */
+	int			b_fd;     /* the fd of the lock file */
+	void			(*b_bast)(void *);
+	void			*b_arg;   /* Argument to ->b_bast() */
+};
 
 struct o2dlm_lock_res
 {
@@ -67,6 +74,7 @@ struct o2dlm_ctxt
 {
 	int		ct_classic;
 	struct list_head *ct_hash;
+	struct list_head *ct_bast_hash;
 	unsigned int     ct_hash_size;
 	char             ct_domain_path[O2DLM_MAX_FULL_DOMAIN_PATH]; /* domain
 								      * dir */
@@ -105,6 +113,8 @@ static void o2dlm_free_ctxt(struct o2dlm_ctxt *ctxt)
 {
 	if (ctxt->ct_hash)
 		free(ctxt->ct_hash);
+	if (ctxt->ct_bast_hash)
+		free(ctxt->ct_bast_hash);
 	free(ctxt);
 }
 
@@ -131,13 +141,17 @@ static errcode_t o2dlm_alloc_ctxt(const char *mnt_path,
 	ctxt->ct_hash_size = O2DLM_DEFAULT_HASH_SIZE;
 
 	ctxt->ct_hash = calloc(ctxt->ct_hash_size, sizeof(struct list_head));
-	if (!ctxt->ct_hash) {
+	ctxt->ct_bast_hash = calloc(ctxt->ct_hash_size,
+				    sizeof(struct list_head));
+	if (!ctxt->ct_hash || !ctxt->ct_bast_hash) {
 		err = O2DLM_ET_NO_MEMORY;
 		goto exit_and_free;
 	}
 
-	for(i = 0; i < ctxt->ct_hash_size; i++)
+	for(i = 0; i < ctxt->ct_hash_size; i++) {
 		INIT_LIST_HEAD(&ctxt->ct_hash[i]);
+		INIT_LIST_HEAD(&ctxt->ct_bast_hash[i]);
+	}
 
 	len = snprintf(ctxt->ct_ctxt_lock_name, O2DLM_LOCK_ID_MAX_LEN,
 		       ".%016"PRIx64, rand);
@@ -378,6 +392,63 @@ static struct o2dlm_lock_res *o2dlm_new_lock_res(const char *id,
 	return lockres;
 }
 
+
+static inline unsigned int o2dlm_hash_bast(struct o2dlm_ctxt *ctxt, int fd)
+{
+	return fd % ctxt->ct_hash_size;
+}
+
+static struct o2dlm_lock_bast *o2dlm_find_bast(struct o2dlm_ctxt *ctxt, int fd)
+{
+	struct o2dlm_lock_bast *bast;
+	struct list_head *p;
+	unsigned int bucket;
+
+	bucket = o2dlm_hash_bast(ctxt, fd);
+
+	list_for_each(p, &ctxt->ct_bast_hash[bucket]) {
+		bast = list_entry(p, struct o2dlm_lock_bast, b_bucket);
+		if (fd == bast->b_fd)
+			return bast;
+	}
+	return NULL;
+}
+
+static void o2dlm_insert_bast(struct o2dlm_ctxt *ctxt,
+			      struct o2dlm_lock_bast *bast)
+{
+	unsigned int bucket;
+
+	bucket = o2dlm_hash_bast(ctxt, bast->b_fd);
+
+	list_add_tail(&bast->b_bucket, &ctxt->ct_bast_hash[bucket]);
+}
+
+static inline void o2dlm_remove_bast(struct o2dlm_lock_bast *bast)
+{
+	list_del(&bast->b_bucket);
+	INIT_LIST_HEAD(&bast->b_bucket);
+}
+
+static struct o2dlm_lock_bast *o2dlm_new_bast(int fd,
+					      void (*bast_func)(void *),
+					      void *bastarg)
+{
+	struct o2dlm_lock_bast *bast;
+
+	bast = malloc(sizeof(*bast));
+	if (bast) {
+		memset(bast, 0, sizeof(*bast));
+
+		INIT_LIST_HEAD(&bast->b_bucket);
+
+		bast->b_bast = bast_func;
+		bast->b_arg = bastarg;
+		bast->b_fd = fd;
+	}
+	return bast;
+}
+
 #define O2DLM_OPEN_MODE         0664
 
 
@@ -584,11 +655,19 @@ static errcode_t o2dlm_destroy_classic(struct o2dlm_ctxt *ctxt)
 	int ret, i;
 	int error = 0;
 	struct o2dlm_lock_res *lockres;
+	struct o2dlm_lock_bast *bast;
         struct list_head *p, *n, *bucket;
 
 	for(i = 0; i < ctxt->ct_hash_size; i++) {
-		bucket = &ctxt->ct_hash[i];
+		bucket = &ctxt->ct_bast_hash[i];
+		list_for_each_safe(p, n, bucket) {
+			bast = list_entry(p, struct o2dlm_lock_bast,
+					  b_bucket);
+			o2dlm_remove_bast(bast);
+			free(bast);
+		}
 
+		bucket = &ctxt->ct_hash[i];
 		list_for_each_safe(p, n, bucket) {
 			lockres = list_entry(p, struct o2dlm_lock_res,
 					     l_bucket);
@@ -1109,6 +1188,44 @@ errcode_t o2dlm_lock(struct o2dlm_ctxt *ctxt,
 	return o2dlm_lock_nochecks(ctxt, lockid, lockflags, level);
 }
 
+errcode_t o2dlm_lock_with_bast(struct o2dlm_ctxt *ctxt,
+			       const char *lockid,
+			       int lockflags,
+			       enum o2dlm_lock_level level,
+			       void (*bast_func)(void *bast_arg),
+			       void *bast_arg,
+			       int *poll_fd)
+{
+	errcode_t ret;
+	struct o2dlm_lock_res *lockres;
+	struct o2dlm_lock_bast *bast;
+
+	if (!ctxt->ct_classic)
+		return O2DLM_ET_BAST_UNSUPPORTED;
+	if (!bast_func || !poll_fd)
+		return O2DLM_ET_INVALID_ARGS;
+
+	ret = o2dlm_lock(ctxt, lockid, lockflags, level);
+	if (ret)
+		return ret;
+
+	lockres = o2dlm_find_lock_res(ctxt, lockid);
+	if (!lockres) {
+		o2dlm_unlock(ctxt, lockid);
+		return O2DLM_ET_INTERNAL_FAILURE;
+	}
+
+	bast = o2dlm_new_bast(lockres->l_fd, bast_func, bast_arg);
+	if (!bast) {
+		o2dlm_unlock(ctxt, lockid);
+		return O2DLM_ET_NO_MEMORY;
+	}
+
+	o2dlm_insert_bast(ctxt, bast);
+	*poll_fd = lockres->l_fd;
+	return 0;
+}
+
 static errcode_t o2dlm_unlock_lock_res(struct o2dlm_ctxt *ctxt,
 				       struct o2dlm_lock_res *lockres)
 {
@@ -1119,10 +1236,11 @@ static errcode_t o2dlm_unlock_lock_res(struct o2dlm_ctxt *ctxt,
 }
 
 errcode_t o2dlm_unlock(struct o2dlm_ctxt *ctxt,
-		       char *lockid)
+		       const char *lockid)
 {
 	int ret;
 	struct o2dlm_lock_res *lockres;
+	struct o2dlm_lock_bast *bast;
 
 	if (!ctxt || !lockid)
 		return O2DLM_ET_INVALID_ARGS;
@@ -1131,6 +1249,10 @@ errcode_t o2dlm_unlock(struct o2dlm_ctxt *ctxt,
 	if (!lockres)
 		return O2DLM_ET_UNKNOWN_LOCK;
 
+	bast = o2dlm_find_bast(ctxt, lockres->l_fd);
+	if (bast)
+		o2dlm_remove_bast(bast);
+
 	o2dlm_remove_lock_res(lockres);
 
 	ret = o2dlm_unlock_lock_res(ctxt, lockres);
@@ -1176,6 +1298,15 @@ errcode_t o2dlm_write_lvb(struct o2dlm_ctxt *ctxt,
 					     bytes_written);
 }
 
+void o2dlm_process_bast(struct o2dlm_ctxt *ctxt, int poll_fd)
+{
+	struct o2dlm_lock_bast *bast;
+
+	bast = o2dlm_find_bast(ctxt, poll_fd);
+	if (bast)
+		bast->b_bast(bast->b_arg);
+}
+
 /* NULL dlmfs_path means fsdlm */
 errcode_t o2dlm_initialize(const char *dlmfs_path,
 			   const char *domain_name,
diff --git a/libo2dlm/o2dlm_err.et b/libo2dlm/o2dlm_err.et
index 528a6e6..184e295 100644
--- a/libo2dlm/o2dlm_err.et
+++ b/libo2dlm/o2dlm_err.et
@@ -111,4 +111,7 @@ ec      O2DLM_ET_SEEK,
 ec	O2DLM_ET_DOMAIN_BUSY,
 	"The domain is busy and cannot be accessed"
 
+ec	O2DLM_ET_BAST_UNSUPPORTED,
+	"This environment does not support BASTs"
+
 	end
-- 
1.6.6


-- 

Life's Little Instruction Book #252

	"Take good care of those you love."

Joel Becker
Principal Software Developer
Oracle
E-mail: joel.becker at oracle.com
Phone: (650) 506-8127



More information about the Ocfs2-tools-devel mailing list