aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Eshel <eshel@almaden.ibm.com>2006-11-14 16:37:25 -0500
committerJ. Bruce Fields <bfields@citi.umich.edu>2007-05-06 20:38:50 -0400
commit586759f03e2e9031ac5589912a51a909ed53c30a (patch)
tree5c788be0c13fb6d0baf3824e29a6bb6b195bf61a
parent1a8322b2b02071b0c7ac37a28357b93e6362f13e (diff)
gfs2: nfs lock support for gfs2
Add NFS lock support to GFS2. Signed-off-by: Marc Eshel <eshel@almaden.ibm.com> Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu> Acked-by: Steven Whitehouse <swhiteho@redhat.com>
-rw-r--r--fs/gfs2/locking/dlm/plock.c109
-rw-r--r--fs/gfs2/ops_file.c5
2 files changed, 104 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;
diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c
index 48b248d7c823..329c4dcdecdb 100644
--- a/fs/gfs2/ops_file.c
+++ b/fs/gfs2/ops_file.c
@@ -520,6 +520,11 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl)
520 } 520 }
521 } 521 }
522 522
523 if (cmd == F_CANCELLK) {
524 /* Hack: */
525 cmd = F_SETLK;
526 fl->fl_type = F_UNLCK;
527 }
523 if (IS_GETLK(cmd)) 528 if (IS_GETLK(cmd))
524 return gfs2_lm_plock_get(sdp, &name, file, fl); 529 return gfs2_lm_plock_get(sdp, &name, file, fl);
525 else if (fl->fl_type == F_UNLCK) 530 else if (fl->fl_type == F_UNLCK)