|
@@ -53,6 +53,7 @@
|
|
#include "super.h"
|
|
#include "super.h"
|
|
#include "uptodate.h"
|
|
#include "uptodate.h"
|
|
#include "quota.h"
|
|
#include "quota.h"
|
|
|
|
+#include "refcounttree.h"
|
|
|
|
|
|
#include "buffer_head_io.h"
|
|
#include "buffer_head_io.h"
|
|
|
|
|
|
@@ -110,6 +111,11 @@ static void ocfs2_dentry_post_unlock(struct ocfs2_super *osb,
|
|
|
|
|
|
static void ocfs2_set_qinfo_lvb(struct ocfs2_lock_res *lockres);
|
|
static void ocfs2_set_qinfo_lvb(struct ocfs2_lock_res *lockres);
|
|
|
|
|
|
|
|
+static int ocfs2_check_refcount_downconvert(struct ocfs2_lock_res *lockres,
|
|
|
|
+ int new_level);
|
|
|
|
+static int ocfs2_refcount_convert_worker(struct ocfs2_lock_res *lockres,
|
|
|
|
+ int blocking);
|
|
|
|
+
|
|
#define mlog_meta_lvb(__level, __lockres) ocfs2_dump_meta_lvb_info(__level, __PRETTY_FUNCTION__, __LINE__, __lockres)
|
|
#define mlog_meta_lvb(__level, __lockres) ocfs2_dump_meta_lvb_info(__level, __PRETTY_FUNCTION__, __LINE__, __lockres)
|
|
|
|
|
|
/* This aids in debugging situations where a bad LVB might be involved. */
|
|
/* This aids in debugging situations where a bad LVB might be involved. */
|
|
@@ -278,6 +284,12 @@ static struct ocfs2_lock_res_ops ocfs2_qinfo_lops = {
|
|
.flags = LOCK_TYPE_REQUIRES_REFRESH | LOCK_TYPE_USES_LVB,
|
|
.flags = LOCK_TYPE_REQUIRES_REFRESH | LOCK_TYPE_USES_LVB,
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+static struct ocfs2_lock_res_ops ocfs2_refcount_block_lops = {
|
|
|
|
+ .check_downconvert = ocfs2_check_refcount_downconvert,
|
|
|
|
+ .downconvert_worker = ocfs2_refcount_convert_worker,
|
|
|
|
+ .flags = 0,
|
|
|
|
+};
|
|
|
|
+
|
|
static inline int ocfs2_is_inode_lock(struct ocfs2_lock_res *lockres)
|
|
static inline int ocfs2_is_inode_lock(struct ocfs2_lock_res *lockres)
|
|
{
|
|
{
|
|
return lockres->l_type == OCFS2_LOCK_TYPE_META ||
|
|
return lockres->l_type == OCFS2_LOCK_TYPE_META ||
|
|
@@ -306,6 +318,12 @@ static inline struct ocfs2_mem_dqinfo *ocfs2_lock_res_qinfo(struct ocfs2_lock_re
|
|
return (struct ocfs2_mem_dqinfo *)lockres->l_priv;
|
|
return (struct ocfs2_mem_dqinfo *)lockres->l_priv;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static inline struct ocfs2_refcount_tree *
|
|
|
|
+ocfs2_lock_res_refcount_tree(struct ocfs2_lock_res *res)
|
|
|
|
+{
|
|
|
|
+ return container_of(res, struct ocfs2_refcount_tree, rf_lockres);
|
|
|
|
+}
|
|
|
|
+
|
|
static inline struct ocfs2_super *ocfs2_get_lockres_osb(struct ocfs2_lock_res *lockres)
|
|
static inline struct ocfs2_super *ocfs2_get_lockres_osb(struct ocfs2_lock_res *lockres)
|
|
{
|
|
{
|
|
if (lockres->l_ops->get_osb)
|
|
if (lockres->l_ops->get_osb)
|
|
@@ -693,6 +711,17 @@ void ocfs2_qinfo_lock_res_init(struct ocfs2_lock_res *lockres,
|
|
info);
|
|
info);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+void ocfs2_refcount_lock_res_init(struct ocfs2_lock_res *lockres,
|
|
|
|
+ struct ocfs2_super *osb, u64 ref_blkno,
|
|
|
|
+ unsigned int generation)
|
|
|
|
+{
|
|
|
|
+ ocfs2_lock_res_init_once(lockres);
|
|
|
|
+ ocfs2_build_lock_name(OCFS2_LOCK_TYPE_REFCOUNT, ref_blkno,
|
|
|
|
+ generation, lockres->l_name);
|
|
|
|
+ ocfs2_lock_res_init_common(osb, lockres, OCFS2_LOCK_TYPE_REFCOUNT,
|
|
|
|
+ &ocfs2_refcount_block_lops, osb);
|
|
|
|
+}
|
|
|
|
+
|
|
void ocfs2_lock_res_free(struct ocfs2_lock_res *res)
|
|
void ocfs2_lock_res_free(struct ocfs2_lock_res *res)
|
|
{
|
|
{
|
|
mlog_entry_void();
|
|
mlog_entry_void();
|
|
@@ -3648,6 +3677,26 @@ static int ocfs2_dentry_convert_worker(struct ocfs2_lock_res *lockres,
|
|
return UNBLOCK_CONTINUE_POST;
|
|
return UNBLOCK_CONTINUE_POST;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int ocfs2_check_refcount_downconvert(struct ocfs2_lock_res *lockres,
|
|
|
|
+ int new_level)
|
|
|
|
+{
|
|
|
|
+ struct ocfs2_refcount_tree *tree =
|
|
|
|
+ ocfs2_lock_res_refcount_tree(lockres);
|
|
|
|
+
|
|
|
|
+ return ocfs2_ci_checkpointed(&tree->rf_ci, lockres, new_level);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int ocfs2_refcount_convert_worker(struct ocfs2_lock_res *lockres,
|
|
|
|
+ int blocking)
|
|
|
|
+{
|
|
|
|
+ struct ocfs2_refcount_tree *tree =
|
|
|
|
+ ocfs2_lock_res_refcount_tree(lockres);
|
|
|
|
+
|
|
|
|
+ ocfs2_metadata_cache_purge(&tree->rf_ci);
|
|
|
|
+
|
|
|
|
+ return UNBLOCK_CONTINUE;
|
|
|
|
+}
|
|
|
|
+
|
|
static void ocfs2_set_qinfo_lvb(struct ocfs2_lock_res *lockres)
|
|
static void ocfs2_set_qinfo_lvb(struct ocfs2_lock_res *lockres)
|
|
{
|
|
{
|
|
struct ocfs2_qinfo_lvb *lvb;
|
|
struct ocfs2_qinfo_lvb *lvb;
|
|
@@ -3760,6 +3809,37 @@ bail:
|
|
return status;
|
|
return status;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+int ocfs2_refcount_lock(struct ocfs2_refcount_tree *ref_tree, int ex)
|
|
|
|
+{
|
|
|
|
+ int status;
|
|
|
|
+ int level = ex ? DLM_LOCK_EX : DLM_LOCK_PR;
|
|
|
|
+ struct ocfs2_lock_res *lockres = &ref_tree->rf_lockres;
|
|
|
|
+ struct ocfs2_super *osb = lockres->l_priv;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ if (ocfs2_is_hard_readonly(osb))
|
|
|
|
+ return -EROFS;
|
|
|
|
+
|
|
|
|
+ if (ocfs2_mount_local(osb))
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ status = ocfs2_cluster_lock(osb, lockres, level, 0, 0);
|
|
|
|
+ if (status < 0)
|
|
|
|
+ mlog_errno(status);
|
|
|
|
+
|
|
|
|
+ return status;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void ocfs2_refcount_unlock(struct ocfs2_refcount_tree *ref_tree, int ex)
|
|
|
|
+{
|
|
|
|
+ int level = ex ? DLM_LOCK_EX : DLM_LOCK_PR;
|
|
|
|
+ struct ocfs2_lock_res *lockres = &ref_tree->rf_lockres;
|
|
|
|
+ struct ocfs2_super *osb = lockres->l_priv;
|
|
|
|
+
|
|
|
|
+ if (!ocfs2_mount_local(osb))
|
|
|
|
+ ocfs2_cluster_unlock(osb, lockres, level);
|
|
|
|
+}
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* This is the filesystem locking protocol. It provides the lock handling
|
|
* This is the filesystem locking protocol. It provides the lock handling
|
|
* hooks for the underlying DLM. It has a maximum version number.
|
|
* hooks for the underlying DLM. It has a maximum version number.
|