Whamcloud - gitweb
Posix record locking changes.
[fs/lustre-release.git] / lustre / ldlm / ldlm_plain.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  Copyright (c) 2002, 2003 Cluster File Systems, Inc.
5  *   Author: Peter Braam <braam@clusterfs.com>
6  *   Author: Phil Schwan <phil@clusterfs.com>
7  *
8  *   This file is part of Lustre, http://www.lustre.org.
9  *
10  *   Lustre is free software; you can redistribute it and/or
11  *   modify it under the terms of version 2 of the GNU General Public
12  *   License as published by the Free Software Foundation.
13  *
14  *   Lustre is distributed in the hope that it will be useful,
15  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *   GNU General Public License for more details.
18  *
19  *   You should have received a copy of the GNU General Public License
20  *   along with Lustre; if not, write to the Free Software
21  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  */
23
24 #define DEBUG_SUBSYSTEM S_LDLM
25
26 #ifdef __KERNEL__
27 #include <linux/lustre_dlm.h>
28 #include <linux/obd_support.h>
29 #include <linux/lustre_lib.h>
30 #else
31 #include <liblustre.h>
32 #endif
33
34 static int
35 ldlm_plain_compat_queue(struct list_head *queue, struct ldlm_lock *new,
36                         int send_cbs, int first_enq)
37 {
38         struct list_head *tmp, *pos;
39         ldlm_mode_t mode = new->l_req_mode;
40         int compat = 1;
41         ENTRY;
42
43         list_for_each_safe(tmp, pos, queue) {
44                 struct ldlm_lock *old;
45
46                 old = list_entry(tmp, struct ldlm_lock, l_res_link);
47                 if (old == new)
48                         continue;
49
50                 if (lockmode_compat(old->l_req_mode, mode) &&
51                     lockmode_compat(old->l_granted_mode, mode)) {
52                         CDEBUG(D_OTHER, "lock modes are compatible, next.\n");
53                         continue;
54                 }
55
56                 compat = 0;
57
58                 /* if we're reprocessing the lock then the blocking ASTs
59                  * have already been sent. No need to continue. */
60                 if (!first_enq)
61                         break;
62
63                 if (send_cbs && (old->l_blocking_ast != NULL)) {
64                         CDEBUG(D_DLMTRACE, "lock %p incompatible; "
65                                "sending blocking AST.\n", old);
66                         ldlm_add_ast_work_item(old, new, NULL, 0);
67                 } else if (!(old->l_flags & LDLM_FL_LOCAL)) {
68                         CDEBUG(D_DLMTRACE, "lock %p incompatible; "
69                                "setting blocking AST.\n", old);
70                         old->l_flags |= LDLM_FL_AST_SENT;
71                 } else {
72                         CDEBUG(D_DLMTRACE, "local lock %p incompatible.\n",
73                                old);
74                 }
75         }
76
77         RETURN(compat);
78 }
79
80 int
81 ldlm_plain_enqueue(struct ldlm_lock **lockp, void *cookie, int *flags,
82                    int first_enq, ldlm_error_t *err)
83 {
84         struct ldlm_lock *lock = *lockp;
85         struct ldlm_resource *res = lock->l_resource;
86         int convert_compat = 1;
87         int waiting_compat = 1;
88         int granted_compat = 1;
89         ENTRY;
90
91         /* FIXME: We may want to optimize by checking lr_most_restr */
92
93         /* On the first enqueue of this lock scan all of the queues
94          * to set the LDLM_FL_AST_SENT flag in conflicting locks.
95          * When the completion AST on the client side runs and sees
96          * this flag is will set the LDLM_FL_CB_PENDING flag in the
97          * lock so the client will know to cancel the lock as soon
98          * as possible. This saves us from sending a blocking AST
99          * in addition to the completion AST.
100          *
101          * If it's NOT the first enqueue of this lock then it must be
102          * the first eligible lock in the queues because of the way that
103          * ldlm_reprocess_all() works. So we don't have to check the
104          * converting or waiting queues. */
105         if (first_enq) {
106                 if (!list_empty(&res->lr_converting)) {
107                         convert_compat = 0;
108                         ldlm_plain_compat_queue(&res->lr_converting,
109                                                 lock, 0, first_enq);
110                 }
111                 if (!list_empty(&res->lr_waiting)) {
112                         waiting_compat = 0;
113                         ldlm_plain_compat_queue(&res->lr_waiting,
114                                                 lock, 0, first_enq);
115                 }
116         }
117         granted_compat =
118                 ldlm_plain_compat_queue(&res->lr_granted, lock, 1, first_enq);
119
120         if (!convert_compat) {
121                 *flags |= LDLM_FL_BLOCK_CONV;
122                 RETURN(LDLM_ITER_STOP);
123         }
124         if (!waiting_compat) {
125                 *flags |= LDLM_FL_BLOCK_WAIT;
126                 RETURN(LDLM_ITER_STOP);
127         }
128         if (!granted_compat) {
129                 *flags |= LDLM_FL_BLOCK_GRANTED;
130                 RETURN(LDLM_ITER_STOP);
131         }
132
133         list_del_init(&lock->l_res_link);
134         ldlm_grant_lock(lock, NULL, 0);
135
136         if (lock->l_flags & LDLM_FL_AST_SENT) {
137                 CDEBUG(D_DLMTRACE, "granted lock %p with AST set\n", lock);
138                 *flags |= (lock->l_flags & LDLM_FL_AST_SENT);
139         }
140
141         RETURN(LDLM_ITER_CONTINUE);
142 }