ceph: check if file lock exists before sending unlock request
authorYan, Zheng <zyan@redhat.com>
Tue, 11 Feb 2020 14:54:43 +0000 (22:54 +0800)
committerIlya Dryomov <idryomov@gmail.com>
Mon, 30 Mar 2020 10:42:40 +0000 (12:42 +0200)
When a process exits, kernel closes its files. locks_remove_file()
is called to remove file locks on these files. locks_remove_file()
tries unlocking files even there is no file lock.

Signed-off-by: "Yan, Zheng" <zyan@redhat.com>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
fs/ceph/locks.c

index 544e9e8..d6b9166 100644 (file)
@@ -210,6 +210,21 @@ static int ceph_lock_wait_for_completion(struct ceph_mds_client *mdsc,
        return 0;
 }
 
+static int try_unlock_file(struct file *file, struct file_lock *fl)
+{
+       int err;
+       unsigned int orig_flags = fl->fl_flags;
+       fl->fl_flags |= FL_EXISTS;
+       err = locks_lock_file_wait(file, fl);
+       fl->fl_flags = orig_flags;
+       if (err == -ENOENT) {
+               if (!(orig_flags & FL_EXISTS))
+                       err = 0;
+               return err;
+       }
+       return 1;
+}
+
 /**
  * Attempt to set an fcntl lock.
  * For now, this just goes away to the server. Later it may be more awesome.
@@ -255,9 +270,15 @@ int ceph_lock(struct file *file, int cmd, struct file_lock *fl)
        else
                lock_cmd = CEPH_LOCK_UNLOCK;
 
+       if (op == CEPH_MDS_OP_SETFILELOCK && F_UNLCK == fl->fl_type) {
+               err = try_unlock_file(file, fl);
+               if (err <= 0)
+                       return err;
+       }
+
        err = ceph_lock_message(CEPH_LOCK_FCNTL, op, inode, lock_cmd, wait, fl);
        if (!err) {
-               if (op == CEPH_MDS_OP_SETFILELOCK) {
+               if (op == CEPH_MDS_OP_SETFILELOCK && F_UNLCK != fl->fl_type) {
                        dout("mds locked, locking locally\n");
                        err = posix_lock_file(file, fl, NULL);
                        if (err) {
@@ -311,9 +332,15 @@ int ceph_flock(struct file *file, int cmd, struct file_lock *fl)
        else
                lock_cmd = CEPH_LOCK_UNLOCK;
 
+       if (F_UNLCK == fl->fl_type) {
+               err = try_unlock_file(file, fl);
+               if (err <= 0)
+                       return err;
+       }
+
        err = ceph_lock_message(CEPH_LOCK_FLOCK, CEPH_MDS_OP_SETFILELOCK,
                                inode, lock_cmd, wait, fl);
-       if (!err) {
+       if (!err && F_UNLCK != fl->fl_type) {
                err = locks_lock_file_wait(file, fl);
                if (err) {
                        ceph_lock_message(CEPH_LOCK_FLOCK,