.. | .. |
---|
32 | 32 | |
---|
33 | 33 | static void ceph_fl_copy_lock(struct file_lock *dst, struct file_lock *src) |
---|
34 | 34 | { |
---|
35 | | - struct inode *inode = file_inode(src->fl_file); |
---|
| 35 | + struct ceph_file_info *fi = dst->fl_file->private_data; |
---|
| 36 | + struct inode *inode = file_inode(dst->fl_file); |
---|
36 | 37 | atomic_inc(&ceph_inode(inode)->i_filelock_ref); |
---|
| 38 | + atomic_inc(&fi->num_locks); |
---|
37 | 39 | } |
---|
38 | 40 | |
---|
39 | 41 | static void ceph_fl_release_lock(struct file_lock *fl) |
---|
40 | 42 | { |
---|
| 43 | + struct ceph_file_info *fi = fl->fl_file->private_data; |
---|
41 | 44 | struct inode *inode = file_inode(fl->fl_file); |
---|
42 | 45 | struct ceph_inode_info *ci = ceph_inode(inode); |
---|
| 46 | + atomic_dec(&fi->num_locks); |
---|
43 | 47 | if (atomic_dec_and_test(&ci->i_filelock_ref)) { |
---|
44 | 48 | /* clear error when all locks are released */ |
---|
45 | 49 | spin_lock(&ci->i_ceph_lock); |
---|
.. | .. |
---|
59 | 63 | static int ceph_lock_message(u8 lock_type, u16 operation, struct inode *inode, |
---|
60 | 64 | int cmd, u8 wait, struct file_lock *fl) |
---|
61 | 65 | { |
---|
62 | | - struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc; |
---|
| 66 | + struct ceph_mds_client *mdsc = ceph_sb_to_mdsc(inode->i_sb); |
---|
63 | 67 | struct ceph_mds_request *req; |
---|
64 | 68 | int err; |
---|
65 | 69 | u64 length = 0; |
---|
.. | .. |
---|
73 | 77 | * window. Caller function will decrease the counter. |
---|
74 | 78 | */ |
---|
75 | 79 | fl->fl_ops = &ceph_fl_lock_ops; |
---|
76 | | - atomic_inc(&ceph_inode(inode)->i_filelock_ref); |
---|
| 80 | + fl->fl_ops->fl_copy_lock(fl, NULL); |
---|
77 | 81 | } |
---|
78 | 82 | |
---|
79 | 83 | if (operation != CEPH_MDS_OP_SETFILELOCK || cmd == CEPH_LOCK_UNLOCK) |
---|
.. | .. |
---|
206 | 210 | return 0; |
---|
207 | 211 | } |
---|
208 | 212 | |
---|
| 213 | +static int try_unlock_file(struct file *file, struct file_lock *fl) |
---|
| 214 | +{ |
---|
| 215 | + int err; |
---|
| 216 | + unsigned int orig_flags = fl->fl_flags; |
---|
| 217 | + fl->fl_flags |= FL_EXISTS; |
---|
| 218 | + err = locks_lock_file_wait(file, fl); |
---|
| 219 | + fl->fl_flags = orig_flags; |
---|
| 220 | + if (err == -ENOENT) { |
---|
| 221 | + if (!(orig_flags & FL_EXISTS)) |
---|
| 222 | + err = 0; |
---|
| 223 | + return err; |
---|
| 224 | + } |
---|
| 225 | + return 1; |
---|
| 226 | +} |
---|
| 227 | + |
---|
209 | 228 | /** |
---|
210 | 229 | * Attempt to set an fcntl lock. |
---|
211 | 230 | * For now, this just goes away to the server. Later it may be more awesome. |
---|
.. | .. |
---|
236 | 255 | spin_lock(&ci->i_ceph_lock); |
---|
237 | 256 | if (ci->i_ceph_flags & CEPH_I_ERROR_FILELOCK) { |
---|
238 | 257 | err = -EIO; |
---|
239 | | - } else if (op == CEPH_MDS_OP_SETFILELOCK) { |
---|
240 | | - /* |
---|
241 | | - * increasing i_filelock_ref closes race window between |
---|
242 | | - * handling request reply and adding file_lock struct to |
---|
243 | | - * inode. Otherwise, i_auth_cap may get trimmed in the |
---|
244 | | - * window. Caller function will decrease the counter. |
---|
245 | | - */ |
---|
246 | | - fl->fl_ops = &ceph_fl_lock_ops; |
---|
247 | | - atomic_inc(&ci->i_filelock_ref); |
---|
248 | 258 | } |
---|
249 | 259 | spin_unlock(&ci->i_ceph_lock); |
---|
250 | 260 | if (err < 0) { |
---|
.. | .. |
---|
260 | 270 | else |
---|
261 | 271 | lock_cmd = CEPH_LOCK_UNLOCK; |
---|
262 | 272 | |
---|
| 273 | + if (op == CEPH_MDS_OP_SETFILELOCK && F_UNLCK == fl->fl_type) { |
---|
| 274 | + err = try_unlock_file(file, fl); |
---|
| 275 | + if (err <= 0) |
---|
| 276 | + return err; |
---|
| 277 | + } |
---|
| 278 | + |
---|
263 | 279 | err = ceph_lock_message(CEPH_LOCK_FCNTL, op, inode, lock_cmd, wait, fl); |
---|
264 | 280 | if (!err) { |
---|
265 | | - if (op == CEPH_MDS_OP_SETFILELOCK) { |
---|
| 281 | + if (op == CEPH_MDS_OP_SETFILELOCK && F_UNLCK != fl->fl_type) { |
---|
266 | 282 | dout("mds locked, locking locally\n"); |
---|
267 | 283 | err = posix_lock_file(file, fl, NULL); |
---|
268 | 284 | if (err) { |
---|
.. | .. |
---|
298 | 314 | spin_lock(&ci->i_ceph_lock); |
---|
299 | 315 | if (ci->i_ceph_flags & CEPH_I_ERROR_FILELOCK) { |
---|
300 | 316 | err = -EIO; |
---|
301 | | - } else { |
---|
302 | | - /* see comment in ceph_lock */ |
---|
303 | | - fl->fl_ops = &ceph_fl_lock_ops; |
---|
304 | | - atomic_inc(&ci->i_filelock_ref); |
---|
305 | 317 | } |
---|
306 | 318 | spin_unlock(&ci->i_ceph_lock); |
---|
307 | 319 | if (err < 0) { |
---|
.. | .. |
---|
320 | 332 | else |
---|
321 | 333 | lock_cmd = CEPH_LOCK_UNLOCK; |
---|
322 | 334 | |
---|
| 335 | + if (F_UNLCK == fl->fl_type) { |
---|
| 336 | + err = try_unlock_file(file, fl); |
---|
| 337 | + if (err <= 0) |
---|
| 338 | + return err; |
---|
| 339 | + } |
---|
| 340 | + |
---|
323 | 341 | err = ceph_lock_message(CEPH_LOCK_FLOCK, CEPH_MDS_OP_SETFILELOCK, |
---|
324 | 342 | inode, lock_cmd, wait, fl); |
---|
325 | | - if (!err) { |
---|
| 343 | + if (!err && F_UNLCK != fl->fl_type) { |
---|
326 | 344 | err = locks_lock_file_wait(file, fl); |
---|
327 | 345 | if (err) { |
---|
328 | 346 | ceph_lock_message(CEPH_LOCK_FLOCK, |
---|