diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-07 15:34:24 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-07 15:34:24 -0400 |
commit | 2d56d3c43cc97ae48586745556f5a5b564d61582 (patch) | |
tree | 28f2edc1e69b79e94d99023041dd0358861b6956 /fs/gfs2/locking/dlm | |
parent | 0f9008ef38d5a6305d94bbdd8f20d68fc75c63b6 (diff) | |
parent | 586759f03e2e9031ac5589912a51a909ed53c30a (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')
-rw-r--r-- | fs/gfs2/locking/dlm/plock.c | 109 |
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 | ||
28 | struct plock_xop { | ||
29 | struct plock_op xop; | ||
30 | void *callback; | ||
31 | void *fl; | ||
32 | void *file; | ||
33 | struct file_lock flc; | ||
34 | }; | ||
35 | |||
36 | |||
28 | static inline void set_version(struct gdlm_plock_info *info) | 37 | static 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 */ | ||
130 | static 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 | |||
180 | out: | ||
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; |