diff options
author | Tao Ma <tao.ma@oracle.com> | 2009-08-17 23:19:58 -0400 |
---|---|---|
committer | Joel Becker <joel.becker@oracle.com> | 2009-09-22 23:09:28 -0400 |
commit | 8dec98edfe9684ce00b580a09dde3dcd21ee785b (patch) | |
tree | 3002e990974163a09ea6d427d7cf775aaca7acca | |
parent | a433848132d8cdfb8173745b922ddb919de11527 (diff) |
ocfs2: Add new refcount tree lock resource in dlmglue.
refcount tree lock resource is used to protect refcount
tree read/write among multiple nodes.
Signed-off-by: Tao Ma <tao.ma@oracle.com>
-rw-r--r-- | fs/ocfs2/dlmglue.c | 80 | ||||
-rw-r--r-- | fs/ocfs2/dlmglue.h | 6 | ||||
-rw-r--r-- | fs/ocfs2/ocfs2_lockid.h | 5 | ||||
-rw-r--r-- | fs/ocfs2/refcounttree.h | 36 |
4 files changed, 127 insertions, 0 deletions
diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c index 79db0557df88..bb2fc6993e2a 100644 --- a/fs/ocfs2/dlmglue.c +++ b/fs/ocfs2/dlmglue.c | |||
@@ -53,6 +53,7 @@ | |||
53 | #include "super.h" | 53 | #include "super.h" |
54 | #include "uptodate.h" | 54 | #include "uptodate.h" |
55 | #include "quota.h" | 55 | #include "quota.h" |
56 | #include "refcounttree.h" | ||
56 | 57 | ||
57 | #include "buffer_head_io.h" | 58 | #include "buffer_head_io.h" |
58 | 59 | ||
@@ -110,6 +111,11 @@ static void ocfs2_dentry_post_unlock(struct ocfs2_super *osb, | |||
110 | 111 | ||
111 | static void ocfs2_set_qinfo_lvb(struct ocfs2_lock_res *lockres); | 112 | static void ocfs2_set_qinfo_lvb(struct ocfs2_lock_res *lockres); |
112 | 113 | ||
114 | static int ocfs2_check_refcount_downconvert(struct ocfs2_lock_res *lockres, | ||
115 | int new_level); | ||
116 | static int ocfs2_refcount_convert_worker(struct ocfs2_lock_res *lockres, | ||
117 | int blocking); | ||
118 | |||
113 | #define mlog_meta_lvb(__level, __lockres) ocfs2_dump_meta_lvb_info(__level, __PRETTY_FUNCTION__, __LINE__, __lockres) | 119 | #define mlog_meta_lvb(__level, __lockres) ocfs2_dump_meta_lvb_info(__level, __PRETTY_FUNCTION__, __LINE__, __lockres) |
114 | 120 | ||
115 | /* This aids in debugging situations where a bad LVB might be involved. */ | 121 | /* 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 = { | |||
278 | .flags = LOCK_TYPE_REQUIRES_REFRESH | LOCK_TYPE_USES_LVB, | 284 | .flags = LOCK_TYPE_REQUIRES_REFRESH | LOCK_TYPE_USES_LVB, |
279 | }; | 285 | }; |
280 | 286 | ||
287 | static struct ocfs2_lock_res_ops ocfs2_refcount_block_lops = { | ||
288 | .check_downconvert = ocfs2_check_refcount_downconvert, | ||
289 | .downconvert_worker = ocfs2_refcount_convert_worker, | ||
290 | .flags = 0, | ||
291 | }; | ||
292 | |||
281 | static inline int ocfs2_is_inode_lock(struct ocfs2_lock_res *lockres) | 293 | static inline int ocfs2_is_inode_lock(struct ocfs2_lock_res *lockres) |
282 | { | 294 | { |
283 | return lockres->l_type == OCFS2_LOCK_TYPE_META || | 295 | 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 | |||
306 | return (struct ocfs2_mem_dqinfo *)lockres->l_priv; | 318 | return (struct ocfs2_mem_dqinfo *)lockres->l_priv; |
307 | } | 319 | } |
308 | 320 | ||
321 | static inline struct ocfs2_refcount_tree * | ||
322 | ocfs2_lock_res_refcount_tree(struct ocfs2_lock_res *res) | ||
323 | { | ||
324 | return container_of(res, struct ocfs2_refcount_tree, rf_lockres); | ||
325 | } | ||
326 | |||
309 | static inline struct ocfs2_super *ocfs2_get_lockres_osb(struct ocfs2_lock_res *lockres) | 327 | static inline struct ocfs2_super *ocfs2_get_lockres_osb(struct ocfs2_lock_res *lockres) |
310 | { | 328 | { |
311 | if (lockres->l_ops->get_osb) | 329 | if (lockres->l_ops->get_osb) |
@@ -693,6 +711,17 @@ void ocfs2_qinfo_lock_res_init(struct ocfs2_lock_res *lockres, | |||
693 | info); | 711 | info); |
694 | } | 712 | } |
695 | 713 | ||
714 | void ocfs2_refcount_lock_res_init(struct ocfs2_lock_res *lockres, | ||
715 | struct ocfs2_super *osb, u64 ref_blkno, | ||
716 | unsigned int generation) | ||
717 | { | ||
718 | ocfs2_lock_res_init_once(lockres); | ||
719 | ocfs2_build_lock_name(OCFS2_LOCK_TYPE_REFCOUNT, ref_blkno, | ||
720 | generation, lockres->l_name); | ||
721 | ocfs2_lock_res_init_common(osb, lockres, OCFS2_LOCK_TYPE_REFCOUNT, | ||
722 | &ocfs2_refcount_block_lops, osb); | ||
723 | } | ||
724 | |||
696 | void ocfs2_lock_res_free(struct ocfs2_lock_res *res) | 725 | void ocfs2_lock_res_free(struct ocfs2_lock_res *res) |
697 | { | 726 | { |
698 | mlog_entry_void(); | 727 | mlog_entry_void(); |
@@ -3648,6 +3677,26 @@ static int ocfs2_dentry_convert_worker(struct ocfs2_lock_res *lockres, | |||
3648 | return UNBLOCK_CONTINUE_POST; | 3677 | return UNBLOCK_CONTINUE_POST; |
3649 | } | 3678 | } |
3650 | 3679 | ||
3680 | static int ocfs2_check_refcount_downconvert(struct ocfs2_lock_res *lockres, | ||
3681 | int new_level) | ||
3682 | { | ||
3683 | struct ocfs2_refcount_tree *tree = | ||
3684 | ocfs2_lock_res_refcount_tree(lockres); | ||
3685 | |||
3686 | return ocfs2_ci_checkpointed(&tree->rf_ci, lockres, new_level); | ||
3687 | } | ||
3688 | |||
3689 | static int ocfs2_refcount_convert_worker(struct ocfs2_lock_res *lockres, | ||
3690 | int blocking) | ||
3691 | { | ||
3692 | struct ocfs2_refcount_tree *tree = | ||
3693 | ocfs2_lock_res_refcount_tree(lockres); | ||
3694 | |||
3695 | ocfs2_metadata_cache_purge(&tree->rf_ci); | ||
3696 | |||
3697 | return UNBLOCK_CONTINUE; | ||
3698 | } | ||
3699 | |||
3651 | static void ocfs2_set_qinfo_lvb(struct ocfs2_lock_res *lockres) | 3700 | static void ocfs2_set_qinfo_lvb(struct ocfs2_lock_res *lockres) |
3652 | { | 3701 | { |
3653 | struct ocfs2_qinfo_lvb *lvb; | 3702 | struct ocfs2_qinfo_lvb *lvb; |
@@ -3760,6 +3809,37 @@ bail: | |||
3760 | return status; | 3809 | return status; |
3761 | } | 3810 | } |
3762 | 3811 | ||
3812 | int ocfs2_refcount_lock(struct ocfs2_refcount_tree *ref_tree, int ex) | ||
3813 | { | ||
3814 | int status; | ||
3815 | int level = ex ? DLM_LOCK_EX : DLM_LOCK_PR; | ||
3816 | struct ocfs2_lock_res *lockres = &ref_tree->rf_lockres; | ||
3817 | struct ocfs2_super *osb = lockres->l_priv; | ||
3818 | |||
3819 | |||
3820 | if (ocfs2_is_hard_readonly(osb)) | ||
3821 | return -EROFS; | ||
3822 | |||
3823 | if (ocfs2_mount_local(osb)) | ||
3824 | return 0; | ||
3825 | |||
3826 | status = ocfs2_cluster_lock(osb, lockres, level, 0, 0); | ||
3827 | if (status < 0) | ||
3828 | mlog_errno(status); | ||
3829 | |||
3830 | return status; | ||
3831 | } | ||
3832 | |||
3833 | void ocfs2_refcount_unlock(struct ocfs2_refcount_tree *ref_tree, int ex) | ||
3834 | { | ||
3835 | int level = ex ? DLM_LOCK_EX : DLM_LOCK_PR; | ||
3836 | struct ocfs2_lock_res *lockres = &ref_tree->rf_lockres; | ||
3837 | struct ocfs2_super *osb = lockres->l_priv; | ||
3838 | |||
3839 | if (!ocfs2_mount_local(osb)) | ||
3840 | ocfs2_cluster_unlock(osb, lockres, level); | ||
3841 | } | ||
3842 | |||
3763 | /* | 3843 | /* |
3764 | * This is the filesystem locking protocol. It provides the lock handling | 3844 | * This is the filesystem locking protocol. It provides the lock handling |
3765 | * hooks for the underlying DLM. It has a maximum version number. | 3845 | * hooks for the underlying DLM. It has a maximum version number. |
diff --git a/fs/ocfs2/dlmglue.h b/fs/ocfs2/dlmglue.h index 7553836931de..d1ce48e1b3d6 100644 --- a/fs/ocfs2/dlmglue.h +++ b/fs/ocfs2/dlmglue.h | |||
@@ -101,6 +101,9 @@ void ocfs2_file_lock_res_init(struct ocfs2_lock_res *lockres, | |||
101 | struct ocfs2_mem_dqinfo; | 101 | struct ocfs2_mem_dqinfo; |
102 | void ocfs2_qinfo_lock_res_init(struct ocfs2_lock_res *lockres, | 102 | void ocfs2_qinfo_lock_res_init(struct ocfs2_lock_res *lockres, |
103 | struct ocfs2_mem_dqinfo *info); | 103 | struct ocfs2_mem_dqinfo *info); |
104 | void ocfs2_refcount_lock_res_init(struct ocfs2_lock_res *lockres, | ||
105 | struct ocfs2_super *osb, u64 ref_blkno, | ||
106 | unsigned int generation); | ||
104 | void ocfs2_lock_res_free(struct ocfs2_lock_res *res); | 107 | void ocfs2_lock_res_free(struct ocfs2_lock_res *res); |
105 | int ocfs2_create_new_inode_locks(struct inode *inode); | 108 | int ocfs2_create_new_inode_locks(struct inode *inode); |
106 | int ocfs2_drop_inode_locks(struct inode *inode); | 109 | int ocfs2_drop_inode_locks(struct inode *inode); |
@@ -148,6 +151,9 @@ int ocfs2_file_lock(struct file *file, int ex, int trylock); | |||
148 | void ocfs2_file_unlock(struct file *file); | 151 | void ocfs2_file_unlock(struct file *file); |
149 | int ocfs2_qinfo_lock(struct ocfs2_mem_dqinfo *oinfo, int ex); | 152 | int ocfs2_qinfo_lock(struct ocfs2_mem_dqinfo *oinfo, int ex); |
150 | void ocfs2_qinfo_unlock(struct ocfs2_mem_dqinfo *oinfo, int ex); | 153 | void ocfs2_qinfo_unlock(struct ocfs2_mem_dqinfo *oinfo, int ex); |
154 | struct ocfs2_refcount_tree; | ||
155 | int ocfs2_refcount_lock(struct ocfs2_refcount_tree *ref_tree, int ex); | ||
156 | void ocfs2_refcount_unlock(struct ocfs2_refcount_tree *ref_tree, int ex); | ||
151 | 157 | ||
152 | 158 | ||
153 | void ocfs2_mark_lockres_freeing(struct ocfs2_lock_res *lockres); | 159 | void ocfs2_mark_lockres_freeing(struct ocfs2_lock_res *lockres); |
diff --git a/fs/ocfs2/ocfs2_lockid.h b/fs/ocfs2/ocfs2_lockid.h index c212cf5a2bdf..d277aabf5dfb 100644 --- a/fs/ocfs2/ocfs2_lockid.h +++ b/fs/ocfs2/ocfs2_lockid.h | |||
@@ -49,6 +49,7 @@ enum ocfs2_lock_type { | |||
49 | OCFS2_LOCK_TYPE_QINFO, | 49 | OCFS2_LOCK_TYPE_QINFO, |
50 | OCFS2_LOCK_TYPE_NFS_SYNC, | 50 | OCFS2_LOCK_TYPE_NFS_SYNC, |
51 | OCFS2_LOCK_TYPE_ORPHAN_SCAN, | 51 | OCFS2_LOCK_TYPE_ORPHAN_SCAN, |
52 | OCFS2_LOCK_TYPE_REFCOUNT, | ||
52 | OCFS2_NUM_LOCK_TYPES | 53 | OCFS2_NUM_LOCK_TYPES |
53 | }; | 54 | }; |
54 | 55 | ||
@@ -89,6 +90,9 @@ static inline char ocfs2_lock_type_char(enum ocfs2_lock_type type) | |||
89 | case OCFS2_LOCK_TYPE_ORPHAN_SCAN: | 90 | case OCFS2_LOCK_TYPE_ORPHAN_SCAN: |
90 | c = 'P'; | 91 | c = 'P'; |
91 | break; | 92 | break; |
93 | case OCFS2_LOCK_TYPE_REFCOUNT: | ||
94 | c = 'T'; | ||
95 | break; | ||
92 | default: | 96 | default: |
93 | c = '\0'; | 97 | c = '\0'; |
94 | } | 98 | } |
@@ -110,6 +114,7 @@ static char *ocfs2_lock_type_strings[] = { | |||
110 | [OCFS2_LOCK_TYPE_QINFO] = "Quota", | 114 | [OCFS2_LOCK_TYPE_QINFO] = "Quota", |
111 | [OCFS2_LOCK_TYPE_NFS_SYNC] = "NFSSync", | 115 | [OCFS2_LOCK_TYPE_NFS_SYNC] = "NFSSync", |
112 | [OCFS2_LOCK_TYPE_ORPHAN_SCAN] = "OrphanScan", | 116 | [OCFS2_LOCK_TYPE_ORPHAN_SCAN] = "OrphanScan", |
117 | [OCFS2_LOCK_TYPE_REFCOUNT] = "Refcount", | ||
113 | }; | 118 | }; |
114 | 119 | ||
115 | static inline const char *ocfs2_lock_type_string(enum ocfs2_lock_type type) | 120 | static inline const char *ocfs2_lock_type_string(enum ocfs2_lock_type type) |
diff --git a/fs/ocfs2/refcounttree.h b/fs/ocfs2/refcounttree.h new file mode 100644 index 000000000000..9a3695cdbb53 --- /dev/null +++ b/fs/ocfs2/refcounttree.h | |||
@@ -0,0 +1,36 @@ | |||
1 | /* -*- mode: c; c-basic-offset: 8; -*- | ||
2 | * vim: noexpandtab sw=8 ts=8 sts=0: | ||
3 | * | ||
4 | * refcounttree.h | ||
5 | * | ||
6 | * Copyright (C) 2009 Oracle. All rights reserved. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public | ||
10 | * License version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | */ | ||
17 | #ifndef OCFS2_REFCOUNTTREE_H | ||
18 | #define OCFS2_REFCOUNTTREE_H | ||
19 | |||
20 | struct ocfs2_refcount_tree { | ||
21 | struct rb_node rf_node; | ||
22 | u64 rf_blkno; | ||
23 | u32 rf_generation; | ||
24 | struct rw_semaphore rf_sem; | ||
25 | struct ocfs2_lock_res rf_lockres; | ||
26 | struct kref rf_getcnt; | ||
27 | int rf_removed; | ||
28 | |||
29 | /* the following 4 fields are used by caching_info. */ | ||
30 | struct ocfs2_caching_info rf_ci; | ||
31 | spinlock_t rf_lock; | ||
32 | struct mutex rf_io_mutex; | ||
33 | struct super_block *rf_sb; | ||
34 | }; | ||
35 | |||
36 | #endif /* OCFS2_REFCOUNTTREE_H */ | ||