From ccbdf514717cb0e48d67b57197d6e538faeea415 Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Mon, 13 Oct 2014 10:44:46 +0800 Subject: [PATCH] client: allow interrupting blocked file lock operation 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 (cherry picked from commit 4134c149d3759dd6a3aaa1a353b77bbfe8e9491b) --- src/client/Client.cc | 68 ++++++++++++++++++++++++++++++++++++------- src/client/Client.h | 11 +++---- src/client/fuse_ll.cc | 4 +-- src/include/ceph_fs.h | 6 ++-- src/mds/Server.cc | 16 ++++++---- 5 files changed, 81 insertions(+), 24 deletions(-) diff --git a/src/client/Client.cc b/src/client/Client.cc index 91262cfc3e38..26e6410aaf02 100644 --- a/src/client/Client.cc +++ b/src/client/Client.cc @@ -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(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); } // ========================================= diff --git a/src/client/Client.h b/src/client/Client.h index 6c3274e38cc7..f102892b679b 100644 --- a/src/client/Client.h +++ b/src/client/Client.h @@ -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); diff --git a/src/client/fuse_ll.cc b/src/client/fuse_ll.cc index cccb64287e25..47339125623e 100644 --- a/src/client/fuse_ll.cc +++ b/src/client/fuse_ll.cc @@ -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 diff --git a/src/include/ceph_fs.h b/src/include/ceph_fs.h index 10b52a5033ab..d16df6272c2f 100644 --- a/src/include/ceph_fs.h +++ b/src/include/ceph_fs.h @@ -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 diff --git a/src/mds/Server.cc b/src/mds/Server.cc index 3a96f931a26c..80a0fba9b521 100644 --- a/src/mds/Server.cc +++ b/src/mds/Server.cc @@ -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 && -- 2.47.3