]> 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)
committerYan, Zheng <zyan@redhat.com>
Mon, 13 Oct 2014 06:43:00 +0000 (14:43 +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>
src/client/Client.cc
src/client/Client.h
src/client/fuse_ll.cc
src/include/ceph_fs.h
src/mds/Server.cc

index c30b45219078fcbcc68160bd066c7366864571c1..aeb0530f7f2170a7b008f10b6c9ffb3cecf26c62 100644 (file)
@@ -7292,7 +7292,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")
@@ -7309,6 +7309,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
@@ -7330,8 +7333,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) {
@@ -7382,6 +7398,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)
@@ -7493,16 +7533,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;
@@ -7530,7 +7570,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;
 }
@@ -9606,28 +9646,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 5669c6600c85be34268f44196c06bce860dfbbe4..f4582a5581d3d9d155f002c8945e7e036e7be1c2 100644 (file)
@@ -639,8 +639,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);
@@ -694,7 +694,8 @@ private:
   }
 
   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);
@@ -910,8 +911,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 1da509435ba409641ba51d1f7b6f1804437c8dd6..21facb97cacf4cff976dd25f0a2413882aa59e62 100644 (file)
@@ -665,7 +665,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);
 }
 
@@ -697,7 +697,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 84f59faebc8a7a620ad1f0709ce5bc46b47f2630..e2159db6048b19af4997ec13297eaca4e455cccc 100644 (file)
@@ -3182,13 +3182,20 @@ void Server::handle_client_file_setlock(MDRequestRef& mdr)
   dout(10) << "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;
@@ -3206,16 +3213,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 &&