]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
client: allow interrupting blocked file lock operation
authorYan, Zheng <zyan@redhat.com>
Mon, 13 Oct 2014 02:44:46 +0000 (10:44 +0800)
committerGreg Farnum <gfarnum@redhat.com>
Fri, 13 Feb 2015 22:41:09 +0000 (14:41 -0800)
This commit introduce two new types of setfilelock request. Unlike
setfilelock (UNLOCK) request, these two new types of setfilelock request
do not drop locks that have alread been acquired, they only interrupt
blocked setfilelock request.

Signed-off-by: Yan, Zheng <zyan@redhat.com>
(cherry picked from commit 4134c149d3759dd6a3aaa1a353b77bbfe8e9491b)

src/client/Client.cc
src/client/Client.h
src/client/fuse_ll.cc
src/include/ceph_fs.h
src/mds/Server.cc

index 91262cfc3e38d04a17202e79ef431ac57b36ed5b..26e6410aaf02a01937a08073b321db17780c6d91 100644 (file)
@@ -6868,7 +6868,7 @@ int Client::statfs(const char *path, struct statvfs *stbuf)
 }
 
 int Client::_do_filelock(Inode *in, Fh *fh, int lock_type, int op, int sleep,
-                        struct flock *fl, uint64_t owner)
+                        struct flock *fl, uint64_t owner, void *fuse_req)
 {
   ldout(cct, 10) << "_do_filelock ino " << in->ino
                 << (lock_type == CEPH_LOCK_FCNTL ? " fcntl" : " flock")
@@ -6885,6 +6885,9 @@ int Client::_do_filelock(Inode *in, Fh *fh, int lock_type, int op, int sleep,
   else
     return -EIO;
 
+  if (op != CEPH_MDS_OP_SETFILELOCK || lock_cmd == CEPH_LOCK_UNLOCK)
+    sleep = 0;
+
   /*
    * Set the most significant bit, so that MDS knows the 'owner'
    * is sufficient to identify the owner of lock. (old code uses
@@ -6906,8 +6909,21 @@ int Client::_do_filelock(Inode *in, Fh *fh, int lock_type, int op, int sleep,
   req->head.args.filelock_change.length = fl->l_len;
   req->head.args.filelock_change.wait = sleep;
 
+  int ret;
   bufferlist bl;
-  int ret = make_request(req, -1, -1, NULL, NULL, -1, &bl);
+
+  if (sleep && switch_interrupt_cb && fuse_req) {
+    // enable interrupt
+    switch_interrupt_cb(fuse_req, req->get());
+
+    ret = make_request(req, -1, -1, NULL, NULL, -1, &bl);
+
+    // disable interrupt
+    switch_interrupt_cb(fuse_req, NULL);
+    put_request(req);
+  } else {
+    ret = make_request(req, -1, -1, NULL, NULL, -1, &bl);
+  }
 
   if (ret == 0) {
     if (op == CEPH_MDS_OP_GETFILELOCK) {
@@ -6958,6 +6974,30 @@ int Client::_do_filelock(Inode *in, Fh *fh, int lock_type, int op, int sleep,
   return ret;
 }
 
+int Client::_interrupt_filelock(MetaRequest *req)
+{
+  Inode *in = req->inode();
+
+  int lock_type;
+  if (req->head.args.filelock_change.rule == CEPH_LOCK_FLOCK)
+    lock_type = CEPH_LOCK_FLOCK_INTR;
+  else if (req->head.args.filelock_change.rule == CEPH_LOCK_FCNTL)
+    lock_type = CEPH_LOCK_FCNTL_INTR;
+  else
+    assert(0);
+
+  MetaRequest *intr_req = new MetaRequest(CEPH_MDS_OP_SETFILELOCK);
+  filepath path;
+  in->make_nosnap_relative_path(path);
+  intr_req->set_filepath(path);
+  intr_req->set_inode(in);
+  intr_req->head.args.filelock_change = req->head.args.filelock_change;
+  intr_req->head.args.filelock_change.rule = lock_type;
+  intr_req->head.args.filelock_change.type = CEPH_LOCK_UNLOCK;
+
+  return make_request(intr_req, -1, -1, NULL, NULL, -1);
+}
+
 void Client::_encode_filelocks(Inode *in, bufferlist& bl)
 {
   if (!in->fcntl_locks && !in->flock_locks)
@@ -7069,16 +7109,16 @@ int Client::_getlk(Fh *fh, struct flock *fl, uint64_t owner)
   return ret;
 }
 
-int Client::_setlk(Fh *fh, struct flock *fl, uint64_t owner, int sleep)
+int Client::_setlk(Fh *fh, struct flock *fl, uint64_t owner, int sleep, void *fuse_req)
 {
   Inode *in = fh->inode;
   ldout(cct, 10) << "_setlk " << fh << " ino " << in->ino << dendl;
-  int ret =  _do_filelock(in, fh, CEPH_LOCK_FCNTL, CEPH_MDS_OP_SETFILELOCK, sleep, fl, owner);
+  int ret =  _do_filelock(in, fh, CEPH_LOCK_FCNTL, CEPH_MDS_OP_SETFILELOCK, sleep, fl, owner, fuse_req);
   ldout(cct, 10) << "_setlk " << fh << " ino " << in->ino << " result=" << ret << dendl;
   return ret;
 }
 
-int Client::_flock(Fh *fh, int cmd, uint64_t owner)
+int Client::_flock(Fh *fh, int cmd, uint64_t owner, void *fuse_req)
 {
   Inode *in = fh->inode;
   ldout(cct, 10) << "_flock " << fh << " ino " << in->ino << dendl;
@@ -7106,7 +7146,7 @@ int Client::_flock(Fh *fh, int cmd, uint64_t owner)
   fl.l_type = type;
   fl.l_whence = SEEK_SET;
 
-  int ret =  _do_filelock(in, fh, CEPH_LOCK_FLOCK, CEPH_MDS_OP_SETFILELOCK, sleep, &fl, owner);
+  int ret =  _do_filelock(in, fh, CEPH_LOCK_FLOCK, CEPH_MDS_OP_SETFILELOCK, sleep, &fl, owner, fuse_req);
   ldout(cct, 10) << "_flock " << fh << " ino " << in->ino << " result=" << ret << dendl;
   return ret;
 }
@@ -9012,28 +9052,36 @@ int Client::ll_getlk(Fh *fh, struct flock *fl, uint64_t owner)
   return _getlk(fh, fl, owner);
 }
 
-int Client::ll_setlk(Fh *fh, struct flock *fl, uint64_t owner, int sleep)
+int Client::ll_setlk(Fh *fh, struct flock *fl, uint64_t owner, int sleep, void *fuse_req)
 {
   Mutex::Locker lock(client_lock);
 
   ldout(cct, 3) << "ll_setlk  (fh) " << fh << " " << fh->inode->ino << dendl;
   tout(cct) << "ll_setk (fh)" << (unsigned long)fh << std::endl;
 
-  return _setlk(fh, fl, owner, sleep);
+  return _setlk(fh, fl, owner, sleep, fuse_req);
 }
 
-int Client::ll_flock(Fh *fh, int cmd, uint64_t owner)
+int Client::ll_flock(Fh *fh, int cmd, uint64_t owner, void *fuse_req)
 {
   Mutex::Locker lock(client_lock);
 
   ldout(cct, 3) << "ll_flock  (fh) " << fh << " " << fh->inode->ino << dendl;
   tout(cct) << "ll_flock (fh)" << (unsigned long)fh << std::endl;
 
-  return _flock(fh, cmd, owner);
+  return _flock(fh, cmd, owner, fuse_req);
 }
 
 void Client::ll_interrupt(void *d)
 {
+  Mutex::Locker lock(client_lock);
+
+  MetaRequest *req = static_cast<MetaRequest*>(d);
+  ldout(cct, 3) << "ll_interrupt tid " << req->get_tid() << dendl;
+  tout(cct) << "ll_interrupt tid " << req->get_tid() << std::endl;
+
+  assert(req->head.op == CEPH_MDS_OP_SETFILELOCK);
+  _interrupt_filelock(req);
 }
 
 // =========================================
index 6c3274e38cc73368ed191ec600fa2d3271578d2f..f102892b679b87be1f67c77179db7b8732b9cf98 100644 (file)
@@ -609,8 +609,8 @@ private:
   int _sync_fs();
   int _fallocate(Fh *fh, int mode, int64_t offset, int64_t length);
   int _getlk(Fh *fh, struct flock *fl, uint64_t owner);
-  int _setlk(Fh *fh, struct flock *fl, uint64_t owner, int sleep);
-  int _flock(Fh *fh, int cmd, uint64_t owner);
+  int _setlk(Fh *fh, struct flock *fl, uint64_t owner, int sleep, void *fuse_req=NULL);
+  int _flock(Fh *fh, int cmd, uint64_t owner, void *fuse_req=NULL);
 
   int get_or_create(Inode *dir, const char* name,
                    Dentry **pdn, bool expect_null=false);
@@ -621,7 +621,8 @@ private:
   inodeno_t _get_inodeno(Inode *in);
 
   int _do_filelock(Inode *in, Fh *fh, int lock_type, int op, int sleep,
-                  struct flock *fl, uint64_t owner);
+                  struct flock *fl, uint64_t owner, void *fuse_req=NULL);
+  int _interrupt_filelock(MetaRequest *req);
   void _encode_filelocks(Inode *in, bufferlist& bl);
   void _release_filelocks(Fh *fh);
   void _update_lock_state(struct flock *fl, uint64_t owner, ceph_lock_state_t *lock_state);
@@ -831,8 +832,8 @@ public:
   int ll_fallocate(Fh *fh, int mode, loff_t offset, loff_t length);
   int ll_release(Fh *fh);
   int ll_getlk(Fh *fh, struct flock *fl, uint64_t owner);
-  int ll_setlk(Fh *fh, struct flock *fl, uint64_t owner, int sleep);
-  int ll_flock(Fh *fh, int cmd, uint64_t owner);
+  int ll_setlk(Fh *fh, struct flock *fl, uint64_t owner, int sleep, void *fuse_req);
+  int ll_flock(Fh *fh, int cmd, uint64_t owner, void *fuse_req);
   void ll_interrupt(void *d);
   int ll_get_stripe_osd(struct Inode *in, uint64_t blockno,
                        ceph_file_layout* layout);
index cccb64287e259e09f09d3811cce7825fb8668995..47339125623e5deb8ca2eb490f9c7b4eda7330d6 100644 (file)
@@ -662,7 +662,7 @@ static void fuse_ll_setlk(fuse_req_t req, fuse_ino_t ino,
     return;
   }
 
-  int r = cfuse->client->ll_setlk(fh, lock, fi->lock_owner, sleep);
+  int r = cfuse->client->ll_setlk(fh, lock, fi->lock_owner, sleep, req);
   fuse_reply_err(req, -r);
 }
 
@@ -694,7 +694,7 @@ static void fuse_ll_flock(fuse_req_t req, fuse_ino_t ino,
     return;
   }
 
-  int r = cfuse->client->ll_flock(fh, cmd, fi->lock_owner);
+  int r = cfuse->client->ll_flock(fh, cmd, fi->lock_owner, req);
   fuse_reply_err(req, -r);
 }
 #endif
index 10b52a5033abe1792e069e1e03331e74e162ede8..d16df6272c2f36d5bc3c47daa69083f29bf07352 100644 (file)
@@ -505,8 +505,10 @@ 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
index 3a96f931a26c231fab5ff57a91fb31f495dc42d7..80a0fba9b52148c7f8441b04ae5201462c036efd 100644 (file)
@@ -3085,13 +3085,20 @@ void Server::handle_client_file_setlock(MDRequestRef& mdr)
   dout(0) << "handle_client_file_setlock: " << set_lock << dendl;
 
   ceph_lock_state_t *lock_state = NULL;
+  bool interrupt = false;
 
   // get the appropriate lock state
   switch (req->head.args.filelock_change.rule) {
+  case CEPH_LOCK_FLOCK_INTR:
+    interrupt = true;
+    // fall-thru
   case CEPH_LOCK_FLOCK:
     lock_state = &cur->flock_locks;
     break;
 
+  case CEPH_LOCK_FCNTL_INTR:
+    interrupt = true;
+    // fall-thru
   case CEPH_LOCK_FCNTL:
     lock_state = &cur->fcntl_locks;
     break;
@@ -3110,16 +3117,15 @@ void Server::handle_client_file_setlock(MDRequestRef& mdr)
     if (lock_state->is_waiting(set_lock)) {
       dout(10) << " unlock removing waiting lock " << set_lock << dendl;
       lock_state->remove_waiting(set_lock);
-    } else {
+      cur->take_waiting(CInode::WAIT_FLOCK, waiters);
+    } else if (!interrupt) {
       dout(10) << " unlock attempt on " << set_lock << dendl;
       lock_state->remove_lock(set_lock, activated_locks);
       cur->take_waiting(CInode::WAIT_FLOCK, waiters);
     }
-    reply_request(mdr, 0);
-    /* For now we're ignoring the activated locks because their responses
-     * will be sent when the lock comes up again in rotation by the MDS.
-     * It's a cheap hack, but it's easy to code. */
     mds->queue_waiters(waiters);
+
+    reply_request(mdr, 0);
   } else {
     dout(10) << " lock attempt on " << set_lock << dendl;
     if (mdr->more()->flock_was_waiting &&