[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