| .. | .. |
|---|
| 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 inode *inode = file_inode(dst->fl_file); |
|---|
| 36 | 36 | atomic_inc(&ceph_inode(inode)->i_filelock_ref); |
|---|
| 37 | 37 | } |
|---|
| 38 | 38 | |
|---|
| .. | .. |
|---|
| 59 | 59 | static int ceph_lock_message(u8 lock_type, u16 operation, struct inode *inode, |
|---|
| 60 | 60 | int cmd, u8 wait, struct file_lock *fl) |
|---|
| 61 | 61 | { |
|---|
| 62 | | - struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc; |
|---|
| 62 | + struct ceph_mds_client *mdsc = ceph_sb_to_mdsc(inode->i_sb); |
|---|
| 63 | 63 | struct ceph_mds_request *req; |
|---|
| 64 | 64 | int err; |
|---|
| 65 | 65 | u64 length = 0; |
|---|
| .. | .. |
|---|
| 73 | 73 | * window. Caller function will decrease the counter. |
|---|
| 74 | 74 | */ |
|---|
| 75 | 75 | fl->fl_ops = &ceph_fl_lock_ops; |
|---|
| 76 | | - atomic_inc(&ceph_inode(inode)->i_filelock_ref); |
|---|
| 76 | + fl->fl_ops->fl_copy_lock(fl, NULL); |
|---|
| 77 | 77 | } |
|---|
| 78 | 78 | |
|---|
| 79 | 79 | if (operation != CEPH_MDS_OP_SETFILELOCK || cmd == CEPH_LOCK_UNLOCK) |
|---|
| .. | .. |
|---|
| 206 | 206 | return 0; |
|---|
| 207 | 207 | } |
|---|
| 208 | 208 | |
|---|
| 209 | +static int try_unlock_file(struct file *file, struct file_lock *fl) |
|---|
| 210 | +{ |
|---|
| 211 | + int err; |
|---|
| 212 | + unsigned int orig_flags = fl->fl_flags; |
|---|
| 213 | + fl->fl_flags |= FL_EXISTS; |
|---|
| 214 | + err = locks_lock_file_wait(file, fl); |
|---|
| 215 | + fl->fl_flags = orig_flags; |
|---|
| 216 | + if (err == -ENOENT) { |
|---|
| 217 | + if (!(orig_flags & FL_EXISTS)) |
|---|
| 218 | + err = 0; |
|---|
| 219 | + return err; |
|---|
| 220 | + } |
|---|
| 221 | + return 1; |
|---|
| 222 | +} |
|---|
| 223 | + |
|---|
| 209 | 224 | /** |
|---|
| 210 | 225 | * Attempt to set an fcntl lock. |
|---|
| 211 | 226 | * For now, this just goes away to the server. Later it may be more awesome. |
|---|
| .. | .. |
|---|
| 236 | 251 | spin_lock(&ci->i_ceph_lock); |
|---|
| 237 | 252 | if (ci->i_ceph_flags & CEPH_I_ERROR_FILELOCK) { |
|---|
| 238 | 253 | 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 | 254 | } |
|---|
| 249 | 255 | spin_unlock(&ci->i_ceph_lock); |
|---|
| 250 | 256 | if (err < 0) { |
|---|
| .. | .. |
|---|
| 260 | 266 | else |
|---|
| 261 | 267 | lock_cmd = CEPH_LOCK_UNLOCK; |
|---|
| 262 | 268 | |
|---|
| 269 | + if (op == CEPH_MDS_OP_SETFILELOCK && F_UNLCK == fl->fl_type) { |
|---|
| 270 | + err = try_unlock_file(file, fl); |
|---|
| 271 | + if (err <= 0) |
|---|
| 272 | + return err; |
|---|
| 273 | + } |
|---|
| 274 | + |
|---|
| 263 | 275 | err = ceph_lock_message(CEPH_LOCK_FCNTL, op, inode, lock_cmd, wait, fl); |
|---|
| 264 | 276 | if (!err) { |
|---|
| 265 | | - if (op == CEPH_MDS_OP_SETFILELOCK) { |
|---|
| 277 | + if (op == CEPH_MDS_OP_SETFILELOCK && F_UNLCK != fl->fl_type) { |
|---|
| 266 | 278 | dout("mds locked, locking locally\n"); |
|---|
| 267 | 279 | err = posix_lock_file(file, fl, NULL); |
|---|
| 268 | 280 | if (err) { |
|---|
| .. | .. |
|---|
| 298 | 310 | spin_lock(&ci->i_ceph_lock); |
|---|
| 299 | 311 | if (ci->i_ceph_flags & CEPH_I_ERROR_FILELOCK) { |
|---|
| 300 | 312 | 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 | 313 | } |
|---|
| 306 | 314 | spin_unlock(&ci->i_ceph_lock); |
|---|
| 307 | 315 | if (err < 0) { |
|---|
| .. | .. |
|---|
| 320 | 328 | else |
|---|
| 321 | 329 | lock_cmd = CEPH_LOCK_UNLOCK; |
|---|
| 322 | 330 | |
|---|
| 331 | + if (F_UNLCK == fl->fl_type) { |
|---|
| 332 | + err = try_unlock_file(file, fl); |
|---|
| 333 | + if (err <= 0) |
|---|
| 334 | + return err; |
|---|
| 335 | + } |
|---|
| 336 | + |
|---|
| 323 | 337 | err = ceph_lock_message(CEPH_LOCK_FLOCK, CEPH_MDS_OP_SETFILELOCK, |
|---|
| 324 | 338 | inode, lock_cmd, wait, fl); |
|---|
| 325 | | - if (!err) { |
|---|
| 339 | + if (!err && F_UNLCK != fl->fl_type) { |
|---|
| 326 | 340 | err = locks_lock_file_wait(file, fl); |
|---|
| 327 | 341 | if (err) { |
|---|
| 328 | 342 | ceph_lock_message(CEPH_LOCK_FLOCK, |
|---|