aboutsummaryrefslogtreecommitdiffstats
path: root/fs/dlm/user.c
diff options
context:
space:
mode:
authorDavid Teigland <teigland@redhat.com>2011-02-21 15:58:21 -0500
committerDavid Teigland <teigland@redhat.com>2011-03-10 11:40:00 -0500
commit8304d6f24cc1221392b6d61fa9d16631cbd6beb7 (patch)
treeca9b333d500d2fc56a45263aa08c4093875cbe12 /fs/dlm/user.c
parent35d34df711e8b44846e759d8cfddb4ec6877cccb (diff)
dlm: record full callback state
Change how callbacks are recorded for locks. Previously, information about multiple callbacks was combined into a couple of variables that indicated what the end result should be. In some situations, we could not tell from this combined state what the exact sequence of callbacks were, and would end up either delivering the callbacks in the wrong order, or suppress redundant callbacks incorrectly. This new approach records all the data for each callback, leaving no uncertainty about what needs to be delivered. Signed-off-by: David Teigland <teigland@redhat.com>
Diffstat (limited to 'fs/dlm/user.c')
-rw-r--r--fs/dlm/user.c185
1 files changed, 64 insertions, 121 deletions
diff --git a/fs/dlm/user.c b/fs/dlm/user.c
index 66d6c16bf440..d5ab3fe7c198 100644
--- a/fs/dlm/user.c
+++ b/fs/dlm/user.c
@@ -24,6 +24,7 @@
24#include "lock.h" 24#include "lock.h"
25#include "lvb_table.h" 25#include "lvb_table.h"
26#include "user.h" 26#include "user.h"
27#include "ast.h"
27 28
28static const char name_prefix[] = "dlm"; 29static const char name_prefix[] = "dlm";
29static const struct file_operations device_fops; 30static const struct file_operations device_fops;
@@ -152,19 +153,16 @@ static void compat_output(struct dlm_lock_result *res,
152 not related to the lifetime of the lkb struct which is managed 153 not related to the lifetime of the lkb struct which is managed
153 entirely by refcount. */ 154 entirely by refcount. */
154 155
155static int lkb_is_endoflife(struct dlm_lkb *lkb, int sb_status, int type) 156static int lkb_is_endoflife(int mode, int status)
156{ 157{
157 switch (sb_status) { 158 switch (status) {
158 case -DLM_EUNLOCK: 159 case -DLM_EUNLOCK:
159 return 1; 160 return 1;
160 case -DLM_ECANCEL: 161 case -DLM_ECANCEL:
161 case -ETIMEDOUT: 162 case -ETIMEDOUT:
162 case -EDEADLK: 163 case -EDEADLK:
163 if (lkb->lkb_grmode == DLM_LOCK_IV)
164 return 1;
165 break;
166 case -EAGAIN: 164 case -EAGAIN:
167 if (type == AST_COMP && lkb->lkb_grmode == DLM_LOCK_IV) 165 if (mode == DLM_LOCK_IV)
168 return 1; 166 return 1;
169 break; 167 break;
170 } 168 }
@@ -174,12 +172,13 @@ static int lkb_is_endoflife(struct dlm_lkb *lkb, int sb_status, int type)
174/* we could possibly check if the cancel of an orphan has resulted in the lkb 172/* we could possibly check if the cancel of an orphan has resulted in the lkb
175 being removed and then remove that lkb from the orphans list and free it */ 173 being removed and then remove that lkb from the orphans list and free it */
176 174
177void dlm_user_add_ast(struct dlm_lkb *lkb, int type, int mode) 175void dlm_user_add_ast(struct dlm_lkb *lkb, uint32_t flags, int mode,
176 int status, uint32_t sbflags, uint64_t seq)
178{ 177{
179 struct dlm_ls *ls; 178 struct dlm_ls *ls;
180 struct dlm_user_args *ua; 179 struct dlm_user_args *ua;
181 struct dlm_user_proc *proc; 180 struct dlm_user_proc *proc;
182 int eol = 0, ast_type; 181 int rv;
183 182
184 if (lkb->lkb_flags & (DLM_IFL_ORPHAN | DLM_IFL_DEAD)) 183 if (lkb->lkb_flags & (DLM_IFL_ORPHAN | DLM_IFL_DEAD))
185 return; 184 return;
@@ -200,49 +199,29 @@ void dlm_user_add_ast(struct dlm_lkb *lkb, int type, int mode)
200 ua = lkb->lkb_ua; 199 ua = lkb->lkb_ua;
201 proc = ua->proc; 200 proc = ua->proc;
202 201
203 if (type == AST_BAST && ua->bastaddr == NULL) 202 if ((flags & DLM_CB_BAST) && ua->bastaddr == NULL)
204 goto out; 203 goto out;
205 204
205 if ((flags & DLM_CB_CAST) && lkb_is_endoflife(mode, status))
206 lkb->lkb_flags |= DLM_IFL_ENDOFLIFE;
207
206 spin_lock(&proc->asts_spin); 208 spin_lock(&proc->asts_spin);
207 209
208 ast_type = lkb->lkb_ast_type; 210 rv = dlm_add_lkb_callback(lkb, flags, mode, status, sbflags, seq);
209 lkb->lkb_ast_type |= type; 211 if (rv < 0) {
210 if (type == AST_BAST) 212 spin_unlock(&proc->asts_spin);
211 lkb->lkb_bastmode = mode; 213 goto out;
212 else 214 }
213 lkb->lkb_castmode = mode;
214 215
215 if (!ast_type) { 216 if (list_empty(&lkb->lkb_astqueue)) {
216 kref_get(&lkb->lkb_ref); 217 kref_get(&lkb->lkb_ref);
217 list_add_tail(&lkb->lkb_astqueue, &proc->asts); 218 list_add_tail(&lkb->lkb_astqueue, &proc->asts);
218 lkb->lkb_ast_first = type;
219 wake_up_interruptible(&proc->wait); 219 wake_up_interruptible(&proc->wait);
220 } 220 }
221 if (type == AST_COMP && (ast_type & AST_COMP))
222 log_debug(ls, "ast overlap %x status %x %x",
223 lkb->lkb_id, ua->lksb.sb_status, lkb->lkb_flags);
224
225 eol = lkb_is_endoflife(lkb, ua->lksb.sb_status, type);
226 if (eol) {
227 lkb->lkb_flags |= DLM_IFL_ENDOFLIFE;
228 }
229
230 /* We want to copy the lvb to userspace when the completion
231 ast is read if the status is 0, the lock has an lvb and
232 lvb_ops says we should. We could probably have set_lvb_lock()
233 set update_user_lvb instead and not need old_mode */
234
235 if ((lkb->lkb_ast_type & AST_COMP) &&
236 (lkb->lkb_lksb->sb_status == 0) &&
237 lkb->lkb_lksb->sb_lvbptr &&
238 dlm_lvb_operations[ua->old_mode + 1][lkb->lkb_grmode + 1])
239 ua->update_user_lvb = 1;
240 else
241 ua->update_user_lvb = 0;
242
243 spin_unlock(&proc->asts_spin); 221 spin_unlock(&proc->asts_spin);
244 222
245 if (eol) { 223 if (lkb->lkb_flags & DLM_IFL_ENDOFLIFE) {
224 /* N.B. spin_lock locks_spin, not asts_spin */
246 spin_lock(&proc->locks_spin); 225 spin_lock(&proc->locks_spin);
247 if (!list_empty(&lkb->lkb_ownqueue)) { 226 if (!list_empty(&lkb->lkb_ownqueue)) {
248 list_del_init(&lkb->lkb_ownqueue); 227 list_del_init(&lkb->lkb_ownqueue);
@@ -705,8 +684,9 @@ static int device_close(struct inode *inode, struct file *file)
705 return 0; 684 return 0;
706} 685}
707 686
708static int copy_result_to_user(struct dlm_user_args *ua, int compat, int type, 687static int copy_result_to_user(struct dlm_user_args *ua, int compat,
709 int mode, char __user *buf, size_t count) 688 uint32_t flags, int mode, int copy_lvb,
689 char __user *buf, size_t count)
710{ 690{
711#ifdef CONFIG_COMPAT 691#ifdef CONFIG_COMPAT
712 struct dlm_lock_result32 result32; 692 struct dlm_lock_result32 result32;
@@ -730,7 +710,7 @@ static int copy_result_to_user(struct dlm_user_args *ua, int compat, int type,
730 notes that a new blocking AST address and parameter are set even if 710 notes that a new blocking AST address and parameter are set even if
731 the conversion fails, so maybe we should just do that. */ 711 the conversion fails, so maybe we should just do that. */
732 712
733 if (type == AST_BAST) { 713 if (flags & DLM_CB_BAST) {
734 result.user_astaddr = ua->bastaddr; 714 result.user_astaddr = ua->bastaddr;
735 result.user_astparam = ua->bastparam; 715 result.user_astparam = ua->bastparam;
736 result.bast_mode = mode; 716 result.bast_mode = mode;
@@ -750,8 +730,7 @@ static int copy_result_to_user(struct dlm_user_args *ua, int compat, int type,
750 /* copy lvb to userspace if there is one, it's been updated, and 730 /* copy lvb to userspace if there is one, it's been updated, and
751 the user buffer has space for it */ 731 the user buffer has space for it */
752 732
753 if (ua->update_user_lvb && ua->lksb.sb_lvbptr && 733 if (copy_lvb && ua->lksb.sb_lvbptr && count >= len + DLM_USER_LVB_LEN) {
754 count >= len + DLM_USER_LVB_LEN) {
755 if (copy_to_user(buf+len, ua->lksb.sb_lvbptr, 734 if (copy_to_user(buf+len, ua->lksb.sb_lvbptr,
756 DLM_USER_LVB_LEN)) { 735 DLM_USER_LVB_LEN)) {
757 error = -EFAULT; 736 error = -EFAULT;
@@ -801,13 +780,12 @@ static ssize_t device_read(struct file *file, char __user *buf, size_t count,
801 struct dlm_user_proc *proc = file->private_data; 780 struct dlm_user_proc *proc = file->private_data;
802 struct dlm_lkb *lkb; 781 struct dlm_lkb *lkb;
803 DECLARE_WAITQUEUE(wait, current); 782 DECLARE_WAITQUEUE(wait, current);
804 int error = 0, removed; 783 struct dlm_callback cb;
805 int ret_type, ret_mode; 784 int rv, resid, copy_lvb = 0;
806 int bastmode, castmode, do_bast, do_cast;
807 785
808 if (count == sizeof(struct dlm_device_version)) { 786 if (count == sizeof(struct dlm_device_version)) {
809 error = copy_version_to_user(buf, count); 787 rv = copy_version_to_user(buf, count);
810 return error; 788 return rv;
811 } 789 }
812 790
813 if (!proc) { 791 if (!proc) {
@@ -854,92 +832,57 @@ static ssize_t device_read(struct file *file, char __user *buf, size_t count,
854 } 832 }
855 } 833 }
856 834
857 /* there may be both completion and blocking asts to return for 835 /* if we empty lkb_callbacks, we don't want to unlock the spinlock
858 the lkb, don't remove lkb from asts list unless no asts remain */ 836 without removing lkb_astqueue; so empty lkb_astqueue is always
837 consistent with empty lkb_callbacks */
859 838
860 lkb = list_entry(proc->asts.next, struct dlm_lkb, lkb_astqueue); 839 lkb = list_entry(proc->asts.next, struct dlm_lkb, lkb_astqueue);
861 840
862 removed = 0; 841 rv = dlm_rem_lkb_callback(lkb->lkb_resource->res_ls, lkb, &cb, &resid);
863 ret_type = 0; 842 if (rv < 0) {
864 ret_mode = 0; 843 /* this shouldn't happen; lkb should have been removed from
865 do_bast = lkb->lkb_ast_type & AST_BAST; 844 list when resid was zero */
866 do_cast = lkb->lkb_ast_type & AST_COMP; 845 log_print("dlm_rem_lkb_callback empty %x", lkb->lkb_id);
867 bastmode = lkb->lkb_bastmode; 846 list_del_init(&lkb->lkb_astqueue);
868 castmode = lkb->lkb_castmode; 847 spin_unlock(&proc->asts_spin);
869 848 /* removes ref for proc->asts, may cause lkb to be freed */
870 /* when both are queued figure out which to do first and 849 dlm_put_lkb(lkb);
871 switch first so the other goes in the next read */ 850 goto try_another;
872
873 if (do_cast && do_bast) {
874 if (lkb->lkb_ast_first == AST_COMP) {
875 ret_type = AST_COMP;
876 ret_mode = castmode;
877 lkb->lkb_ast_type &= ~AST_COMP;
878 lkb->lkb_ast_first = AST_BAST;
879 } else {
880 ret_type = AST_BAST;
881 ret_mode = bastmode;
882 lkb->lkb_ast_type &= ~AST_BAST;
883 lkb->lkb_ast_first = AST_COMP;
884 }
885 } else {
886 ret_type = lkb->lkb_ast_first;
887 ret_mode = (ret_type == AST_COMP) ? castmode : bastmode;
888 lkb->lkb_ast_type &= ~ret_type;
889 lkb->lkb_ast_first = 0;
890 } 851 }
852 if (!resid)
853 list_del_init(&lkb->lkb_astqueue);
854 spin_unlock(&proc->asts_spin);
891 855
892 /* if we're doing a bast but the bast is unnecessary, then 856 if (cb.flags & DLM_CB_SKIP) {
893 switch to do nothing or do a cast if that was needed next */ 857 /* removes ref for proc->asts, may cause lkb to be freed */
894 858 if (!resid)
895 if ((ret_type == AST_BAST) && 859 dlm_put_lkb(lkb);
896 dlm_modes_compat(bastmode, lkb->lkb_castmode_done)) { 860 goto try_another;
897 ret_type = 0;
898 ret_mode = 0;
899
900 if (do_cast) {
901 ret_type = AST_COMP;
902 ret_mode = castmode;
903 lkb->lkb_ast_type &= ~AST_COMP;
904 lkb->lkb_ast_first = 0;
905 }
906 } 861 }
907 862
908 if (lkb->lkb_ast_first != lkb->lkb_ast_type) { 863 if (cb.flags & DLM_CB_CAST) {
909 log_print("device_read %x ast_first %x ast_type %x", 864 int old_mode, new_mode;
910 lkb->lkb_id, lkb->lkb_ast_first, lkb->lkb_ast_type);
911 }
912 865
913 if (!lkb->lkb_ast_type) { 866 old_mode = lkb->lkb_last_cast.mode;
914 list_del(&lkb->lkb_astqueue); 867 new_mode = cb.mode;
915 removed = 1;
916 }
917 spin_unlock(&proc->asts_spin);
918 868
919 if (ret_type) { 869 if (!cb.sb_status && lkb->lkb_lksb->sb_lvbptr &&
920 error = copy_result_to_user(lkb->lkb_ua, 870 dlm_lvb_operations[old_mode + 1][new_mode + 1])
921 test_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags), 871 copy_lvb = 1;
922 ret_type, ret_mode, buf, count);
923 872
924 if (ret_type == AST_COMP) 873 lkb->lkb_lksb->sb_status = cb.sb_status;
925 lkb->lkb_castmode_done = castmode; 874 lkb->lkb_lksb->sb_flags = cb.sb_flags;
926 if (ret_type == AST_BAST)
927 lkb->lkb_bastmode_done = bastmode;
928 } 875 }
929 876
930 /* removes reference for the proc->asts lists added by 877 rv = copy_result_to_user(lkb->lkb_ua,
931 dlm_user_add_ast() and may result in the lkb being freed */ 878 test_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags),
879 cb.flags, cb.mode, copy_lvb, buf, count);
932 880
933 if (removed) 881 /* removes ref for proc->asts, may cause lkb to be freed */
882 if (!resid)
934 dlm_put_lkb(lkb); 883 dlm_put_lkb(lkb);
935 884
936 /* the bast that was queued was eliminated (see unnecessary above), 885 return rv;
937 leaving nothing to return */
938
939 if (!ret_type)
940 goto try_another;
941
942 return error;
943} 886}
944 887
945static unsigned int device_poll(struct file *file, poll_table *wait) 888static unsigned int device_poll(struct file *file, poll_table *wait)