aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2/locking/dlm/plock.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-07 15:34:24 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-07 15:34:24 -0400
commit2d56d3c43cc97ae48586745556f5a5b564d61582 (patch)
tree28f2edc1e69b79e94d99023041dd0358861b6956 /fs/gfs2/locking/dlm/plock.c
parent0f9008ef38d5a6305d94bbdd8f20d68fc75c63b6 (diff)
parent586759f03e2e9031ac5589912a51a909ed53c30a (diff)
Merge branch 'server-cluster-locking-api' of git://linux-nfs.org/~bfields/linux
* 'server-cluster-locking-api' of git://linux-nfs.org/~bfields/linux: gfs2: nfs lock support for gfs2 lockd: add code to handle deferred lock requests lockd: always preallocate block in nlmsvc_lock() lockd: handle test_lock deferrals lockd: pass cookie in nlmsvc_testlock lockd: handle fl_grant callbacks lockd: save lock state on deferral locks: add fl_grant callback for asynchronous lock return nfsd4: Convert NFSv4 to new lock interface locks: add lock cancel command locks: allow {vfs,posix}_lock_file to return conflicting lock locks: factor out generic/filesystem switch from setlock code locks: factor out generic/filesystem switch from test_lock locks: give posix_test_lock same interface as ->lock locks: make ->lock release private data before returning in GETLK case locks: create posix-to-flock helper functions locks: trivial removal of unnecessary parentheses
Diffstat (limited to 'fs/gfs2/locking/dlm/plock.c')
-rw-r--r--fs/gfs2/locking/dlm/plock.c109
1 files changed, 99 insertions, 10 deletions
diff --git a/fs/gfs2/locking/dlm/plock.c b/fs/gfs2/locking/dlm/plock.c
index 1dd4215b83d0..f82495e18c2d 100644
--- a/fs/gfs2/locking/dlm/plock.c
+++ b/fs/gfs2/locking/dlm/plock.c
@@ -25,6 +25,15 @@ struct plock_op {
25 struct gdlm_plock_info info; 25 struct gdlm_plock_info info;
26}; 26};
27 27
28struct plock_xop {
29 struct plock_op xop;
30 void *callback;
31 void *fl;
32 void *file;
33 struct file_lock flc;
34};
35
36
28static inline void set_version(struct gdlm_plock_info *info) 37static inline void set_version(struct gdlm_plock_info *info)
29{ 38{
30 info->version[0] = GDLM_PLOCK_VERSION_MAJOR; 39 info->version[0] = GDLM_PLOCK_VERSION_MAJOR;
@@ -64,12 +73,14 @@ int gdlm_plock(void *lockspace, struct lm_lockname *name,
64{ 73{
65 struct gdlm_ls *ls = lockspace; 74 struct gdlm_ls *ls = lockspace;
66 struct plock_op *op; 75 struct plock_op *op;
76 struct plock_xop *xop;
67 int rv; 77 int rv;
68 78
69 op = kzalloc(sizeof(*op), GFP_KERNEL); 79 xop = kzalloc(sizeof(*xop), GFP_KERNEL);
70 if (!op) 80 if (!xop)
71 return -ENOMEM; 81 return -ENOMEM;
72 82
83 op = &xop->xop;
73 op->info.optype = GDLM_PLOCK_OP_LOCK; 84 op->info.optype = GDLM_PLOCK_OP_LOCK;
74 op->info.pid = fl->fl_pid; 85 op->info.pid = fl->fl_pid;
75 op->info.ex = (fl->fl_type == F_WRLCK); 86 op->info.ex = (fl->fl_type == F_WRLCK);
@@ -79,9 +90,21 @@ int gdlm_plock(void *lockspace, struct lm_lockname *name,
79 op->info.start = fl->fl_start; 90 op->info.start = fl->fl_start;
80 op->info.end = fl->fl_end; 91 op->info.end = fl->fl_end;
81 op->info.owner = (__u64)(long) fl->fl_owner; 92 op->info.owner = (__u64)(long) fl->fl_owner;
93 if (fl->fl_lmops && fl->fl_lmops->fl_grant) {
94 xop->callback = fl->fl_lmops->fl_grant;
95 locks_init_lock(&xop->flc);
96 locks_copy_lock(&xop->flc, fl);
97 xop->fl = fl;
98 xop->file = file;
99 } else
100 xop->callback = NULL;
82 101
83 send_op(op); 102 send_op(op);
84 wait_event(recv_wq, (op->done != 0)); 103
104 if (xop->callback == NULL)
105 wait_event(recv_wq, (op->done != 0));
106 else
107 return -EINPROGRESS;
85 108
86 spin_lock(&ops_lock); 109 spin_lock(&ops_lock);
87 if (!list_empty(&op->list)) { 110 if (!list_empty(&op->list)) {
@@ -99,7 +122,63 @@ int gdlm_plock(void *lockspace, struct lm_lockname *name,
99 (unsigned long long)name->ln_number); 122 (unsigned long long)name->ln_number);
100 } 123 }
101 124
102 kfree(op); 125 kfree(xop);
126 return rv;
127}
128
129/* Returns failure iff a succesful lock operation should be canceled */
130static int gdlm_plock_callback(struct plock_op *op)
131{
132 struct file *file;
133 struct file_lock *fl;
134 struct file_lock *flc;
135 int (*notify)(void *, void *, int) = NULL;
136 struct plock_xop *xop = (struct plock_xop *)op;
137 int rv = 0;
138
139 spin_lock(&ops_lock);
140 if (!list_empty(&op->list)) {
141 printk(KERN_INFO "plock op on list\n");
142 list_del(&op->list);
143 }
144 spin_unlock(&ops_lock);
145
146 /* check if the following 2 are still valid or make a copy */
147 file = xop->file;
148 flc = &xop->flc;
149 fl = xop->fl;
150 notify = xop->callback;
151
152 if (op->info.rv) {
153 notify(flc, NULL, op->info.rv);
154 goto out;
155 }
156
157 /* got fs lock; bookkeep locally as well: */
158 flc->fl_flags &= ~FL_SLEEP;
159 if (posix_lock_file(file, flc, NULL)) {
160 /*
161 * This can only happen in the case of kmalloc() failure.
162 * The filesystem's own lock is the authoritative lock,
163 * so a failure to get the lock locally is not a disaster.
164 * As long as GFS cannot reliably cancel locks (especially
165 * in a low-memory situation), we're better off ignoring
166 * this failure than trying to recover.
167 */
168 log_error("gdlm_plock: vfs lock error file %p fl %p",
169 file, fl);
170 }
171
172 rv = notify(flc, NULL, 0);
173 if (rv) {
174 /* XXX: We need to cancel the fs lock here: */
175 printk("gfs2 lock granted after lock request failed;"
176 " dangling lock!\n");
177 goto out;
178 }
179
180out:
181 kfree(xop);
103 return rv; 182 return rv;
104} 183}
105 184
@@ -138,6 +217,9 @@ int gdlm_punlock(void *lockspace, struct lm_lockname *name,
138 217
139 rv = op->info.rv; 218 rv = op->info.rv;
140 219
220 if (rv == -ENOENT)
221 rv = 0;
222
141 kfree(op); 223 kfree(op);
142 return rv; 224 return rv;
143} 225}
@@ -161,6 +243,7 @@ int gdlm_plock_get(void *lockspace, struct lm_lockname *name,
161 op->info.start = fl->fl_start; 243 op->info.start = fl->fl_start;
162 op->info.end = fl->fl_end; 244 op->info.end = fl->fl_end;
163 245
246
164 send_op(op); 247 send_op(op);
165 wait_event(recv_wq, (op->done != 0)); 248 wait_event(recv_wq, (op->done != 0));
166 249
@@ -173,9 +256,10 @@ int gdlm_plock_get(void *lockspace, struct lm_lockname *name,
173 256
174 rv = op->info.rv; 257 rv = op->info.rv;
175 258
176 if (rv == 0) 259 fl->fl_type = F_UNLCK;
177 fl->fl_type = F_UNLCK; 260 if (rv == -ENOENT)
178 else if (rv > 0) { 261 rv = 0;
262 else if (rv == 0 && op->info.pid != fl->fl_pid) {
179 fl->fl_type = (op->info.ex) ? F_WRLCK : F_RDLCK; 263 fl->fl_type = (op->info.ex) ? F_WRLCK : F_RDLCK;
180 fl->fl_pid = op->info.pid; 264 fl->fl_pid = op->info.pid;
181 fl->fl_start = op->info.start; 265 fl->fl_start = op->info.start;
@@ -243,9 +327,14 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count,
243 } 327 }
244 spin_unlock(&ops_lock); 328 spin_unlock(&ops_lock);
245 329
246 if (found) 330 if (found) {
247 wake_up(&recv_wq); 331 struct plock_xop *xop;
248 else 332 xop = (struct plock_xop *)op;
333 if (xop->callback)
334 count = gdlm_plock_callback(op);
335 else
336 wake_up(&recv_wq);
337 } else
249 printk(KERN_INFO "gdlm dev_write no op %x %llx\n", info.fsid, 338 printk(KERN_INFO "gdlm dev_write no op %x %llx\n", info.fsid,
250 (unsigned long long)info.number); 339 (unsigned long long)info.number);
251 return count; 340 return count;