| .. | .. | 
|---|
| 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, | 
|---|