ceph: fix file lock interruption
authorYan, Zheng <zyan@redhat.com>
Tue, 14 Oct 2014 02:33:35 +0000 (10:33 +0800)
committerIlya Dryomov <idryomov@redhat.com>
Wed, 17 Dec 2014 17:09:49 +0000 (20:09 +0300)
When a lock operation is interrupted, current code sends a unlock request to
MDS to undo the lock operation. This method does not work as expected because
the unlock request can drop locks that have already been acquired.

The fix is use the newly introduced CEPH_LOCK_FCNTL_INTR/CEPH_LOCK_FLOCK_INTR
requests to interrupt blocked file lock request. These requests do not drop
locks that have alread been acquired, they only interrupt blocked file lock
request.

Signed-off-by: Yan, Zheng <zyan@redhat.com>
fs/ceph/locks.c
fs/ceph/mds_client.c
fs/ceph/mds_client.h
include/linux/ceph/ceph_fs.h

index fbc39c47bacd17150581e2741531c610e5e89f56..c35c5c614e381764d4e8418c8327369d19ff8936 100644 (file)
@@ -9,6 +9,8 @@
 #include <linux/ceph/pagelist.h>
 
 static u64 lock_secret;
+static int ceph_lock_wait_for_completion(struct ceph_mds_client *mdsc,
+                                         struct ceph_mds_request *req);
 
 static inline u64 secure_addr(void *addr)
 {
@@ -40,6 +42,9 @@ static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file,
        u64 length = 0;
        u64 owner;
 
+       if (operation != CEPH_MDS_OP_SETFILELOCK || cmd == CEPH_LOCK_UNLOCK)
+               wait = 0;
+
        req = ceph_mdsc_create_request(mdsc, operation, USE_AUTH_MDS);
        if (IS_ERR(req))
                return PTR_ERR(req);
@@ -68,6 +73,9 @@ static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file,
        req->r_args.filelock_change.length = cpu_to_le64(length);
        req->r_args.filelock_change.wait = wait;
 
+       if (wait)
+               req->r_wait_for_completion = ceph_lock_wait_for_completion;
+
        err = ceph_mdsc_do_request(mdsc, inode, req);
 
        if (operation == CEPH_MDS_OP_GETFILELOCK) {
@@ -96,6 +104,52 @@ static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file,
        return err;
 }
 
+static int ceph_lock_wait_for_completion(struct ceph_mds_client *mdsc,
+                                         struct ceph_mds_request *req)
+{
+       struct ceph_mds_request *intr_req;
+       struct inode *inode = req->r_inode;
+       int err, lock_type;
+
+       BUG_ON(req->r_op != CEPH_MDS_OP_SETFILELOCK);
+       if (req->r_args.filelock_change.rule == CEPH_LOCK_FCNTL)
+               lock_type = CEPH_LOCK_FCNTL_INTR;
+       else if (req->r_args.filelock_change.rule == CEPH_LOCK_FLOCK)
+               lock_type = CEPH_LOCK_FLOCK_INTR;
+       else
+               BUG_ON(1);
+       BUG_ON(req->r_args.filelock_change.type == CEPH_LOCK_UNLOCK);
+
+       err = wait_for_completion_interruptible(&req->r_completion);
+       if (!err)
+               return 0;
+
+       dout("ceph_lock_wait_for_completion: request %llu was interrupted\n",
+            req->r_tid);
+
+       intr_req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SETFILELOCK,
+                                           USE_AUTH_MDS);
+       if (IS_ERR(intr_req))
+               return PTR_ERR(intr_req);
+
+       intr_req->r_inode = inode;
+       ihold(inode);
+       intr_req->r_num_caps = 1;
+
+       intr_req->r_args.filelock_change = req->r_args.filelock_change;
+       intr_req->r_args.filelock_change.rule = lock_type;
+       intr_req->r_args.filelock_change.type = CEPH_LOCK_UNLOCK;
+
+       err = ceph_mdsc_do_request(mdsc, inode, intr_req);
+       ceph_mdsc_put_request(intr_req);
+
+       if (err && err != -ERESTARTSYS)
+               return err;
+
+       wait_for_completion(&req->r_completion);
+       return 0;
+}
+
 /**
  * Attempt to set an fcntl lock.
  * For now, this just goes away to the server. Later it may be more awesome.
@@ -143,11 +197,6 @@ int ceph_lock(struct file *file, int cmd, struct file_lock *fl)
                                     err);
                        }
                }
-
-       } else if (err == -ERESTARTSYS) {
-               dout("undoing lock\n");
-               ceph_lock_message(CEPH_LOCK_FCNTL, op, file,
-                                 CEPH_LOCK_UNLOCK, 0, fl);
        }
        return err;
 }
@@ -186,11 +235,6 @@ int ceph_flock(struct file *file, int cmd, struct file_lock *fl)
                                          file, CEPH_LOCK_UNLOCK, 0, fl);
                        dout("got %d on flock_lock_file_wait, undid lock", err);
                }
-       } else if (err == -ERESTARTSYS) {
-               dout("undoing lock\n");
-               ceph_lock_message(CEPH_LOCK_FLOCK,
-                                 CEPH_MDS_OP_SETFILELOCK,
-                                 file, CEPH_LOCK_UNLOCK, 0, fl);
        }
        return err;
 }
index a92d3f5c6c12fa3ae0b7308c9fcd379ac821cc67..5a47ed760e6d4e6bd78ecdb19bf945edc1935f1d 100644 (file)
@@ -2208,6 +2208,8 @@ int ceph_mdsc_do_request(struct ceph_mds_client *mdsc,
                        &req->r_completion, req->r_timeout);
                if (err == 0)
                        err = -EIO;
+       } else if (req->r_wait_for_completion) {
+               err = req->r_wait_for_completion(mdsc, req);
        } else {
                err = wait_for_completion_killable(&req->r_completion);
        }
index 3288359353e9b84783a0d5ef65c06141398e625c..230bda791d4f44df5127a9e878ad501d302acaf1 100644 (file)
@@ -166,6 +166,11 @@ struct ceph_mds_client;
  */
 typedef void (*ceph_mds_request_callback_t) (struct ceph_mds_client *mdsc,
                                             struct ceph_mds_request *req);
+/*
+ * wait for request completion callback
+ */
+typedef int (*ceph_mds_request_wait_callback_t) (struct ceph_mds_client *mdsc,
+                                                struct ceph_mds_request *req);
 
 /*
  * an in-flight mds request
@@ -239,6 +244,7 @@ struct ceph_mds_request {
        struct completion r_completion;
        struct completion r_safe_completion;
        ceph_mds_request_callback_t r_callback;
+       ceph_mds_request_wait_callback_t r_wait_for_completion;
        struct list_head  r_unsafe_item;  /* per-session unsafe list item */
        bool              r_got_unsafe, r_got_safe, r_got_result;
 
index 3c97d5e9b951ed419bfb1663be0c4f1c9d416fd7..31d8b98b7f96b8746c7ab8c086d08cf9c08f4e7d 100644 (file)
@@ -522,8 +522,11 @@ struct ceph_mds_reply_dirfrag {
        __le32 dist[];
 } __attribute__ ((packed));
 
-#define CEPH_LOCK_FCNTL    1
-#define CEPH_LOCK_FLOCK    2
+#define CEPH_LOCK_FCNTL                1
+#define CEPH_LOCK_FLOCK                2
+#define CEPH_LOCK_FCNTL_INTR    3
+#define CEPH_LOCK_FLOCK_INTR    4
+
 
 #define CEPH_LOCK_SHARED   1
 #define CEPH_LOCK_EXCL     2